changeset 145:644bd31e8301

* Include the uncommitted item in general graph layout (in case it is not at the head, when other items will need to avoid it)
author Chris Cannam
date Wed, 01 Dec 2010 17:41:14 +0000
parents f61f032b06f9
children 5e16b83374fd
files changesetitem.cpp connectionitem.cpp connectionitem.h grapher.cpp grapher.h hgtabwidget.cpp hgtabwidget.h historywidget.cpp historywidget.h main.cpp mainwindow.cpp mainwindow.h uncommitteditem.cpp
diffstat 13 files changed, 212 insertions(+), 104 deletions(-) [+]
line wrap: on
line diff
--- a/changesetitem.cpp	Wed Dec 01 11:54:01 2010 +0000
+++ b/changesetitem.cpp	Wed Dec 01 17:41:14 2010 +0000
@@ -188,7 +188,7 @@
         paint->drawRect(QRectF(x0 - 4, -4, width + 5, height + 8));
     }
 
-    if (scale < 0.1) {
+    if (scale < 0.2) {
 	paint->restore();
 	return;
     }
--- a/connectionitem.cpp	Wed Dec 01 11:54:01 2010 +0000
+++ b/connectionitem.cpp	Wed Dec 01 17:41:14 2010 +0000
@@ -16,6 +16,7 @@
 */
 
 #include "connectionitem.h"
+#include "uncommitteditem.h"
 
 #include "changesetitem.h"
 #include "changeset.h"
@@ -26,33 +27,49 @@
 QRectF
 ConnectionItem::boundingRect() const
 {
-    if (!m_parent || !m_child) return QRectF();
+    if (!m_parent || !(m_child || m_uncommitted)) return QRectF();
     float xscale = 100;
     float yscale = 90;
     float size = 50;
-    return QRectF(xscale * m_child->column() + size/2 - 2,
-		  yscale * m_child->row() + size - 2,
-		  xscale * m_parent->column() - xscale * m_child->column() + 4,
-		  yscale * m_parent->row() - yscale * m_child->row() - size + 4)
+
+    int p_col = m_parent->column(), p_row = m_parent->row();
+    int c_col, c_row;
+    if (m_child) {
+        c_col = m_child->column(); c_row = m_child->row();
+    } else {
+        c_col = m_uncommitted->column(); c_row = m_uncommitted->row();
+    }
+
+    return QRectF(xscale * c_col + size/2 - 2,
+		  yscale * c_row + size - 2,
+		  xscale * p_col - xscale * c_col + 4,
+		  yscale * p_row - yscale * c_row - size + 4)
 	.normalized();
 }
 
 void
 ConnectionItem::paint(QPainter *paint, const QStyleOptionGraphicsItem *, QWidget *)
 {
+    if (!m_parent || !(m_child || m_uncommitted)) return;
     QPainterPath p;
 
     paint->save();
 
     ColourSet *colourSet = ColourSet::instance();
-    QColor branchColour = colourSet->getColourFor(m_child->getChangeset()->branch());
+    QString branch;
+    if (m_child) branch = m_child->getChangeset()->branch();
+    else branch = m_uncommitted->branch();
+    QColor branchColour = colourSet->getColourFor(branch);
+
+    Qt::PenStyle ls = Qt::SolidLine;
+    if (!m_child) ls = Qt::DashLine;
 
     QTransform t = paint->worldTransform();
     float scale = std::min(t.m11(), t.m22());
-    if (scale < 0.1) {
-	paint->setPen(QPen(branchColour, 0));
+    if (scale < 0.2) {
+	paint->setPen(QPen(branchColour, 0, ls));
     } else {
-	paint->setPen(QPen(branchColour, 2));
+	paint->setPen(QPen(branchColour, 2, ls));
     }
 
     float xscale = 100;
@@ -61,8 +78,13 @@
     float size = 50;
     float ygap = yscale - size;
 
-    int c_col = m_child->column(), c_row = m_child->row();
     int p_col = m_parent->column(), p_row = m_parent->row();
+    int c_col, c_row;
+    if (m_child) {
+        c_col = m_child->column(); c_row = m_child->row();
+    } else {
+        c_col = m_uncommitted->column(); c_row = m_uncommitted->row();
+    }
 
     float c_x = xscale * c_col + size/2;
     float p_x = xscale * p_col + size/2;
--- a/connectionitem.h	Wed Dec 01 11:54:01 2010 +0000
+++ b/connectionitem.h	Wed Dec 01 17:41:14 2010 +0000
@@ -23,6 +23,7 @@
 class Connection;
 
 class ChangesetItem;
+class UncommittedItem;
 
 class ConnectionItem : public QGraphicsItem
 {
@@ -41,18 +42,20 @@
     Type connectionType() const { return m_type; }
     void setConnectionType(Type t) { m_type = t; }
 
-    //!!! deletion signals from parent/child
+    //!!! deletion signals from parent/child?
 
     ChangesetItem *parent() { return m_parent; }
     ChangesetItem *child() { return m_child; }
 
     void setParent(ChangesetItem *p) { m_parent = p; }
     void setChild(ChangesetItem *c) { m_child = c; }
+    void setChild(UncommittedItem *u) { m_uncommitted = u; }
 
 private:
     Type m_type;
     ChangesetItem *m_parent;
     ChangesetItem *m_child;
+    UncommittedItem *m_uncommitted;
 };
 
 #endif // CONNECTIONITEM_H
--- a/grapher.cpp	Wed Dec 01 11:54:01 2010 +0000
+++ b/grapher.cpp	Wed Dec 01 17:41:14 2010 +0000
@@ -27,24 +27,30 @@
 {
     int col = parent;
     if (preferParentCol) {
-        if (!m_alloc[row].contains(col)) {
-            return col;
-        }
+        if (isAvailable(row, col)) return col;
     }
     while (col > 0) {
-        if (!m_alloc[row].contains(--col)) return col;
+        if (isAvailable(row, --col)) return col;
     }
     while (col < 0) {
-        if (!m_alloc[row].contains(++col)) return col;
+        if (isAvailable(row, ++col)) return col;
     }
     col = parent;
     int sign = (col < 0 ? -1 : 1);
     while (1) {
         col += sign;
-        if (!m_alloc[row].contains(col)) return col;
+        if (isAvailable(row, col)) return col;
     }
 }
 
+bool Grapher::isAvailable(int row, int col)
+{
+    if (m_alloc.contains(row) && m_alloc[row].contains(col)) return false;
+    if (!m_haveAllocatedUncommittedColumn) return true;
+    if (!m_uncommitted) return true;
+    return !(row <= m_uncommittedParentRow && col == m_uncommitted->column());
+}
+
 void Grapher::layoutRow(QString id)
 {
     if (m_handled.contains(id)) {
@@ -102,6 +108,12 @@
         m_rowDates[row] = date;
     }
 
+    // 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) {
+        m_uncommittedParentRow = row;
+    }
+
     DEBUG << "putting " << cs->id().toStdString() << " at row " << row 
           << endl;
 
@@ -186,6 +198,15 @@
     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 (m_uncommittedParentId == id) {
+        int ucol = findAvailableColumn(row-1, col, true);
+        m_uncommitted->setColumn(ucol);
+        m_haveAllocatedUncommittedColumn = true;
+    }
+
     // Normally the children will lay out themselves, but we can do
     // a better job in some special cases:
 
@@ -306,39 +327,46 @@
 }
 
 static bool
-        compareChangesetsByDate(Changeset *const &a, Changeset *const &b)
+compareChangesetsByDate(Changeset *const &a, Changeset *const &b)
 {
     return a->timestamp() < b->timestamp();
 }
 
 ChangesetItem *
-        Grapher::getItemFor(Changeset *cs)
+Grapher::getItemFor(Changeset *cs)
 {
     if (!cs || !m_items.contains(cs->id())) return 0;
     return m_items[cs->id()];
 }
 
-void Grapher::layout(Changesets csets)
+void Grapher::layout(Changesets csets, QString uncommittedSproutsFrom)
 {
     m_changesets.clear();
     m_items.clear();
     m_alloc.clear();
     m_branchHomes.clear();
 
+    m_uncommittedParentId = uncommittedSproutsFrom;
+    m_haveAllocatedUncommittedColumn = false;
+    m_uncommittedParentRow = 0;
+    m_uncommitted = 0;
+
     DEBUG << "Grapher::layout: Have " << csets.size() << " changesets" << endl;
 
     if (csets.empty()) return;
 
+    // Create (but don't yet position) the changeset items
+
     foreach (Changeset *cs, csets) {
 
         QString id = cs->id();
-//        DEBUG << id.toStdString() << endl;
 
         if (id == "") {
             throw LayoutException("Changeset has no ID");
         }
         if (m_changesets.contains(id)) {
-            DEBUG << "Duplicate changeset ID " << id << " in Grapher::layout()" << endl;
+            DEBUG << "Duplicate changeset ID " << id
+                  << " in Grapher::layout()" << endl;
             throw LayoutException(QString("Duplicate changeset ID %1").arg(id));
         }
 
@@ -368,8 +396,20 @@
             m_scene->addItem(conn);
         }
     }
+    
+    // Add uncommitted item and connecting line as necessary
+
+    if (m_uncommittedParentId != "") {
+        m_uncommitted = new UncommittedItem();
+        m_scene->addItem(m_uncommitted);
+        ConnectionItem *conn = new ConnectionItem();
+        conn->setParent(m_items[m_uncommittedParentId]);
+        conn->setChild(m_uncommitted);
+        m_scene->addItem(conn);
+    }
 
     // Add the branch labels
+
     foreach (Changeset *cs, csets) {
         QString id = cs->id();
         ChangesetItem *item = m_items[id];
@@ -394,7 +434,8 @@
     qStableSort(csets.begin(), csets.end(), compareChangesetsByDate);
 
     foreach (Changeset *cs, csets) {
-        DEBUG << "id " << cs->id().toStdString() << ", ts " << cs->timestamp() << ", date " << cs->datetime().toStdString() << endl;
+        DEBUG << "id " << cs->id().toStdString() << ", ts " << cs->timestamp()
+              << ", date " << cs->datetime().toStdString() << endl;
     }
 
     m_handled.clear();
@@ -415,16 +456,10 @@
         layoutCol(cs->id());
     }
 
-    foreach (Changeset *cs, csets) {
-        ChangesetItem *item = m_items[cs->id()];
-        if (!m_alloc[item->row()].contains(item->column()-1) &&
-            !m_alloc[item->row()].contains(item->column()+1)) {
-            item->setWide(true);
-        }
-    }
+    // Find row and column extents.  We know that 0 is an upper bound
+    // on row, and that mincol must be <= 0 and maxcol >= 0, so these
+    // initial values are good
 
-    // we know that 0 is an upper bound on row, and that mincol must
-    // be <= 0 and maxcol >= 0, so these initial values are good
     int minrow = 0, maxrow = 0;
     int mincol = 0, maxcol = 0;
 
@@ -438,12 +473,44 @@
         }
     }
 
