annotate src/historywidget.cpp @ 644:ae67ea0af696

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