/guitone-1.0rc5/src/GuitoneStandalone.cpp
C++ | 360 lines | 252 code | 52 blank | 56 comment | 26 complexity | 4065a372bbe0842b1a7fb6410f629cbe MD5 | raw file
Possible License(s): GPL-3.0
- /***************************************************************************
- * Copyright (C) 2008 by Thomas Keller *
- * me@thomaskeller.biz *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation, either version 3 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program. If not, see <http://www.gnu.org/licenses/>. *
- ***************************************************************************/
- #include "GuitoneStandalone.h"
- #include "WorkspaceWindow.h"
- #include "DatabaseWindow.h"
- #include "ServerWindow.h"
- #include "Settings.h"
- #include <QMutexLocker>
- #include <QMessageBox>
- #include <QFileInfo>
- #include <QFileDialog>
- #include <QDesktopWidget>
- #include <QFileOpenEvent>
- #ifdef Q_WS_MACX
- #include <Carbon/Carbon.h>
- #endif
- GuitoneStandalone::GuitoneStandalone(int & argc, char** argv)
- : GuitoneCore(argc, argv), openPrompt(0), somethingLoaded(false)
- {
- #ifdef Q_WS_MACX
- // this is kind of backwards, but there is no other way to do it:
- // to hide an application from the doc on Mac OS X, you have to
- // set LSUIElement to 1 in its Info.plist - this is done globally
- // for guitone so we don't get an application menu if we're running
- // in driver mode; however this also hides the app in standalone mode!
- // so, as a little trick we're doing what Qt does inside
- // qapplication_mac.cpp: we're explicitely foregrounding the
- // standalone version, and therefor ignoring the plist setting
- ProcessSerialNumber psn;
- if (GetCurrentProcess(&psn) == noErr)
- {
- OSStatus returnCode =
- TransformProcessType(&psn, kProcessTransformToForegroundApplication);
- if (returnCode != 0)
- {
- C(QString("Could not bring the application to front (error %1)")
- .arg(returnCode));
- }
- }
- #endif
- setQuitOnLastWindowClosed(false);
- programArgs = arguments();
- connect(
- this, SIGNAL(monotoneBinaryPathSet()),
- this, SLOT(tryLoadSomething()),
- Qt::QueuedConnection
- );
- }
- GuitoneStandalone::~GuitoneStandalone()
- {
- // wait until all windows have been closed
- while (openWindows.size() > 0)
- QCoreApplication::processEvents();
- }
- void GuitoneStandalone::tryLoadSomething()
- {
- I(manager()->monotoneBinaryPathSet());
- D("checking command line arguments and file open requests");
- for (int i=1, j=programArgs.size(); i<j; i++)
- {
- // we're ok if any of these arguments could be loaded
- somethingLoaded = somethingLoaded || loadFromString(programArgs.at(i));
- }
- if (somethingLoaded) return;
- // if nothing was requested, prompt the user to load a workspace or database
- openPrompt = new OpenPrompt(NULL);
- connect(
- openPrompt, SIGNAL(loadFromHandle(const MonotoneHandlePtr &)),
- this, SLOT(loadFromHandle(const MonotoneHandlePtr &))
- );
- connect(
- openPrompt, SIGNAL(loadFromString(const QString &)),
- this, SLOT(loadFromString(const QString &))
- );
- connect(
- openPrompt, SIGNAL(quitApp()),
- this, SLOT(quit())
- );
- connect(
- openPrompt, SIGNAL(quitApp()),
- openPrompt, SLOT(deleteLater())
- );
- connect(
- this, SIGNAL(updateRecentLists()),
- openPrompt, SLOT(updateRecentLists())
- );
- connect(
- this, SIGNAL(loadFromStringFailed(const QString &, const QString &)),
- openPrompt, SLOT(loadFromStringFailed(const QString &, const QString &))
- );
- openPrompt->show();
- }
- // this code is borrowed and adapted from QDesigner - thanks to the Trolls!
- bool GuitoneStandalone::event(QEvent * ev)
- {
- bool eaten = false;
- switch (ev->type())
- {
- case QEvent::FileOpen:
- {
- QFileOpenEvent * fopev = reinterpret_cast<QFileOpenEvent *>(ev);
- QString fileOrUri = fopev->file();
- if (fileOrUri.isEmpty())
- {
- fileOrUri = QString(fopev->url().toEncoded());
- }
- if (!manager()->monotoneBinaryPathSet())
- {
- D("deferring FileOpen event since binary path is not yet set");
- programArgs.push_back(fileOrUri);
- }
- else
- {
- loadFromString(fileOrUri);
- }
- eaten = true;
- break;
- }
- #ifdef Q_WS_MAC
- // I'm not sure if this is a bug in Qt or a bug in my code, but
- // if you click on "Quit" in the application menu in the dock,
- // Qt receives a Close event on the application, not on the widget
- // and completly ignores that. (Close events are only documented on
- // widgets, _not_ the application!) Calling quit() here directly will
- // at first close all windows (see our quit() implementation above)
- // and then call quit() again, so we just close all windos here
- // and, oh magic, even though quitOnLastWindowClose is set to false
- // Qt magically ends the event loop as well!
- case QEvent::Close:
- {
- eaten = closeAllWindows();
- }
- #endif
- default:
- eaten = QCoreApplication::event(ev);
- break;
- }
- return eaten;
- }
- void GuitoneStandalone::loadFromHandle(const MonotoneHandlePtr & handle)
- {
- QMutexLocker locker(&lock);
- MainWindow * wnd = 0;
- I(!handle.isNull());
- switch (handle->getType())
- {
- case MonotoneHandle::database_handle:
- wnd = new DatabaseWindow();
- Settings::addItemToList("RecentDatabaseList", handle->getData(), 5);
- break;
- case MonotoneHandle::workspace_handle:
- wnd = new WorkspaceWindow();
- Settings::addItemToList("RecentWorkspaceList", handle->getData(), 5);
- break;
- case MonotoneHandle::server_handle:
- wnd = new ServerWindow();
- Settings::addItemToList("RecentServerList", handle->getData(), 5);
- break;
- default:
- I(false);
- }
- wnd->init();
- wnd->load(handle);
- openWindows.append(wnd);
- ensureCascadedWindowPlacement(wnd);
- wnd->show();
- triggerUpdateWindowList();
- emit updateRecentLists();
- if (openPrompt)
- {
- openPrompt->hide();
- // we delete the cruft and invalidate all the set-up connections
- // once we have something loaded to avoid unwanted side effects
- // calling delete here directly will fail because there are still
- // some signals which might have to be delivered to the dialog
- // before
- openPrompt->deleteLater();
- openPrompt = 0;
- }
- }
- bool GuitoneStandalone::loadFromString(const QString & pathOrURI)
- {
- MonotoneHandlePtr handle;
- try
- {
- handle = MonotoneHandle::create(pathOrURI);
- if (handle->getType() == MonotoneHandle::empty_handle)
- {
- throw new GuitoneException(tr("Source was empty"));
- }
- }
- catch (GuitoneException & e)
- {
- Settings::removeItemFromList("RecentWorkspaceList", pathOrURI);
- Settings::removeItemFromList("RecentDatabaseList", pathOrURI);
- Settings::removeItemFromList("RecentServerList", pathOrURI);
- emit updateRecentLists();
- W(QString("loading of '%1' failed: %2").arg(pathOrURI).arg(e.what()));
- emit loadFromStringFailed(pathOrURI, e.what());
- return false;
- }
- loadFromHandle(handle);
- return true;
- }
- void GuitoneStandalone::windowClosed(MainWindow * wnd)
- {
- QMutexLocker locker(&lock);
- int i = openWindows.indexOf(wnd);
- I(i != -1);
- openWindows.removeAt(i);
- delete wnd;
- if (openWindows.size() == 0)
- {
- quit();
- }
- triggerUpdateWindowList();
- }
- void GuitoneStandalone::triggerUpdateWindowList()
- {
- QStringList list;
- foreach (MainWindow * win, openWindows)
- {
- list.append(win->windowTitle());
- }
- emit updateWindowList(list);
- }
- bool GuitoneStandalone::closeAllWindows()
- {
- // do we need to close any windows?
- if (openWindows.size() > 0)
- {
- // let all open windows close themselves to allow them cleaning up
- // stuff and saving settings
- // note that if the last window is closed, quit() is called again,
- // so we return here after closing all windows to avoid recursion
- // problems
- foreach (MainWindow * wnd, openWindows)
- {
- // QWidget::close() returns true if the widget could be closed,
- // i.e. hasn't ignored the close event
- if (!wnd->close()) return false;
- }
- }
- return true;
- }
- void GuitoneStandalone::quit()
- {
- if (!closeAllWindows()) return;
- GuitoneCore::quit();
- }
- /*!
- 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 GuitoneStandalone::ensureCascadedWindowPlacement(MainWindow * window)
- {
- int curIdx = openWindows.indexOf(window);
- if (curIdx > 0)
- {
- MainWindow * prevWnd = openWindows.at(curIdx - 1);
- I(prevWnd);
- QDesktopWidget * desk = QApplication::desktop();
- int cascade = 20;
- QRect geom = desk->availableGeometry(prevWnd);
- 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 GuitoneStandalone::activateWindow(int idx)
- {
- if (idx < 0 || idx > openWindows.size() - 1)
- return;
- MainWindow * wnd = openWindows.at(idx);
- wnd->activateWindow();
- wnd->raise();
- }
- void GuitoneStandalone::raiseAllWindows()
- {
- for (int i=0, j=openWindows.size(); i<j; i++)
- {
- MainWindow * wnd = openWindows.at(i);
- wnd->activateWindow();
- wnd->raise();
- }
- }