annotate filestatuswidget.cpp @ 109:1721c580c10e

* Add a queueing mechanism for Hg actions, instead of refusing to start an action if something else is already happening. This is essential now that actions can be prompted by asynchronous events (e.g. filesystem watcher). * Make Revert behave sensibly
author Chris Cannam
date Fri, 26 Nov 2010 12:48:29 +0000
parents 729438d70af8
children 78374cefa10f
rev   line source
Chris@88 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@88 2
Chris@88 3 /*
Chris@88 4 EasyMercurial
Chris@88 5
Chris@88 6 Based on HgExplorer by Jari Korhonen
Chris@88 7 Copyright (c) 2010 Jari Korhonen
Chris@88 8 Copyright (c) 2010 Chris Cannam
Chris@88 9 Copyright (c) 2010 Queen Mary, University of London
Chris@88 10
Chris@88 11 This program is free software; you can redistribute it and/or
Chris@88 12 modify it under the terms of the GNU General Public License as
Chris@88 13 published by the Free Software Foundation; either version 2 of the
Chris@88 14 License, or (at your option) any later version. See the file
Chris@88 15 COPYING included with this distribution for more information.
Chris@88 16 */
Chris@88 17
Chris@88 18 #include "filestatuswidget.h"
Chris@88 19
Chris@88 20 #include <QLabel>
Chris@88 21 #include <QListWidget>
Chris@88 22 #include <QGridLayout>
Chris@93 23 #include <QFileInfo>
Chris@93 24 #include <QApplication>
Chris@93 25 #include <QDateTime>
Chris@93 26
Chris@93 27 #include "debug.h"
Chris@88 28
Chris@88 29 FileStatusWidget::FileStatusWidget(QWidget *parent) :
Chris@93 30 QWidget(parent),
Chris@93 31 m_dateReference(0)
Chris@88 32 {
Chris@88 33 QGridLayout *layout = new QGridLayout;
Chris@88 34 setLayout(layout);
Chris@88 35
Chris@88 36 int row = 0;
Chris@88 37
Chris@88 38 layout->addWidget(new QLabel(tr("Local:")), row, 0);
Chris@88 39 m_localPathLabel = new QLabel;
Chris@89 40 QFont f(m_localPathLabel->font());
Chris@89 41 f.setBold(true);
Chris@89 42 m_localPathLabel->setFont(f);
Chris@88 43 layout->addWidget(m_localPathLabel, row, 1);
Chris@88 44
Chris@88 45 ++row;
Chris@88 46 layout->addWidget(new QLabel(tr("Remote:")), row, 0);
Chris@88 47 m_remoteURLLabel = new QLabel;
Chris@88 48 layout->addWidget(m_remoteURLLabel, row, 1);
Chris@88 49
Chris@106 50 ++row;
Chris@106 51 layout->addWidget(new QLabel(tr("Branch:")), row, 0);
Chris@106 52 m_branchLabel = new QLabel;
Chris@106 53 layout->addWidget(m_branchLabel, row, 1);
Chris@106 54
Chris@89 55 layout->setColumnStretch(1, 20);
Chris@88 56
Chris@106 57 layout->addWidget(new QLabel("<qt><hr></qt>"), ++row, 0, 1, 2);
Chris@106 58
Chris@100 59 m_simpleLabels[FileStates::Clean] = tr("Unmodified:");
Chris@100 60 m_simpleLabels[FileStates::Modified] = tr("Modified:");
Chris@100 61 m_simpleLabels[FileStates::Added] = tr("Added:");
Chris@100 62 m_simpleLabels[FileStates::Removed] = tr("Removed:");
Chris@100 63 m_simpleLabels[FileStates::Missing] = tr("Missing:");
Chris@100 64 m_simpleLabels[FileStates::Unknown] = tr("Untracked:");
Chris@99 65
Chris@100 66 m_descriptions[FileStates::Clean] = tr("You have not changed these files.");
Chris@100 67 m_descriptions[FileStates::Modified] = tr("You have changed these files since you last committed them.");
Chris@100 68 m_descriptions[FileStates::Added] = tr("These files will be added to version control next time you commit.");
Chris@100 69 m_descriptions[FileStates::Removed] = tr("These files will be removed from version control next time you commit.<br>"
Chris@100 70 "They will not be deleted from the local folder.");
Chris@109 71 m_descriptions[FileStates::Missing] = tr("These files are recorded in the version control, but absent from your working folder.<br>"
Chris@109 72 "If you deleted them by accident, select them here and use Revert to restore their previous contents.<br>"
Chris@109 73 "If you deleted them intentionally, select them here and use Remove to tell the version control system about it.");
Chris@100 74 m_descriptions[FileStates::Unknown] = tr("These files are in your working folder but are not under version control.<br>"
Chris@100 75 "Select a file and use Add to place it under version control or Ignore to remove it from this list.");
Chris@100 76
Chris@102 77 m_highlightExplanation = tr("Files highlighted <font color=red>in red</font> "
Chris@100 78 "have appeared since your most recent commit or update.");
Chris@89 79
Chris@94 80 for (int i = int(FileStates::FirstState);
Chris@94 81 i <= int(FileStates::LastState); ++i) {
Chris@89 82
Chris@94 83 FileStates::State s = FileStates::State(i);
Chris@89 84
Chris@89 85 QWidget *box = new QWidget;
Chris@89 86 QGridLayout *boxlayout = new QGridLayout;
Chris@99 87 boxlayout->setMargin(0);
Chris@89 88 box->setLayout(boxlayout);
Chris@89 89
Chris@106 90 boxlayout->addItem(new QSpacerItem(5, 5), 0, 0);
Chris@101 91
Chris@101 92 boxlayout->addWidget(new QLabel(labelFor(s)), 1, 0);
Chris@89 93
Chris@94 94 QListWidget *w = new QListWidget;
Chris@94 95 m_stateListMap[s] = w;
Chris@94 96 w->setSelectionMode(QListWidget::ExtendedSelection);
Chris@101 97 boxlayout->addWidget(w, 2, 0);
Chris@89 98
Chris@95 99 connect(w, SIGNAL(itemSelectionChanged()),
Chris@95 100 this, SLOT(itemSelectionChanged()));
Chris@95 101
Chris@89 102 layout->addWidget(box, ++row, 0, 1, 2);
Chris@89 103 box->hide();
Chris@89 104 }
Chris@89 105
Chris@89 106 layout->setRowStretch(++row, 20);
Chris@88 107 }
Chris@88 108
Chris@93 109 FileStatusWidget::~FileStatusWidget()
Chris@93 110 {
Chris@93 111 delete m_dateReference;
Chris@93 112 }
Chris@93 113
Chris@100 114 QString FileStatusWidget::labelFor(FileStates::State s, bool addHighlightExplanation)
Chris@100 115 {
Chris@100 116 if (addHighlightExplanation) {
Chris@100 117 return QString("<qt><b>%1</b><br>%2<br>%3</qt>")
Chris@100 118 .arg(m_simpleLabels[s])
Chris@100 119 .arg(m_descriptions[s])
Chris@100 120 .arg(m_highlightExplanation);
Chris@100 121 } else {
Chris@100 122 return QString("<qt><b>%1</b><br>%2</qt>")
Chris@100 123 .arg(m_simpleLabels[s])
Chris@100 124 .arg(m_descriptions[s]);
Chris@100 125 }
Chris@100 126 }
Chris@100 127
Chris@95 128 void FileStatusWidget::itemSelectionChanged()
Chris@95 129 {
Chris@95 130 m_selectedFiles.clear();
Chris@95 131
Chris@95 132 DEBUG << "FileStatusWidget::itemSelectionChanged" << endl;
Chris@95 133
Chris@95 134 foreach (QListWidget *w, m_stateListMap) {
Chris@95 135 QList<QListWidgetItem *> sel = w->selectedItems();
Chris@95 136 foreach (QListWidgetItem *i, sel) {
Chris@95 137 m_selectedFiles.push_back(i->text());
Chris@95 138 DEBUG << "file " << i->text() << " is selected" << endl;
Chris@95 139 }
Chris@95 140 }
Chris@95 141
Chris@95 142 emit selectionChanged();
Chris@95 143 }
Chris@95 144
Chris@94 145 void FileStatusWidget::clearSelections()
Chris@94 146 {
Chris@95 147 m_selectedFiles.clear();
Chris@94 148 foreach (QListWidget *w, m_stateListMap) {
Chris@94 149 w->clearSelection();
Chris@94 150 }
Chris@94 151 }
Chris@94 152
Chris@95 153 bool FileStatusWidget::haveChangesToCommit() const
Chris@95 154 {
Chris@95 155 return !m_fileStates.added().empty() ||
Chris@95 156 !m_fileStates.removed().empty() ||
Chris@95 157 !m_fileStates.modified().empty();
Chris@95 158 }
Chris@95 159
Chris@95 160 bool FileStatusWidget::haveSelection() const
Chris@95 161 {
Chris@95 162 return !m_selectedFiles.empty();
Chris@95 163 }
Chris@95 164
Chris@95 165 QStringList FileStatusWidget::getAllSelectedFiles() const
Chris@95 166 {
Chris@95 167 return m_selectedFiles;
Chris@95 168 }
Chris@95 169
Chris@95 170 QStringList FileStatusWidget::getSelectedCommittableFiles() const
Chris@95 171 {
Chris@95 172 QStringList files;
Chris@95 173 foreach (QString f, m_selectedFiles) {
Chris@95 174 switch (m_fileStates.getStateOfFile(f)) {
Chris@95 175 case FileStates::Added:
Chris@95 176 case FileStates::Modified:
Chris@95 177 case FileStates::Removed:
Chris@95 178 files.push_back(f);
Chris@95 179 break;
Chris@95 180 default: break;
Chris@95 181 }
Chris@95 182 }
Chris@95 183 return files;
Chris@95 184 }
Chris@95 185
Chris@103 186 QStringList FileStatusWidget::getAllCommittableFiles() const
Chris@103 187 {
Chris@103 188 QStringList files;
Chris@103 189 files << m_fileStates.getFilesInState(FileStates::Modified);
Chris@103 190 files << m_fileStates.getFilesInState(FileStates::Added);
Chris@103 191 files << m_fileStates.getFilesInState(FileStates::Removed);
Chris@103 192 return files;
Chris@103 193 }
Chris@103 194
Chris@109 195 QStringList FileStatusWidget::getSelectedRevertableFiles() const
Chris@109 196 {
Chris@109 197 QStringList files;
Chris@109 198 foreach (QString f, m_selectedFiles) {
Chris@109 199 switch (m_fileStates.getStateOfFile(f)) {
Chris@109 200 case FileStates::Added:
Chris@109 201 case FileStates::Modified:
Chris@109 202 case FileStates::Removed:
Chris@109 203 case FileStates::Missing:
Chris@109 204 files.push_back(f);
Chris@109 205 break;
Chris@109 206 default: break;
Chris@109 207 }
Chris@109 208 }
Chris@109 209 return files;
Chris@109 210 }
Chris@109 211
Chris@109 212 QStringList FileStatusWidget::getAllRevertableFiles() const
Chris@109 213 {
Chris@109 214 QStringList files;
Chris@109 215 files << m_fileStates.getFilesInState(FileStates::Modified);
Chris@109 216 files << m_fileStates.getFilesInState(FileStates::Added);
Chris@109 217 files << m_fileStates.getFilesInState(FileStates::Removed);
Chris@109 218 files << m_fileStates.getFilesInState(FileStates::Missing);
Chris@109 219 return files;
Chris@109 220 }
Chris@109 221
Chris@95 222 QStringList FileStatusWidget::getSelectedAddableFiles() const
Chris@95 223 {
Chris@95 224 QStringList files;
Chris@95 225 foreach (QString f, m_selectedFiles) {
Chris@95 226 switch (m_fileStates.getStateOfFile(f)) {
Chris@95 227 case FileStates::Unknown:
Chris@95 228 case FileStates::Removed:
Chris@95 229 files.push_back(f);
Chris@95 230 break;
Chris@95 231 default: break;
Chris@95 232 }
Chris@95 233 }
Chris@95 234 return files;
Chris@95 235 }
Chris@95 236
Chris@103 237 QStringList FileStatusWidget::getAllAddableFiles() const
Chris@103 238 {
Chris@103 239 QStringList files;
Chris@103 240 files << m_fileStates.getFilesInState(FileStates::Removed);
Chris@103 241 files << m_fileStates.getFilesInState(FileStates::Unknown);
Chris@103 242 return files;
Chris@103 243 }
Chris@103 244
Chris@95 245 QStringList FileStatusWidget::getSelectedRemovableFiles() const
Chris@95 246 {
Chris@95 247 QStringList files;
Chris@95 248 foreach (QString f, m_selectedFiles) {
Chris@95 249 switch (m_fileStates.getStateOfFile(f)) {
Chris@95 250 case FileStates::Clean:
Chris@95 251 case FileStates::Added:
Chris@95 252 case FileStates::Modified:
Chris@95 253 case FileStates::Missing:
Chris@95 254 files.push_back(f);
Chris@95 255 break;
Chris@95 256 default: break;
Chris@95 257 }
Chris@95 258 }
Chris@95 259 return files;
Chris@95 260 }
Chris@95 261
Chris@103 262 QStringList FileStatusWidget::getAllRemovableFiles() const
Chris@103 263 {
Chris@103 264 QStringList files;
Chris@103 265 files << m_fileStates.getFilesInState(FileStates::Clean);
Chris@103 266 files << m_fileStates.getFilesInState(FileStates::Added);
Chris@103 267 files << m_fileStates.getFilesInState(FileStates::Modified);
Chris@103 268 files << m_fileStates.getFilesInState(FileStates::Missing);
Chris@103 269 return files;
Chris@103 270 }
Chris@103 271
Chris@88 272 void
Chris@88 273 FileStatusWidget::setLocalPath(QString p)
Chris@88 274 {
Chris@88 275 m_localPath = p;
Chris@88 276 m_localPathLabel->setText(p);
Chris@93 277 delete m_dateReference;
Chris@93 278 m_dateReference = new QFileInfo(p + "/.hg/dirstate");
Chris@93 279 if (!m_dateReference->exists() ||
Chris@93 280 !m_dateReference->isFile() ||
Chris@93 281 !m_dateReference->isReadable()) {
Chris@93 282 DEBUG << "FileStatusWidget::setLocalPath: date reference file "
Chris@93 283 << m_dateReference->absoluteFilePath()
Chris@93 284 << " does not exist, is not a file, or cannot be read"
Chris@93 285 << endl;
Chris@93 286 delete m_dateReference;
Chris@93 287 m_dateReference = 0;
Chris@93 288 }
Chris@88 289 }
Chris@88 290
Chris@88 291 void
Chris@88 292 FileStatusWidget::setRemoteURL(QString r)
Chris@88 293 {
Chris@88 294 m_remoteURL = r;
Chris@88 295 m_remoteURLLabel->setText(r);
Chris@88 296 }
Chris@88 297
Chris@88 298 void
Chris@92 299 FileStatusWidget::setFileStates(FileStates p)
Chris@88 300 {
Chris@92 301 m_fileStates = p;
Chris@88 302 updateWidgets();
Chris@88 303 }
Chris@88 304
Chris@88 305 void
Chris@106 306 FileStatusWidget::setBranch(QString b)
Chris@106 307 {
Chris@106 308 m_branch = b;
Chris@106 309 m_branchLabel->setText(b);
Chris@106 310 }
Chris@106 311
Chris@106 312 void
Chris@88 313 FileStatusWidget::updateWidgets()
Chris@88 314 {
Chris@95 315 QDateTime lastInteractionTime;
Chris@95 316 if (m_dateReference) {
Chris@95 317 lastInteractionTime = m_dateReference->lastModified();
Chris@95 318 DEBUG << "reference time: " << lastInteractionTime << endl;
Chris@95 319 }
Chris@95 320
Chris@95 321 QSet<QString> selectedFiles;
Chris@95 322 foreach (QString f, m_selectedFiles) selectedFiles.insert(f);
Chris@95 323
Chris@94 324 foreach (FileStates::State s, m_stateListMap.keys()) {
Chris@95 325
Chris@94 326 QListWidget *w = m_stateListMap[s];
Chris@94 327 w->clear();
Chris@95 328 QStringList files = m_fileStates.getFilesInState(s);
Chris@93 329
Chris@95 330 QStringList highPriority, lowPriority;
Chris@95 331
Chris@95 332 foreach (QString file, files) {
Chris@95 333
Chris@95 334 bool highlighted = false;
Chris@95 335
Chris@95 336 if (s == FileStates::Unknown) {
Chris@95 337 // We want to highlight untracked files that have appeared
Chris@95 338 // since the last interaction with the repo
Chris@95 339 QString fn(m_localPath + "/" + file);
Chris@95 340 DEBUG << "comparing with " << fn << endl;
Chris@95 341 QFileInfo fi(fn);
Chris@100 342 if (fi.exists() && fi.created() > lastInteractionTime) {
Chris@95 343 DEBUG << "file " << fn << " is newer (" << fi.lastModified()
Chris@95 344 << ") than reference" << endl;
Chris@95 345 highlighted = true;
Chris@95 346 }
Chris@95 347 }
Chris@95 348
Chris@95 349 if (highlighted) {
Chris@95 350 highPriority.push_back(file);
Chris@95 351 } else {
Chris@95 352 lowPriority.push_back(file);
Chris@93 353 }
Chris@93 354 }
Chris@95 355
Chris@95 356 foreach (QString file, highPriority) {
Chris@95 357 QListWidgetItem *item = new QListWidgetItem(file);
Chris@95 358 w->addItem(item);
Chris@95 359 item->setForeground(Qt::red); //!!! and a nice gold star
Chris@95 360 item->setSelected(selectedFiles.contains(file));
Chris@95 361 }
Chris@95 362
Chris@95 363 foreach (QString file, lowPriority) {
Chris@95 364 QListWidgetItem *item = new QListWidgetItem(file);
Chris@95 365 w->addItem(item);
Chris@95 366 item->setSelected(selectedFiles.contains(file));
Chris@95 367 }
Chris@95 368
Chris@100 369 setLabelFor(w, s, !highPriority.empty());
Chris@100 370
Chris@95 371 w->parentWidget()->setVisible(!files.empty());
Chris@93 372 }
Chris@88 373 }
Chris@88 374
Chris@100 375 void FileStatusWidget::setLabelFor(QWidget *w, FileStates::State s, bool addHighlight)
Chris@100 376 {
Chris@100 377 QString text = labelFor(s, addHighlight);
Chris@100 378 QWidget *p = w->parentWidget();
Chris@100 379 QList<QLabel *> ql = p->findChildren<QLabel *>();
Chris@100 380 if (!ql.empty()) ql[0]->setText(text);
Chris@100 381 }