# # # patch "src/view/MainWindow.cpp" # from [a32016854c4c6176fec3e49a15d3171bd67cc45b] # to [5939804133e67de08c47753f3aafe3b532e4be97] # # patch "src/view/MainWindow.h" # from [5f1c4888651d0b6ca0273ef517e54f3b46eab047] # to [78c7c12c18b07825e2ef8955d6689ef69d02d67f] # ============================================================ --- src/view/MainWindow.cpp a32016854c4c6176fec3e49a15d3171bd67cc45b +++ src/view/MainWindow.cpp 5939804133e67de08c47753f3aafe3b532e4be97 @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2006 by Thomas Keller * + * Copyright (C) 2007 by Thomas Keller * * address@hidden * * * * This program is free software; you can redistribute it and/or modify * @@ -19,716 +19,87 @@ ***************************************************************************/ #include "MainWindow.h" -#include "MonotoneUtil.h" -#include "Platform.h" -#include "Settings.h" +#include "WorkspaceMenuBar.h" +#include "DatabaseMenuBar.h" #include "Guitone.h" -#include "InventoryItem.h" -#ifdef Q_WS_MAC -#include "CocoaUtil.h" -#else -#include "ApplicationUpdate.h" -#endif - -#include -#include -#include -#include #include -#include #include -MainWindow::MainWindow(const QString & database, const QString & workspace) - : QMainWindow(), closeCounter(0), databaseFile(database), - workspacePath(workspace) +MainWindow::MainWindow() : QMainWindow() { - // 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, 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 &)), - this, SLOT(readAttributes(const QModelIndex &)) - ); - connect( - listView, SIGNAL(clicked(const QModelIndex &)), - this, SLOT(readAttributes(const QModelIndex &)) - ); - - // filelist/tree synchronization - connect( - treeView, SIGNAL(directoryChanged(const QModelIndex &)), - listView, SLOT(changeDirectory(const QModelIndex &)) - ); - connect( - listView, SIGNAL(directoryChanged(const QModelIndex &)), - treeView, SLOT(changeDirectory(const QModelIndex &)) - ); - - // 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()), + menuBar, SIGNAL(showAbout()), dialogManager, SLOT(showAbout()) ); connect( - actionPreferences, SIGNAL(triggered()), + menuBar, SIGNAL(showPreferences()), dialogManager, SLOT(showPreferences()) ); connect( - actionUpdate_workspace, SIGNAL(triggered()), - dialogManager, SLOT(showUpdateWorkspace()) + menuBar, SIGNAL(closeWindow()), + this, SLOT(close()) ); connect( - actionCommit_revision, SIGNAL(triggered()), - dialogManager, SLOT(showCommitRevision()) + menuBar, SIGNAL(loadWorkspace(const QString &)), + APP, SLOT(loadWorkspace(const QString &)) ); connect( - actionCheckout_revision, SIGNAL(triggered()), - dialogManager, SLOT(showCheckoutRevision()) + menuBar, SIGNAL(loadDatabase(const QString &)), + APP, SLOT(loadDatabase(const QString &)) ); connect( - actionKey_management, SIGNAL(triggered()), - dialogManager, SLOT(showKeyManagement()) + menuBar, SIGNAL(checkForApplicationUpdates()), + APP, SLOT(checkForApplicationUpdates()) ); connect( - actionChangeset_browser, SIGNAL(triggered()), - dialogManager, SLOT(showChangesetBrowser()) + menuBar, SIGNAL(activateWindow(int)), + APP, SLOT(activateWindow(int)) ); connect( - actionReload_workspace, SIGNAL(triggered()), - invModel, SLOT(readInventory()) + menuBar, SIGNAL(bringAllWindowsToFront()), + APP, SLOT(bringAllWindowsToFront()) ); - // update recent workspace and database lists on request connect( - this, SIGNAL(updatePreviousWorkspacesMenu()), - this, SLOT(doUpdatePreviousWorkspacesMenu()) + APP, SIGNAL(updateRecentLists()), + menuBar, SLOT(updateRecentLists()) ); connect( - this, SIGNAL(updatePreviousDatabasesMenu()), - this, SLOT(doUpdatePreviousDatabasesMenu()) + APP, SIGNAL(updateWindowList(const QStringList &)), + menuBar, SLOT(updateWindowList(const QStringList &)) ); - - doUpdatePreviousWorkspacesMenu(); - doUpdatePreviousDatabasesMenu(); - - // set the data for some menu elements - actionAll_files->setData(QVariant(InventoryProxyModel::All)); - actionAll_changed_files->setData(QVariant(InventoryProxyModel::Changed)); - actionPatched_files->setData(QVariant(InventoryProxyModel::Patched)); - actionAdded_files->setData(QVariant(InventoryProxyModel::Added)); - actionRemoved_files->setData(QVariant(InventoryProxyModel::Dropped)); - actionRenamed_files->setData(QVariant(InventoryProxyModel::Renamed)); - actionMissing_files->setData(QVariant(InventoryProxyModel::Missing)); - actionUnknown_files->setData(QVariant(InventoryProxyModel::Unknown)); - 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(); } MainWindow::~MainWindow() { - delete invModel; - delete attrModel; - delete proxyModelFolderTree; - delete proxyModelFileList; + cleanup(); } -void MainWindow::on_actionOpen_Workspace_triggered() +void MainWindow::cleanup() { - QString fn = QFileDialog::getExistingDirectory(0, tr("Select your workspace...")); - - if (fn.isEmpty()) - { - statusBar()->showMessage(tr("Loading aborted"), 2000); - return; - } - - emit loadWorkspace(fn); + if (menuBar) delete menuBar; + if (dialogManager) delete dialogManager; } -bool MainWindow::doLoadWorkspace(const QString & fn) +void MainWindow::init() { - 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%1").arg(e), - QMessageBox::Ok - ); - - // remove the workspace if it was recorded as recent workspace - Settings::removeItemFromList("RecentWorkspaceList", workspacePath); - - emit updatePreviousWorkspacesMenu(); - - return false; - } - - switchMode(Workspace); - - invModel->readInventory(); - - // add the workspace to the recent workspace list - // FIXME: the amount of recent workspaces should be made configurable - Settings::addItemToList("RecentWorkspaceList", workspacePath, 5); - - emit updatePreviousWorkspacesMenu(); - - return true; + cleanup(); + menuBar = new MenuBar(this); + dialogManager = new DialogManager(this); } -void MainWindow::on_actionOpen_Database_triggered() -{ - QString fn = QFileDialog::getOpenFileName( - 0, - tr("Select your database..."), - QString(), - tr("monotone Databases (*.mtn *.db)") - ); - - if (fn.isEmpty()) - { - statusBar()->showMessage(tr("Loading aborted"), 2000); - return; - } - - emit loadDatabase(fn); -} - -bool MainWindow::doLoadDatabase(const QString & 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%1").arg(e), - QMessageBox::Ok - ); - - Settings::removeItemFromList("RecentDatabaseList", fn); - - emit updatePreviousDatabasesMenu(); - - return false; - } - - switchMode(Database); - - Settings::addItemToList("RecentDatabaseList", fn, 5); - - emit updatePreviousDatabasesMenu(); - - return true; -} - -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 - int curIdx = openWindows.indexOf(this); - if (curIdx > 0) - { - 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 " - "more than one monitor yet."); - } - else - { - int cascade = 20; - QRect geom = desk->availableGeometry(); - int newX = prevWnd->x() + cascade; - int newY = prevWnd->y() + cascade; - - if (newX + width() > geom.right() || - newY + height() > geom.bottom()) - { - newX = geom.x(); - newY = geom.y(); - } - move(newX, newY); - } - } - - if (mode == Database) - { - menuView->menuAction()->setVisible(false); - menuWorkspace->menuAction()->setVisible(false); - menuDatabase->menuAction()->setVisible(true); - - loadedDatabase->setText(tr("Loaded database: %1").arg(databaseFile)); - - QFileInfo fi(databaseFile); - setWindowTitle( - tr("%1 - database mode - guitone").arg(fi.fileName()) - ); - } - else - if (mode == Workspace) - { - menuView->menuAction()->setVisible(true); - menuWorkspace->menuAction()->setVisible(true); - menuDatabase->menuAction()->setVisible(true); - - setWindowTitle( - tr("%1 - workspace mode - guitone"). - arg(MonotoneUtil::getBranchNameShort(workspacePath)) - ); - } - else - { - I(false); - } - - emit modeChanged(mode); -} - -void MainWindow::on_actionHide_ignored_files_triggered() -{ - 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) 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); - // we assume that this action is only assigned to one widget and that - // is the QMenu widget we need to find out all the other actions - QList list = assocWidgets[0]->actions(); - for (int i=0, j=list.size(); isetChecked(false); - } - act->setChecked(true); -} - -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)); -} - -void MainWindow::openRecentWorkspace() -{ - QAction *action = qobject_cast(sender()); - if (action) - { - emit loadWorkspace(action->data().toString()); - } -} - -void MainWindow::openRecentDatabase() -{ - QAction *action = qobject_cast(sender()); - if (action) - { - emit loadDatabase(action->data().toString()); - } -} - -void MainWindow::doUpdatePreviousWorkspacesMenu() -{ - // clear previous actions - menuRecent_Workspaces->clear(); - - QStringList previousWs = Settings::getItemList("RecentWorkspaceList"); - int elemCount = previousWs.size(); - if (elemCount == 0) - { - menuRecent_Workspaces->addAction(tr("No previous workspaces available.")); - return; - } - - QAction *act; - // add the new actions - for (int i = 0; i < elemCount; ++i) - { - act = menuRecent_Workspaces->addAction( - tr("&%1 %2").arg(i + 1).arg(previousWs[i]), - this, - SLOT(openRecentWorkspace()) - ); - act->setData(previousWs[i]); - } -} - -void MainWindow::doUpdatePreviousDatabasesMenu() -{ - // clear previous actions - menuRecent_Databases->clear(); - - QStringList previousDb = Settings::getItemList("RecentDatabaseList"); - int elemCount = previousDb.size(); - if (elemCount == 0) - { - menuRecent_Databases->addAction(tr("No previous databases available.")); - return; - } - - QAction *act; - // add the new actions - for (int i = 0; i < elemCount; ++i) - { - act = menuRecent_Databases->addAction( - tr("&%1 %2").arg(i + 1).arg(previousDb[i]), - this, - SLOT(openRecentDatabase()) - ); - act->setData(previousDb[i]); - } -} - -void MainWindow::updateWindowList() -{ - // remove old actions - QList actions = menuWindow->actions(); - for (int i=0, j=actions.size(); idata().isValid()) - { - 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()), - this, - SLOT(activateOtherWindow()) - ); - act->setData(i); - } -} - -void MainWindow::activateOtherWindow() -{ - // FIXME: the list of windows is not constant, theoretically it might - // be possible that we've just been notified to raise a window which - // was just removed. Since we can't / won't transport pointers around - // we try to identify the window by its index in the windowList again, - // if this fails, we do nothing. It might occur that we raise the wrong - // window by this, of course, but all this is better than the alternatives. - QAction *action = qobject_cast(sender()); - if (action) - { - int idx = action->data().toInt(); - QList list = APP->windowList(); - if (list.size() > idx) - { - MainWindow * wnd = list.at(idx); - wnd->activateWindow(); - wnd->raise(); - } - } -} - -void MainWindow::on_actionBring_all_to_front_triggered() -{ - // FIXME: we should implement something here which prevents window - // flickering if all windows are already activated - QList list = APP->windowList(); - for (int i=0, j=list.size(); iactivateWindow(); - wnd->raise(); - } -} - -void MainWindow::on_actionAbout_Qt_triggered() -{ - qApp->aboutQt(); -} - -void MainWindow::on_actionCheck_for_updates_triggered() -{ -#ifdef Q_WS_MACX - CocoaUtil::checkForUpdates(); -#else - ApplicationUpdate dlg(this); - if (!dlg.updateAvailable()) - { - QMessageBox::information( - this, - tr("No updates available"), - tr("Your version of guitone (%1) is already up-to-date.") - .arg(GUITONE_VERSION), - QMessageBox::Ok - ); - return; - } - dlg.exec(); -#endif -} - -void MainWindow::invalidWorkspaceFormat(const QString & error) -{ - QMessageBox::critical( - this, - tr("Unable to load workspace"), - tr("The workspace '%1' could not be loaded.\nmonotone returned:\n\n%2") - .arg(workspacePath) - .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 -// 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 -// first place. Of course the underlying bug (that the app segfaults at all) -// should be fixed someday... -void MainWindow::enableClosing() -{ - I(closeCounter > 0); - closeCounter--; -} - -void MainWindow::disableClosing() -{ - closeCounter++; -} - void MainWindow::closeEvent(QCloseEvent * event) { - I(closeCounter >= 0); - - // ignore the close event if there are still open dialog windows - if (closeCounter > 0) - { - D(QString("Ignoring close request for %1").arg((int)this)); - 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_actionFind_unaccounted_renames_triggered() -{ - QMap renames = invModel->findUnaccountedRenames(); - if (renames.size() == 0) - { - QMessageBox::information( - this, - tr("Nothing found"), - tr("No unaccounted renames found for this workspace."), - QMessageBox::Ok - ); - return; - } - - 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; - } - - 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 5f1c4888651d0b6ca0273ef517e54f3b46eab047 +++ src/view/MainWindow.h 78c7c12c18b07825e2ef8955d6689ef69d02d67f @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2006 by Thomas Keller * + * Copyright (C) 2007 by Thomas Keller * * address@hidden * * * * This program is free software; you can redistribute it and/or modify * @@ -21,76 +21,31 @@ #ifndef MAINWINDOW_H #define MAINWINDOW_H -#include "ui_main_window.h" - -#include "Inventory.h" -#include "InventoryProxyModel.h" -#include "GetAttributes.h" +#include "MenuBar.h" #include "DialogManager.h" +#include -class MainWindow: public QMainWindow, private Ui::MainWindow +class MainWindow : public QMainWindow { Q_OBJECT - public: - enum Mode { Workspace = 0, Database}; - MainWindow(const QString &, const QString &); + MainWindow(); ~MainWindow(); + virtual void init(); + virtual bool load(const QString &) = 0; - bool doLoadWorkspace(const QString &); - bool doLoadDatabase(const QString &); - void enableClosing(); - void disableClosing(); - -public slots: - void doUpdatePreviousWorkspacesMenu(); - void doUpdatePreviousDatabasesMenu(); - signals: - void modeChanged(Mode); void windowClosed(MainWindow *); - void quitApplication(); - void updatePreviousWorkspacesMenu(); - 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_actionAbout_Qt_triggered(); - void on_actionBring_all_to_front_triggered(); - void on_actionCheck_for_updates_triggered(); - void on_actionFind_unaccounted_renames_triggered(); +protected: + void cleanup(); - void openRecentWorkspace(); - void openRecentDatabase(); - void updateWindowList(); - void activateOtherWindow(); - void openFile(const QString &); - void invalidWorkspaceFormat(const QString &); - void readAttributes(const QModelIndex &); + MenuBar * menuBar; + DialogManager * dialogManager; private: void closeEvent(QCloseEvent *); - void switchMode(Mode); - - DialogManager * dialogManager; - Inventory * invModel; - GetAttributes * attrModel; - InventoryProxyModel * proxyModelFolderTree; - InventoryProxyModel * proxyModelFileList; - Mode mode; - int closeCounter; - - QString databaseFile; - QString workspacePath; }; #endif +