# # # patch "src/view/MainWindow.cpp" # from [c4b6cf1f128df54b18ba2a5b8ca2a2fddc0231aa] # to [a32016854c4c6176fec3e49a15d3171bd67cc45b] # # patch "src/view/MainWindow.h" # from [49a87144c3f5ef2d99f1ca0acc4acb11e21a402c] # to [5f1c4888651d0b6ca0273ef517e54f3b46eab047] # ============================================================ --- src/view/MainWindow.cpp c4b6cf1f128df54b18ba2a5b8ca2a2fddc0231aa +++ src/view/MainWindow.cpp a32016854c4c6176fec3e49a15d3171bd67cc45b @@ -19,26 +19,11 @@ ***************************************************************************/ #include "MainWindow.h" -#include "Monotone.h" -#include "Inventory.h" -#include "InventoryItem.h" -#include "GetAttributes.h" -#include "InventoryProxyModel.h" -#include "Splitter.h" -#include "InventoryView.h" -#include "AttributesView.h" -#include "UpdateWorkspace.h" -#include "CommitRevision.h" -#include "CheckoutRevision.h" +#include "MonotoneUtil.h" #include "Platform.h" -#include "Preferences.h" -#include "KeyManagement.h" -#include "About.h" #include "Settings.h" -#include "ChangesetBrowser.h" -#include "WorkspaceCreator.h" -#include "UnaccountedRenames.h" #include "Guitone.h" +#include "InventoryItem.h" #ifdef Q_WS_MAC #include "CocoaUtil.h" @@ -54,39 +39,56 @@ #include #include -MainWindow::MainWindow() - : QMainWindow(), closeCounter(0) +MainWindow::MainWindow(const QString & database, const QString & workspace) + : QMainWindow(), closeCounter(0), databaseFile(database), + workspacePath(workspace) { // ensure that the shortcut keys are properly recognized by linguist QShortcut::tr("Ctrl"); QShortcut::tr("Alt"); QShortcut::tr("Shift"); QShortcut::tr("Meta"); - + setupUi(this); - + // create the main models - invModel = new Inventory(this); - attrModel = new GetAttributes(this); - + invModel = new Inventory(this, workspacePath); + attrModel = new GetAttributes(this, workspacePath); + connect( invModel, SIGNAL(invalidWorkspaceFormat(const QString &)), this, SLOT(invalidWorkspaceFormat(const QString &)) ); - + // ProxyModels proxyModelFolderTree = new InventoryProxyModel(this, true); proxyModelFileList = new InventoryProxyModel(this, false); proxyModelFolderTree->setSourceModel(invModel); proxyModelFileList->setSourceModel(invModel); + // + // The dialog manager + // + dialogManager = new DialogManager(this); + dialogManager->initWithWorkspace(workspace); + + connect( + dialogManager, SIGNAL(revisionCheckedOut(const QString &)), + this, SIGNAL(loadWorkspace(const QString &)) + ); + + connect( + dialogManager, SIGNAL(revisionCommitted(const QString &)), + invModel, SIGNAL(readInventory()) + ); + // tree and list views treeView->setModel(proxyModelFolderTree); treeView->setType(InventoryView::FolderTree); listView->setModel(proxyModelFileList); listView->setType(InventoryView::FileList); attrView->setModel(attrModel); - + // query attributes on click connect( treeView, SIGNAL(clicked(const QModelIndex &)), @@ -96,7 +98,7 @@ MainWindow::MainWindow() listView, SIGNAL(clicked(const QModelIndex &)), this, SLOT(readAttributes(const QModelIndex &)) ); - + // filelist/tree synchronization connect( treeView, SIGNAL(directoryChanged(const QModelIndex &)), @@ -107,26 +109,100 @@ MainWindow::MainWindow() treeView, SLOT(changeDirectory(const QModelIndex &)) ); - // rename the appQuit signal + // file actions from the list view connect( + listView, SIGNAL(diffFile(const QString &)), + this, SLOT(showFileDiff(const QString &)) + ); + + connect( + listView, SIGNAL(diffRevision(const QString &, const QString &, const QString &)), + this, SLOT(showRevisionDiff(const QString &, const QString &, const QString &)) + ); + + connect( + listView, SIGNAL(fileHistory(const QString &)), + this, SLOT(showFileHistory(const QString &)) + ); + + connect( + listView, SIGNAL(openFile(const QString &)), + this, SLOT(openFile(const QString &)) + ); + + // the tree view shows only directories, therefor file diff / file history + // doesn't make sense there + connect( + treeView, SIGNAL(diffRevision(const QString &, const QString &, const QString &)), + this, SLOT(showRevisionDiff(const QString &, const QString &, const QString &)) + ); + + connect( + treeView, SIGNAL(openFile(const QString &)), + this, SLOT(openFile(const QString &)) + ); + + // foward the appQuit signal + connect( actionQuit, SIGNAL(triggered()), this, SIGNAL(quitApplication()) ); - + + // delegate some menu actions... + connect( + actionAbout_guitone, SIGNAL(triggered()), + dialogManager, SLOT(showAbout()) + ); + + connect( + actionPreferences, SIGNAL(triggered()), + dialogManager, SLOT(showPreferences()) + ); + + connect( + actionUpdate_workspace, SIGNAL(triggered()), + dialogManager, SLOT(showUpdateWorkspace()) + ); + + connect( + actionCommit_revision, SIGNAL(triggered()), + dialogManager, SLOT(showCommitRevision()) + ); + + connect( + actionCheckout_revision, SIGNAL(triggered()), + dialogManager, SLOT(showCheckoutRevision()) + ); + + connect( + actionKey_management, SIGNAL(triggered()), + dialogManager, SLOT(showKeyManagement()) + ); + + connect( + actionChangeset_browser, SIGNAL(triggered()), + dialogManager, SLOT(showChangesetBrowser()) + ); + + connect( + actionReload_workspace, SIGNAL(triggered()), + invModel, SLOT(readInventory()) + ); + // update recent workspace and database lists on request - connect( + connect( this, SIGNAL(updatePreviousWorkspacesMenu()), this, SLOT(doUpdatePreviousWorkspacesMenu()) ); - + connect( this, SIGNAL(updatePreviousDatabasesMenu()), this, SLOT(doUpdatePreviousDatabasesMenu()) ); - + doUpdatePreviousWorkspacesMenu(); doUpdatePreviousDatabasesMenu(); - + // set the data for some menu elements actionAll_files->setData(QVariant(InventoryProxyModel::All)); actionAll_changed_files->setData(QVariant(InventoryProxyModel::Changed)); @@ -139,7 +215,7 @@ MainWindow::MainWindow() actionIgnored_files->setData(QVariant(InventoryProxyModel::Ignored)); actionExpand_tree->setData(QVariant(false)); actionHide_ignored_files->setData(QVariant(false)); - + // after laying out everything, restore the splitter views mainSplitter->init(); listSplitter->init(); @@ -156,52 +232,52 @@ void MainWindow::on_actionOpen_Workspace void MainWindow::on_actionOpen_Workspace_triggered() { QString fn = QFileDialog::getExistingDirectory(0, tr("Select your workspace...")); - + if (fn.isEmpty()) { statusBar()->showMessage(tr("Loading aborted"), 2000); return; } - - emit loadWorkspace(fn); + + emit loadWorkspace(fn); } -bool MainWindow::doLoadWorkspace(QString fn) +bool MainWindow::doLoadWorkspace(const QString & fn) { - Monotone * mtn = MTN(this); - - if (!mtn->loadWorkspace(fn)) + QString workspacePath; + try { + workspacePath = MonotoneManager::normalizeWorkspacePath(fn); + APP->manager()->getThreadForWorkspace(workspacePath); + + } + catch (GuitoneException e) + { QMessageBox::critical( this, tr("Failed to load workspace"), - tr("The workspace could not be loaded.\n" - "The last output was:\n\n%1").arg(mtn->getStderr()), + tr("The workspace could not be loaded:\n%1").arg(e), QMessageBox::Ok ); // remove the workspace if it was recorded as recent workspace - Settings::removeItemFromList("RecentWorkspaceList", fn); - + Settings::removeItemFromList("RecentWorkspaceList", workspacePath); + emit updatePreviousWorkspacesMenu(); - + return false; } switchMode(Workspace); - - if (!invModel->readInventory()) - { - C("Could not read inventory"); - return false; - } - + + invModel->readInventory(); + // add the workspace to the recent workspace list // FIXME: the amount of recent workspaces should be made configurable - Settings::addItemToList("RecentWorkspaceList", mtn->getNormalizedWorkspacePath(), 5); - + Settings::addItemToList("RecentWorkspaceList", workspacePath, 5); + emit updatePreviousWorkspacesMenu(); - + return true; } @@ -213,42 +289,45 @@ void MainWindow::on_actionOpen_Database_ QString(), tr("monotone Databases (*.mtn *.db)") ); - + if (fn.isEmpty()) { statusBar()->showMessage(tr("Loading aborted"), 2000); return; } - - emit loadDatabase(fn); + + emit loadDatabase(fn); } -bool MainWindow::doLoadDatabase(QString fn) +bool MainWindow::doLoadDatabase(const QString & fn) { - Monotone * mtn = MTN(this); - if (!mtn->loadDatabase(fn)) + try { + APP->manager()->getThreadForDatabase(fn); + + } + catch (GuitoneException e) + { QMessageBox::critical( this, tr("Failed to load database"), - tr("The database could not be loaded.\n" - "The last output was:\n\n%1").arg(mtn->getStderr()), + tr("The database could not be loaded:\n%1").arg(e), QMessageBox::Ok ); - + Settings::removeItemFromList("RecentDatabaseList", fn); - + emit updatePreviousDatabasesMenu(); - + return false; } - + switchMode(Database); - + Settings::addItemToList("RecentDatabaseList", fn, 5); - + emit updatePreviousDatabasesMenu(); - + return true; } @@ -257,9 +336,9 @@ void MainWindow::switchMode(Mode m) mode = m; windowMode->setCurrentIndex(mode); restoreGeometry(Settings::getWindowGeometry("MainWindow_mode" + mode)); - + QList openWindows = APP->windowList(); - + // ensure somewhat that new windows do not overdraw current ones // by adding a little x/y offset the original position of the window // opened before this window @@ -268,9 +347,9 @@ void MainWindow::switchMode(Mode m) { MainWindow * prevWnd = openWindows.at(curIdx - 1); I(prevWnd); - + QDesktopWidget * desk = APP->desktop(); - + if (desk->numScreens() > 1) { W("No support for window cascading on systems with " @@ -282,7 +361,7 @@ void MainWindow::switchMode(Mode m) QRect geom = desk->availableGeometry(); int newX = prevWnd->x() + cascade; int newY = prevWnd->y() + cascade; - + if (newX + width() > geom.right() || newY + height() > geom.bottom()) { @@ -292,20 +371,16 @@ void MainWindow::switchMode(Mode m) move(newX, newY); } } - + if (mode == Database) { menuView->menuAction()->setVisible(false); menuWorkspace->menuAction()->setVisible(false); menuDatabase->menuAction()->setVisible(true); - - QString path(MTN(this)->getDatabaseFilePath()); - - loadedDatabase->setText(tr("Loaded database: %1").arg( - MTN(this)->getDatabaseFilePath()) - ); - - QFileInfo fi(path); + + loadedDatabase->setText(tr("Loaded database: %1").arg(databaseFile)); + + QFileInfo fi(databaseFile); setWindowTitle( tr("%1 - database mode - guitone").arg(fi.fileName()) ); @@ -316,17 +391,17 @@ void MainWindow::switchMode(Mode m) menuView->menuAction()->setVisible(true); menuWorkspace->menuAction()->setVisible(true); menuDatabase->menuAction()->setVisible(true); - + setWindowTitle( tr("%1 - workspace mode - guitone"). - arg(MonotoneDelegate::getBranchNameShort(this)) + arg(MonotoneUtil::getBranchNameShort(workspacePath)) ); } else { I(false); } - + emit modeChanged(mode); } @@ -335,21 +410,21 @@ void MainWindow::on_actionHide_ignored_f bool hide = actionHide_ignored_files->data().toBool(); proxyModelFolderTree->setHideIgnoredFiles(!hide); proxyModelFileList->setHideIgnoredFiles(!hide); - + actionHide_ignored_files->setText( hide ? tr("Hide ignored files") : tr("Show ignored files") ); - + actionHide_ignored_files->setData(QVariant(!hide)); } void MainWindow::on_menuShow_triggered(QAction * act) { - InventoryProxyModel::ViewOption opt = + InventoryProxyModel::ViewOption opt = (InventoryProxyModel::ViewOption) act->data().toInt(); proxyModelFolderTree->setViewOption(opt); proxyModelFileList->setViewOption(opt); - + // disable any previous action and check the new action entry QList assocWidgets = act->associatedWidgets(); I(assocWidgets.size() > 0); @@ -366,16 +441,16 @@ void MainWindow::on_actionExpand_tree_tr void MainWindow::on_actionExpand_tree_triggered() { bool expanded = actionExpand_tree->data().toBool(); - + if (expanded) treeView->collapseAll(); else treeView->expandAll(); - + actionExpand_tree->setText( expanded ? tr("Expand tree") : tr("Collapse tree") ); - + actionExpand_tree->setData(QVariant(!expanded)); } @@ -384,25 +459,24 @@ void MainWindow::openRecentWorkspace() QAction *action = qobject_cast(sender()); if (action) { - emit loadWorkspace(action->data().toString()); + emit loadWorkspace(action->data().toString()); } } - void MainWindow::openRecentDatabase() { QAction *action = qobject_cast(sender()); if (action) { - emit loadDatabase(action->data().toString()); + emit loadDatabase(action->data().toString()); } } void MainWindow::doUpdatePreviousWorkspacesMenu() { // clear previous actions - menuRecent_Workspaces->clear(); - + menuRecent_Workspaces->clear(); + QStringList previousWs = Settings::getItemList("RecentWorkspaceList"); int elemCount = previousWs.size(); if (elemCount == 0) @@ -412,7 +486,7 @@ void MainWindow::doUpdatePreviousWorkspa } QAction *act; - // add the new actions + // add the new actions for (int i = 0; i < elemCount; ++i) { act = menuRecent_Workspaces->addAction( @@ -427,8 +501,8 @@ void MainWindow::doUpdatePreviousDatabas void MainWindow::doUpdatePreviousDatabasesMenu() { // clear previous actions - menuRecent_Databases->clear(); - + menuRecent_Databases->clear(); + QStringList previousDb = Settings::getItemList("RecentDatabaseList"); int elemCount = previousDb.size(); if (elemCount == 0) @@ -438,7 +512,7 @@ void MainWindow::doUpdatePreviousDatabas } QAction *act; - // add the new actions + // add the new actions for (int i = 0; i < elemCount; ++i) { act = menuRecent_Databases->addAction( @@ -462,18 +536,18 @@ void MainWindow::updateWindowList() menuWindow->removeAction(act); } } - + // TODO: we should integrate a small indicator which window is actually // active here, but this needs central work in the App QList list = APP->windowList(); for (int i=0, j=list.size(); iaddAction( - tr("&%1 %2").arg(i + 1).arg(list.at(i)->windowTitle()), + { + QAction * act = menuWindow->addAction( + tr("&%1 %2").arg(i + 1).arg(list.at(i)->windowTitle()), this, - SLOT(activateOtherWindow()) - ); - act->setData(i); + SLOT(activateOtherWindow()) + ); + act->setData(i); } } @@ -512,67 +586,6 @@ void MainWindow::on_actionBring_all_to_f } } -void MainWindow::on_actionKey_management_triggered() -{ - KeyManagement dialog(this); - dialog.execDocumentModal(); -} - -void MainWindow:: on_actionChangeset_browser_triggered() -{ - ChangesetBrowser dialog(this); - dialog.execDocumentModal(); -} - -void MainWindow::on_actionUpdate_workspace_triggered() -{ - UpdateWorkspace dialog(this); - dialog.execDocumentModal(); -} - -void MainWindow::on_actionCommit_revision_triggered() -{ - CommitRevision dialog(this); - if (dialog.execDocumentModal() == QDialog::Accepted) - { - on_actionReload_workspace_triggered(); - } -} - -void MainWindow::on_actionCheckout_revision_triggered() -{ - CheckoutRevision dialog(this); - int ret = dialog.execDocumentModal(); - - if (ret == 0) - { - QDir checkoutDir = dialog.getSelectedCheckoutDirectory(); - QString revision = dialog.getSelectedRevision(); - WorkspaceCreator creator(this, revision, checkoutDir); - - if (!creator.run()) - { - C("Could not create workspace."); - return; - } - emit loadWorkspace(checkoutDir.absolutePath()); - } -} - -// FIXME: the next two handlers should probably ensure that the according dialog -// is only opened once per application -void MainWindow::on_actionPreferences_triggered() -{ - Preferences dialog(this); - dialog.exec(); -} - -void MainWindow::on_actionAbout_guitone_triggered() -{ - About dialog(this); - dialog.exec(); -} - void MainWindow::on_actionAbout_Qt_triggered() { qApp->aboutQt(); @@ -601,8 +614,6 @@ void MainWindow::invalidWorkspaceFormat( void MainWindow::invalidWorkspaceFormat(const QString & error) { - QString workspacePath = MTN(this)->getNormalizedWorkspacePath(); - QMessageBox::critical( this, tr("Unable to load workspace"), @@ -611,17 +622,17 @@ void MainWindow::invalidWorkspaceFormat( .arg(error), QMessageBox::Ok ); - + Settings::removeItemFromList("RecentWorkspaceList", workspacePath); - + emit updatePreviousWorkspacesMenu(); - + close(); } // FIXME: These two functions are actually a hack: we block the closing of this -// window if a non-blocking (non-modal) dialog is still open which expects that -// its parent window pointer is still valid at some point. As dialogs can be +// window if a non-blocking (non-modal) dialog is still open which expects that +// its parent window pointer is still valid at some point. As dialogs can be // nested, a simple boolean value wouldn't be sufficient since the close action // of the main window would get enabled again as soon as the first subsequent // dialog has been closed, which would lead to segfaults for the one opened in @@ -641,7 +652,7 @@ void MainWindow::closeEvent(QCloseEvent void MainWindow::closeEvent(QCloseEvent * event) { I(closeCounter >= 0); - + // ignore the close event if there are still open dialog windows if (closeCounter > 0) { @@ -649,19 +660,13 @@ void MainWindow::closeEvent(QCloseEvent event->ignore(); return; } - + // the last closed window sets the geometry for the next one which is opened Settings::setWindowGeometry(saveGeometry(), "MainWindow_mode" + mode); event->accept(); emit windowClosed(this); } -void MainWindow::on_actionReload_workspace_triggered() -{ - bool ret = invModel->readInventory(); - if (!ret) C("Could not read inventory."); -} - void MainWindow::on_actionFind_unaccounted_renames_triggered() { QMap renames = invModel->findUnaccountedRenames(); @@ -675,30 +680,55 @@ void MainWindow::on_actionFind_unaccount ); return; } - - UnaccountedRenames dlg(this, renames); - dlg.execDocumentModal(); + + dialogManager->showUnaccountedRenames(renames); } void MainWindow::readAttributes(const QModelIndex & index) { QModelIndex sourceIndex = static_cast(index.model())->mapToSource(index); InventoryItem * item = static_cast(sourceIndex.internalPointer()); - + if (item->isRootDirectory() || item->isCdUp()) { D("item is pseudo item (root or cdup)"); attrModel->revert(); - return; + return; } - + if (item->hasStatus(InventoryItem::Dropped) || !item->isTracked()) { D("item is not tracked or dropped"); attrModel->revert(); return; } - + attrModel->readAttributes(item->getPath()); } +void MainWindow::openFile(const QString & filePath) +{ + QFileInfo file(workspacePath + "/" + filePath); + if (!file.exists()) + { + QMessageBox::critical( + this, + tr("Error"), + tr("The file you're trying to open does not exist."), + QMessageBox::Ok, 0, 0 + ); + return; + } + + if (!Platform::openFile(this, file.absoluteFilePath())) + { + QMessageBox::critical( + this, + tr("Error"), + tr("Unable to open files on your platform - please contact the " + "author about this problem."), + QMessageBox::Ok, 0, 0 + ); + } +} + ============================================================ --- src/view/MainWindow.h 49a87144c3f5ef2d99f1ca0acc4acb11e21a402c +++ src/view/MainWindow.h 5f1c4888651d0b6ca0273ef517e54f3b46eab047 @@ -23,32 +23,29 @@ #include "ui_main_window.h" -class QModelIndex; +#include "Inventory.h" +#include "InventoryProxyModel.h" +#include "GetAttributes.h" +#include "DialogManager.h" -class Inventory; -class GetAttributes; -class InventoryProxyModel; -class InventoryView; -class AttributesView; - class MainWindow: public QMainWindow, private Ui::MainWindow { Q_OBJECT public: enum Mode { Workspace = 0, Database}; - MainWindow(); + MainWindow(const QString &, const QString &); ~MainWindow(); - - bool doLoadWorkspace(QString); - bool doLoadDatabase(QString); + + bool doLoadWorkspace(const QString &); + bool doLoadDatabase(const QString &); void enableClosing(); void disableClosing(); - + public slots: - void doUpdatePreviousWorkspacesMenu(); + void doUpdatePreviousWorkspacesMenu(); void doUpdatePreviousDatabasesMenu(); - + signals: void modeChanged(Mode); void windowClosed(MainWindow *); @@ -57,44 +54,43 @@ signals: void updatePreviousDatabasesMenu(); void loadDatabase(const QString &); void loadWorkspace(const QString &); - + void revisionSelected(const QString &); + void keyGenerated(); + private slots: + //! menu actions void on_actionOpen_Workspace_triggered(); void on_actionOpen_Database_triggered(); void on_actionHide_ignored_files_triggered(); void on_menuShow_triggered(QAction *); void on_actionExpand_tree_triggered(); - void on_actionUpdate_workspace_triggered(); - void on_actionCommit_revision_triggered(); - void on_actionCheckout_revision_triggered(); - void on_actionKey_management_triggered(); - void on_actionPreferences_triggered(); - void on_actionAbout_guitone_triggered(); void on_actionAbout_Qt_triggered(); - void on_actionChangeset_browser_triggered(); void on_actionBring_all_to_front_triggered(); void on_actionCheck_for_updates_triggered(); - void on_actionReload_workspace_triggered(); void on_actionFind_unaccounted_renames_triggered(); - + void openRecentWorkspace(); void openRecentDatabase(); void updateWindowList(); void activateOtherWindow(); + void openFile(const QString &); void invalidWorkspaceFormat(const QString &); void readAttributes(const QModelIndex &); - + private: void closeEvent(QCloseEvent *); void switchMode(Mode); - - Inventory * invModel; - GetAttributes * attrModel; + + DialogManager * dialogManager; + Inventory * invModel; + GetAttributes * attrModel; InventoryProxyModel * proxyModelFolderTree; InventoryProxyModel * proxyModelFileList; Mode mode; int closeCounter; + + QString databaseFile; + QString workspacePath; }; - #endif