+    // We've given the uncommitted item a column, but not a row yet --
+    // it always goes at the top
+
+    if (m_uncommitted) {
+        --minrow;
+        DEBUG << "putting uncommitted item at row " << minrow << endl;
+        m_uncommitted->setRow(minrow);
+    }
+
+    // Changeset items that have nothing to either side of them can be
+    // made double-width
+
+    foreach (Changeset *cs, csets) {
+        ChangesetItem *item = m_items[cs->id()];
+        if (isAvailable(item->row(), item->column()-1) &&
+            isAvailable(item->row(), item->column()+1)) {
+            item->setWide(true);
+        }
+    }
+
+    if (m_uncommitted) {
+        if (isAvailable(m_uncommitted->row(), m_uncommitted->column()-1) &&
+            isAvailable(m_uncommitted->row(), m_uncommitted->column()+1)) {
+            m_uncommitted->setWide(true);
+        }
+    }
+
     QString prevDate;
     int changeRow = 0;
 
     bool even = false;
     int n = 0;
 
+    if (mincol == maxcol) {
+        --mincol;
+        ++maxcol;
+    }
+
     for (int row = minrow; row <= maxrow; ++row) {
 
         QString date = m_rowDates[row];
--- a/grapher.h	Wed Dec 01 11:54:01 2010 +0000
+++ b/grapher.h	Wed Dec 01 17:41:14 2010 +0000
@@ -20,6 +20,7 @@
 
 #include "changeset.h"
 #include "changesetitem.h"
+#include "uncommitteditem.h"
 #include "changesetscene.h"
 
 #include <QSet>
@@ -33,10 +34,12 @@
 public:
     Grapher(ChangesetScene *scene) { m_scene = scene; }
 
-    void layout(Changesets csets);
+    void layout(Changesets csets, QString uncommittedSproutsFrom = "");
 
     ChangesetItem *getItemFor(Changeset *cs);
 
+    UncommittedItem *getUncommittedItem() { return m_uncommitted; }
+
     class LayoutException : public std::exception {
     public:
 	LayoutException(QString message) throw() : m_message(message) { }
@@ -74,11 +77,17 @@
     typedef QMap<int, QString> RowDateMap;
     RowDateMap m_rowDates;
 
+    QString m_uncommittedParentId;
+    int m_uncommittedParentRow;
+    UncommittedItem *m_uncommitted;
+    bool m_haveAllocatedUncommittedColumn;
+
     void layoutRow(QString id);
     void layoutCol(QString id);
     void allocateBranchHomes(Changesets csets);
     bool rangesConflict(const Range &r1, const Range &r2);
     int findAvailableColumn(int row, int parent, bool preferParentCol);
+    bool isAvailable(int row, int col);
 };
 
 #endif 
--- a/hgtabwidget.cpp	Wed Dec 01 11:54:01 2010 +0000
+++ b/hgtabwidget.cpp	Wed Dec 01 17:41:14 2010 +0000
@@ -73,14 +73,9 @@
     m_fileStatusWidget->clearSelections();
 }
 
