annotate src/historywidget.cpp @ 519:000f13faa089

Bookmarks are now displayed -- but exactly like tags, so far, there's no differentiation yet
author Chris Cannam
date Tue, 08 Nov 2011 16:42:09 +0000
parents 306a62fe851e
children a17c06f773cd
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@513 30 #include <QSettings>
Chris@116 31
Chris@154 32 HistoryWidget::HistoryWidget() :
Chris@154 33 m_showUncommitted(false),
Chris@154 34 m_refreshNeeded(false)
Chris@116 35 {
Chris@397 36 m_panned = new ChangesetView;
Chris@116 37 m_panner = new Panner;
Chris@116 38
Chris@168 39 m_panned->setDragMode(QGraphicsView::ScrollHandDrag);
Chris@250 40 m_panned->setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
Chris@397 41 m_panned->setCacheMode(QGraphicsView::CacheNone);
Chris@168 42
Chris@513 43 int row = 0;
Chris@513 44
Chris@116 45 QGridLayout *layout = new QGridLayout;
Chris@513 46 layout->setMargin(10);
Chris@513 47 layout->addWidget(m_panned, row, 0);
Chris@513 48 layout->addWidget(m_panner, row, 1);
Chris@116 49 m_panner->setMaximumWidth(80);
Chris@116 50 m_panner->connectToPanned(m_panned);
Chris@116 51
Chris@513 52 layout->setRowStretch(row, 20);
Chris@513 53
Chris@513 54 QSettings settings;
Chris@513 55 settings.beginGroup("Presentation");
Chris@513 56 bool showClosed = (settings.value("showclosedbranches", false).toBool());
Chris@513 57
Chris@513 58 m_showClosedBranches = new QCheckBox(tr("Show closed branches"), this);
Chris@513 59 m_showClosedBranches->setChecked(showClosed);
Chris@513 60 connect(m_showClosedBranches, SIGNAL(toggled(bool)),
Chris@513 61 this, SLOT(showClosedChanged(bool)));
Chris@513 62 layout->addWidget(m_showClosedBranches, ++row, 0, Qt::AlignLeft);
Chris@513 63 m_showClosedBranches->hide();
Chris@513 64
Chris@116 65 setLayout(layout);
Chris@116 66 }
Chris@116 67
Chris@116 68 HistoryWidget::~HistoryWidget()
Chris@116 69 {
Chris@116 70 clearChangesets();
Chris@145 71 }
Chris@145 72
Chris@145 73 QGraphicsScene *HistoryWidget::scene()
Chris@145 74 {
Chris@145 75 return m_panned->scene();
Chris@116 76 }
Chris@116 77
Chris@116 78 void HistoryWidget::clearChangesets()
Chris@116 79 {
Chris@116 80 foreach (Changeset *cs, m_changesets) delete cs;
Chris@116 81 m_changesets.clear();
Chris@116 82 }
Chris@128 83
Chris@153 84 void HistoryWidget::setCurrent(QStringList ids, QString branch,
Chris@153 85 bool showUncommitted)
Chris@128 86 {
Chris@153 87 if (m_currentIds == ids &&
Chris@153 88 m_currentBranch == branch &&
Chris@153 89 m_showUncommitted == showUncommitted) return;
Chris@145 90
Chris@145 91 DEBUG << "HistoryWidget::setCurrent: " << ids.size() << " ids, "
Chris@145 92 << "showUncommitted: " << showUncommitted << endl;
Chris@145 93
Chris@133 94 m_currentIds.clear();
Chris@153 95 m_currentBranch = branch;
Chris@145 96 m_showUncommitted = showUncommitted;
Chris@145 97
Chris@145 98 if (ids.empty()) return;
Chris@145 99
Chris@133 100 foreach (QString id, ids) {
Chris@133 101 m_currentIds.push_back(id);
Chris@133 102 }
Chris@128 103
Chris@154 104 m_refreshNeeded = true;
Chris@128 105 }
Chris@505 106
Chris@519 107 void HistoryWidget::setBookmarks(QHash<QString, QStringList> bookmarks)
Chris@519 108 {
Chris@519 109 m_bookmarks = bookmarks;
Chris@519 110 }
Chris@519 111
Chris@506 112 void HistoryWidget::setClosedHeadIds(QSet<QString> closed)
Chris@506 113 {
Chris@506 114 if (closed == m_closedIds) return;
Chris@506 115 m_closedIds = closed;
Chris@513 116 m_showClosedBranches->setVisible(!closed.empty());
Chris@506 117 m_refreshNeeded = true;
Chris@506 118 }
Chris@506 119
Chris@505 120 void HistoryWidget::setShowUncommitted(bool showUncommitted)
Chris@505 121 {
Chris@505 122 setCurrent(m_currentIds, m_currentBranch, showUncommitted);
Chris@505 123 }
Chris@513 124
Chris@513 125 void HistoryWidget::showClosedChanged(bool show)
Chris@513 126 {
Chris@513 127 QSettings settings;
Chris@513 128 settings.beginGroup("Presentation");
Chris@513 129 settings.setValue("showclosedbranches", show);
Chris@513 130 layoutAll();
Chris@513 131 }
Chris@116 132
Chris@120 133 void HistoryWidget::parseNewLog(QString log)
Chris@120 134 {
Chris@120 135 DEBUG << "HistoryWidget::parseNewLog: log has " << log.length() << " chars" << endl;
Chris@122 136 Changesets csets = Changeset::parseChangesets(log);
Chris@120 137 DEBUG << "HistoryWidget::parseNewLog: log has " << csets.size() << " changesets" << endl;
Chris@133 138 replaceChangesets(csets);
Chris@154 139 m_refreshNeeded = true;
Chris@120 140 }
Chris@120 141
Chris@120 142 void HistoryWidget::parseIncrementalLog(QString log)
Chris@120 143 {
Chris@120 144 DEBUG << "HistoryWidget::parseIncrementalLog: log has " << log.length() << " chars" << endl;
Chris@122 145 Changesets csets = Changeset::parseChangesets(log);
Chris@120 146 DEBUG << "HistoryWidget::parseIncrementalLog: log has " << csets.size() << " changesets" << endl;
Chris@120 147 if (!csets.empty()) {
Chris@133 148 addChangesets(csets);
Chris@120 149 }
Chris@154 150 m_refreshNeeded = true;
Chris@120 151 }
Chris@120 152
Chris@133 153 void HistoryWidget::replaceChangesets(Changesets csets)
Chris@133 154 {
Chris@133 155 QSet<QString> oldIds;
Chris@133 156 foreach (Changeset *cs, m_changesets) {
Chris@133 157 oldIds.insert(cs->id());
Chris@133 158 }
Chris@133 159
Chris@133 160 QSet<QString> newIds;
Chris@133 161 foreach (Changeset *cs, csets) {
Chris@133 162 if (!oldIds.contains(cs->id())) {
Chris@133 163 newIds.insert(cs->id());
Chris@133 164 }
Chris@133 165 }
Chris@133 166
Chris@133 167 if (newIds.size() == csets.size()) {
Chris@133 168 // completely new set, unrelated to the old: don't mark new
Chris@133 169 m_newIds.clear();
Chris@133 170 } else {
Chris@133 171 m_newIds = newIds;
Chris@133 172 }
Chris@133 173
Chris@133 174 clearChangesets();
Chris@133 175 m_changesets = csets;
Chris@133 176 }
Chris@133 177
Chris@133 178 void HistoryWidget::addChangesets(Changesets csets)
Chris@133 179 {
Chris@133 180 m_newIds.clear();
Chris@138 181
Chris@138 182 if (csets.empty()) return;
Chris@138 183
Chris@133 184 foreach (Changeset *cs, csets) {
Chris@133 185 m_newIds.insert(cs->id());
Chris@133 186 }
Chris@133 187
Chris@305 188 DEBUG << "addChangesets: " << csets.size() << " new changesets have ("
Chris@305 189 << m_changesets.size() << " already)" << endl;
Chris@138 190
Chris@133 191 csets << m_changesets;
Chris@133 192 m_changesets = csets;
Chris@133 193 }
Chris@133 194
Chris@154 195 void HistoryWidget::update()
Chris@154 196 {
Chris@154 197 if (m_refreshNeeded) {
Chris@154 198 layoutAll();
Chris@154 199 }
Chris@154 200 }
Chris@154 201
Chris@120 202 void HistoryWidget::layoutAll()
Chris@116 203 {
Chris@154 204 m_refreshNeeded = false;
Chris@154 205
Chris@122 206 setChangesetParents();
Chris@122 207
Chris@119 208 ChangesetScene *scene = new ChangesetScene();
Chris@116 209 ChangesetItem *tipItem = 0;
Chris@116 210
Chris@138 211 QGraphicsScene *oldScene = m_panned->scene();
Chris@138 212
Chris@138 213 m_panned->setScene(0);
Chris@138 214 m_panner->setScene(0);
Chris@138 215
Chris@138 216 delete oldScene;
Chris@138 217
Chris@145 218 QGraphicsItem *toFocus = 0;
Chris@145 219
Chris@120 220 if (!m_changesets.empty()) {
Chris@116 221 Grapher g(scene);
Chris@506 222 g.setClosedHeadIds(m_closedIds);
Chris@116 223 try {
Chris@153 224 g.layout(m_changesets,
Chris@153 225 m_showUncommitted ? m_currentIds : QStringList(),
Chris@153 226 m_currentBranch);
Chris@116 227 } catch (std::string s) {
Chris@116 228 std::cerr << "Internal error: Layout failed: " << s << std::endl;
Chris@116 229 }
Chris@145 230 toFocus = g.getUncommittedItem();
Chris@145 231 if (!toFocus) {
Chris@371 232 if (!m_currentIds.empty()) {
Chris@371 233 toFocus = g.getItemFor(m_currentIds[0]);
Chris@371 234 } else {
Chris@371 235 toFocus = g.getItemFor(m_changesets[0]);
Chris@371 236 }
Chris@145 237 }
Chris@134 238 }
Chris@134 239
Chris@116 240 m_panned->setScene(scene);
Chris@116 241 m_panner->setScene(scene);
Chris@116 242
Chris@133 243 updateNewAndCurrentItems();
Chris@134 244
Chris@145 245 if (toFocus) {
Chris@145 246 toFocus->ensureVisible();
Chris@134 247 }
Chris@141 248
Chris@141 249 connectSceneSignals();
Chris@116 250 }
Chris@116 251
Chris@122 252 void HistoryWidget::setChangesetParents()
Chris@116 253 {
Chris@139 254 for (int i = 0; i < m_changesets.size(); ++i) {
Chris@122 255 Changeset *cs = m_changesets[i];
Chris@123 256 // Need to reset this, as Grapher::layout will recalculate it
Chris@123 257 // and we don't want to end up with twice the children for
Chris@123 258 // each parent...
Chris@123 259 cs->setChildren(QStringList());
Chris@139 260 }
Chris@139 261 for (int i = 0; i+1 < m_changesets.size(); ++i) {
Chris@139 262 Changeset *cs = m_changesets[i];
Chris@116 263 if (cs->parents().empty()) {
Chris@116 264 QStringList list;
Chris@122 265 list.push_back(m_changesets[i+1]->id());
Chris@116 266 cs->setParents(list);
Chris@116 267 }
Chris@116 268 }
Chris@116 269 }
Chris@128 270
Chris@133 271 void HistoryWidget::updateNewAndCurrentItems()
Chris@128 272 {
Chris@128 273 QGraphicsScene *scene = m_panned->scene();
Chris@128 274 if (!scene) return;
Chris@133 275
Chris@128 276 QList<QGraphicsItem *> items = scene->items();
Chris@128 277 foreach (QGraphicsItem *it, items) {
Chris@133 278
Chris@128 279 ChangesetItem *csit = dynamic_cast<ChangesetItem *>(it);
Chris@133 280 if (!csit) continue;
Chris@133 281
Chris@133 282 QString id = csit->getChangeset()->id();
Chris@133 283
Chris@133 284 bool current = m_currentIds.contains(id);
Chris@133 285 if (current) {
Chris@133 286 DEBUG << "id " << id << " is current" << endl;
Chris@133 287 }
Chris@133 288 bool newid = m_newIds.contains(id);
Chris@133 289 if (newid) {
Chris@133 290 DEBUG << "id " << id << " is new" << endl;
Chris@133 291 }
Chris@147 292
Chris@519 293 if (m_bookmarks.contains(id)) {
Chris@519 294 csit->setBookmarks(m_bookmarks[id]);
Chris@519 295 } else {
Chris@519 296 csit->setBookmarks(QStringList());
Chris@519 297 }
Chris@519 298
Chris@506 299 if (csit->isCurrent() != current ||
Chris@506 300 csit->isNew() != newid) {
Chris@147 301 csit->setCurrent(current);
Chris@147 302 csit->setNew(newid);
Chris@147 303 csit->update();
Chris@147 304 }
Chris@128 305 }
Chris@128 306 }
Chris@141 307
Chris@141 308 void HistoryWidget::connectSceneSignals()
Chris@141 309 {
Chris@141 310 ChangesetScene *scene = qobject_cast<ChangesetScene *>(m_panned->scene());
Chris@141 311 if (!scene) return;
Chris@141 312
Chris@141 313 connect(scene, SIGNAL(commit()),
Chris@141 314 this, SIGNAL(commit()));
Chris@141 315
Chris@141 316 connect(scene, SIGNAL(revert()),
Chris@141 317 this, SIGNAL(revert()));
Chris@141 318
Chris@141 319 connect(scene, SIGNAL(diffWorkingFolder()),
Chris@141 320 this, SIGNAL(diffWorkingFolder()));
Chris@141 321
Chris@168 322 connect(scene, SIGNAL(showSummary()),
Chris@168 323 this, SIGNAL(showSummary()));
Chris@168 324
Chris@153 325 connect(scene, SIGNAL(showWork()),
Chris@153 326 this, SIGNAL(showWork()));
Chris@311 327
Chris@311 328 connect(scene, SIGNAL(newBranch()),
Chris@311 329 this, SIGNAL(newBranch()));
Chris@311 330
Chris@311 331 connect(scene, SIGNAL(noBranch()),
Chris@311 332 this, SIGNAL(noBranch()));
Chris@153 333
Chris@141 334 connect(scene, SIGNAL(updateTo(QString)),
Chris@141 335 this, SIGNAL(updateTo(QString)));
Chris@141 336
Chris@141 337 connect(scene, SIGNAL(diffToCurrent(QString)),
Chris@141 338 this, SIGNAL(diffToCurrent(QString)));
Chris@141 339
Chris@148 340 connect(scene, SIGNAL(diffToParent(QString, QString)),
Chris@148 341 this, SIGNAL(diffToParent(QString, QString)));
Chris@141 342
Chris@289 343 connect(scene, SIGNAL(showSummary(Changeset *)),
Chris@289 344 this, SIGNAL(showSummary(Changeset *)));
Chris@288 345
Chris@141 346 connect(scene, SIGNAL(mergeFrom(QString)),
Chris@141 347 this, SIGNAL(mergeFrom(QString)));
Chris@141 348
Chris@278 349 connect(scene, SIGNAL(newBranch(QString)),
Chris@278 350 this, SIGNAL(newBranch(QString)));
Chris@278 351
Chris@514 352 connect(scene, SIGNAL(closeBranch(QString)),
Chris@514 353 this, SIGNAL(closeBranch(QString)));
Chris@514 354
Chris@141 355 connect(scene, SIGNAL(tag(QString)),
Chris@141 356 this, SIGNAL(tag(QString)));
Chris@141 357 }