annotate historywidget.cpp @ 154:6bcb4a4d6521

* Try to reduce unnecessary history updates; add --new-branch option on push
author Chris Cannam
date Thu, 02 Dec 2010 18:04:21 +0000
parents 70fe12873106
children 4bad3c5c053a
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@116 8 Copyright (c) 2010 Chris Cannam
Chris@116 9 Copyright (c) 2010 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@116 21 #include "panned.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@116 35 m_panned = new Panned;
Chris@116 36 m_panner = new Panner;
Chris@116 37
Chris@116 38 QGridLayout *layout = new QGridLayout;
Chris@116 39 layout->addWidget(m_panned, 0, 0);
Chris@116 40 layout->addWidget(m_panner, 0, 1);
Chris@116 41 m_panner->setMaximumWidth(80);
Chris@116 42 m_panner->connectToPanned(m_panned);
Chris@116 43
Chris@116 44 setLayout(layout);
Chris@116 45 }
Chris@116 46
Chris@116 47 HistoryWidget::~HistoryWidget()
Chris@116 48 {
Chris@116 49 clearChangesets();
Chris@145 50 }
Chris@145 51
Chris@145 52 QGraphicsScene *HistoryWidget::scene()
Chris@145 53 {
Chris@145 54 return m_panned->scene();
Chris@116 55 }
Chris@116 56
Chris@116 57 void HistoryWidget::clearChangesets()
Chris@116 58 {
Chris@116 59 foreach (Changeset *cs, m_changesets) delete cs;
Chris@116 60 m_changesets.clear();
Chris@116 61 }
Chris@128 62
Chris@153 63 void HistoryWidget::setCurrent(QStringList ids, QString branch,
Chris@153 64 bool showUncommitted)
Chris@128 65 {
Chris@153 66 if (m_currentIds == ids &&
Chris@153 67 m_currentBranch == branch &&
Chris@153 68 m_showUncommitted == showUncommitted) return;
Chris@145 69
Chris@145 70 DEBUG << "HistoryWidget::setCurrent: " << ids.size() << " ids, "
Chris@145 71 << "showUncommitted: " << showUncommitted << endl;
Chris@145 72
Chris@133 73 m_currentIds.clear();
Chris@153 74 m_currentBranch = branch;
Chris@145 75 m_showUncommitted = showUncommitted;
Chris@145 76
Chris@145 77 if (ids.empty()) return;
Chris@145 78
Chris@133 79 foreach (QString id, ids) {
Chris@133 80 m_currentIds.push_back(id);
Chris@133 81 }
Chris@128 82
Chris@154 83 m_refreshNeeded = true;
Chris@128 84 }
Chris@116 85
Chris@120 86 void HistoryWidget::parseNewLog(QString log)
Chris@120 87 {
Chris@120 88 DEBUG << "HistoryWidget::parseNewLog: log has " << log.length() << " chars" << endl;
Chris@122 89 Changesets csets = Changeset::parseChangesets(log);
Chris@120 90 DEBUG << "HistoryWidget::parseNewLog: log has " << csets.size() << " changesets" << endl;
Chris@133 91 replaceChangesets(csets);
Chris@154 92 m_refreshNeeded = true;
Chris@120 93 }
Chris@120 94
Chris@120 95 void HistoryWidget::parseIncrementalLog(QString log)
Chris@120 96 {
Chris@120 97 DEBUG << "HistoryWidget::parseIncrementalLog: log has " << log.length() << " chars" << endl;
Chris@122 98 Changesets csets = Changeset::parseChangesets(log);
Chris@120 99 DEBUG << "HistoryWidget::parseIncrementalLog: log has " << csets.size() << " changesets" << endl;
Chris@120 100 if (!csets.empty()) {
Chris@133 101 addChangesets(csets);
Chris@120 102 }
Chris@154 103 m_refreshNeeded = true;
Chris@120 104 }
Chris@120 105
Chris@133 106 void HistoryWidget::replaceChangesets(Changesets csets)
Chris@133 107 {
Chris@133 108 QSet<QString> oldIds;
Chris@133 109 foreach (Changeset *cs, m_changesets) {
Chris@133 110 oldIds.insert(cs->id());
Chris@133 111 }
Chris@133 112
Chris@133 113 QSet<QString> newIds;
Chris@133 114 foreach (Changeset *cs, csets) {
Chris@133 115 if (!oldIds.contains(cs->id())) {
Chris@133 116 newIds.insert(cs->id());
Chris@133 117 }
Chris@133 118 }
Chris@133 119
Chris@133 120 if (newIds.size() == csets.size()) {
Chris@133 121 // completely new set, unrelated to the old: don't mark new
Chris@133 122 m_newIds.clear();
Chris@133 123 } else {
Chris@133 124 m_newIds = newIds;
Chris@133 125 }
Chris@133 126
Chris@133 127 clearChangesets();
Chris@133 128 m_changesets = csets;
Chris@133 129 }
Chris@133 130
Chris@133 131 void HistoryWidget::addChangesets(Changesets csets)
Chris@133 132 {
Chris@133 133 m_newIds.clear();
Chris@138 134
Chris@138 135 if (csets.empty()) return;
Chris@138 136
Chris@133 137 foreach (Changeset *cs, csets) {
Chris@133 138 m_newIds.insert(cs->id());
Chris@133 139 }
Chris@133 140
Chris@138 141 DEBUG << "addChangesets: " << csets.size() << " new changesets" << endl;
Chris@138 142
Chris@133 143 csets << m_changesets;
Chris@133 144 m_changesets = csets;
Chris@133 145 }
Chris@133 146
Chris@154 147 void HistoryWidget::update()
Chris@154 148 {
Chris@154 149 if (m_refreshNeeded) {
Chris@154 150 layoutAll();
Chris@154 151 }
Chris@154 152 }
Chris@154 153
Chris@120 154 void HistoryWidget::layoutAll()
Chris@116 155 {
Chris@154 156 m_refreshNeeded = false;
Chris@154 157
Chris@122 158 setChangesetParents();
Chris@122 159
Chris@119 160 ChangesetScene *scene = new ChangesetScene();
Chris@116 161 ChangesetItem *tipItem = 0;
Chris@116 162
Chris@138 163 QGraphicsScene *oldScene = m_panned->scene();
Chris@138 164
Chris@138 165 m_panned->setScene(0);
Chris@138 166 m_panner->setScene(0);
Chris@138 167
Chris@138 168 delete oldScene;
Chris@138 169
Chris@145 170 QGraphicsItem *toFocus = 0;
Chris@145 171
Chris@120 172 if (!m_changesets.empty()) {
Chris@116 173 Grapher g(scene);
Chris@116 174 try {
Chris@153 175 g.layout(m_changesets,
Chris@153 176 m_showUncommitted ? m_currentIds : QStringList(),
Chris@153 177 m_currentBranch);
Chris@116 178 } catch (std::string s) {
Chris@116 179 std::cerr << "Internal error: Layout failed: " << s << std::endl;
Chris@116 180 }
Chris@145 181 toFocus = g.getUncommittedItem();
Chris@145 182 if (!toFocus) {
Chris@145 183 toFocus = g.getItemFor(m_changesets[0]);
Chris@145 184 }
Chris@134 185 }
Chris@134 186
Chris@116 187 m_panned->setScene(scene);
Chris@116 188 m_panner->setScene(scene);
Chris@116 189
Chris@133 190 updateNewAndCurrentItems();
Chris@134 191
Chris@145 192 if (toFocus) {
Chris@145 193 toFocus->ensureVisible();
Chris@134 194 }
Chris@141 195
Chris@141 196 connectSceneSignals();
Chris@116 197 }
Chris@116 198
Chris@122 199 void HistoryWidget::setChangesetParents()
Chris@116 200 {
Chris@139 201 for (int i = 0; i < m_changesets.size(); ++i) {
Chris@122 202 Changeset *cs = m_changesets[i];
Chris@123 203 // Need to reset this, as Grapher::layout will recalculate it
Chris@123 204 // and we don't want to end up with twice the children for
Chris@123 205 // each parent...
Chris@123 206 cs->setChildren(QStringList());
Chris@139 207 }
Chris@139 208 for (int i = 0; i+1 < m_changesets.size(); ++i) {
Chris@139 209 Changeset *cs = m_changesets[i];
Chris@116 210 if (cs->parents().empty()) {
Chris@116 211 QStringList list;
Chris@122 212 list.push_back(m_changesets[i+1]->id());
Chris@116 213 cs->setParents(list);
Chris@116 214 }
Chris@116 215 }
Chris@116 216 }
Chris@128 217
Chris@133 218 void HistoryWidget::updateNewAndCurrentItems()
Chris@128 219 {
Chris@128 220 QGraphicsScene *scene = m_panned->scene();
Chris@128 221 if (!scene) return;
Chris@133 222
Chris@128 223 QList<QGraphicsItem *> items = scene->items();
Chris@128 224 foreach (QGraphicsItem *it, items) {
Chris@133 225
Chris@128 226 ChangesetItem *csit = dynamic_cast<ChangesetItem *>(it);
Chris@133 227 if (!csit) continue;
Chris@133 228
Chris@133 229 QString id = csit->getChangeset()->id();
Chris@133 230
Chris@133 231 bool current = m_currentIds.contains(id);
Chris@133 232 if (current) {
Chris@133 233 DEBUG << "id " << id << " is current" << endl;
Chris@133 234 }
Chris@133 235 bool newid = m_newIds.contains(id);
Chris@133 236 if (newid) {
Chris@133 237 DEBUG << "id " << id << " is new" << endl;
Chris@133 238 }
Chris@147 239
Chris@147 240 if (csit->isCurrent() != current || csit->isNew() != newid) {
Chris@147 241 csit->setCurrent(current);
Chris@147 242 csit->setNew(newid);
Chris@147 243 csit->update();
Chris@147 244 }
Chris@128 245 }
Chris@128 246 }
Chris@141 247
Chris@141 248 void HistoryWidget::connectSceneSignals()
Chris@141 249 {
Chris@141 250 ChangesetScene *scene = qobject_cast<ChangesetScene *>(m_panned->scene());
Chris@141 251 if (!scene) return;
Chris@141 252
Chris@141 253 connect(scene, SIGNAL(commit()),
Chris@141 254 this, SIGNAL(commit()));
Chris@141 255
Chris@141 256 connect(scene, SIGNAL(revert()),
Chris@141 257 this, SIGNAL(revert()));
Chris@141 258
Chris@141 259 connect(scene, SIGNAL(diffWorkingFolder()),
Chris@141 260 this, SIGNAL(diffWorkingFolder()));
Chris@141 261
Chris@153 262 connect(scene, SIGNAL(showWork()),
Chris@153 263 this, SIGNAL(showWork()));
Chris@153 264
Chris@141 265 connect(scene, SIGNAL(updateTo(QString)),
Chris@141 266 this, SIGNAL(updateTo(QString)));
Chris@141 267
Chris@141 268 connect(scene, SIGNAL(diffToCurrent(QString)),
Chris@141 269 this, SIGNAL(diffToCurrent(QString)));
Chris@141 270
Chris@148 271 connect(scene, SIGNAL(diffToParent(QString, QString)),
Chris@148 272 this, SIGNAL(diffToParent(QString, QString)));
Chris@141 273
Chris@141 274 connect(scene, SIGNAL(mergeFrom(QString)),
Chris@141 275 this, SIGNAL(mergeFrom(QString)));
Chris@141 276
Chris@141 277 connect(scene, SIGNAL(tag(QString)),
Chris@141 278 this, SIGNAL(tag(QString)));
Chris@141 279 }