-void HgTabWidget::setCurrent(QStringList ids)
+void HgTabWidget::setCurrent(QStringList ids, bool showUncommittedChanges)
 {
-    m_historyWidget->setCurrent(ids);
-}
-
-void HgTabWidget::showUncommittedChanges(bool u)
-{
-    m_historyWidget->showUncommittedChanges(u);
+    m_historyWidget->setCurrent(ids, showUncommittedChanges);
 }
 
 bool HgTabWidget::canCommit() const
--- a/hgtabwidget.h	Wed Dec 01 11:54:01 2010 +0000
+++ b/hgtabwidget.h	Wed Dec 01 17:41:14 2010 +0000
@@ -48,8 +48,7 @@
     void setWorkFolderAndRepoNames(QString workFolderPath, QString remoteRepoPath);
     void setState(QString state);
 
-    void setCurrent(QStringList ids);
-    void showUncommittedChanges(bool);
+    void setCurrent(QStringList ids, bool showUncommittedChanges);
 
     FileStates getFileStates() { return m_fileStates; }
 
--- a/historywidget.cpp	Wed Dec 01 11:54:01 2010 +0000
+++ b/historywidget.cpp	Wed Dec 01 17:41:14 2010 +0000
@@ -32,9 +32,6 @@
 {
     m_panned = new Panned;
     m_panner = new Panner;
-    m_uncommitted = new UncommittedItem();
-    m_uncommitted->setRow(-1);
-    m_uncommittedVisible = false;
 
     QGridLayout *layout = new QGridLayout;
     layout->addWidget(m_panned, 0, 0);
@@ -48,7 +45,11 @@
 HistoryWidget::~HistoryWidget()
 {
     clearChangesets();
-    if (!m_uncommittedVisible) delete m_uncommitted;
+}
+
+QGraphicsScene *HistoryWidget::scene()
+{
+    return m_panned->scene();
 }
 
 void HistoryWidget::clearChangesets()
@@ -57,29 +58,25 @@
     m_changesets.clear();
 }
 
