annotate src/historywidget.cpp @ 425:ad106f5fe75f

Add "Ignore Files" and "Edit Ignored List" to Work menu (latter is subsumed from Advanced menu formerly). Also subsume Serve via HTTP into File menu as Share Repository, and add a more helpful description of it. Remove Advanced menu
author Chris Cannam
date Thu, 23 Jun 2011 10:58:32 +0100
parents 61bde1f0ff0a
children 1c05e7576ea5
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@116 30
Chris@154 31 HistoryWidget::HistoryWidget() :
Chris@154 32 m_showUncommitted(false),
Chris@154 33 m_refreshNeeded(false)
Chris@116 34 {
Chris@397 35 m_panned = new ChangesetView;
Chris@116 36 m_panner = new Panner;
Chris@116 37
Chris@168 38 m_panned->setDragMode(QGraphicsView::ScrollHandDrag);
Chris@250 39 m_panned->setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
Chris@397 40 m_panned->setCacheMode(QGraphicsView::CacheNone);
Chris@168 41
Chris@116 42 QGridLayout *layout = new QGridLayout;
Chris@116 43 layout->addWidget(m_panned, 0, 0);
Chris@116 44 layout->addWidget(m_panner, 0, 1);
Chris@116 45 m_panner->setMaximumWidth(80);
Chris@116 46 m_panner->connectToPanned(m_panned);
Chris@116 47
Chris@116 48 setLayout(layout);
Chris@116 49 }
Chris@116 50
Chris@116 51 HistoryWidget::~HistoryWidget()
Chris@116 52 {
Chris@116 53 clearChangesets();
Chris@145 54 }
Chris@145 55
Chris@145 56 QGraphicsScene *HistoryWidget::scene()
Chris@145 57 {
Chris@145 58 return m_panned->scene();
Chris@116 59 }
Chris@116 60
Chris@116 61 void HistoryWidget::clearChangesets()
Chris@116 62 {
Chris@116 63 foreach (Changeset *cs, m_changesets) delete cs;
Chris@116 64 m_changesets.clear();
Chris@116 65 }
Chris@128 66
Chris@153 67 void HistoryWidget::setCurrent(QStringList ids, QString branch,
Chris@153 68 bool showUncommitted)
Chris@128 69 {
Chris@153 70 if (m_currentIds == ids &&
Chris@153 71 m_currentBranch == branch &&
Chris@153 72 m_showUncommitted == showUncommitted) return;
Chris@145 73
Chris@145 74 DEBUG << "HistoryWidget::setCurrent: " << ids.size() << " ids, "
Chris@145 75 << "showUncommitted: " << showUncommitted << endl;
Chris@145 76
Chris@133 77 m_currentIds.clear();
Chris@153 78 m_currentBranch = branch;
Chris@145 79 m_showUncommitted = showUncommitted;
Chris@145 80
Chris@145 81 if (ids.empty()) return;
Chris@145 82
Chris@133 83 foreach (QString id, ids) {
Chris@133 84 m_currentIds.push_back(id);
Chris@133 85 }
Chris@128 86
Chris@154 87 m_refreshNeeded = true;
Chris@128 88 }
Chris@116 89
Chris@120 90 void HistoryWidget::parseNewLog(QString log)
Chris@120 91 {
Chris@120 92 DEBUG << "HistoryWidget::parseNewLog: log has " << log.length() << " chars" << endl;
Chris@122 93 Changesets csets = Changeset::parseChangesets(log);
Chris@120 94 DEBUG << "HistoryWidget::parseNewLog: log has " << csets.size() << " changesets" << endl;
Chris@133 95 replaceChangesets(csets);
Chris@154 96 m_refreshNeeded = true;
Chris@120 97 }
Chris@120 98
Chris@120 99 void HistoryWidget::parseIncrementalLog(QString log)
Chris@120 100 {
Chris@120 101 DEBUG << "HistoryWidget::parseIncrementalLog: log has " << log.length() << " chars" << endl;
Chris@122 102 Changesets csets = Changeset::parseChangesets(log);
Chris@120 103 DEBUG << "HistoryWidget::parseIncrementalLog: log has " << csets.size() << " changesets" << endl;
Chris@120 104 if (!csets.empty()) {
Chris@133 105 addChangesets(csets);
Chris@120 106 }
Chris@154 107 m_refreshNeeded = true;
Chris@120 108 }
Chris@120 109
Chris@133 110 void HistoryWidget::replaceChangesets(Changesets csets)
Chris@133 111 {
Chris@133 112 QSet<QString> oldIds;
Chris@133 113 foreach (Changeset *cs, m_changesets) {
Chris@133 114 oldIds.insert(cs->id());
Chris@133 115 }
Chris@133 116
Chris@133 117 QSet<QString> newIds;
Chris@133 118 foreach (Changeset *cs, csets) {
Chris@133 119 if (!oldIds.contains(cs->id())) {
Chris@133 120 newIds.insert(cs->id());
Chris@133 121 }
Chris@133 122 }
Chris@133 123
Chris@133 124 if (newIds.size() == csets.size()) {
Chris@133 125 // completely new set, unrelated to the old: don't mark new
Chris@133 126 m_newIds.clear();
Chris@133 127 } else {
Chris@133 128 m_newIds = newIds;
Chris@133 129 }
Chris@133 130
Chris@133 131 clearChangesets();
Chris@133 132 m_changesets = csets;
Chris@133 133 }
Chris@133 134
Chris@133 135 void HistoryWidget::addChangesets(Changesets csets)
Chris@133 136 {
Chris@133 137 m_newIds.clear();
Chris@138 138
Chris@138 139 if (csets.empty()) return;
Chris@138 140
Chris@133 141 foreach (Changeset *cs, csets) {
Chris@133 142 m_newIds.insert(cs->id());
Chris@133 143 }
Chris@133 144
Chris@305 145 DEBUG << "addChangesets: " << csets.size() << " new changesets have ("
Chris@305 146 << m_changesets.size() << " already)" << endl;
Chris@138 147
Chris@133 148 csets << m_changesets;
Chris@133 149 m_changesets = csets;
Chris@133 150 }
Chris@133 151
Chris@154 152 void HistoryWidget::update()
Chris@154 153 {
Chris@154 154 if (m_refreshNeeded) {
Chris@154 155 layoutAll();
Chris@154 156 }
Chris@154 157 }
Chris@154 158
Chris@120 159 void HistoryWidget::layoutAll()
Chris@116 160 {
Chris@154 161 m_refreshNeeded = false;
Chris@154 162
Chris@122 163 setChangesetParents();
Chris@122 164
Chris@119 165 ChangesetScene *scene = new ChangesetScene();
Chris@116 166 ChangesetItem *tipItem = 0;
Chris@116 167
Chris@138 168 QGraphicsScene *oldScene = m_panned->scene();
Chris@138 169
Chris@138 170 m_panned->setScene(0);
Chris@138 171 m_panner->setScene(0);
Chris@138 172
Chris@138 173 delete oldScene;
Chris@138 174
Chris@145 175 QGraphicsItem *toFocus = 0;
Chris@145 176
Chris@120 177 if (!m_changesets.empty()) {
Chris@116 178 Grapher g(scene);
Chris@116 179 try {
Chris@153 180 g.layout(m_changesets,
Chris@153 181 m_showUncommitted ? m_currentIds : QStringList(),
Chris@153 182 m_currentBranch);
Chris@116 183 } catch (std::string s) {
Chris@116 184 std::cerr << "Internal error: Layout failed: " << s << std::endl;
Chris@116 185 }
Chris@145 186 toFocus = g.getUncommittedItem();
Chris@145 187 if (!toFocus) {
Chris@371 188 if (!m_currentIds.empty()) {
Chris@371 189 toFocus = g.getItemFor(m_currentIds[0]);
Chris@371 190 } else {
Chris@371 191 toFocus = g.getItemFor(m_changesets[0]);
Chris@371 192 }
Chris@145 193 }
Chris@134 194 }
Chris@134 195
Chris@116 196 m_panned->setScene(scene);
Chris@116 197 m_panner->setScene(scene);
Chris@116 198
Chris@133 199 updateNewAndCurrentItems();
Chris@134 200
Chris@145 201 if (toFocus) {
Chris@145 202 toFocus->ensureVisible();
Chris@134 203 }
Chris@141 204
Chris@141 205 connectSceneSignals();
Chris@116 206 }
Chris@116 207
Chris@122 208 void HistoryWidget::setChangesetParents()
Chris@116 209 {
Chris@139 210 for (int i = 0; i < m_changesets.size(); ++i) {
Chris@122 211 Changeset *cs = m_changesets[i];
Chris@123 212 // Need to reset this, as Grapher::layout will recalculate it
Chris@123 213 // and we don't want to end up with twice the children for
Chris@123 214 // each parent...
Chris@123 215 cs->setChildren(QStringList());
Chris@139 216 }
Chris@139 217 for (int i = 0; i+1 < m_changesets.size(); ++i) {
Chris@139 218 Changeset *cs = m_changesets[i];
Chris@116 219 if (cs->parents().empty()) {
Chris@116 220 QStringList list;
Chris@122 221 list.push_back(m_changesets[i+1]->id());
Chris@116 222 cs->setParents(list);
Chris@116 223 }
Chris@116 224 }
Chris@116 225 }
Chris@128 226
Chris@133 227 void HistoryWidget::updateNewAndCurrentItems()
Chris@128 228 {
Chris@128 229 QGraphicsScene *scene = m_panned->scene();
Chris@128 230 if (!scene) return;
Chris@133 231
Chris@128 232 QList<QGraphicsItem *> items = scene->items();
Chris@128 233 foreach (QGraphicsItem *it, items) {
Chris@133 234
Chris@128 235 ChangesetItem *csit = dynamic_cast<ChangesetItem *>(it);
Chris@133 236 if (!csit) continue;
Chris@133 237
Chris@133 238 QString id = csit->getChangeset()->id();
Chris@133 239
Chris@133 240 bool current = m_currentIds.contains(id);
Chris@133 241 if (current) {
Chris@133 242 DEBUG << "id " << id << " is current" << endl;
Chris@133 243 }
Chris@133 244 bool newid = m_newIds.contains(id);
Chris@133 245 if (newid) {
Chris@133 246 DEBUG << "id " << id << " is new" << endl;
Chris@133 247 }
Chris@147 248
Chris@147 249 if (csit->isCurrent() != current || csit->isNew() != newid) {
Chris@147 250 csit->setCurrent(current);
Chris@147 251 csit->setNew(newid);
Chris@147 252 csit->update();
Chris@147 253 }
Chris@128 254 }
Chris@128 255 }
Chris@141 256
Chris@141 257 void HistoryWidget::connectSceneSignals()
Chris@141 258 {
Chris@141 259 ChangesetScene *scene = qobject_cast<ChangesetScene *>(m_panned->scene());
Chris@141 260 if (!scene) return;
Chris@141 261
Chris@141 262 connect(scene, SIGNAL(commit()),
Chris@141 263 this, SIGNAL(commit()));
Chris@141 264
Chris@141 265 connect(scene, SIGNAL(revert()),
Chris@141 266 this, SIGNAL(revert()));
Chris@141 267
Chris@141 268 connect(scene, SIGNAL(diffWorkingFolder()),
Chris@141 269 this, SIGNAL(diffWorkingFolder()));
Chris@141 270
Chris@168 271 connect(scene, SIGNAL(showSummary()),
Chris@168 272 this, SIGNAL(showSummary()));
Chris@168 273
Chris@153 274 connect(scene, SIGNAL(showWork()),
Chris@153 275 this, SIGNAL(showWork()));
Chris@311 276
Chris@311 277 connect(scene, SIGNAL(newBranch()),
Chris@311 278 this, SIGNAL(newBranch()));
Chris@311 279
Chris@311 280 connect(scene, SIGNAL(noBranch()),
Chris@311 281 this, SIGNAL(noBranch()));
Chris@153 282
Chris@141 283 connect(scene, SIGNAL(updateTo(QString)),
Chris@141 284 this, SIGNAL(updateTo(QString)));
Chris@141 285
Chris@141 286 connect(scene, SIGNAL(diffToCurrent(QString)),
Chris@141 287 this, SIGNAL(diffToCurrent(QString)));
Chris@141 288
Chris@148 289 connect(scene, SIGNAL(diffToParent(QString, QString)),
Chris@148 290 this, SIGNAL(diffToParent(QString, QString)));
Chris@141 291
Chris@289 292 connect(scene, SIGNAL(showSummary(Changeset *)),
Chris@289 293 this, SIGNAL(showSummary(Changeset *)));
Chris@288 294
Chris@141 295 connect(scene, SIGNAL(mergeFrom(QString)),
Chris@141 296 this, SIGNAL(mergeFrom(QString)));
Chris@141 297
Chris@278 298 connect(scene, SIGNAL(newBranch(QString)),
Chris@278 299 this, SIGNAL(newBranch(QString)));
Chris@278 300
Chris@141 301 connect(scene, SIGNAL(tag(QString)),
Chris@141 302 this, SIGNAL(tag(QString)));
Chris@141 303 }