annotate src/historywidget.cpp @ 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 ddc7238fc3b0
rev   line source
Chris@116 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@116 2
Chris@116 3 /*
Chris@116 4 EasyMercurial
Chris@116 5
Chris@116 6 Based on HgExplorer by Jari Korhonen
Chris@116 7 Copyright (c) 2010 Jari Korhonen
Chris@244 8 Copyright (c) 2011 Chris Cannam
Chris@244 9 Copyright (c) 2011 Queen Mary, University of London
Chris@116 10
Chris@116 11 This program is free software; you can redistribute it and/or
Chris@116 12 modify it under the terms of the GNU General Public License as
Chris@116 13 published by the Free Software Foundation; either version 2 of the
Chris@116 14 License, or (at your option) any later version. See the file
Chris@116 15 COPYING included with this distribution for more information.
Chris@116 16 */
Chris@116 17
Chris@116 18 #include "historywidget.h"
Chris@116 19
Chris@119 20 #include "changesetscene.h"
Chris@397 21 #include "changesetview.h"
Chris@116 22 #include "panner.h"
Chris@116 23 #include "grapher.h"
Chris@116 24 #include "debug.h"
Chris@129 25 #include "uncommitteditem.h"
Chris@116 26
Chris@116 27 #include <iostream>
Chris@116 28
Chris@116 29 #include <QGridLayout>
Chris@116 30
Chris@154 31 HistoryWidget::HistoryWidget() :
Chris@154 32 m_showUncommitted(false),
Chris@154 33 m_refreshNeeded(false)
Chris@116 34 {
Chris@397 35 m_panned = new ChangesetView;
Chris@116 36 m_panner = new Panner;
Chris@116 37
Chris@168 38 m_panned->setDragMode(QGraphicsView::ScrollHandDrag);
Chris@250 39 m_panned->setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
Chris@397 40 m_panned->setCacheMode(QGraphicsView::CacheNone);
Chris@168 41
Chris@116 42 QGridLayout *layout = new QGridLayout;
Chris@116 43 layout->addWidget(m_panned, 0, 0);
Chris@116 44 layout->addWidget(m_panner, 0, 1);
Chris@116 45 m_panner->setMaximumWidth(80);
Chris@116 46 m_panner->connectToPanned(m_panned);
Chris@116 47
Chris@116 48 setLayout(layout);
Chris@116 49 }
Chris@116 50
Chris@116 51 HistoryWidget::~HistoryWidget()
Chris@116 52 {
Chris@116 53 clearChangesets();
Chris@145 54 }
Chris@145 55
Chris@145 56 QGraphicsScene *HistoryWidget::scene()
Chris@145 57 {
Chris@145 58 return m_panned->scene();
Chris@116 59 }
Chris@116 60
Chris@116 61 void HistoryWidget::clearChangesets()
Chris@116 62 {
Chris@116 63 foreach (Changeset *cs, m_changesets) delete cs;
Chris@116 64 m_changesets.clear();
Chris@116 65 }
Chris@128 66
Chris@153 67 void HistoryWidget::setCurrent(QStringList ids, QString branch,
Chris@153 68 bool showUncommitted)
Chris@128 69 {
Chris@153 70 if (m_currentIds == ids &&
Chris@153 71 m_currentBranch == branch &&
Chris@153 72 m_showUncommitted == showUncommitted) return;
Chris@145 73
Chris@145 74 DEBUG << "HistoryWidget::setCurrent: " << ids.size() << " ids, "
Chris@145 75 << "showUncommitted: " << showUncommitted << endl;
Chris@145 76
Chris@133 77 m_currentIds.clear();
Chris@153 78 m_currentBranch = branch;
Chris@145 79 m_showUncommitted = showUncommitted;
Chris@145 80
Chris@145 81 if (ids.empty()) return;
Chris@145 82
Chris@133 83 foreach (QString id, ids) {
Chris@133 84 m_currentIds.push_back(id);
Chris@133 85 }
Chris@128 86
Chris@154 87 m_refreshNeeded = true;
Chris@128 88 }
Chris@505 89
Chris@506 90 void HistoryWidget::setClosedHeadIds(QSet<QString> closed)
Chris@506 91 {
Chris@506 92 if (closed == m_closedIds) return;
Chris@506 93 m_closedIds = closed;
Chris@506 94 m_refreshNeeded = true;
Chris@506 95 }
Chris@506 96
Chris@505 97 void HistoryWidget::setShowUncommitted(bool showUncommitted)
Chris@505 98 {
Chris@505 99 setCurrent(m_currentIds, m_currentBranch, showUncommitted);
Chris@505 100 }
Chris@116 101
Chris@120 102 void HistoryWidget::parseNewLog(QString log)
Chris@120 103 {
Chris@120 104 DEBUG << "HistoryWidget::parseNewLog: log has " << log.length() << " chars" << endl;
Chris@122 105 Changesets csets = Changeset::parseChangesets(log);
Chris@120 106 DEBUG << "HistoryWidget::parseNewLog: log has " << csets.size() << " changesets" << endl;
Chris@133 107 replaceChangesets(csets);
Chris@154 108 m_refreshNeeded = true;
Chris@120 109 }
Chris@120 110
Chris@120 111 void HistoryWidget::parseIncrementalLog(QString log)
Chris@120 112 {
Chris@120 113 DEBUG << "HistoryWidget::parseIncrementalLog: log has " << log.length() << " chars" << endl;
Chris@122 114 Changesets csets = Changeset::parseChangesets(log);
Chris@120 115 DEBUG << "HistoryWidget::parseIncrementalLog: log has " << csets.size() << " changesets" << endl;
Chris@120 116 if (!csets.empty()) {
Chris@133 117 addChangesets(csets);
Chris@120 118 }
Chris@154 119 m_refreshNeeded = true;
Chris@120 120 }
Chris@120 121
Chris@133 122 void HistoryWidget::replaceChangesets(Changesets csets)
Chris@133 123 {
Chris@133 124 QSet<QString> oldIds;
Chris@133 125 foreach (Changeset *cs, m_changesets) {
Chris@133 126 oldIds.insert(cs->id());
Chris@133 127 }
Chris@133 128
Chris@133 129 QSet<QString> newIds;
Chris@133 130 foreach (Changeset *cs, csets) {
Chris@133 131 if (!oldIds.contains(cs->id())) {
Chris@133 132 newIds.insert(cs->id());
Chris@133 133 }
Chris@133 134 }
Chris@133 135
Chris@133 136 if (newIds.size() == csets.size()) {
Chris@133 137 // completely new set, unrelated to the old: don't mark new
Chris@133 138 m_newIds.clear();
Chris@133 139 } else {
Chris@133 140 m_newIds = newIds;
Chris@133 141 }
Chris@133 142
Chris@133 143 clearChangesets();
Chris@133 144 m_changesets = csets;
Chris@133 145 }
Chris@133 146
Chris@133 147 void HistoryWidget::addChangesets(Changesets csets)
Chris@133 148 {
Chris@133 149 m_newIds.clear();
Chris@138 150
Chris@138 151 if (csets.empty()) return;
Chris@138 152
Chris@133 153 foreach (Changeset *cs, csets) {
Chris@133 154 m_newIds.insert(cs->id());
Chris@133 155 }
Chris@133 156
Chris@305 157 DEBUG << "addChangesets: " << csets.size() << " new changesets have ("
Chris@305 158 << m_changesets.size() << " already)" << endl;
Chris@138 159
Chris@133 160 csets << m_changesets;
Chris@133 161 m_changesets = csets;
Chris@133 162 }
Chris@133 163
Chris@154 164 void HistoryWidget::update()
Chris@154 165 {
Chris@154 166 if (m_refreshNeeded) {
Chris@154 167 layoutAll();
Chris@154 168 }
Chris@154 169 }
Chris@154 170
Chris@120 171 void HistoryWidget::layoutAll()
Chris@116 172 {
Chris@154 173 m_refreshNeeded = false;
Chris@154 174
Chris@122 175 setChangesetParents();
Chris@122 176
Chris@119 177 ChangesetScene *scene = new ChangesetScene();
Chris@116 178 ChangesetItem *tipItem = 0;
Chris@116 179
Chris@138 180 QGraphicsScene *oldScene = m_panned->scene();
Chris@138 181
Chris@138 182 m_panned->setScene(0);
Chris@138 183 m_panner->setScene(0);
Chris@138 184
Chris@138 185 delete oldScene;
Chris@138 186
Chris@145 187 QGraphicsItem *toFocus = 0;
Chris@145 188
Chris@120 189 if (!m_changesets.empty()) {
Chris@116 190 Grapher g(scene);
Chris@506 191 g.setClosedHeadIds(m_closedIds);
Chris@116 192 try {
Chris@153 193 g.layout(m_changesets,
Chris@153 194 m_showUncommitted ? m_currentIds : QStringList(),
Chris@153 195 m_currentBranch);
Chris@116 196 } catch (std::string s) {
Chris@116 197 std::cerr << "Internal error: Layout failed: " << s << std::endl;
Chris@116 198 }
Chris@145 199 toFocus = g.getUncommittedItem();
Chris@145 200 if (!toFocus) {
Chris@371 201 if (!m_currentIds.empty()) {
Chris@371 202 toFocus = g.getItemFor(m_currentIds[0]);
Chris@371 203 } else {
Chris@371 204 toFocus = g.getItemFor(m_changesets[0]);
Chris@371 205 }
Chris@145 206 }
Chris@134 207 }
Chris@134 208
Chris@116 209 m_panned->setScene(scene);
Chris@116 210 m_panner->setScene(scene);
Chris@116 211
Chris@133 212 updateNewAndCurrentItems();
Chris@134 213
Chris@145 214 if (toFocus) {
Chris@145 215 toFocus->ensureVisible();
Chris@134 216 }
Chris@141 217
Chris@141 218 connectSceneSignals();
Chris@116 219 }
Chris@116 220
Chris@122 221 void HistoryWidget::setChangesetParents()
Chris@116 222 {
Chris@139 223 for (int i = 0; i < m_changesets.size(); ++i) {
Chris@122 224 Changeset *cs = m_changesets[i];
Chris@123 225 // Need to reset this, as Grapher::layout will recalculate it
Chris@123 226 // and we don't want to end up with twice the children for
Chris@123 227 // each parent...
Chris@123 228 cs->setChildren(QStringList());
Chris@139 229 }
Chris@139 230 for (int i = 0; i+1 < m_changesets.size(); ++i) {
Chris@139 231 Changeset *cs = m_changesets[i];
Chris@116 232 if (cs->parents().empty()) {
Chris@116 233 QStringList list;
Chris@122 234 list.push_back(m_changesets[i+1]->id());
Chris@116 235 cs->setParents(list);
Chris@116 236 }
Chris@116 237 }
Chris@116 238 }
Chris@128 239
Chris@133 240 void HistoryWidget::updateNewAndCurrentItems()
Chris@128 241 {
Chris@128 242 QGraphicsScene *scene = m_panned->scene();
Chris@128 243 if (!scene) return;
Chris@133 244
Chris@128 245 QList<QGraphicsItem *> items = scene->items();
Chris@128 246 foreach (QGraphicsItem *it, items) {
Chris@133 247
Chris@128 248 ChangesetItem *csit = dynamic_cast<ChangesetItem *>(it);
Chris@133 249 if (!csit) continue;
Chris@133 250
Chris@133 251 QString id = csit->getChangeset()->id();
Chris@133 252
Chris@133 253 bool current = m_currentIds.contains(id);
Chris@133 254 if (current) {
Chris@133 255 DEBUG << "id " << id << " is current" << endl;
Chris@133 256 }
Chris@133 257 bool newid = m_newIds.contains(id);
Chris@133 258 if (newid) {
Chris@133 259 DEBUG << "id " << id << " is new" << endl;
Chris@133 260 }
Chris@147 261
Chris@506 262 if (csit->isCurrent() != current ||
Chris@506 263 csit->isNew() != newid) {
Chris@147 264 csit->setCurrent(current);
Chris@147 265 csit->setNew(newid);
Chris@147 266 csit->update();
Chris@147 267 }
Chris@128 268 }
Chris@128 269 }
Chris@141 270
Chris@141 271 void HistoryWidget::connectSceneSignals()
Chris@141 272 {
Chris@141 273 ChangesetScene *scene = qobject_cast<ChangesetScene *>(m_panned->scene());
Chris@141 274 if (!scene) return;
Chris@141 275
Chris@141 276 connect(scene, SIGNAL(commit()),
Chris@141 277 this, SIGNAL(commit()));
Chris@141 278
Chris@141 279 connect(scene, SIGNAL(revert()),
Chris@141 280 this, SIGNAL(revert()));
Chris@141 281
Chris@141 282 connect(scene, SIGNAL(diffWorkingFolder()),
Chris@141 283 this, SIGNAL(diffWorkingFolder()));
Chris@141 284
Chris@168 285 connect(scene, SIGNAL(showSummary()),
Chris@168 286 this, SIGNAL(showSummary()));
Chris@168 287
Chris@153 288 connect(scene, SIGNAL(showWork()),
Chris@153 289 this, SIGNAL(showWork()));
Chris@311 290
Chris@311 291 connect(scene, SIGNAL(newBranch()),
Chris@311 292 this, SIGNAL(newBranch()));
Chris@311 293
Chris@311 294 connect(scene, SIGNAL(noBranch()),
Chris@311 295 this, SIGNAL(noBranch()));
Chris@153 296
Chris@141 297 connect(scene, SIGNAL(updateTo(QString)),
Chris@141 298 this, SIGNAL(updateTo(QString)));
Chris@141 299
Chris@141 300 connect(scene, SIGNAL(diffToCurrent(QString)),
Chris@141 301 this, SIGNAL(diffToCurrent(QString)));
Chris@141 302
Chris@148 303 connect(scene, SIGNAL(diffToParent(QString, QString)),
Chris@148 304 this, SIGNAL(diffToParent(QString, QString)));
Chris@141 305
Chris@289 306 connect(scene, SIGNAL(showSummary(Changeset *)),
Chris@289 307 this, SIGNAL(showSummary(Changeset *)));
Chris@288 308
Chris@141 309 connect(scene, SIGNAL(mergeFrom(QString)),
Chris@141 310 this, SIGNAL(mergeFrom(QString)));
Chris@141 311
Chris@278 312 connect(scene, SIGNAL(newBranch(QString)),
Chris@278 313 this, SIGNAL(newBranch(QString)));
Chris@278 314
Chris@141 315 connect(scene, SIGNAL(tag(QString)),
Chris@141 316 this, SIGNAL(tag(QString)));
Chris@141 317 }