-void HistoryWidget::setCurrent(QStringList ids)
+void HistoryWidget::setCurrent(QStringList ids, bool showUncommitted)
 {
-    if (m_currentIds == ids) return;
-    DEBUG << "HistoryWidget::setCurrent: " << ids.size() << " ids" << endl;
+    if (m_currentIds == ids && m_showUncommitted == showUncommitted) return;
+
+    DEBUG << "HistoryWidget::setCurrent: " << ids.size() << " ids, "
+          << "showUncommitted: " << showUncommitted << endl;
+
     m_currentIds.clear();
+    m_uncommittedParentId = "";
+    m_showUncommitted = showUncommitted;
+
+    if (ids.empty()) return;
+
     foreach (QString id, ids) {
         m_currentIds.push_back(id);
     }
-    updateNewAndCurrentItems();
-}
 
-void HistoryWidget::showUncommittedChanges(bool show)
-{
-    if (m_uncommittedVisible == show) return;
-    m_uncommittedVisible = show;
-    ChangesetScene *scene = qobject_cast<ChangesetScene *>(m_panned->scene());
-    if (!scene) return;
-    if (m_uncommittedVisible) {
-        scene->addUncommittedItem(m_uncommitted);
-        m_uncommitted->ensureVisible();
-    } else {
-        scene->removeItem(m_uncommitted);
-    }
+    if (m_showUncommitted) m_uncommittedParentId = m_currentIds[0];
+    layoutAll();
 }
     
 void HistoryWidget::parseNewLog(QString log)
