changeset 153:70fe12873106

* Show both parents of uncommitted merge; fixes to right-button menus
author Chris Cannam
date Thu, 02 Dec 2010 17:55:21 +0000
parents 2b997861174b
children 6bcb4a4d6521
files changeset.cpp changeset.h changesetitem.cpp changesetitem.h changesetscene.cpp changesetscene.h connectionitem.cpp filestatuswidget.cpp grapher.cpp grapher.h hgtabwidget.cpp hgtabwidget.h historywidget.cpp historywidget.h mainwindow.cpp uncommitteditem.cpp uncommitteditem.h
diffstat 17 files changed, 217 insertions(+), 65 deletions(-) [+]
line wrap: on
line diff
--- a/changeset.cpp	Thu Dec 02 11:51:15 2010 +0000
+++ b/changeset.cpp	Thu Dec 02 17:55:21 2010 +0000
@@ -49,7 +49,7 @@
 QString Changeset::formatHtml()
 {
     QString description;
-    QString rowTemplate = "<tr><td><b>%1</b></td><td>%2</td></tr>";
+    QString rowTemplate = "<tr><td><b>%1</b>&nbsp;</td><td>%2</td></tr>";
 
     description = "<qt><table border=0>";
 
--- a/changeset.h	Thu Dec 02 11:51:15 2010 +0000
+++ b/changeset.h	Thu Dec 02 17:55:21 2010 +0000
@@ -86,6 +86,10 @@
         return false;
     }
 
