# # # patch "src/Guitone.cpp" # from [444b0af3793794d34e4657b2fea5e5e983d90ae2] # to [2ac47c52c7ee6fbb935a2d81bbb4e8156b40f45e] # # patch "src/Guitone.h" # from [9c9143ee93f0633494e48c42e0ee0f64d6af46d6] # to [935169a8e02bc159e96a0fc6f52b68429508b7fa] # ============================================================ --- src/Guitone.cpp 444b0af3793794d34e4657b2fea5e5e983d90ae2 +++ src/Guitone.cpp 2ac47c52c7ee6fbb935a2d81bbb4e8156b40f45e @@ -19,8 +19,8 @@ ***************************************************************************/ #include "Guitone.h" -#include "MainWindow.h" -#include "Monotone.h" +#include "WorkspaceWindow.h" +#include "DatabaseWindow.h" #include "Preferences.h" #include "Settings.h" @@ -33,104 +33,87 @@ #include #include #include -#include +#include +#include Guitone::Guitone(int argc, char** argv) - : QApplication(argc, argv), updateDialog(0), somethingLoaded(false) + : QApplication(argc, argv), monotoneManager(0), + somethingLoaded(false), updateDialog(0) { setQuitOnLastWindowClosed(false); - + setOrganizationName("Thomas Keller"); setOrganizationDomain("thomaskeller.biz"); setApplicationName("guitone"); - + // check for updates immediatly on launch if (Settings::getBool("CheckForUpdates", true)) { -#ifdef Q_WS_MACX - CocoaUtil::initialize(); -#else - updateDialog = new ApplicationUpdate(NULL); - if (updateDialog->updateAvailable()) - { - updateDialog->setStayOnTop(); - updateDialog->show(); - } -#endif + checkForApplicationUpdates(); } + monotoneManager = new MonotoneManager(); + // // Try to load something given on the command line // or found in one of the recent items lists // - // FIXME: This is disabled for OSX since it interfers terribly with - // FileOpen events on this platform, i.e. we can't determine - // properly if the program is opened and shortly afterwards gets - // a FileOpen event or if there will no such event and we have to look - // at the command line or in the recent lists for something to load. - // - // What we're doing instead here for Mac OS X (whose users would otherwise - // fail to use guitone by opening it without also opening a workspace or - // database) is to create a global QMenuBar (MacStartMenu), which contains - // the basic file menu entries to open (recent) workspaces and databases - // amongst regular stuff like about dialogs and the update stuff. This is - // certainly not the end for "load recent automatically" on Mac, but a - // workaround. - // -#ifdef Q_WS_MACX - macStartMenu = new MacStartMenu(); - - connect( - macStartMenu, SIGNAL(loadWorkspace(const QString &)), - this, SLOT(loadWorkspace(const QString &)) - ); - - connect( - macStartMenu, SIGNAL(loadDatabase(const QString &)), - this, SLOT(loadDatabase(const QString &)) - ); -#else QTimer::singleShot(0, this, SLOT(loadSomething())); -#endif } Guitone::~Guitone() { I(openWindows.size() == 0); - I(monotoneInstances.size() == 0); if (updateDialog) delete updateDialog; - -#ifdef Q_WS_MACX - disconnect( - macStartMenu, SIGNAL(loadWorkspace(const QString &)), - this, SLOT(loadWorkspace(const QString &)) - ); - - disconnect( - macStartMenu, SIGNAL(loadDatabase(const QString &)), - this, SLOT(loadDatabase(const QString &)) - ); - - delete macStartMenu; -#endif } -#ifndef Q_WS_MACX void Guitone::loadSomething() { + // + // try to set the monotone binary path from the settings + // + QString installedVersion; + if (!monotoneManager->setMonotoneBinaryPath( + Settings::getMtnBinaryPath(), installedVersion)) + { + QMessageBox::critical( + NULL, + tr("Error"), + tr("The path to the monotone binary is either invalid " + "or points to a version of monotone with which guitone can't " + "work with. Guitone requires monotone with an interface version " + "between '%1' and '%2'. Your installation has the interface " + "version '%3'.") + .arg(MonotoneManager::MinInterfaceVersion) + .arg(MonotoneManager::MaxInterfaceVersion) + .arg(installedVersion), + QMessageBox::Ok, 0, 0 + ); + + // note: the pref dialog tries to set the mtn binary path on its + // own again and can only be accepted successfully, if the user + // enters/selects a valid monotone binary path + Preferences dialog(NULL); + + // the user has rejected the dialog, i.e. made no new settings + if (dialog.exec() == QDialog::Rejected) + { + return; + } + } + QStringList args = arguments(); - + if (!somethingLoaded) { D("checking command line arguments"); for (int i=1, j=args.size(); i 0 && loadWorkspace(workspaces.at(0)); + somethingLoaded = workspaces.size() > 0 && tryLoadSomething(workspaces.at(0)); } - + if (!somethingLoaded) { D("trying to load recent database"); QStringList databases = Settings::getItemList("RecentDatabaseList"); - somethingLoaded = databases.size() > 0 && loadDatabase(databases.at(0)); + somethingLoaded = databases.size() > 0 && tryLoadSomething(databases.at(0)); } - - // if still nothing is loaded, prompt the user to load a workspace + + // if still nothing is loaded, prompt the user to load a workspace or database if (!somethingLoaded) { - D("prompting for a workspace"); - QString workspaceDir = - QFileDialog::getExistingDirectory(0, tr("Select your workspace...")); - somethingLoaded = !workspaceDir.isEmpty() && loadWorkspace(workspaceDir); + D("prompting for a workspace or database"); + QString fileOrDir = QFileDialog::getOpenFileName( + 0, + tr("Select your workspace or database...") + ); + somethingLoaded = !fileOrDir.isEmpty() && tryLoadSomething(fileOrDir); } // if nothing could be loaded (= no window could be created), @@ -165,8 +150,24 @@ void Guitone::loadSomething() quit(); } } -#endif +bool Guitone::tryLoadSomething(const QString & path) +{ + bool loaded = true; + try + { + loadFromPath(path); + } + catch (GuitoneException e) + { + W(QString("loading of '%1' failed: %1").arg(path).arg(e)); + loaded = false; + } + D(QString("loading of '%1' succeeded").arg(path)); + + return loaded; +} + // this code is borrowed and adapted from QDesigner - thanks to the Trolls! bool Guitone::event(QEvent * ev) { @@ -177,10 +178,8 @@ bool Guitone::event(QEvent * ev) { QApplication::processEvents(); D("got load event"); - if (loadFromPath(static_cast(ev)->file())) + if (tryLoadSomething(static_cast(ev)->file())) { - QApplication::processEvents(); - D("loading from path succeeded"); somethingLoaded = true; } eaten = true; @@ -190,10 +189,10 @@ bool Guitone::event(QEvent * ev) { D("got close event"); QCloseEvent * closeEvent = static_cast(ev); - + // try to close all windows, if any window refuses to be closed, // just eat the event and do nothing - if (closeAllWindows()) + if (closeAllWindows()) { closeEvent->setAccepted(true); eaten = QApplication::event(ev); @@ -214,197 +213,102 @@ bool Guitone::event(QEvent * ev) return eaten; } -bool Guitone::loadFromPath(const QString & path) +void Guitone::loadFromPath(const QString & path) { + QMutexLocker locker(&lock); + QFileInfo fileInfo(path); if (!fileInfo.exists()) { - W(QString("Non-existant file/folder %1").arg(path)); - return false; + throw new GuitoneException(tr("Non-existant path '%1'")); } - + + MainWindow * wnd; if (fileInfo.isDir()) { - return loadWorkspace(path); + wnd = new WorkspaceWindow(); } - - return loadDatabase(path); -} - -bool Guitone::loadWorkspace(const QString & path) -{ - QMutexLocker locker(&mutex); - - MainWindow * wnd = addWindow(); - if (!addMonotoneInstance(wnd) || !wnd->doLoadWorkspace(path)) + else if (fileInfo.isFile()) { - removeWindow(wnd); - return false; + wnd = new DatabaseWindow(); } - - // now that the workspace is loaded, the window should have gotten a - // reasonable name - emit windowListChanged(); - - wnd->show(); - - return true; -} + else + { + throw new GuitoneException(tr("Path is neither a file nor a directory")); + } -bool Guitone::loadDatabase(const QString & path) -{ - QMutexLocker locker(&mutex); - - MainWindow * wnd = addWindow(); - if (!addMonotoneInstance(wnd) || !wnd->doLoadDatabase(path)) + wnd->init(); + + try { - removeWindow(wnd); - return false; + wnd->load(path); } - // now that the database is loaded, the window should have gotten a - // reasonable name - emit windowListChanged(); - + catch (GuitoneException e) + { + delete wnd; + throw e; + } + + ensureCascadedWindowPlacement(wnd); + openWindows.append(wnd); wnd->show(); - - return true; + + triggerUpdateWindowList(); + emit updateRecentLists(); } -void Guitone::windowClosed(MainWindow * wnd) +void Guitone::loadWorkspace(const QString & path) { - QMutexLocker locker(&mutex); - - removeMonotoneInstance(wnd); - removeWindow(wnd); - if (openWindows.size() == 0) quit(); + try + { + loadFromPath(path); + } + catch (GuitoneException e) + { + QMessageBox::critical( + NULL, + tr("Failed to load workspace"), + tr("The workspace could not be loaded:\n%1").arg(e), + QMessageBox::Ok + ); + } } -MainWindow * Guitone::addWindow() +void Guitone::loadDatabase(const QString & path) { - MainWindow * wnd = new MainWindow(); - - connect( - wnd, SIGNAL(quitApplication()), - this, SLOT(quit()) - ); - - connect( - wnd, SIGNAL(windowClosed(MainWindow *)), - this, SLOT(windowClosed(MainWindow *)) - ); - - connect( - wnd, SIGNAL(loadWorkspace(const QString &)), - this, SLOT(loadWorkspace(const QString &)) - ); - - connect( - wnd, SIGNAL(loadDatabase(const QString &)), - this, SLOT(loadDatabase(const QString &)) - ); - - connect( - this, SIGNAL(windowListChanged()), - wnd, SLOT(updateWindowList()) - ); - - for (int i=0, j=openWindows.size(); i Guitone::windowList() const +void Guitone::triggerUpdateWindowList() { - return openWindows; + QStringList list; + foreach (MainWindow * win, openWindows) + { + list.append(win->windowTitle()); + } + emit updateWindowList(list); } bool Guitone::closeAllWindows() @@ -433,94 +337,87 @@ void Guitone::quit() QApplication::quit(); } -bool Guitone::addMonotoneInstance(MainWindow * wnd) +void Guitone::checkForApplicationUpdates() { - I(wnd); - - Monotone * mtn = new Monotone(wnd); - - // check the current monotone version and prompt the user - // to enter the correct path if there is a problem - while (true) +#ifdef Q_WS_MACX + CocoaUtil::checkForUpdates(); +#else + if (!updateDialog) { - if (mtn->setMtnBinaryPath(Settings::getMtnBinaryPath())) break; - - QMessageBox::critical( - wnd, - tr("Error"), - tr("The path to the monotone binary is either invalid " - "or points to a version of monotone with which guitone can't " - "work with. Guitone requires monotone with an interface version " - "between %2 and %3. You can check the interface version of " - "your monotone installation by executing " - "`mtn automate interface_version`.") - .arg(Monotone::MinInterfaceVersion) - .arg(Monotone::MaxInterfaceVersion), - QMessageBox::Ok, 0, 0 + updateDialog = new UpdateDialog(this); + } + + if (!updateDialog->updateAvailable()) + { + QMessageBox::information( + NULL, + tr("No updates available"), + tr("Your version of guitone (%1) is already up-to-date.") + .arg(GUITONE_VERSION), + QMessageBox::Ok ); - - Preferences dialog(wnd); - - // if new settings have been entered, try to setup the wrapper - if (dialog.exec() == QDialog::Accepted) continue; - - // the user has rejected the dialog, i.e. made no new settings - return false; + return; } - - monotoneInstances.insert(wnd, mtn); - - D(QString("Added monotone instance %1 for %2").arg((qint64)mtn).arg((qint64)wnd)); - - return true; + updateDialog->show(); +#endif } -bool Guitone::removeMonotoneInstance(MainWindow * wnd) +/*! + Ensures 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 +*/ +void Guitone::ensureCascadedWindowPlacement(MainWindow * window) { - I(wnd); - - if (!monotoneInstances.contains(wnd)) return false; - - Monotone * mtn = monotoneInstances.value(wnd); - - D(QString("Removing monotone instance %1 for %2").arg((qint64)mtn).arg((qint64)wnd)); - - delete mtn; - monotoneInstances.remove(wnd); - - return true; -} + int curIdx = openWindows.indexOf(window); -MainWindow * Guitone::findMainWindow(QObject * obj) -{ - do + if (curIdx > 0) { - if (obj->inherits("MainWindow")) break; - obj = obj->parent(); - } while (obj); - - I(obj); - MainWindow * wnd = qobject_cast(obj); - return wnd; -} + MainWindow * prevWnd = openWindows.at(curIdx - 1); + I(prevWnd); -Monotone * Guitone::getMonotoneInstance(QObject * obj) -{ - MainWindow * wnd = findMainWindow(obj); - I(wnd); - I(monotoneInstances.contains(wnd)); - return monotoneInstances.value(wnd); + QDesktopWidget * desk = 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 + window->width() > geom.right() || + newY + window->height() > geom.bottom()) + { + newX = geom.x(); + newY = geom.y(); + } + window->move(newX, newY); + } + } } -void Guitone::lock() +void Guitone::activateWindow(int idx) { - D("lock called"); - mutex.lock(); + if (idx < 0 || idx > openWindows.size() - 1) + return; + + MainWindow * wnd = openWindows.at(idx); + wnd->activateWindow(); + wnd->raise(); } -void Guitone::unlock() +void Guitone::bringAllWindowsToFront() { - D("unlock called"); - mutex.unlock(); + for (int i=0, j=openWindows.size(); iactivateWindow(); + wnd->raise(); + } } ============================================================ --- src/Guitone.h 9c9143ee93f0633494e48c42e0ee0f64d6af46d6 +++ src/Guitone.h 935169a8e02bc159e96a0fc6f52b68429508b7fa @@ -22,68 +22,57 @@ #define GUITONE_H #include "MainWindow.h" -#include "Monotone.h" +#include "MonotoneManager.h" #include "ApplicationUpdate.h" #include "DebugLog.h" -#ifdef Q_WS_MACX -#include "MacStartMenu.h" -#endif - #include #include #include #include +class Monotone; + class Guitone : public QApplication { - Q_OBJECT + Q_OBJECT public: Guitone(int, char**); ~Guitone(); - const QList windowList() const; - - MainWindow * findMainWindow(QObject *); - Monotone * getMonotoneInstance(QObject *); - bool loadFromPath(const QString &); - - void lock(); - void unlock(); - + inline MonotoneManager * manager() { return monotoneManager; } + signals: - void windowListChanged(); + void updateWindowList(const QStringList &); + void updateRecentLists(); +public slots: + void checkForApplicationUpdates(); + + void loadWorkspace(const QString &); + void loadDatabase(const QString &); + + void activateWindow(int); + void bringAllWindowsToFront(); + private slots: - bool loadWorkspace(const QString &); - bool loadDatabase(const QString &); void windowClosed(MainWindow *); -#ifndef Q_WS_MACX void loadSomething(); -#endif void quit(); private: - MainWindow * addWindow(); - void removeWindow(MainWindow *); - - bool addMonotoneInstance(MainWindow *); - bool removeMonotoneInstance(MainWindow *); - + bool tryLoadSomething(const QString &); + void loadFromPath(const QString &); + void triggerUpdateWindowList(); + void ensureCascadedWindowPlacement(MainWindow *); bool closeAllWindows(); - bool event(QEvent *); - QList openWindows; - QMap monotoneInstances; - QMutex mutex; - ApplicationUpdate * updateDialog; + MonotoneManager * monotoneManager; + QList openWindows; + QMutex lock; bool somethingLoaded; - -#ifdef Q_WS_MACX - MacStartMenu * macStartMenu; -#endif - + ApplicationUpdate * updateDialog; }; #endif