@@ -152,30 +149,24 @@
 
     QGraphicsScene *oldScene = m_panned->scene();
 
-    // detach m_uncommitted from old scene so it doesn't get deleted
-    if (oldScene && (m_uncommitted->scene() == oldScene)) {
-        oldScene->removeItem(m_uncommitted);
-    }
-
     m_panned->setScene(0);
     m_panner->setScene(0);
 
     delete oldScene;
 
+    QGraphicsItem *toFocus = 0;
+
     if (!m_changesets.empty()) {
 	Grapher g(scene);
 	try {
-	    g.layout(m_changesets);
+	    g.layout(m_changesets, m_uncommittedParentId);
 	} catch (std::string s) {
 	    std::cerr << "Internal error: Layout failed: " << s << std::endl;
 	}
-	tipItem = g.getItemFor(m_changesets[0]);
-        DEBUG << "tipItem is " << tipItem << " for tip changeset " 
-              << m_changesets[0]->id() << endl;
-    }
-
-    if (m_uncommittedVisible) {
-        scene->addUncommittedItem(m_uncommitted);
+        toFocus = g.getUncommittedItem();
+        if (!toFocus) {
+            toFocus = g.getItemFor(m_changesets[0]);
+        }
     }
 
     m_panned->setScene(scene);
@@ -183,12 +174,8 @@
 
     updateNewAndCurrentItems();
 
-    if (m_uncommittedVisible) {
-        DEBUG << "asking uncommitted item to be visible" << endl;
-        m_uncommitted->ensureVisible();
-    } else if (tipItem) {
-        DEBUG << "asking tip item to be visible" << endl;
-        tipItem->ensureVisible();
+    if (toFocus) {
+        toFocus->ensureVisible();
     }
 
     connectSceneSignals();
@@ -237,13 +224,6 @@
         
         csit->setCurrent(current);
         csit->setNew(newid);
-        
-        if (current) {
-            m_uncommitted->setRow(csit->row() - 1);
-            m_uncommitted->setColumn(csit->column());
-            m_uncommitted->setWide(csit->isWide());
-            m_uncommitted->setBranch(csit->getChangeset()->branch());
-        }
     }
 }
 
--- a/historywidget.h	Wed Dec 01 11:54:01 2010 +0000
+++ b/historywidget.h	Wed Dec 01 17:41:14 2010 +0000
@@ -26,6 +26,7 @@
 class Panned;
 class Panner;
 class UncommittedItem;
