#
#
# patch "guitone.pro"
# from [ed7cd2d7b369b4fe918668e2d94b57090c962c8b]
# to [c255b8e3fe24ff5499440754f8e8acab3f651a8a]
#
# patch "res/forms/main_window.ui"
# from [47bc6a1094496073f1befd61a20d5b2fed5f5f39]
# to [6c5b7e9f7df0fc48722a97cf9e48cbc51ea46e2d]
#
# patch "src/Guitone.cpp"
# from [c9a9565124a9a03a2d6d61b51f0a59650bcaaaf7]
# to [53f0f6999f12e2ee3ffb89b6f74acc0dbdcfc753]
#
# patch "src/Guitone.h"
# from [f56c7a540e0185fa8ef7008a7b35d2af4376bbb7]
# to [881dffddd5bdd9999f2ed36ecdcaa019de153cb4]
#
# patch "src/util/CocoaUtil.h"
# from [023ccba6801d260542c9311a01e3ca39e20b69c5]
# to [8424a0c7f877f0167271bb2386fd00472a32f551]
#
# patch "src/util/CocoaUtil.mm"
# from [122f1726e6d7f1289c48a51074063ebb753bf26e]
# to [af7058410a39e0fa1f7fdb9d1ff5019261fd0960]
#
# patch "src/view/MainWindow.cpp"
# from [1e0d6b1c8dc5305f78a6e72f8dae9cf118ab5866]
# to [d90f84228175d6b63f614248e511611bcf167cf3]
#
# patch "src/view/MainWindow.h"
# from [b662cc90c17734984e6a62fa323d2168def713ba]
# to [627db714e8b3f00acd00cd164015dffc4c3f3075]
#
============================================================
--- guitone.pro ed7cd2d7b369b4fe918668e2d94b57090c962c8b
+++ guitone.pro c255b8e3fe24ff5499440754f8e8acab3f651a8a
@@ -183,10 +183,10 @@ macx {
macx {
# add sources for Sparkle
HEADERS += src/util/CocoaUtil.h
- OBJECTIVE_SOURCES += src/util/CocoaUtil.mm
+ SOURCES += src/util/CocoaUtil.mm
- # add the Sparkle framework
- QMAKE_LFLAGS += -framework Sparkle
+ # add the Sparkle and the Carbon framework
+ QMAKE_LFLAGS += -framework Sparkle -framework Carbon
# copy i18n resources into the final app bundle and
# put the current version number into Info.plist
============================================================
--- res/forms/main_window.ui 47bc6a1094496073f1befd61a20d5b2fed5f5f39
+++ res/forms/main_window.ui 6c5b7e9f7df0fc48722a97cf9e48cbc51ea46e2d
@@ -26,7 +26,7 @@
-
- 0
+ 1
@@ -90,29 +90,6 @@
-
-
-
- 0
-
-
- 0
-
- -
-
-
- Currently there is no workspace or database loaded.
-
-To open a workspace, go to File > Open workspace
-or File > Open Database for a database respectively.
-
-
- Qt::AlignCenter
-
-
-
-
-
@@ -476,9 +453,9 @@ or File > Open Database for a database r
- AttributesView
- QTreeView
-
+ Splitter
+ QSplitter
+
InventoryView
@@ -486,9 +463,9 @@ or File > Open Database for a database r
- Splitter
- QSplitter
-
+ AttributesView
+ QTreeView
+
============================================================
--- src/Guitone.cpp c9a9565124a9a03a2d6d61b51f0a59650bcaaaf7
+++ src/Guitone.cpp 53f0f6999f12e2ee3ffb89b6f74acc0dbdcfc753
@@ -24,14 +24,92 @@
#include "Preferences.h"
#include "Settings.h"
-#ifdef Q_WS_MAC
+#ifdef Q_WS_MACX
#include "CocoaUtil.h"
+#include
#endif
#include
#include
#include
+#include
+#include
+#ifdef Q_WS_MACX
+static OSErr OpenDocumentAE(const AppleEvent * evt, AppleEvent *, long)
+{
+ AEDescList docList;
+ DescType retType;
+ AEKeyword keywd;
+ FSRef fsref;
+ long count, size;
+
+ AEGetParamDesc(evt, keyDirectObject, typeAEList, &docList);
+ AECountItems(&docList, &count);
+
+ OSErr err;
+
+ for (int i = 1; i <= count; i++)
+ {
+ err = AEGetNthPtr(&docList, i, typeFSRef, &keywd,
+ &retType, (Ptr)&fsref, sizeof(fsref), &size);
+
+ if (err != noErr)
+ {
+ W("Couldn't retrieve FSRef.");
+ continue;
+ }
+
+ QString path = CocoaUtil::FSRefToPath(fsref);
+ if (path.isEmpty())
+ {
+ W("Couldn't convert FSRef to path.");
+ continue;
+ }
+
+ D(QString("Acquired new path: %1").arg(path));
+ APP->loadFromPath(path);
+ }
+ AEDisposeDesc(&docList);
+
+ return 0;
+}
+
+bool Guitone::macEventFilter(EventHandlerCallRef caller, EventRef event)
+{
+ //
+ // taken from
+ // http://developer.apple.com/documentation/AppleScript/Conceptual/
+ // AppleEvents/dispatch_aes_aepg/chapter_4_section_3.html
+ //
+ Boolean release = false;
+ EventRecord eventRecord;
+ OSErr ignoredErr;
+
+ // Events of type kEventAppleEvent must be removed from the queue
+ // before being passed to AEProcessAppleEvent.
+ if (IsEventInQueue(GetMainEventQueue(), event))
+ {
+ // RemoveEventFromQueue will release the event, which will
+ // destroy it if we don't retain it first.
+ RetainEvent(event);
+ release = true;
+ RemoveEventFromQueue(GetMainEventQueue(), event);
+ }
+
+ // Convert the event ref to the type AEProcessAppleEvent expects.
+ ConvertEventRefToEventRecord(event, &eventRecord);
+ ignoredErr = AEProcessAppleEvent(&eventRecord);
+
+ if (release)
+ ReleaseEvent(event);
+
+ // This Carbon event has been handled, even if no AppleEvent handlers
+ // were installed for the Apple event.
+ return noErr;
+}
+#endif
+
Guitone::Guitone(int argc, char** argv)
: QApplication(argc, argv), updateDialog(0)
{
@@ -40,14 +118,27 @@ Guitone::Guitone(int argc, char** argv)
setOrganizationName("Thomas Keller");
setOrganizationDomain("thomaskeller.biz");
setApplicationName("guitone");
+
+#ifdef Q_WS_MACX
+ // install apple event handler to open documents
+ OSErr err = AEInstallEventHandler(
+ kCoreEventClass, kAEOpenDocuments,
+ NewAEEventHandlerUPP(OpenDocumentAE), 0, false
+ );
+ require_noerr(err, error_installing_event_handler);
+ return;
+
+error_installing_event_handler:
+ C("Could not install OpenDocumentAE event handler");
+#endif
}
bool Guitone::init()
{
if (Settings::getBool("CheckForUpdates", true))
{
-#ifdef Q_WS_MAC
- //CocoaUtil::initialize();
+#ifdef Q_WS_MACX
+ //CocoaUtil::initialize();
#else
updateDialog = new ApplicationUpdate(NULL);
if (updateDialog->updateAvailable())
@@ -58,21 +149,40 @@ bool Guitone::init()
#endif
}
- MainWindow * mainWnd = addWindow();
- if (!addMonotoneInstance(mainWnd))
+ QStringList args = arguments();
+ bool somethingLoaded = false;
+
+ for (int i=1, j=args.size(); iloadRecent();
+ // if no command line arguments have been given or
+ // they have been invalid or anything else went wrong,
+ // try to load the recently used workspace/database
+ if (!somethingLoaded)
+ {
+ QStringList workspaces = Settings::getItemList("RecentWorkspaceList");
+ somethingLoaded = workspaces.size() > 0 && loadWorkspace(workspaces.at(0));
+ }
- // trigger the setting of the correct window title in the window menu
- emit windowListChanged();
+ if (!somethingLoaded)
+ {
+ QStringList databases = Settings::getItemList("RecentDatabaseList");
+ somethingLoaded = databases.size() > 0 && loadDatabase(databases.at(0));
+ }
- mainWnd->show();
- return true;
+ // if still nothing is loaded, prompt the user to load a workspace
+ if (!somethingLoaded)
+ {
+ QString workspaceDir =
+ QFileDialog::getExistingDirectory(0, tr("Select your workspace..."));
+ somethingLoaded = !workspaceDir.isEmpty() && loadWorkspace(workspaceDir);
+ }
+
+ // if nothing could be loaded (= no window could be created),
+ // let the app close itself
+ return somethingLoaded;
}
Guitone::~Guitone()
@@ -82,13 +192,32 @@ Guitone::~Guitone()
if (updateDialog) delete updateDialog;
}
-void Guitone::loadWorkspace(const QString & path)
+bool Guitone::loadFromPath(const QString & path)
{
+ QFileInfo fileInfo(path);
+ if (!fileInfo.exists())
+ {
+ W(QString("Non-existant file/folder %1").arg(path));
+ return false;
+ }
+
+ if (fileInfo.isDir())
+ {
+ return loadWorkspace(path);
+ }
+
+ return loadDatabase(path);
+}
+
+bool Guitone::loadWorkspace(const QString & path)
+{
+ QMutexLocker locker(&mutex);
+
MainWindow * wnd = addWindow();
if (!addMonotoneInstance(wnd) || !wnd->doLoadWorkspace(path))
{
removeWindow(wnd);
- return;
+ return false;
}
// now that the workspace is loaded, the window should have gotten a
@@ -96,25 +225,33 @@ void Guitone::loadWorkspace(const QStrin
emit windowListChanged();
wnd->show();
+
+ return true;
}
-void Guitone::loadDatabase(const QString & path)
+bool Guitone::loadDatabase(const QString & path)
{
+ QMutexLocker locker(&mutex);
+
MainWindow * wnd = addWindow();
if (!addMonotoneInstance(wnd) || !wnd->doLoadDatabase(path))
{
removeWindow(wnd);
- return;
+ return false;
}
// now that the database is loaded, the window should have gotten a
// reasonable name
emit windowListChanged();
wnd->show();
+
+ return true;
}
void Guitone::windowClosed(MainWindow * wnd)
{
+ QMutexLocker locker(&mutex);
+
removeMonotoneInstance(wnd);
removeWindow(wnd);
if (openWindows.size() == 0) quit();
@@ -122,8 +259,6 @@ MainWindow * Guitone::addWindow()
MainWindow * Guitone::addWindow()
{
- QMutexLocker locker(&lock);
-
MainWindow * wnd = new MainWindow();
connect(
@@ -177,13 +312,17 @@ MainWindow * Guitone::addWindow()
openWindows.append(wnd);
+ D(QString("Added window %1").arg((int)wnd));
+
return wnd;
}
void Guitone::removeWindow(MainWindow * wnd)
{
- QMutexLocker locker(&lock);
+ Q_ASSERT(wnd);
+ D(QString("Removing window %1").arg((int)wnd));
+
int i = openWindows.indexOf(wnd);
if (i == -1) return;
openWindows.removeAt(i);
@@ -269,6 +408,8 @@ bool Guitone::addMonotoneInstance(MainWi
bool Guitone::addMonotoneInstance(MainWindow * wnd)
{
+ Q_ASSERT(wnd);
+
Monotone * mtn = new Monotone(wnd);
// check the current monotone version and prompt the user
@@ -300,15 +441,21 @@ bool Guitone::addMonotoneInstance(MainWi
monotoneInstances.insert(wnd, mtn);
+ D(QString("Added monotone instance %1 for %2").arg((int)mtn).arg((int)wnd));
+
return true;
}
bool Guitone::removeMonotoneInstance(MainWindow * wnd)
{
+ Q_ASSERT(wnd);
+
if (!monotoneInstances.contains(wnd)) return false;
Monotone * mtn = monotoneInstances.value(wnd);
+ D(QString("Removing monotone instance %1 for %2").arg((int)mtn).arg((int)wnd));
+
delete mtn;
monotoneInstances.remove(wnd);
@@ -336,3 +483,15 @@ Monotone * Guitone::getMonotoneInstance(
return monotoneInstances.value(wnd);
}
+void Guitone::lock()
+{
+ D("lock called");
+ mutex.lock();
+}
+
+void Guitone::unlock()
+{
+ D("unlock called");
+ mutex.unlock();
+}
+
============================================================
--- src/Guitone.h f56c7a540e0185fa8ef7008a7b35d2af4376bbb7
+++ src/Guitone.h 881dffddd5bdd9999f2ed36ecdcaa019de153cb4
@@ -42,13 +42,17 @@ public:
MainWindow * findMainWindow(QObject *);
Monotone * getMonotoneInstance(QObject *);
-
+ bool loadFromPath(const QString &);
+
+ void lock();
+ void unlock();
+
signals:
void windowListChanged();
private slots:
- void loadWorkspace(const QString &);
- void loadDatabase(const QString &);
+ bool loadWorkspace(const QString &);
+ bool loadDatabase(const QString &);
void windowClosed(MainWindow *);
void quit();
@@ -58,10 +62,14 @@ private:
bool addMonotoneInstance(MainWindow *);
bool removeMonotoneInstance(MainWindow *);
+
+#ifdef Q_WS_MACX
+ bool macEventFilter(EventHandlerCallRef, EventRef);
+#endif
QList openWindows;
QMap monotoneInstances;
- QMutex lock;
+ QMutex mutex;
ApplicationUpdate * updateDialog;
};
============================================================
--- src/util/CocoaUtil.h 023ccba6801d260542c9311a01e3ca39e20b69c5
+++ src/util/CocoaUtil.h 8424a0c7f877f0167271bb2386fd00472a32f551
@@ -5,7 +5,8 @@
#ifndef COCOAUTIL_H
#define COCOAUTIL_H
-#include
+#include
+#include
class SUUpdater;
@@ -13,6 +14,7 @@ namespace CocoaUtil
{
void initialize();
void checkForUpdates();
+ QString FSRefToPath(FSRef ref);
};
#endif
============================================================
--- src/util/CocoaUtil.mm 122f1726e6d7f1289c48a51074063ebb753bf26e
+++ src/util/CocoaUtil.mm af7058410a39e0fa1f7fdb9d1ff5019261fd0960
@@ -1,9 +1,10 @@
/*
* taken from the Axel project (http://excalibur.inria.fr/),
* licensed under GPL
*/
#include
#include
+
#include "CocoaUtil.h"
void CocoaUtil::initialize()
@@ -18,3 +19,16 @@ void CocoaUtil::checkForUpdates()
SUUpdater * updater = [SUUpdater alloc];
[updater checkForUpdates:nil];
}
+
+QString CocoaUtil::FSRefToPath(FSRef fsref)
+{
+ CFURLRef url = CFURLCreateFromFSRef(kCFAllocatorDefault, &fsref);
+ if (!url)
+ {
+ return QString();
+ }
+ NSString * pathName = (NSString*)CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
+ [pathName autorelease];
+ CFRelease(url);
+ return QString::fromUtf8([pathName UTF8String]);
+}
============================================================
--- src/view/MainWindow.cpp 1e0d6b1c8dc5305f78a6e72f8dae9cf118ab5866
+++ src/view/MainWindow.cpp d90f84228175d6b63f614248e511611bcf167cf3
@@ -55,7 +55,6 @@ MainWindow::MainWindow()
MainWindow::MainWindow()
: QMainWindow()
{
- mode = None;
setAttribute(Qt::WA_MacMetalStyle);
// ensure that the shortcut keys are properly recognized by linguist
@@ -125,17 +124,6 @@ MainWindow::MainWindow()
this, SLOT(doUpdatePreviousDatabasesMenu())
);
- connect(
- this, SIGNAL(loadWorkspace(const QString &)),
- this, SLOT(checkIfWindowClose())
- );
-
- connect(
- this, SIGNAL(loadDatabase(const QString &)),
- this, SLOT(checkIfWindowClose())
- );
-
-
doUpdatePreviousWorkspacesMenu();
doUpdatePreviousDatabasesMenu();
@@ -165,26 +153,6 @@ MainWindow::~MainWindow()
delete proxyModelFileList;
}
-// try to load the most recent workspace or database, if there are any
-// if everything fails, load nothing and hide the appropriate menus
-void MainWindow::loadRecent()
-{
- QStringList workspaces = Settings::getItemList("RecentWorkspaceList");
- bool something_loaded = workspaces.size() > 0 && doLoadWorkspace(workspaces[0]);
-
- if (!something_loaded)
- {
- QStringList databases = Settings::getItemList("RecentDatabaseList");
- something_loaded = databases.size() > 0 && doLoadDatabase(databases[0]);
- }
-
- if (!something_loaded)
- {
- switchMode(None);
- }
-
-}
-
void MainWindow::on_actionOpen_Workspace_triggered()
{
QString fn = QFileDialog::getExistingDirectory(0, tr("Select your workspace..."));
@@ -299,9 +267,6 @@ void MainWindow::switchMode(Mode m)
void MainWindow::switchMode(Mode m)
{
- // FIXME: by switching the current mode we're also changing the window
- // title - we should find an easy way to tell all other windows about
- // that so a user can still recognize the entry properly
mode = m;
windowMode->setCurrentIndex(mode);
restoreGeometry(Settings::getWindowGeometry("MainWindow_mode" + mode));
@@ -311,16 +276,18 @@ void MainWindow::switchMode(Mode m)
// 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
- if (openWindows.size() > 1)
+ int curIdx = openWindows.indexOf(this);
+ if (curIdx > 0)
{
- MainWindow * prevWnd = openWindows.at(openWindows.indexOf(this) - 1);
+ MainWindow * prevWnd = openWindows.at(curIdx - 1);
Q_ASSERT(prevWnd);
+
QDesktopWidget * desk = APP->desktop();
if (desk->numScreens() > 1)
{
- qWarning("Guitone::addWindow: No support for window cascading "
- "on systems with more than one monitor yet.");
+ W("No support for window cascading on systems with "
+ "more than one monitor yet.");
}
else
{
@@ -370,11 +337,7 @@ void MainWindow::switchMode(Mode m)
}
else
{
- menuView->menuAction()->setVisible(false);
- menuWorkspace->menuAction()->setVisible(false);
- menuDatabase->menuAction()->setVisible(false);
-
- setWindowTitle(tr("No workspace or database loaded - guitone"));
+ Q_ASSERT(false);
}
emit modeChanged(mode);
@@ -663,14 +626,6 @@ void MainWindow::invalidWorkspaceFormat(
emit updatePreviousWorkspacesMenu();
- switchMode(None);
+ close();
}
-// this slot is called whenever a new workspace or database is loaded
-// if the current window is in "None" mode, we can safely close it because
-// it cannot be switched to something else anymore anyways
-void MainWindow::checkIfWindowClose()
-{
- if (mode == None) QTimer::singleShot(0, this, SLOT(close()));
-}
-
============================================================
--- src/view/MainWindow.h b662cc90c17734984e6a62fa323d2168def713ba
+++ src/view/MainWindow.h 627db714e8b3f00acd00cd164015dffc4c3f3075
@@ -36,12 +36,10 @@ public:
Q_OBJECT
public:
- enum Mode { Workspace = 0, Database, None };
+ enum Mode { Workspace = 0, Database};
MainWindow();
~MainWindow();
- void loadRecent();
- void switchMode(Mode);
-
+
bool doLoadWorkspace(QString);
bool doLoadDatabase(QString);
@@ -80,11 +78,11 @@ private slots:
void updateWindowList();
void activateOtherWindow();
void invalidWorkspaceFormat(const QString &);
- void checkIfWindowClose();
private:
void closeEvent(QCloseEvent *);
-
+ void switchMode(Mode);
+
Inventory *invModel;
Attributes *attrModel;
InventoryProxyModel *proxyModelFolderTree;