annotate src/historywidget.cpp @ 672:88fa1544b407

Merge from branch qt5. There's much more to be done before we can make another release, but clearly it's going to be done using qt5
author Chris Cannam
date Wed, 05 Dec 2018 09:44:10 +0000
parents ce29dc775650
children
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@138 222 QGraphicsScene *oldScene = m_panned->scene();
Chris@138 223
Chris@138 224 m_panned->setScene(0);
Chris@138 225 m_panner->setScene(0);
Chris@138 226
Chris@138 227 delete oldScene;
Chris@138 228
Chris@145 229 QGraphicsItem *toFocus = 0;
Chris@145 230
Chris@120 231 if (!m_changesets.empty()) {
Chris@116 232 Grapher g(scene);
Chris@506 233 g.setClosedHeadIds(m_closedIds);
Chris@116 234 try {
Chris@153 235 g.layout(m_changesets,
Chris@153 236 m_showUncommitted ? m_currentIds : QStringList(),
Chris@153 237 m_currentBranch);
Chris@116 238 } catch (std::string s) {
Chris@116 239 std::cerr << "Internal error: Layout failed: " << s << std::endl;
Chris@116 240 }
Chris@145 241 toFocus = g.getUncommittedItem();
Chris@145 242 if (!toFocus) {
Chris@371 243 if (!m_currentIds.empty()) {
pozofelipe@621 244 for (int i = 0; i < m_currentIds.size(); ++i) {
pozofelipe@621 245 toFocus = g.getItemFor(m_currentIds[i]);
pozofelipe@621 246 if (toFocus != 0) {
pozofelipe@621 247 break;
pozofelipe@621 248 }
pozofelipe@621 249 }
Chris@371 250 } else {
Chris@371 251 toFocus = g.getItemFor(m_changesets[0]);
Chris@371 252 }
Chris@145 253 }
pozofelipe@621 254 if (!toFocus) {
pozofelipe@621 255 for (int i = 0; i < m_changesets.size(); ++i) {
pozofelipe@621 256 toFocus = g.getItemFor(m_changesets[i]);
pozofelipe@621 257 if (toFocus != 0) {
pozofelipe@621 258 break;
pozofelipe@621 259 }
pozofelipe@621 260 }
pozofelipe@621 261 }
Chris@134 262 }
Chris@134 263
Chris@116 264 m_panned->setScene(scene);
Chris@116 265 m_panner->setScene(scene);
Chris@116 266
Chris@133 267 updateNewAndCurrentItems();
Chris@134 268
Chris@145 269 if (toFocus) {
Chris@145 270 toFocus->ensureVisible();
Chris@134 271 }
Chris@141 272
Chris@572 273 if (m_searchText != "") {
Chris@572 274 updateSearchStatus();
Chris@572 275 }
Chris@141 276 connectSceneSignals();
Chris@116 277 }
Chris@116 278
Chris@122 279 void HistoryWidget::setChangesetParents()
Chris@116 280 {
Chris@139 281 for (int i = 0; i < m_changesets.size(); ++i) {
Chris@122 282 Changeset *cs = m_changesets[i];
Chris@123 283 // Need to reset this, as Grapher::layout will recalculate it
Chris@123 284 // and we don't want to end up with twice the children for
Chris@123 285 // each parent...
Chris@123 286 cs->setChildren(QStringList());
Chris@139 287 }
Chris@139 288 for (int i = 0; i+1 < m_changesets.size(); ++i) {
Chris@139 289 Changeset *cs = m_changesets[i];
Chris@116 290 if (cs->parents().empty()) {
Chris@116 291 QStringList list;
Chris@122 292 list.push_back(m_changesets[i+1]->id());
Chris@116 293 cs->setParents(list);
Chris@116 294 }
Chris@116 295 }
Chris@116 296 }
Chris@128 297
Chris@133 298 void HistoryWidget::updateNewAndCurrentItems()
Chris@128 299 {
Chris@128 300 QGraphicsScene *scene = m_panned->scene();
Chris@128 301 if (!scene) return;
Chris@133 302
Chris@128 303 QList<QGraphicsItem *> items = scene->items();
Chris@128 304 foreach (QGraphicsItem *it, items) {
Chris@133 305
Chris@128 306 ChangesetItem *csit = dynamic_cast<ChangesetItem *>(it);
Chris@133 307 if (!csit) continue;
Chris@133 308
Chris@133 309 QString id = csit->getChangeset()->id();
Chris@133 310
Chris@133 311 bool current = m_currentIds.contains(id);
Chris@133 312 if (current) {
Chris@133 313 DEBUG << "id " << id << " is current" << endl;
Chris@133 314 }
Chris@133 315 bool newid = m_newIds.contains(id);
Chris@133 316 if (newid) {
Chris@133 317 DEBUG << "id " << id << " is new" << endl;
Chris@133 318 }
Chris@147 319
Chris@506 320 if (csit->isCurrent() != current ||
Chris@506 321 csit->isNew() != newid) {
Chris@147 322 csit->setCurrent(current);
Chris@147 323 csit->setNew(newid);
Chris@147 324 csit->update();
Chris@147 325 }
Chris@128 326 }
Chris@128 327 }
Chris@141 328
Chris@555 329 void HistoryWidget::setSearchText(QString text)
Chris@555 330 {
Chris@555 331 if (m_searchText == text) return;
Chris@555 332 m_searchText = text;
Chris@555 333 updateSearchStatus();
Chris@555 334 }
Chris@555 335
Chris@555 336 void HistoryWidget::updateSearchStatus()
Chris@555 337 {
Chris@555 338 QGraphicsScene *scene = m_panned->scene();
Chris@555 339 if (!scene) return;
Chris@555 340
Chris@555 341 ChangesetItem *toFocus = 0;
Chris@555 342
Chris@555 343 QList<QGraphicsItem *> items = scene->items();
Chris@555 344 foreach (QGraphicsItem *it, items) {
Chris@555 345
Chris@555 346 ChangesetItem *csit = dynamic_cast<ChangesetItem *>(it);
Chris@555 347 if (!csit) continue;
Chris@555 348
Chris@566 349 bool matched = csit->matchSearchText(m_searchText);
Chris@555 350 if (matched && (!toFocus || csit->row() < toFocus->row())) {
Chris@555 351 toFocus = csit;
Chris@555 352 }
Chris@555 353 csit->update();
Chris@555 354 }
Chris@555 355
Chris@555 356 if (toFocus) {
Chris@555 357 toFocus->ensureVisible();
Chris@555 358 }
Chris@555 359 }
Chris@555 360
Chris@141 361 void HistoryWidget::connectSceneSignals()
Chris@141 362 {
Chris@141 363 ChangesetScene *scene = qobject_cast<ChangesetScene *>(m_panned->scene());
Chris@141 364 if (!scene) return;
Chris@141 365
Chris@141 366 connect(scene, SIGNAL(commit()),
Chris@141 367 this, SIGNAL(commit()));
Chris@141 368
Chris@141 369 connect(scene, SIGNAL(revert()),
Chris@141 370 this, SIGNAL(revert()));
Chris@141 371
Chris@141 372 connect(scene, SIGNAL(diffWorkingFolder()),
Chris@141 373 this, SIGNAL(diffWorkingFolder()));
Chris@141 374
Chris@168 375 connect(scene, SIGNAL(showSummary()),
Chris@168 376 this, SIGNAL(showSummary()));
Chris@168 377
Chris@153 378 connect(scene, SIGNAL(showWork()),
Chris@153 379 this, SIGNAL(showWork()));
Chris@311 380
Chris@311 381 connect(scene, SIGNAL(newBranch()),
Chris@311 382 this, SIGNAL(newBranch()));
Chris@311 383
Chris@311 384 connect(scene, SIGNAL(noBranch()),
Chris@311 385 this, SIGNAL(noBranch()));
Chris@153 386
Chris@141 387 connect(scene, SIGNAL(updateTo(QString)),
Chris@141 388 this, SIGNAL(updateTo(QString)));
Chris@141 389
Chris@141 390 connect(scene, SIGNAL(diffToCurrent(QString)),
Chris@141 391 this, SIGNAL(diffToCurrent(QString)));
Chris@141 392
Chris@148 393 connect(scene, SIGNAL(diffToParent(QString, QString)),
Chris@148 394 this, SIGNAL(diffToParent(QString, QString)));
Chris@141 395
Chris@289 396 connect(scene, SIGNAL(showSummary(Changeset *)),
Chris@289 397 this, SIGNAL(showSummary(Changeset *)));
Chris@288 398
Chris@141 399 connect(scene, SIGNAL(mergeFrom(QString)),
Chris@141 400 this, SIGNAL(mergeFrom(QString)));
Chris@141 401
Chris@278 402 connect(scene, SIGNAL(newBranch(QString)),
Chris@278 403 this, SIGNAL(newBranch(QString)));
Chris@278 404
Chris@514 405 connect(scene, SIGNAL(closeBranch(QString)),
Chris@514 406 this, SIGNAL(closeBranch(QString)));
Chris@514 407
Chris@141 408 connect(scene, SIGNAL(tag(QString)),
Chris@141 409 this, SIGNAL(tag(QString)));
Chris@141 410 }