+    static QString hashOf(QString id) {
+        return id.split(':')[1];
+    }
+
     static QStringList getIds(Changesets csets) {
         QStringList ids;
         foreach (Changeset *cs, csets) ids.push_back(cs->id());
--- a/changesetitem.cpp	Thu Dec 02 11:51:15 2010 +0000
+++ b/changesetitem.cpp	Thu Dec 02 17:55:21 2010 +0000
@@ -29,6 +29,8 @@
 #include <QAction>
 #include <QLabel>
 #include <QWidgetAction>
+#include <QApplication>
+#include <QClipboard>
 
 ChangesetItem::ChangesetItem(Changeset *cs) :
     m_changeset(cs), m_detail(0),
@@ -103,29 +105,53 @@
 void
 ChangesetItem::activateMenu()
 {
+    m_parentDiffActions.clear();
+
     QMenu *menu = new QMenu;
-    QLabel *label = new QLabel(tr("<qt><b>Revision: </b>%1</qt>")
+    QLabel *label = new QLabel(tr("<qt>&nbsp;<b>Revision: </b>%1</qt>")
                                .arg(m_changeset->id()));
     QWidgetAction *wa = new QWidgetAction(menu);
     wa->setDefaultWidget(label);
     menu->addAction(wa);
     menu->addSeparator();
 
-    QAction *update = menu->addAction(tr("Update to this revision"));
-    connect(update, SIGNAL(triggered()), this, SLOT(updateActivated()));
+    QAction *copyId = menu->addAction(tr("Copy identifier to clipboard"));
+    connect(copyId, SIGNAL(triggered()), this, SLOT(copyIdActivated()));
 
     menu->addSeparator();
 
-    QAction *diffParent = menu->addAction(tr("Diff against previous revision"));
-    connect(diffParent, SIGNAL(triggered()), this, SLOT(diffToPreviousActivated()));
-    QAction *diffCurrent = menu->addAction(tr("Diff against current revision"));
+    if (m_changeset->parents().size() > 1) {
+
+        foreach (QString parentId, m_changeset->parents()) {
+            QAction *diffParent =
+                menu->addAction(tr("Diff to parent %1").arg(parentId));
+            connect(diffParent, SIGNAL(triggered()),
+                    this, SLOT(diffToParentActivated()));
+            m_parentDiffActions[diffParent] = parentId;
+        }
+
+    } else {
+
+        QAction *diffParent =
+            menu->addAction(tr("Diff to parent"));
+        connect(diffParent, SIGNAL(triggered()),
+                this, SLOT(diffToParentActivated()));
+    }
+
+    QAction *diffCurrent = menu->addAction(tr("Diff to current working folder"));
     connect(diffCurrent, SIGNAL(triggered()), this, SLOT(diffToCurrentActivated()));
 
     menu->addSeparator();
 
+    QAction *update = menu->addAction(tr("Update to this revision"));
+    connect(update, SIGNAL(triggered()), this, SLOT(updateActivated()));
+
     QAction *merge = menu->addAction(tr("Merge from here to current"));
     connect(merge, SIGNAL(triggered()), this, SLOT(mergeActivated()));
-    QAction *tag = menu->addAction(tr("Tag this revision"));
+
+    menu->addSeparator();
+
+    QAction *tag = menu->addAction(tr("Add tag..."));
     connect(tag, SIGNAL(triggered()), this, SLOT(tagActivated()));
 
     menu->exec(QCursor::pos());
@@ -133,8 +159,32 @@
     ungrabMouse();
 }
 
+void
+ChangesetItem::copyIdActivated()
+{
+    QClipboard *clipboard = QApplication::clipboard();
+    clipboard->setText(Changeset::hashOf(m_changeset->id()));
+}
+
+void ChangesetItem::diffToParentActivated()
+{
+    QAction *a = qobject_cast<QAction *>(sender());
+    QString parentId;
+    if (m_parentDiffActions.contains(a)) {
+        parentId = m_parentDiffActions[a];
+        DEBUG << "ChangesetItem::diffToParentActivated: specific parent " 
+              << parentId << " selected" << endl;
+    } else {
+        parentId = m_changeset->parents()[0];
+        DEBUG << "ChangesetItem::diffToParentActivated: "
+              << "no specific parent selected, using first parent "
+              << parentId << endl;
+    }
+
+    emit diffToParent(getId(), parentId);
+}
+
 void ChangesetItem::updateActivated() { emit updateTo(getId()); }
-void ChangesetItem::diffToPreviousActivated() { emit diffToParent(getId(), m_changeset->parents()[0]); } //!!! no, this is most likely to be useful when something has more than one parent!
 void ChangesetItem::diffToCurrentActivated() { emit diffToCurrent(getId()); }
 void ChangesetItem::mergeActivated() { emit mergeFrom(getId()); }
 void ChangesetItem::tagActivated() { emit tag(getId()); }
@@ -228,17 +278,19 @@
 
     if (m_showBranch) {
 	// write branch name
+        paint->save();
 	f.setBold(true);
 	paint->setFont(f);
+	paint->setPen(QPen(branchColour));
 	QString branch = m_changeset->branch();
         if (branch == "") branch = "default";
 	int wid = width - 3;
 	branch = TextAbbrev::abbreviate(branch, QFontMetrics(f), wid);
 	paint->drawText(x0, -fh + fm.ascent() - 4, branch);
 	f.setBold(false);
+        paint->restore();
     }
 
-//    f.setItalic(true);
     fm = QFontMetrics(f);
     fh = fm.height();
     paint->setFont(f);
--- a/changesetitem.h	Thu Dec 02 11:51:15 2010 +0000
+++ b/changesetitem.h	Thu Dec 02 17:55:21 2010 +0000
@@ -24,6 +24,8 @@
 class Changeset;
 class ChangesetDetailItem;
 
+class QAction;
+
 class ChangesetItem : public QObject, public QGraphicsItem
 {
     Q_OBJECT
@@ -52,7 +54,7 @@
     bool isNew() const { return m_new; }
     void setNew(bool n) { m_new = n; }
 
-    bool shouldShowBranch() const { return m_showBranch; }
+    bool showBranch() const { return m_showBranch; }
     void setShowBranch(bool s) { m_showBranch = s; }
 
 signals:
@@ -70,8 +72,9 @@
     void hideDetail();
 
 private slots:
+    void copyIdActivated();
     void updateActivated();
-    void diffToPreviousActivated();
+    void diffToParentActivated();
     void diffToCurrentActivated();
     void mergeActivated();
     void tagActivated();
@@ -91,6 +94,8 @@
     bool m_wide;
     bool m_current;
     bool m_new;
+
+    QMap<QAction *, QString> m_parentDiffActions;
 };
 
 #endif // CHANGESETITEM_H
--- a/changesetscene.cpp	Thu Dec 02 11:51:15 2010 +0000
+++ b/changesetscene.cpp	Thu Dec 02 17:55:21 2010 +0000
@@ -61,6 +61,9 @@
     
     connect(item, SIGNAL(diff()),
             this, SIGNAL(diffWorkingFolder()));
+
+    connect(item, SIGNAL(showWork()),
+            this, SIGNAL(showWork()));
 }
 
 void
--- a/changesetscene.h	Thu Dec 02 11:51:15 2010 +0000
+++ b/changesetscene.h	Thu Dec 02 17:55:21 2010 +0000
@@ -37,6 +37,7 @@
     void commit();
     void revert();
     void diffWorkingFolder();
+    void showWork();
 
     void updateTo(QString id);
     void diffToParent(QString id, QString parent);
--- a/connectionitem.cpp	Thu Dec 02 11:51:15 2010 +0000
+++ b/connectionitem.cpp	Thu Dec 02 17:55:21 2010 +0000
@@ -76,7 +76,7 @@
 
     float yscale = 90;
     float size = 50;
-    float ygap = yscale - size;
+    float ygap = yscale - size - 2;
 
     int p_col = m_parent->column(), p_row = m_parent->row();
     int c_col, c_row;
--- a/filestatuswidget.cpp	Thu Dec 02 11:51:15 2010 +0000
+++ b/filestatuswidget.cpp	Thu Dec 02 17:55:21 2010 +0000
@@ -78,8 +78,8 @@
     m_descriptions[FileStates::Removed] = tr("These files will be removed from version control next time you commit.<br>"
                                              "They will not be deleted from the local folder.");
     m_descriptions[FileStates::Missing] = tr("These files are recorded in the version control, but absent from your working folder.<br>"
-                                             "If you deleted them by accident, select them here and use Revert to restore their previous contents.<br>"
-                                             "If you deleted them intentionally, select them here and use Remove to tell the version control system about it.");
+                                             "If you intended to delete them, select them and use Remove to tell the version control system about it.<br>"
+                                             "If you deleted them by accident, select them and use Revert to restore their previous contents.");
     m_descriptions[FileStates::Unknown] = tr("These files are in your working folder but are not under version control.<br>"
                                              "Select a file and use Add to place it under version control or Ignore to remove it from this list.");
 