+class QGraphicsScene;
 
 class HistoryWidget : public QWidget
 {
@@ -35,8 +36,7 @@
     HistoryWidget();
     virtual ~HistoryWidget();
 
-    void setCurrent(QStringList ids);
-    void showUncommittedChanges(bool);
+    void setCurrent(QStringList ids, bool showUncommitted);
 
     void parseNewLog(QString log);
     void parseIncrementalLog(QString log);
@@ -58,12 +58,13 @@
     Changesets m_changesets;
     QStringList m_currentIds;
     QSet<QString> m_newIds;
-    UncommittedItem *m_uncommitted;
-    bool m_uncommittedVisible;
+    bool m_showUncommitted;
+    QString m_uncommittedParentId;
 
     Panned *m_panned;
     Panner *m_panner;
 
+    QGraphicsScene *scene();
     void clearChangesets();
     void replaceChangesets(Changesets);
     void addChangesets(Changesets);
--- a/main.cpp	Wed Dec 01 11:54:01 2010 +0000
+++ b/main.cpp	Wed Dec 01 17:41:14 2010 +0000
@@ -15,12 +15,13 @@
     COPYING included with this distribution for more information.
 */
 
-#include <QApplication>
-
 #include "mainwindow.h"
 #include "common.h"
 #include "debug.h"
 
+#include <QApplication>
+#include <QDir>
+
 int main(int argc, char *argv[])
 {
     QApplication::setOrganizationName("easymercurial");
@@ -34,7 +35,18 @@
     installSignalHandlers();
 
     QApplication app(argc, argv);
+    QStringList args = app.arguments();
     MainWindow mainWin;
     mainWin.show();
+
+    if (args.size() == 2) {
+        QString path = args[1];
+        DEBUG << "Opening " << args[1] << endl;
+        if (QDir(path).exists()) {
+            path = QDir(path).canonicalPath();
+            mainWin.open(path);
+        }
+    }
+
     return app.exec();
 }
--- a/mainwindow.cpp	Wed Dec 01 11:54:01 2010 +0000
+++ b/mainwindow.cpp	Wed Dec 01 17:41:14 2010 +0000
@@ -743,6 +743,15 @@
     }
 }
 
+void MainWindow::open(QString local)
+{
+    if (openLocal(local)) {
+        enableDisableActions();
+        clearState();
+        hgQueryPaths();
+    }
+}
+
 bool MainWindow::complainAboutFilePath(QString arg)
 {    
     QMessageBox::critical
@@ -1435,8 +1444,8 @@
 
     QDir localRepoDir;
     QDir workFolderDir;
-    bool workFolderExist;
-    bool localRepoExist;
+    bool workFolderExist = true;
+    bool localRepoExist = true;
 
     remoteRepoActionsEnabled = true;
     if (remoteRepoPath.isEmpty()) {
@@ -1544,8 +1553,7 @@
 
     QStringList ids;
     foreach (Changeset *cs, currentParents) ids.push_back(cs->id());
-    hgTabs->setCurrent(ids);
-    hgTabs->showUncommittedChanges(hgTabs->canCommit());
+    hgTabs->setCurrent(ids, hgTabs->canCommit());
 
     // Set the state field on the file status widget
 
--- a/mainwindow.h	Wed Dec 01 11:54:01 2010 +0000
+++ b/mainwindow.h	Wed Dec 01 17:41:14 2010 +0000
@@ -56,6 +56,7 @@
     void closeEvent(QCloseEvent *event);
 
 public slots:
+    void open(QString local);
     void hgRefresh();
     void commandCompleted(HgAction action, QString stdOut);
     void commandFailed(HgAction action, QString stdErr);
--- a/uncommitteditem.cpp	Wed Dec 01 11:54:01 2010 +0000
+++ b/uncommitteditem.cpp	Wed Dec 01 17:41:14 2010 +0000
@@ -113,10 +113,21 @@
     QRectF r(x0, 0, width - 3, height);
     paint->drawRect(r);
 
-    paint->drawLine(x0 + width/2, height, x0 + width/2, height + 40);
-
-    QString label = tr("Uncommitted changes");
-    paint->drawText(-(fm.width(label) - 50)/2, 25 - fm.height()/2 + fm.ascent(), label);
+    if (m_wide) {
+        QString label = tr("Uncommitted changes");
+        paint->drawText(-(fm.width(label) - 50)/2,
+                        25 - fm.height()/2 + fm.ascent(),
+                        label);
+    } else {
+        QString label = tr("Uncommitted");
+        paint->drawText(-(fm.width(label) - 50)/2,
+                        25 - fm.height() + fm.ascent(),
+                        label);
+        label = tr("changes");
+        paint->drawText(-(fm.width(label) - 50)/2,
+                        25 + fm.ascent(),
+                        label);
+    }        
 
     paint->restore();
     return;