# # # patch "guitone/guitone.pro" # from [73540fd82e20d285acdfbc3069b410942b96cf55] # to [9d2671d1b85e6268ddd8652b4c5e266262074481] # # patch "guitone/res/i18n/guitone_de.ts" # from [60fe3c5152a9fe7a0b82931f987a79c0263fdedd] # to [7f11c943fc9ed5ebb69a7ba9586b94c2e53892d2] # # patch "guitone/src/Guitone.cpp" # from [b24e64854e45ef0832b72a299e1982c6af971fb2] # to [72db4ba5a31fd28c6994ba6d756343996ceeabcd] # # patch "guitone/src/Guitone.h" # from [b59a496010ede1bd51b8144c825fdd064e157a5e] # to [be48ddb461736a277c9f13faba817ae60d4b2fff] # # patch "guitone/src/model/Inventory.cpp" # from [58d0e21effeff5955284a02e3d08f5f64d750e1e] # to [40891673d2f0b9c232012c2db529c3aab2700a43] # # patch "guitone/src/model/Inventory.h" # from [1338e141daf45f9d78054e9e259be83969e76106] # to [5833ddc9dfa3fcfb09b13621730469f59041751b] # # patch "guitone/src/view/InventoryView.cpp" # from [692c80b1d24969ff915206b9c715e11c9f0eff52] # to [e59f8f435f3595d675129944b2806aceaef744f9] # # patch "guitone/src/view/InventoryView.h" # from [7ce754d4fede57bc2df067eb97fb41547ecdbf70] # to [b9bd6ab533371f623c4a08e8abcbeeb5b4bb3b4f] # # patch "guitone/src/view/MainWindow.cpp" # from [86d7eebe192976754605003e2a4ec2846a3e3ef4] # to [e0fc8ca82505ae00d1d0c41b69e6d4407a4676f8] # # patch "guitone/src/view/MainWindow.h" # from [c56fc1fb9768759a01093105fa03415d98474522] # to [781c1b946f381431d22a9ef8fac33778b43e35de] # # patch "guitone/src/view/dialogs/Dialog.cpp" # from [8d60a12cf4e2cd831b21f95508644908b908fd65] # to [0fc11e87783526f1d650fecc3756af84b28b0afe] # ============================================================ --- guitone/guitone.pro 73540fd82e20d285acdfbc3069b410942b96cf55 +++ guitone/guitone.pro 9d2671d1b85e6268ddd8652b4c5e266262074481 @@ -6,6 +6,7 @@ CONFIG += qt debug TARGET = guitone CONFIG += qt debug + INCLUDEPATH = src/ \ src/view \ src/view/dialogs \ @@ -149,7 +150,7 @@ macx { ICON = res/osx/guitone.icns # add x86, ppc or both to build for either or both platforms (universal)^ - CONFIG += ppc x86 + CONFIG += x86 #ppc # do not try to build a universal binary if precompiled headers # are enabled (this will fail badly) ============================================================ --- guitone/res/i18n/guitone_de.ts 60fe3c5152a9fe7a0b82931f987a79c0263fdedd +++ guitone/res/i18n/guitone_de.ts 7f11c943fc9ed5ebb69a7ba9586b94c2e53892d2 @@ -344,22 +344,30 @@ Guitone - + Error Fehler - + The path to the monotone binary is either invalid or points to an older version of monotone. Guitone requires monotone version %1 or a monotone with interface version %2 or later. Der Pfad zur ausführbaren Datei von monotone ist entweder ungültig oder zeigt auf eine ältere Version von monotone. Guitone benötigt monotone Version %1 oder ein monotone mit einer Interface-Version %2 oder neuer. - + Critical Monotone Error Kritischer monotone-Fehler + Inventory + + + [unknown branch] + + + + InventoryItem @@ -420,127 +428,127 @@ InventoryView - + &Add &Hinzufügen - + Add to workspace Zum Arbeitsbereich hinzufügen - + &Remove En&tfernen - + Remove from workspace Vom Arbeitsbereich entfernen - + &Commit &Einpflegen - + Commit Einpflegen - + I&gnore Datei &ignorieren - + Ignore file Datei ignorieren - + &Unignore Datei nicht ign&orieren - + Unignore file Datei nicht mehr ignorieren - + R&evert &Zurücksetzen - + Revert uncommitted changes Nicht eingepflegte Änderungen verwerfen - + Rena&me Um&benennen - + Rename file Datei umbenennen - + D&iff U&nterschiede anzeigen - + Diff against base revision Unterschiede im Vergleich zur Basisrevision anzeigen - + &Go into &Wechseln zu - + Go into the directory Wechsle in das Verzeichnis - + &Open &Öffnen - + Open in default program In Standardprogramm öffnen - + Error Fehler - + The file you're trying to open does not exist. Die Datei, die Sie versucht haben zu öffnen, existiert nicht. - + Unable to open files on your platform - please contact the author about this problem. Kann keine Dateien auf Ihrer Plattform öffnen - bitte kontaktieren Sie den Autor über dieses Problem. - + D&iff all Alle U&nterschiede anzeigen - + Show all differences Zeigt Unterschiede in allen Dateien @@ -664,7 +672,7 @@ Strg+O - + No previous workspaces available. Keine vorherigen Arbeitsbereiche verfügbar. @@ -689,7 +697,7 @@ Strg+Q - + Hide ignored files Ignorierte Dateien verstecken @@ -789,7 +797,7 @@ I - + Expand tree Baum aufklappen @@ -849,32 +857,32 @@ Kritischer monotone-Fehler - + Select your workspace... Wählen Sie Ihren Arbeitsbereich aus... - + Loading aborted Laden abgebrochen - + Invalid workspace Ungültiger Arbeitsbereich - + The chosen directory is no monotone workspace! Das gewählte Verzeichnis ist kein monotone-Arbeitsverzeichnis! - + Unable to execute command Konnte Kommando nicht ausführen - + Unable to execute '%1' - maybe another command is still running? Konnte '%1' nicht ausführen - eventuell läuft noch ein anderes Kommando? @@ -884,17 +892,17 @@ Lade Arbeitsbereich... - + Show ignored files Zeige ignorierte Dateien - + Collapse tree Baum zuklappen - + &%1 %2 &%1 %2 @@ -914,7 +922,7 @@ Datenbank öffnen - + No previous databases available. Keine vorherigen geöffneten Datenbanken verfügbar. @@ -929,22 +937,22 @@ Strg+Shift+O - + Loaded database: %1 Geladene Datenbank: %1 - + Select your database... Wählen Sie eine Datenbank aus... - + monotone Databases (*.mtn *.db) monotone-Datenbanken (*.mtn *.db) - + No database loaded Keine Datenbank geladen @@ -985,6 +993,16 @@ Sie können zum Arbeitsbereich-Modus jed Bring all to front + + + %1 - workspace mode - guitone + + + + + %1 - database mode - guitone + + Manifest @@ -1036,7 +1054,7 @@ monotone gab zurück: %2 - + The monotone process exited unexpectedly (return code %1). Please reconfigure the path to the monotone binary in the Preferences dialog or check if the version of the database you try to load matches the monotone version you are using. monotone returned: @@ -1151,22 +1169,22 @@ monotone gab zurück: QShortcut - + Ctrl Strg - + Shift Umschalt - + Alt Alt - + Meta Meta ============================================================ --- guitone/src/Guitone.cpp b24e64854e45ef0832b72a299e1982c6af971fb2 +++ guitone/src/Guitone.cpp 72db4ba5a31fd28c6994ba6d756343996ceeabcd @@ -86,7 +86,12 @@ bool Guitone::init() removeWindow(mainWnd); return false; } + mainWnd->loadRecent(); + + // trigger the setting of the correct window title in the window menu + emit windowListChanged(); + mainWnd->show(); return true; } @@ -116,6 +121,11 @@ void Guitone::loadWorkspace(const QStrin removeWindow(wnd); return; } + + // now that the workspace is loaded, the window should have gotten a + // reasonable name + emit windowListChanged(); + wnd->show(); } @@ -127,6 +137,10 @@ void Guitone::loadDatabase(const QString removeWindow(wnd); return; } + // now that the database is loaded, the window should have gotten a + // reasonable name + emit windowListChanged(); + wnd->show(); } @@ -134,10 +148,7 @@ void Guitone::windowClosed(MainWindow * { removeMonotoneInstance(wnd); removeWindow(wnd); - if (openWindows.size() == 0) - { - QTimer::singleShot(0, this, SLOT(quit())); - } + if (openWindows.size() == 0) quit(); } MainWindow * Guitone::addWindow() @@ -195,6 +206,11 @@ MainWindow * Guitone::addWindow() this, SLOT(loadDatabase(const QString &)) ); + connect( + this, SIGNAL(windowListChanged()), + wnd, SLOT(updateWindowList()) + ); + for (int i=0, j=openWindows.size(); i Guitone::windowList() const +{ + return openWindows; +} + void Guitone::quit() { Settings::sync(); ============================================================ --- guitone/src/Guitone.h b59a496010ede1bd51b8144c825fdd064e157a5e +++ guitone/src/Guitone.h be48ddb461736a277c9f13faba817ae60d4b2fff @@ -40,9 +40,13 @@ public: Guitone(int, char**); ~Guitone(); bool init(); + const QList windowList() const; Monotone * monotoneInstance(QObject *); - + +signals: + void windowListChanged(); + private slots: void criticalMtnError(const QString &); void loadWorkspace(const QString &); ============================================================ --- guitone/src/model/Inventory.cpp 58d0e21effeff5955284a02e3d08f5f64d750e1e +++ guitone/src/model/Inventory.cpp 40891673d2f0b9c232012c2db529c3aab2700a43 @@ -31,13 +31,12 @@ Inventory::Inventory(QObject *parent) : // in the model, otherwise the app crashes rootItem = new InventoryItem(); + // FIXME: we need a global provider... iconProvider = new IconProvider(); regex = new QRegExp("^(R|D|[ ])(R|A|[ ])(M|P|U|I|[ ])\\s(\\d+)\\s(\\d+)\\s(.+)$"); regex->setMinimal(true); mtnDelegate = new MonotoneDelegate(this); - - modelPresent = false; } Inventory::~Inventory() @@ -50,11 +49,6 @@ bool Inventory::readInventory() bool Inventory::readInventory() { - if (modelPresent) - { - deleteModel(); - } - QStringList cmd; cmd << "inventory"; @@ -63,13 +57,7 @@ void Inventory::parseOutput() void Inventory::parseOutput() { - if (modelPresent) - { - qWarning("Inventory::parseOutput: A model was already created!"); - return; - } - - QStringList lines = AutomateCommand::data.split("\n", QString::SkipEmptyParts); + QStringList lines = AutomateCommand::data.split("\n", QString::SkipEmptyParts); QMap renameMap; QMap::iterator renameIter; @@ -116,20 +104,18 @@ void Inventory::parseOutput() // FIXME: we shouldn't really add a workspace root item here, but // mtn automate inventory currently doesn't print the root workspace dir - InventoryItem* workspace = new InventoryItem(rootItem, ".", 0, true, true); - workspace->setLabel(MTN(this)->getNormalizedWorkspacePath()); - rootItem->appendChild(workspace); - workspace->setChildren(buildTreeRecursive(tempItems, NULL)); + InventoryItem * branch = new InventoryItem(rootItem, ".", 0, true, true); + branch->setLabel(getBranchName()); + rootItem->appendChild(branch); + branch->setChildren(buildTreeRecursive(tempItems, NULL)); // reset the model to repaint the view completly // (all QModelIndexes are discarded through that, e.g. selections!) - this->reset(); + reset(); // restore the normal cursor qApp->restoreOverrideCursor(); - modelPresent = true; - emit modelCreated(); } @@ -386,10 +372,54 @@ bool Inventory::parseInventoryLine( return true; } -void Inventory::deleteModel(void) +QString Inventory::getOption(const QString & opt) { - rootItem->deleteAllChildren(); - modelPresent = false; - this->reset(); + Monotone * mtn = MTN(this); + + int cmdNum; + mtn->executeCommand(QStringList() << "get_option" << opt, cmdNum); + + QString data = mtn->getDecodedData(cmdNum); + + if (mtn->getReturnCode(cmdNum) > 0) + { + qCritical("Inventory::getOoption: Couldn't retrieve option %s: %s", + qPrintable(opt), qPrintable(data)); + return QString(); + } + + if (data.length() > 1) + data.chop(1); + return data; } +QString Inventory::getBranchName() +{ + QString branchName = getOption("branch"); + + if (branchName.size() == 0) + { + branchName = QString(tr("[unknown branch]")); + } + return branchName; +} + +QString Inventory::getBranchNameShort() +{ + // FIXME: currently there is only support for the domain branch scheme + // tld.domain.project.branch + QString branchName = getBranchName(); + QStringList parts = branchName.split('.'); + if (parts.size() == 1) return branchName; + + QString shortBranchName; + for (int i=0, j=parts.size()-1; i buildTreeRecursive(QList &, InventoryItem*); - void deleteModel(void); - + InventoryItem * rootItem; IconProvider * iconProvider; QRegExp * regex; MonotoneDelegate * mtnDelegate; - bool modelPresent; + QString branchName; signals: void modelCreated(); ============================================================ --- guitone/src/view/InventoryView.cpp 692c80b1d24969ff915206b9c715e11c9f0eff52 +++ guitone/src/view/InventoryView.cpp e59f8f435f3595d675129944b2806aceaef744f9 @@ -93,11 +93,44 @@ void InventoryView::setModel(QAbstractIt Q_ASSERT(false); } -void InventoryView::setModel(QSortFilterProxyModel * model) +void InventoryView::setModel(QSortFilterProxyModel * newModel) { - TreeView::setModel(model); + QAbstractItemModel * oldModel = model(); + if (oldModel) + { + disconnect( + oldModel, SIGNAL(modelReset()), + this, SLOT(modelReset()) + ); + } + + TreeView::setModel(newModel); + + connect( + newModel, SIGNAL(modelReset()), + this, SLOT(modelReset()) + ); } +void InventoryView::modelReset() +{ + QModelIndex index(rootIndex()); + if (!index.isValid()) return; + + index = index.child(0,0); + Q_ASSERT(index.isValid()); + InventoryItem * item = static_cast(index.internalPointer()); + qDebug(qPrintable(item->getLabel())); + if (type == FolderTree) + { + setRootIndex(index); + } + else + { + expand(index); + } +} + // adds elements to the popup menu based on the selected items // since not all actions may apply on all items void InventoryView::slotContextMenuRequested(const QModelIndexList & indexList, const QPoint & pos) ============================================================ --- guitone/src/view/InventoryView.h 7ce754d4fede57bc2df067eb97fb41547ecdbf70 +++ guitone/src/view/InventoryView.h b9bd6ab533371f623c4a08e8abcbeeb5b4bb3b4f @@ -62,8 +62,10 @@ private: QAction *actRevisionDiff; Type type; - + private slots: + void modelReset(); + void changeDirectory(const QModelIndex &); void itemClicked(const QModelIndex & index); void slotContextMenuRequested(const QModelIndexList &, const QPoint &); ============================================================ --- guitone/src/view/MainWindow.cpp 86d7eebe192976754605003e2a4ec2846a3e3ef4 +++ guitone/src/view/MainWindow.cpp e0fc8ca82505ae00d1d0c41b69e6d4407a4676f8 @@ -40,6 +40,7 @@ #include #include #include +#include MainWindow::MainWindow() : QMainWindow() @@ -200,6 +201,11 @@ bool MainWindow::doLoadWorkspace(QString return false; } + setWindowTitle( + tr("%1 - workspace mode - guitone"). + arg(invModel->getBranchNameShort()) + ); + // add the workspace to the recent workspace list // FIXME: the amount of recent workspaces should be made configurable Settings::addItemToList("RecentWorkspaceList", mtn->getNormalizedWorkspacePath(), 5); @@ -249,7 +255,13 @@ bool MainWindow::doLoadDatabase(QString return false; } - + + QFileInfo fi(fn); + setWindowTitle( + tr("%1 - database mode - guitone"). + arg(fi.fileName()) + ); + switchMode(Database); Settings::addItemToList("RecentDatabaseList", fn, 5); @@ -415,6 +427,68 @@ void MainWindow::doUpdatePreviousDatabas } } +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_actionSwitch_revision_triggered() { // TODO: connect Inventory with the accept() signal here somehow ============================================================ --- guitone/src/view/MainWindow.h c56fc1fb9768759a01093105fa03415d98474522 +++ guitone/src/view/MainWindow.h 781c1b946f381431d22a9ef8fac33778b43e35de @@ -70,9 +70,12 @@ private slots: void on_actionAbout_guitone_triggered(); void on_actionAbout_Qt_triggered(); void on_actionChangeset_browser_triggered(); + void on_actionBring_all_to_front_triggered(); void openRecentWorkspace(); void openRecentDatabase(); + void updateWindowList(); + void activateOtherWindow(); private: void closeEvent(QCloseEvent *); ============================================================ --- guitone/src/view/dialogs/Dialog.cpp 8d60a12cf4e2cd831b21f95508644908b908fd65 +++ guitone/src/view/dialogs/Dialog.cpp 0fc11e87783526f1d650fecc3756af84b28b0afe @@ -68,15 +68,36 @@ int Dialog::execDocumentModal() // ensure that this is only called from top level windows Q_ASSERT(parent()->inherits("QMainWindow")); - // FIXME: for some unknown reason this does _not_ disable the menubar - // completly on OSX - is this a bug or are we doing something wrong? - qobject_cast(parent())->menuBar()->setEnabled(false); + QMap enableState; + // disable all menu actions (for some reason disabling the menuBar itself + // does not result in the desired effect under OSX) + QList list = qobject_cast(parent())->menuBar()->actions(); + foreach(QAction * act, list) + { + QList innerList = act->menu()->actions(); + foreach(QAction * innerAct, innerList) + { + // skip actions which are later placed into the application menu + // on OSX or serve other special purposes + if (innerAct->menuRole() != QAction::NoRole && + innerAct->menuRole() != QAction::TextHeuristicRole) + continue; + + enableState.insert(innerAct, innerAct->isEnabled()); + innerAct->setEnabled(false); + } + } + show(); SignalWaiter waiter(this, SIGNAL(finished(int))); waiter.wait(); - qobject_cast(parent())->menuBar()->setEnabled(true); + // restore the enable state for all items + foreach(QAction * act, enableState.keys()) + { + act->setEnabled(enableState.value(act)); + } return result(); }