annotate src/historywidget.cpp @ 571:012ba1b83328

Show cancel button with progress bar only when running an operation that it makes sense to cancel (we don't really want people cancelling e.g. initial folder scan because it would leave things in an inconsistent state)
author Chris Cannam
date Thu, 01 Mar 2012 22:53:54 +0000
parents 1e76d1009167
children 88ec0ae91dcc
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@560 8 Copyright (c) 2012 Chris Cannam
Chris@560 9 Copyright (c) 2012 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@513 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@120 208 void HistoryWidget::layoutAll()
Chris@116 209 {
Chris@154 210 m_refreshNeeded = false;
Chris@154 211
Chris@122 212 setChangesetParents();
Chris@122 213
Chris@119 214 ChangesetScene *scene = new ChangesetScene();
Chris@116 215 ChangesetItem *tipItem = 0;
Chris@116 216
Chris@138 217 QGraphicsScene *oldScene = m_panned->scene();
Chris@138 218
Chris@138 219 m_panned->setScene(0);
Chris@138 220 m_panner->setScene(0);
Chris@138 221
Chris@138 222 delete oldScene;
Chris@138 223
Chris@145 224 QGraphicsItem *toFocus = 0;
Chris@145 225
Chris@120 226 if (!m_changesets.empty()) {
Chris@116 227 Grapher g(scene);
Chris@506 228 g.setClosedHeadIds(m_closedIds);
Chris@116 229 try {
Chris@153 230 g.layout(m_changesets,
Chris@153 231 m_showUncommitted ? m_currentIds : QStringList(),
Chris@153 232 m_currentBranch);
Chris@116 233 } catch (std::string s) {
Chris@116 234 std::cerr << "Internal error: Layout failed: " << s << std::endl;
Chris@116 235 }
Chris@145 236 toFocus = g.getUncommittedItem();
Chris@145 237 if (!toFocus) {
Chris@371 238 if (!m_currentIds.empty()) {
Chris@371 239 toFocus = g.getItemFor(m_currentIds[0]);
Chris@371 240 } else {
Chris@371 241 toFocus = g.getItemFor(m_changesets[0]);
Chris@371 242 }
Chris@145 243 }
Chris@134 244 }
Chris@134 245
Chris@116 246 m_panned->setScene(scene);
Chris@116 247 m_panner->setScene(scene);
Chris@116 248
Chris@133 249 updateNewAndCurrentItems();
Chris@134 250
Chris@145 251 if (toFocus) {
Chris@145 252 toFocus->ensureVisible();
Chris@134 253 }
Chris@141 254
Chris@555 255 updateSearchStatus();
Chris@141 256 connectSceneSignals();
Chris@116 257 }
Chris@116 258
Chris@122 259 void HistoryWidget::setChangesetParents()
Chris@116 260 {
Chris@139 261 for (int i = 0; i < m_changesets.size(); ++i) {
Chris@122 262 Changeset *cs = m_changesets[i];
Chris@123 263 // Need to reset this, as Grapher::layout will recalculate it
Chris@123 264 // and we don't want to end up with twice the children for
Chris@123 265 // each parent...
Chris@123 266 cs->setChildren(QStringList());
Chris@139 267 }
Chris@139 268 for (int i = 0; i+1 < m_changesets.size(); ++i) {
Chris@139 269 Changeset *cs = m_changesets[i];
Chris@116 270 if (cs->parents().empty()) {
Chris@116 271 QStringList list;
Chris@122 272 list.push_back(m_changesets[i+1]->id());
Chris@116 273 cs->setParents(list);
Chris@116 274 }
Chris@116 275 }
Chris@116 276 }
Chris@128 277
Chris@133 278 void HistoryWidget::updateNewAndCurrentItems()
Chris@128 279 {
Chris@128 280 QGraphicsScene *scene = m_panned->scene();
Chris@128 281 if (!scene) return;
Chris@133 282
Chris@128 283 QList<QGraphicsItem *> items = scene->items();
Chris@128 284 foreach (QGraphicsItem *it, items) {
Chris@133 285
Chris@128 286 ChangesetItem *csit = dynamic_cast<ChangesetItem *>(it);
Chris@133 287 if (!csit) continue;
Chris@133 288
Chris@133 289 QString id = csit->getChangeset()->id();
Chris@133 290
Chris@133 291 bool current = m_currentIds.contains(id);
Chris@133 292 if (current) {
Chris@133 293 DEBUG << "id " << id << " is current" << endl;
Chris@133 294 }
Chris@133 295 bool newid = m_newIds.contains(id);
Chris@133 296 if (newid) {
Chris@133 297 DEBUG << "id " << id << " is new" << endl;
Chris@133 298 }
Chris@147 299
Chris@506 300 if (csit->isCurrent() != current ||
Chris@506 301 csit->isNew() != newid) {
Chris@147 302 csit->setCurrent(current);
Chris@147 303 csit->setNew(newid);
Chris@147 304 csit->update();
Chris@147 305 }
Chris@128 306 }
Chris@128 307 }
Chris@141 308
Chris@555 309 void HistoryWidget::setSearchText(QString text)
Chris@555 310 {
Chris@555 311 if (m_searchText == text) return;
Chris@555 312 m_searchText = text;
Chris@555 313 updateSearchStatus();
Chris@555 314 }
Chris@555 315
Chris@555 316 void HistoryWidget::updateSearchStatus()
Chris@555 317 {
Chris@555 318 QGraphicsScene *scene = m_panned->scene();
Chris@555 319 if (!scene) return;
Chris@555 320
Chris@555 321 ChangesetItem *toFocus = 0;
Chris@555 322
Chris@555 323 QList<QGraphicsItem *> items = scene->items();
Chris@555 324 foreach (QGraphicsItem *it, items) {
Chris@555 325
Chris@555 326 ChangesetItem *csit = dynamic_cast<ChangesetItem *>(it);
Chris@555 327 if (!csit) continue;
Chris@555 328
Chris@566 329 bool matched = csit->matchSearchText(m_searchText);
Chris@555 330 if (matched && (!toFocus || csit->row() < toFocus->row())) {
Chris@555 331 toFocus = csit;
Chris@555 332 }
Chris@555 333 csit->update();
Chris@555 334 }
Chris@555 335
Chris@555 336 if (toFocus) {
Chris@555 337 toFocus->ensureVisible();
Chris@555 338 }
Chris@555 339 }
Chris@555 340
Chris@141 341 void HistoryWidget::connectSceneSignals()
Chris@141 342 {
Chris@141 343 ChangesetScene *scene = qobject_cast<ChangesetScene *>(m_panned->scene());
Chris@141 344 if (!scene) return;
Chris@141 345
Chris@141 346 connect(scene, SIGNAL(commit()),
Chris@141 347 this, SIGNAL(commit()));
Chris@141 348
Chris@141 349 connect(scene, SIGNAL(revert()),
Chris@141 350 this, SIGNAL(revert()));
Chris@141 351
Chris@141 352 connect(scene, SIGNAL(diffWorkingFolder()),
Chris@141 353 this, SIGNAL(diffWorkingFolder()));
Chris@141 354
Chris@168 355 connect(scene, SIGNAL(showSummary()),
Chris@168 356 this, SIGNAL(showSummary()));
Chris@168 357
Chris@153 358 connect(scene, SIGNAL(showWork()),
Chris@153 359 this, SIGNAL(showWork()));
Chris@311 360
Chris@311 361 connect(scene, SIGNAL(newBranch()),
Chris@311 362 this, SIGNAL(newBranch()));
Chris@311 363
Chris@311 364 connect(scene, SIGNAL(noBranch()),
Chris@311 365 this, SIGNAL(noBranch()));
Chris@153 366
Chris@141 367 connect(scene, SIGNAL(updateTo(QString)),
Chris@141 368 this, SIGNAL(updateTo(QString)));
Chris@141 369
Chris@141 370 connect(scene, SIGNAL(diffToCurrent(QString)),
Chris@141 371 this, SIGNAL(diffToCurrent(QString)));
Chris@141 372
Chris@148 373 connect(scene, SIGNAL(diffToParent(QString, QString)),
Chris@148 374 this, SIGNAL(diffToParent(QString, QString)));
Chris@141 375
Chris@289 376 connect(scene, SIGNAL(showSummary(Changeset *)),
Chris@289 377 this, SIGNAL(showSummary(Changeset *)));
Chris@288 378
Chris@141 379 connect(scene, SIGNAL(mergeFrom(QString)),
Chris@141 380 this, SIGNAL(mergeFrom(QString)));
Chris@141 381
Chris@278 382 connect(scene, SIGNAL(newBranch(QString)),
Chris@278 383 this, SIGNAL(newBranch(QString)));
Chris@278 384
Chris@514 385 connect(scene, SIGNAL(closeBranch(QString)),
Chris@514 386 this, SIGNAL(closeBranch(QString)));
Chris@514 387
Chris@141 388 connect(scene, SIGNAL(tag(QString)),
Chris@141 389 this, SIGNAL(tag(QString)));
Chris@141 390 }