changeset 506:470829a21f98

Identify closed branches and display them in a lighter shade
author Chris Cannam
date Mon, 17 Oct 2011 22:08:05 +0100
parents 1c05e7576ea5
children 459aa20d3eee
files src/changesetitem.cpp src/changesetitem.h src/connectionitem.cpp src/grapher.cpp src/grapher.h src/hgaction.h src/hgtabwidget.cpp src/hgtabwidget.h src/historywidget.cpp src/historywidget.h src/mainwindow.cpp src/mainwindow.h
diffstat 12 files changed, 150 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/src/changesetitem.cpp	Mon Oct 17 16:25:02 2011 +0100
+++ b/src/changesetitem.cpp	Mon Oct 17 22:08:05 2011 +0100
@@ -38,7 +38,7 @@
 ChangesetItem::ChangesetItem(Changeset *cs) :
     m_changeset(cs), m_detail(0),
     m_showBranch(false), m_column(0), m_row(0), m_wide(false),
-    m_current(false), m_new(false)
+    m_current(false), m_closed(false), m_new(false)
 {
     m_font = QFont();
     m_font.setPixelSize(11);
@@ -262,10 +262,16 @@
 {
     paint->save();
     
+    int alpha = 255;
+    if (m_closed) alpha = 90;
+
     ColourSet *colourSet = ColourSet::instance();
     QColor branchColour = colourSet->getColourFor(m_changeset->branch());
     QColor userColour = colourSet->getColourFor(m_changeset->author());
 
+    branchColour.setAlpha(alpha);
+    userColour.setAlpha(alpha);
+
     QFont f(m_font);
 
     QTransform t = paint->worldTransform();
@@ -363,7 +369,10 @@
                                             fm, textwid);
     paint->drawText(x0 + 3, fm.ascent(), person);
 
-    paint->setPen(QPen(Qt::black));
+    QColor textColour = Qt::black;
+    textColour.setAlpha(alpha);
+
+    paint->setPen(QPen(textColour));
 
     QStringList tags = m_changeset->tags();
     if (!tags.empty()) {
@@ -427,11 +436,17 @@
 ChangesetItem::paintMerge(QPainter *paint)
 {
     paint->save();
+
+    int alpha = 255;
+    if (m_closed) alpha = 40;
     
     ColourSet *colourSet = ColourSet::instance();
     QColor branchColour = colourSet->getColourFor(m_changeset->branch());
     QColor userColour = colourSet->getColourFor(m_changeset->author());
 
+    branchColour.setAlpha(alpha);
+    userColour.setAlpha(alpha);
+
     QFont f(m_font);
 
     QTransform t = paint->worldTransform();
--- a/src/changesetitem.h	Mon Oct 17 16:25:02 2011 +0100
+++ b/src/changesetitem.h	Mon Oct 17 22:08:05 2011 +0100
@@ -51,6 +51,9 @@
     bool isCurrent() const { return m_current; }
     void setCurrent(bool c) { m_current = c; }
 
+    bool isClosed() const { return m_closed; }
+    void setClosed(bool c) { m_closed = c; }
+
     bool isNew() const { return m_new; }
     void setNew(bool n) { m_new = n; }
 
@@ -98,6 +101,7 @@
     int m_row;
     bool m_wide;
     bool m_current;
+    bool m_closed;
     bool m_new;
 
     QMap<QAction *, QString> m_parentDiffActions;
--- a/src/connectionitem.cpp	Mon Oct 17 16:25:02 2011 +0100
+++ b/src/connectionitem.cpp	Mon Oct 17 22:08:05 2011 +0100
@@ -55,12 +55,17 @@
 
     paint->save();
 
+    int alpha = 255;
+    if (m_child && m_child->isClosed()) alpha = 90;
+
     ColourSet *colourSet = ColourSet::instance();
     QString branch;
     if (m_child) branch = m_child->getChangeset()->branch();
     else branch = m_uncommitted->branch();
     QColor branchColour = colourSet->getColourFor(branch);
 
+    branchColour.setAlpha(alpha);
+
     Qt::PenStyle ls = Qt::SolidLine;
     if (!m_child) ls = Qt::DashLine;
 
--- a/src/grapher.cpp	Mon Oct 17 16:25:02 2011 +0100
+++ b/src/grapher.cpp	Mon Oct 17 22:08:05 2011 +0100
@@ -435,6 +435,35 @@
         }
     }
     
+    // Ensure the closed branches are all marked as closed
+
+    foreach (QString closedId, m_closedIds) {
+        
+        if (!m_items.contains(closedId)) continue;
+        
+        Changeset *cs = m_changesets[closedId];
+        ChangesetItem *item = m_items[closedId];
+
+        while (cs && item) {
+
+            if (cs->children().size() > 1) {
+                break;
+            }
+
+            item->setClosed(true);
+
+            int pcount = cs->parents().size();
+            if (pcount >= 1) {
+                QString pid = cs->parents()[0];
+                if (!m_items.contains(pid)) break;
+                cs = m_changesets[pid];
+                item = m_items[pid];
+            } else {
+                item = 0;
+            }
+        }
+    }
+
     // Add uncommitted item and connecting line as necessary
 
     if (!m_uncommittedParents.empty()) {
--- a/src/grapher.h	Mon Oct 17 16:25:02 2011 +0100
+++ b/src/grapher.h	Mon Oct 17 22:08:05 2011 +0100
@@ -43,6 +43,8 @@
 
     UncommittedItem *getUncommittedItem() { return m_uncommitted; }
 
+    void setClosedHeadIds(QSet<QString> closed) { m_closedIds = closed; }
+
     class LayoutException : public std::exception {
     public:
 	LayoutException(QString message) throw() : m_message(message) { }
@@ -80,6 +82,8 @@
     typedef QMap<int, QString> RowDateMap;
     RowDateMap m_rowDates;
 
+    QSet<QString> m_closedIds;
+
     bool m_showDates;
 
     QStringList m_uncommittedParents;
--- a/src/hgaction.h	Mon Oct 17 16:25:02 2011 +0100
+++ b/src/hgaction.h	Mon Oct 17 22:08:05 2011 +0100
@@ -31,6 +31,7 @@
     ACT_STAT,
     ACT_RESOLVE_LIST,
     ACT_QUERY_HEADS,
+    ACT_QUERY_HEADS_ACTIVE,
     ACT_QUERY_PARENTS,
     ACT_LOG,
     ACT_LOG_INCREMENTAL,
@@ -92,6 +93,7 @@
         case ACT_STAT:
         case ACT_RESOLVE_LIST:
         case ACT_QUERY_HEADS:
+        case ACT_QUERY_HEADS_ACTIVE:
         case ACT_QUERY_PARENTS:
         case ACT_LOG_INCREMENTAL:
             return true;
--- a/src/hgtabwidget.cpp	Mon Oct 17 16:25:02 2011 +0100
+++ b/src/hgtabwidget.cpp	Mon Oct 17 22:08:05 2011 +0100
@@ -136,6 +136,11 @@
     m_historyWidget->setCurrent(ids, branch, haveChangesToCommit());
 }
 
+void HgTabWidget::setClosedHeadIds(QSet<QString> closed)
+{
+    m_historyWidget->setClosedHeadIds(closed);
+}
+
 void HgTabWidget::updateFileStates()
 {
     m_fileStatusWidget->updateWidgets();
--- a/src/hgtabwidget.h	Mon Oct 17 16:25:02 2011 +0100
+++ b/src/hgtabwidget.h	Mon Oct 17 22:08:05 2011 +0100
@@ -48,6 +48,7 @@
     void setLocalPath(QString workFolderPath);
 
     void setCurrent(QStringList ids, QString branch);
+    void setClosedHeadIds(QSet<QString> ids);
 
     void setHaveMerge(bool);
 
--- a/src/historywidget.cpp	Mon Oct 17 16:25:02 2011 +0100
+++ b/src/historywidget.cpp	Mon Oct 17 22:08:05 2011 +0100
@@ -87,6 +87,13 @@
     m_refreshNeeded = true;
 }
 
+void HistoryWidget::setClosedHeadIds(QSet<QString> closed)
+{
+    if (closed == m_closedIds) return;
+    m_closedIds = closed;
+    m_refreshNeeded = true;
+}
+
 void HistoryWidget::setShowUncommitted(bool showUncommitted)
 {
     setCurrent(m_currentIds, m_currentBranch, showUncommitted);
@@ -181,6 +188,7 @@
 
     if (!m_changesets.empty()) {
 	Grapher g(scene);
+        g.setClosedHeadIds(m_closedIds);
 	try {
 	    g.layout(m_changesets,
                      m_showUncommitted ? m_currentIds : QStringList(),
@@ -251,7 +259,8 @@
             DEBUG << "id " << id << " is new" << endl;
         }
 
-        if (csit->isCurrent() != current || csit->isNew() != newid) {
+        if (csit->isCurrent() != current ||
+            csit->isNew() != newid) {
             csit->setCurrent(current);
             csit->setNew(newid);
             csit->update();
--- a/src/historywidget.h	Mon Oct 17 16:25:02 2011 +0100
+++ b/src/historywidget.h	Mon Oct 17 22:08:05 2011 +0100
@@ -39,6 +39,8 @@
     void setCurrent(QStringList ids, QString branch, bool showUncommitted);
     void setShowUncommitted(bool showUncommitted);
 
+    void setClosedHeadIds(QSet<QString> closed);
+
     void parseNewLog(QString log);
     void parseIncrementalLog(QString log);
 
@@ -68,6 +70,7 @@
     QStringList m_currentIds;
     QString m_currentBranch;
     QSet<QString> m_newIds;
+    QSet<QString> m_closedIds;
     bool m_showUncommitted;
     bool m_refreshNeeded;
 
--- a/src/mainwindow.cpp	Mon Oct 17 16:25:02 2011 +0100
+++ b/src/mainwindow.cpp	Mon Oct 17 22:08:05 2011 +0100
@@ -323,6 +323,13 @@
 */
 }
 
+void MainWindow::hgQueryHeadsActive()
+{
+    QStringList params;
+    params << "heads" << "--active";
+    m_runner->requestAction(HgAction(ACT_QUERY_HEADS_ACTIVE, m_workFolderPath, params));
+}
+
 void MainWindow::hgQueryHeads()
 {
     QStringList params;
@@ -1251,6 +1258,7 @@
     m_currentParents.clear();
     foreach (Changeset *cs, m_currentHeads) delete cs;
     m_currentHeads.clear();
+    m_closedHeadIds.clear();
     m_currentBranch = "";
     m_lastStatOutput = "";
     m_lastRevertedFiles.clear();
@@ -1979,18 +1987,18 @@
     bool headsAreLocal = false;
 
     if (m_currentParents.size() == 1) {
-        int m_currentBranchHeads = 0;
+        int currentBranchActiveHeads = 0;
         bool parentIsHead = false;
         Changeset *parent = m_currentParents[0];
-        foreach (Changeset *head, m_currentHeads) {
+        foreach (Changeset *head, m_activeHeads) {
             if (head->isOnBranch(m_currentBranch)) {
-                ++m_currentBranchHeads;
+                ++currentBranchActiveHeads;
             }
             if (parent->id() == head->id()) {
                 parentIsHead = true;
             }
         }
-        if (m_currentBranchHeads == 2 && parentIsHead) {
+        if (currentBranchActiveHeads == 2 && parentIsHead) {
             headsAreLocal = true;
         }
     }
@@ -2138,6 +2146,7 @@
             return;
         }
         break; // go on to default report
+    case ACT_QUERY_HEADS_ACTIVE:
     case ACT_QUERY_HEADS:
         // fails if repo is empty; we don't care (if there's a genuine
         // problem, something else will fail too).  Pretend it
@@ -2324,6 +2333,11 @@
     }
         break;
         
+    case ACT_QUERY_HEADS_ACTIVE:
+        foreach (Changeset *cs, m_activeHeads) delete cs;
+        m_activeHeads = Changeset::parseChangesets(output);
+        break;
+
     case ACT_QUERY_HEADS:
     {
         oldHeadIds = Changeset::getIds(m_currentHeads);
@@ -2336,6 +2350,7 @@
             headsChanged = true;
             foreach (Changeset *cs, m_currentHeads) delete cs;
             m_currentHeads = newHeads;
+            updateClosedHeads();
         }
     }
         break;
@@ -2486,6 +2501,10 @@
         break;
 
     case ACT_RESOLVE_LIST:
+        hgQueryHeadsActive();
+        break;
+
+    case ACT_QUERY_HEADS_ACTIVE:
         hgQueryHeads();
         break;
 
@@ -2725,24 +2744,32 @@
     bool emptyRepo = false;
     bool noWorkingCopy = false;
     bool newBranch = false;
-    int m_currentBranchHeads = 0;
+    bool closedBranch = false;
+    int currentBranchActiveHeads = 0;
 
     if (m_currentParents.size() == 1) {
         bool parentIsHead = false;
+        bool parentIsActiveHead = false;
         Changeset *parent = m_currentParents[0];
-        foreach (Changeset *head, m_currentHeads) {
-            DEBUG << "head branch " << head->branch() << ", current branch " << m_currentBranch << endl;
+        foreach (Changeset *head, m_activeHeads) {
             if (head->isOnBranch(m_currentBranch)) {
-                ++m_currentBranchHeads;
+                ++currentBranchActiveHeads;
             }
             if (parent->id() == head->id()) {
-                parentIsHead = true;
+                parentIsActiveHead = parentIsHead = true;
             }
         }
-        if (m_currentBranchHeads == 2 && parentIsHead) {
+        if (!parentIsActiveHead) {
+            foreach (Changeset *head, m_currentHeads) {
+                if (parent->id() == head->id()) {
+                    parentIsHead = true;
+                }
+            }
+        }
+        if (currentBranchActiveHeads == 2 && parentIsActiveHead) {
             canMerge = true;
         }
-        if (m_currentBranchHeads == 0 && parentIsHead) {
+        if (currentBranchActiveHeads == 0 && parentIsActiveHead) {
             // Just created a new branch
             newBranch = true;
         }
@@ -2753,6 +2780,8 @@
             foreach (Changeset *h, m_currentHeads) {
                 DEBUG << "head id = " << h->id() << endl;
             }
+        } else if (!parentIsActiveHead) {
+            closedBranch = true;
         }
         m_justMerged = false;
     } else if (m_currentParents.size() == 0) {
@@ -2778,9 +2807,9 @@
     m_hgPushAct->setEnabled(m_localRepoActionsEnabled && !emptyRepo);
 
     m_hgMergeAct->setEnabled(m_localRepoActionsEnabled &&
-                           (canMerge || m_hgTabs->canResolve()));
+                             (canMerge || m_hgTabs->canResolve()));
     m_hgUpdateAct->setEnabled(m_localRepoActionsEnabled &&
-                            (canUpdate && !m_hgTabs->haveChangesToCommit()));
+                              (canUpdate && !m_hgTabs->haveChangesToCommit()));
 
     // Set the state field on the file status widget
 
@@ -2809,6 +2838,12 @@
         m_workStatus->setState(tr("Have merged but not yet committed on %1").arg(branchText));
     } else if (newBranch) {
         m_workStatus->setState(tr("On %1.  New branch: has not yet been committed").arg(branchText));
+    } else if (closedBranch) {
+        if (canUpdate) {
+            m_workStatus->setState(tr("On a closed branch. Not at the head of the branch"));
+        } else {
+            m_workStatus->setState(tr("At the head of a closed branch"));
+        }
     } else if (canUpdate) {
         if (m_hgTabs->haveChangesToCommit()) {
             // have uncommitted changes
@@ -2817,14 +2852,29 @@
             // no uncommitted changes
             m_workStatus->setState(tr("On %1. Not at the head of the branch: consider updating").arg(branchText));
         }
-    } else if (m_currentBranchHeads > 1) {
-        m_workStatus->setState(tr("At one of %n heads of %1", "", m_currentBranchHeads).arg(branchText));
+    } else if (currentBranchActiveHeads > 1) {
+        m_workStatus->setState(tr("At one of %n heads of %1", "", currentBranchActiveHeads).arg(branchText));
     } else {
         m_workStatus->setState(tr("At the head of %1").arg(branchText));
     }
 }
 
 
+void MainWindow::updateClosedHeads()
+{
+    m_closedHeadIds.clear();
+    QSet<QString> activeIds;
+    foreach (Changeset *cs, m_activeHeads) {
+        activeIds.insert(cs->id());
+    }
+    foreach (Changeset *cs, m_currentHeads) {
+        if (!activeIds.contains(cs->id())) {
+            m_closedHeadIds.insert(cs->id());
+        }
+    }
+    m_hgTabs->setClosedHeadIds(m_closedHeadIds);
+}
+
 void MainWindow::updateRecentMenu()
 {
     m_recentMenu->clear();
--- a/src/mainwindow.h	Mon Oct 17 16:25:02 2011 +0100
+++ b/src/mainwindow.h	Mon Oct 17 22:08:05 2011 +0100
@@ -121,6 +121,7 @@
 
 private:
     void hgQueryBranch();
+    void hgQueryHeadsActive();
     void hgQueryHeads();
     void hgQueryParents();
     void hgLog();
@@ -178,6 +179,8 @@
     void suspendFileSystemWatcher();
     void restoreFileSystemWatcher();
 
+    void updateClosedHeads();
+
     void updateWorkFolderAndRepoNames();
 
     WorkStatusWidget *m_workStatus;
@@ -187,6 +190,8 @@
     QString m_workFolderPath;
     QString m_currentBranch;
     Changesets m_currentHeads;
+    Changesets m_activeHeads;
+    QSet<QString> m_closedHeadIds;
     Changesets m_currentParents;
     int m_commitsSincePush;
     bool m_stateUnknown;