--- a/grapher.cpp	Thu Dec 02 11:51:15 2010 +0000
+++ b/grapher.cpp	Thu Dec 02 17:55:21 2010 +0000
@@ -110,7 +110,7 @@
 
     // If we're the parent of the uncommitted item, make a note of our
     // row (we need it later, to avoid overwriting the connecting line)
-    if (m_uncommittedParentId == id) {
+    if (!m_uncommittedParents.empty() && m_uncommittedParents[0] == id) {
         m_uncommittedParentRow = row;
     }
 
@@ -158,7 +158,7 @@
         parentId = cs->parents()[0];
 
         if (!m_changesets.contains(parentId) ||
-            m_changesets[parentId]->branch() != branch) {
+            !m_changesets[parentId]->isOnBranch(branch)) {
             // new branch
             col = m_branchHomes[branch];
         } else {
@@ -176,7 +176,7 @@
 
         foreach (QString parentId, cs->parents()) {
             if (!m_changesets.contains(parentId)) continue;
-            if (m_changesets[parentId]->branch() == branch) {
+            if (m_changesets[parentId]->isOnBranch(branch)) {
                 ChangesetItem *parentItem = m_items[parentId];
                 col += parentItem->column();
                 parentsOnSameBranch++;
@@ -198,13 +198,24 @@
     item->setColumn(col);
     m_handled.insert(id);
 
-    // If we're the parent of the uncommitted item, it should be given
-    // the same column as us (ideally)
+    // If we're the first parent of the uncommitted item, it should be
+    // given the same column as us (we already noted that its
+    // connecting line would end at our row)
 
-    if (m_uncommittedParentId == id) {
-        int ucol = findAvailableColumn(row-1, col, true);
-        m_uncommitted->setColumn(ucol);
-        m_haveAllocatedUncommittedColumn = true;
+    if (m_uncommittedParents.contains(id)) {
+        if (m_uncommittedParents[0] == id) {
+            int ucol = findAvailableColumn(row-1, col, true);
+            m_uncommitted->setColumn(ucol);
+            m_haveAllocatedUncommittedColumn = true;
+        }
+        // also, if the uncommitted item has a different branch from
+        // any of its parents, tell it to show the branch
+        if (!cs->isOnBranch(m_uncommitted->branch())) {
+            DEBUG << "Uncommitted branch " << m_uncommitted->branch()
+                  << " differs from my branch " << cs->branch()
+                  << ", asking it to show branch" << endl;
+            m_uncommitted->setShowBranch(true);
+        }
     }
 
     // Normally the children will lay out themselves, but we can do
@@ -222,7 +233,7 @@
         Changeset *child = m_changesets[childId];
         int childRow = m_items[childId]->row();
         if (child->parents().size() > 1 ||
-            child->branch() == cs->branch()) {
+            child->isOnBranch(cs->branch())) {
             for (int r = row-1; r > childRow; --r) {
                 m_alloc[r].insert(col);
             }
@@ -237,7 +248,7 @@
         foreach (QString childId, cs->children()) {
             if (!m_changesets.contains(childId)) continue;
             Changeset *child = m_changesets[childId];
-            if (child->branch() == branch &&
+            if (child->isOnBranch(branch) &&
                 child->parents().size() == 1) {
                 special.push_back(childId);
             }
@@ -287,6 +298,7 @@
     }
 
     m_branchHomes[""] = 0;
+    m_branchHomes["default"] = 0;
 
     foreach (QString branch, m_branchRanges.keys()) {
         if (branch == "") continue;
@@ -339,14 +351,16 @@
     return m_items[cs->id()];
 }
 
-void Grapher::layout(Changesets csets, QString uncommittedSproutsFrom)
+void Grapher::layout(Changesets csets,
+                     QStringList uncommittedParents,
+                     QString uncommittedBranch)
 {
     m_changesets.clear();
     m_items.clear();
     m_alloc.clear();
     m_branchHomes.clear();
 
-    m_uncommittedParentId = uncommittedSproutsFrom;
+    m_uncommittedParents = uncommittedParents;
     m_haveAllocatedUncommittedColumn = false;
     m_uncommittedParentRow = 0;
     m_uncommitted = 0;
@@ -399,13 +413,17 @@
     
     // Add uncommitted item and connecting line as necessary
 
-    if (m_uncommittedParentId != "") {
+    if (!m_uncommittedParents.empty()) {
         m_uncommitted = new UncommittedItem();
+        m_uncommitted->setBranch(uncommittedBranch);
         m_scene->addUncommittedItem(m_uncommitted);
-        ConnectionItem *conn = new ConnectionItem();
-        conn->setParent(m_items[m_uncommittedParentId]);
-        conn->setChild(m_uncommitted);
-        m_scene->addItem(conn);
+        foreach (QString p, m_uncommittedParents) {
+            ConnectionItem *conn = new ConnectionItem();
+            conn->setConnectionType(ConnectionItem::Merge);
+            conn->setParent(m_items[p]);
+            conn->setChild(m_uncommitted);
+            m_scene->addItem(conn);
+        }
     }
 
     // Add the branch labels
@@ -473,6 +491,15 @@
         }
     }
 
+    int datemincol = mincol, datemaxcol = maxcol;
+
+    if (mincol == maxcol) {
+        --datemincol;
+        ++datemaxcol;
+    } else if (m_alloc[minrow].contains(mincol)) {
+        --datemincol;
+    }
+
     // We've given the uncommitted item a column, but not a row yet --
     // it always goes at the top
 
@@ -506,11 +533,6 @@
     bool even = false;
     int n = 0;
 
-    if (mincol == maxcol) {
-        --mincol;
-        ++maxcol;
-    }
-
     for (int row = minrow; row <= maxrow; ++row) {
 
         QString date = m_rowDates[row];
@@ -520,7 +542,7 @@
             if (prevDate != "") {
                 DateItem *item = new DateItem();
                 item->setDateString(prevDate);
-                item->setCols(mincol, maxcol - mincol + 1);
+                item->setCols(datemincol, datemaxcol - datemincol + 1);
                 item->setRows(changeRow, n);
                 item->setEven(even);
                 item->setZValue(-1);
@@ -536,7 +558,7 @@
     if (n > 0) {
         DateItem *item = new DateItem();
         item->setDateString(prevDate);
-        item->setCols(mincol, maxcol - mincol + 1);
+        item->setCols(datemincol, datemaxcol - datemincol + 1);
         item->setRows(changeRow, n+1);
         item->setEven(even);
         item->setZValue(-1);
--- a/grapher.h	Thu Dec 02 11:51:15 2010 +0000
+++ b/grapher.h	Thu Dec 02 17:55:21 2010 +0000
@@ -34,7 +34,9 @@
 public:
     Grapher(ChangesetScene *scene) { m_scene = scene; }
 
-    void layout(Changesets csets, QString uncommittedSproutsFrom = "");
+    void layout(Changesets csets,
+                QStringList uncommittedParents,
+                QString uncommittedBranch);
 
     ChangesetItem *getItemFor(Changeset *cs);
 
@@ -77,7 +79,7 @@
     typedef QMap<int, QString> RowDateMap;
     RowDateMap m_rowDates;
 
-    QString m_uncommittedParentId;
+    QStringList m_uncommittedParents;
     int m_uncommittedParentRow;
     UncommittedItem *m_uncommitted;
     bool m_haveAllocatedUncommittedColumn;
--- a/hgtabwidget.cpp	Thu Dec 02 11:51:15 2010 +0000
+++ b/hgtabwidget.cpp	Thu Dec 02 17:55:21 2010 +0000
@@ -52,6 +52,9 @@
     connect(m_historyWidget, SIGNAL(diffWorkingFolder()),
             this, SIGNAL(diffWorkingFolder()));
 
+    connect(m_historyWidget, SIGNAL(showWork()),
+            this, SLOT(showWorkTab()));
+
     connect(m_historyWidget, SIGNAL(updateTo(QString)),
             this, SIGNAL(updateTo(QString)));
 
@@ -73,9 +76,9 @@
     m_fileStatusWidget->clearSelections();
 }
 
-void HgTabWidget::setCurrent(QStringList ids)
+void HgTabWidget::setCurrent(QStringList ids, QString branch)
 {
-    m_historyWidget->setCurrent(ids, canCommit());
+    m_historyWidget->setCurrent(ids, branch, canCommit());
 }
 
 bool HgTabWidget::canCommit() const
@@ -160,7 +163,7 @@
 {
     m_historyWidget->parseNewLog(hgLogList);
     if (m_historyWidget->haveNewItems()) {
-        setCurrentWidget(m_historyWidget);
+        showHistoryTab();
     }
 }
 
@@ -168,7 +171,7 @@
 {
     m_historyWidget->parseIncrementalLog(hgLogList);
     if (m_historyWidget->haveNewItems()) {
-        setCurrentWidget(m_historyWidget);
+        showHistoryTab();
     }
 }
 
@@ -182,3 +185,14 @@
 {
     m_fileStatusWidget->setState(state);
 }
+
+void HgTabWidget::showWorkTab()
+{
+    setCurrentWidget(m_fileStatusWidget);
+}
+
+void HgTabWidget::showHistoryTab()
+{
+    setCurrentWidget(m_historyWidget);
+}
+
--- a/hgtabwidget.h	Thu Dec 02 11:51:15 2010 +0000
+++ b/hgtabwidget.h	Thu Dec 02 17:55:21 2010 +0000
@@ -48,7 +48,7 @@
     void setWorkFolderAndRepoNames(QString workFolderPath, QString remoteRepoPath);
     void setState(QString state);
 
-    void setCurrent(QStringList ids);
+    void setCurrent(QStringList ids, QString branch);
 
     FileStates getFileStates() { return m_fileStates; }
 
@@ -87,6 +87,8 @@
 
 public slots:
     void clearSelections();
+    void showWorkTab();
+    void showHistoryTab();
 
 private:
     FileStatusWidget *m_fileStatusWidget;
--- a/historywidget.cpp	Thu Dec 02 11:51:15 2010 +0000
+++ b/historywidget.cpp	Thu Dec 02 17:55:21 2010 +0000
@@ -58,15 +58,18 @@
     m_changesets.clear();
 }
 
-void HistoryWidget::setCurrent(QStringList ids, bool showUncommitted)
+void HistoryWidget::setCurrent(QStringList ids, QString branch,
+                               bool showUncommitted)
 {
-    if (m_currentIds == ids && m_showUncommitted == showUncommitted) return;
+    if (m_currentIds == ids &&
+        m_currentBranch == branch &&
+        m_showUncommitted == showUncommitted) return;
 
     DEBUG << "HistoryWidget::setCurrent: " << ids.size() << " ids, "
           << "showUncommitted: " << showUncommitted << endl;
 
     m_currentIds.clear();
-    m_uncommittedParentId = "";
+    m_currentBranch = branch;
     m_showUncommitted = showUncommitted;
 
     if (ids.empty()) return;
@@ -75,7 +78,6 @@
         m_currentIds.push_back(id);
     }
 
-    if (m_showUncommitted) m_uncommittedParentId = m_currentIds[0];
     layoutAll();
 }
     
@@ -159,7 +161,9 @@
     if (!m_changesets.empty()) {
 	Grapher g(scene);
 	try {
-	    g.layout(m_changesets, m_uncommittedParentId);
+	    g.layout(m_changesets,
+                     m_showUncommitted ? m_currentIds : QStringList(),
+                     m_currentBranch);
 	} catch (std::string s) {
 	    std::cerr << "Internal error: Layout failed: " << s << std::endl;
 	}
@@ -244,6 +248,9 @@
     connect(scene, SIGNAL(diffWorkingFolder()),
             this, SIGNAL(diffWorkingFolder()));
 
+    connect(scene, SIGNAL(showWork()),
+            this, SIGNAL(showWork()));
+    
     connect(scene, SIGNAL(updateTo(QString)),
             this, SIGNAL(updateTo(QString)));
 
--- a/historywidget.h	Thu Dec 02 11:51:15 2010 +0000
+++ b/historywidget.h	Thu Dec 02 17:55:21 2010 +0000
@@ -36,7 +36,7 @@
     HistoryWidget();
     virtual ~HistoryWidget();
 
-    void setCurrent(QStringList ids, bool showUncommitted);
+    void setCurrent(QStringList ids, QString branch, bool showUncommitted);
 
     void parseNewLog(QString log);
     void parseIncrementalLog(QString log);
@@ -47,6 +47,7 @@
     void commit();
     void revert();
     void diffWorkingFolder();
+    void showWork();
 
     void updateTo(QString id);
     void diffToParent(QString id, QString parent);
@@ -57,9 +58,9 @@
 private:
     Changesets m_changesets;
     QStringList m_currentIds;
+    QString m_currentBranch;
     QSet<QString> m_newIds;
     bool m_showUncommitted;
-    QString m_uncommittedParentId;
 
     Panned *m_panned;
     Panner *m_panner;
--- a/mainwindow.cpp	Thu Dec 02 11:51:15 2010 +0000
+++ b/mainwindow.cpp	Thu Dec 02 17:55:21 2010 +0000
@@ -89,6 +89,7 @@
     ColourSet *cs = ColourSet::instance();
     cs->clearDefaultNames();
     cs->addDefaultName("");
+    cs->addDefaultName("default");
     cs->addDefaultName(getUserInfo());
 
     if (workFolderPath == "") {
@@ -159,6 +160,12 @@
 {
     QStringList params;
     params << "stat" << "-ardum";
+
+    // annoyingly, hg stat actually modifies the working directory --
+    // it creates files called hg-checklink and hg-checkexec to test
+    // properties of the filesystem
+    if (fsWatcher) fsWatcher->blockSignals(true);
+
     runner->requestAction(HgAction(ACT_STAT, workFolderPath, params));
 }
 
@@ -204,8 +211,7 @@
     params << "log";
 
     foreach (QString p, prune) {
-        QString number = p.split(':')[0];
-        params << "--prune" << number;
+        params << "--prune" << Changeset::hashOf(p);
     }
         
     params << "--template";
@@ -450,6 +456,8 @@
     params << "--config" << "extensions.extdiff=" << "extdiff";
     params << "--program" << diffBinaryName;
 
+    params << hgTabs->getSelectedCommittableFiles(); // may be none: whole dir
+
     runner->requestAction(HgAction(ACT_FOLDERDIFF, workFolderPath, params));
 }
 
@@ -462,7 +470,7 @@
 
     params << "--config" << "extensions.extdiff=" << "extdiff";
     params << "--program" << diffBinaryName;
-    params << "--rev" << id;
+    params << "--rev" << Changeset::hashOf(id);
 
     runner->requestAction(HgAction(ACT_FOLDERDIFF, workFolderPath, params));
 }
@@ -476,7 +484,8 @@
 
     params << "--config" << "extensions.extdiff=" << "extdiff";
     params << "--program" << diffBinaryName;
-    params << "--rev" << parent << "--rev" << child;
+    params << "--rev" << Changeset::hashOf(parent)
+           << "--rev" << Changeset::hashOf(child);
 
     runner->requestAction(HgAction(ACT_CHGSETDIFF, workFolderPath, params));
 }
@@ -496,7 +505,7 @@
 {
     QStringList params;
 
-    params << "update" << "--rev" << id << "--check";
+    params << "update" << "--rev" << Changeset::hashOf(id) << "--check";
 
     runner->requestAction(HgAction(ACT_UPDATE, workFolderPath, params));
 }
@@ -551,7 +560,7 @@
     QStringList params;
 
     params << "merge";
-    params << "--rev" << id;
+    params << "--rev" << Changeset::hashOf(id);
     
     runner->requestAction(HgAction(ACT_MERGE, workFolderPath, params));
 }
@@ -1236,6 +1245,7 @@
         break;
 
     case ACT_STAT:
+        if (fsWatcher) fsWatcher->blockSignals(false);
         hgTabs->updateWorkFolderFileList(output);
         updateFileSystemWatcher();
         break;
@@ -1290,7 +1300,7 @@
         foreach (Changeset *cs, currentParents) delete cs;
         currentParents = Changeset::parseChangesets(output);
         QStringList parentIds = Changeset::getIds(currentParents);
-        hgTabs->setCurrent(parentIds);
+        hgTabs->setCurrent(parentIds, currentBranch);
     }
         break;
         
--- a/uncommitteditem.cpp	Thu Dec 02 11:51:15 2010 +0000
+++ b/uncommitteditem.cpp	Thu Dec 02 17:55:21 2010 +0000
@@ -18,6 +18,7 @@
 #include "uncommitteditem.h"
 #include "colourset.h"
 #include "debug.h"
+#include "textabbrev.h"
 
 #include <QPainter>
 #include <QGraphicsScene>
@@ -28,7 +29,7 @@
 #include <QWidgetAction>
 
 UncommittedItem::UncommittedItem() :
-    m_column(0), m_row(0), m_wide(false)
+    m_showBranch(false), m_column(0), m_row(0), m_wide(false)
 {
     m_font = QFont();
     m_font.setPixelSize(11);
@@ -55,21 +56,33 @@
 }
 
 void
+UncommittedItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *e)
+{
+    DEBUG << "UncommittedItem::mouseDoubleClickEvent" << endl;
+    if (e->button() == Qt::LeftButton) {
+        emit showWork();
+    }
+}
+
+void
 UncommittedItem::activateMenu()
 {
     QMenu *menu = new QMenu;
-    QLabel *label = new QLabel(tr("<qt><b>Uncommitted changes</b></qt>"));
+    QLabel *label = new QLabel(tr("<qt>&nbsp;<b>Uncommitted changes</b></qt>"));
     QWidgetAction *wa = new QWidgetAction(menu);
     wa->setDefaultWidget(label);
     menu->addAction(wa);
     menu->addSeparator();
 
+    QAction *dif = menu->addAction(tr("Diff"));
+    connect(dif, SIGNAL(triggered()), this, SIGNAL(diff()));
+    
+    menu->addSeparator();
+
     QAction *commit = menu->addAction(tr("Commit..."));
     connect(commit, SIGNAL(triggered()), this, SIGNAL(commit()));
     QAction *revert = menu->addAction(tr("Revert..."));
     connect(revert, SIGNAL(triggered()), this, SIGNAL(revert()));
-    QAction *dif = menu->addAction(tr("Diff"));
-    connect(dif, SIGNAL(triggered()), this, SIGNAL(diff()));
 
     menu->exec(QCursor::pos());
 
@@ -129,6 +142,16 @@
                         label);
     }        
 
+    if (m_showBranch && m_branch != "") {
+        // write branch name
+        f.setBold(true);
+        paint->setFont(f);
+        int wid = width - 3;
+        QString b = TextAbbrev::abbreviate(m_branch, QFontMetrics(f), wid);
+        paint->drawText(x0, -fh + fm.ascent() - 4, b);
+        f.setBold(false);
+    }
+
     paint->restore();
     return;
 }
--- a/uncommitteditem.h	Thu Dec 02 11:51:15 2010 +0000
+++ b/uncommitteditem.h	Thu Dec 02 17:55:21 2010 +0000
@@ -34,6 +34,9 @@
 
     QString branch() const { return m_branch; }
     void setBranch(QString b) { m_branch = b; }
+
+    bool showBranch() const { return m_showBranch; }
+    void setShowBranch(bool s) { m_showBranch = s; }
     
     int column() const { return m_column; }
     int row() const { return m_row; }
@@ -47,14 +50,17 @@
     void commit();
     void revert();
     void diff();
+    void showWork();
 
 protected:
     virtual void mousePressEvent(QGraphicsSceneMouseEvent *);
+    virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *);
 
 private:
     void activateMenu();
 
     QString m_branch;
+    bool m_showBranch;
     QFont m_font;
     int m_column;
     int m_row;