annotate mainwindow.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 8ae3b44c0073
children 4bd17f36d059
rev   line source
Chris@57 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
jtkorhonen@0 2
Chris@57 3 /*
Chris@57 4 EasyMercurial
Chris@57 5
Chris@98 6 Based on hgExplorer by Jari Korhonen
Chris@57 7 Copyright (c) 2010 Jari Korhonen
Chris@57 8 Copyright (c) 2010 Chris Cannam
Chris@57 9 Copyright (c) 2010 Queen Mary, University of London
Chris@57 10
Chris@57 11 This program is free software; you can redistribute it and/or
Chris@57 12 modify it under the terms of the GNU General Public License as
Chris@57 13 published by the Free Software Foundation; either version 2 of the
Chris@57 14 License, or (at your option) any later version. See the file
Chris@57 15 COPYING included with this distribution for more information.
Chris@57 16 */
Chris@50 17
jtkorhonen@0 18 #include <QStringList>
jtkorhonen@0 19 #include <QDir>
jtkorhonen@24 20 #include <QNetworkInterface>
jtkorhonen@17 21 #include <QHostAddress>
jtkorhonen@17 22 #include <QHostInfo>
jtkorhonen@34 23 #include <QDesktopServices>
Chris@50 24 #include <QStatusBar>
Chris@50 25 #include <QMessageBox>
Chris@50 26 #include <QMenuBar>
Chris@50 27 #include <QApplication>
Chris@50 28 #include <QToolBar>
Chris@61 29 #include <QToolButton>
Chris@50 30 #include <QSettings>
Chris@90 31 #include <QInputDialog>
jtkorhonen@0 32
Chris@53 33 #include "mainwindow.h"
Chris@53 34 #include "settingsdialog.h"
Chris@69 35 #include "multichoicedialog.h"
Chris@64 36 #include "startupdialog.h"
Chris@53 37 #include "colourset.h"
Chris@62 38 #include "debug.h"
Chris@74 39 #include "logparser.h"
Chris@103 40 #include "confirmcommentdialog.h"
Chris@53 41
jtkorhonen@0 42
jtkorhonen@0 43 MainWindow::MainWindow()
jtkorhonen@0 44 {
jtkorhonen@0 45 QString wndTitle;
jtkorhonen@0 46
Chris@90 47 fsWatcher = 0;
Chris@90 48
jtkorhonen@0 49 createActions();
jtkorhonen@0 50 createMenus();
jtkorhonen@0 51 createToolBars();
jtkorhonen@0 52 createStatusBar();
jtkorhonen@0 53
jtkorhonen@0 54 runner = new HgRunner(this);
Chris@109 55 connect(runner, SIGNAL(commandCompleted(HgAction, QString)),
Chris@109 56 this, SLOT(commandCompleted(HgAction, QString)));
Chris@109 57 connect(runner, SIGNAL(commandFailed(HgAction, QString)),
Chris@109 58 this, SLOT(commandFailed(HgAction, QString)));
jtkorhonen@0 59 statusBar()->addPermanentWidget(runner);
jtkorhonen@0 60
Chris@61 61 setWindowTitle(tr("EasyMercurial"));
jtkorhonen@0 62
jtkorhonen@0 63 remoteRepoPath = "";
jtkorhonen@0 64 workFolderPath = "";
jtkorhonen@0 65
jtkorhonen@0 66 readSettings();
jtkorhonen@0 67
Chris@109 68 // tabPage = 0;
jtkorhonen@33 69 justMerged = false;
Chris@98 70 hgTabs = new HgTabWidget((QWidget *) this, remoteRepoPath, workFolderPath);
Chris@98 71 setCentralWidget(hgTabs);
jtkorhonen@0 72
Chris@98 73 connect(hgTabs, SIGNAL(selectionChanged()),
Chris@95 74 this, SLOT(enableDisableActions()));
Chris@95 75
jtkorhonen@0 76 setUnifiedTitleAndToolBarOnMac(true);
jtkorhonen@0 77 connectActions();
jtkorhonen@0 78 enableDisableActions();
jtkorhonen@0 79
Chris@64 80 if (firstStart) {
Chris@64 81 startupDialog();
jtkorhonen@0 82 }
jtkorhonen@0 83
Chris@64 84 ColourSet *cs = ColourSet::instance();
Chris@64 85 cs->clearDefaultNames();
Chris@64 86 cs->addDefaultName("");
Chris@64 87 cs->addDefaultName(getUserInfo());
Chris@62 88
Chris@72 89 if (workFolderPath == "") {
Chris@72 90 open();
Chris@72 91 }
Chris@72 92
Chris@109 93 hgQueryPaths();
jtkorhonen@0 94 }
jtkorhonen@0 95
jtkorhonen@0 96
jtkorhonen@0 97 void MainWindow::closeEvent(QCloseEvent *)
jtkorhonen@0 98 {
jtkorhonen@0 99 writeSettings();
Chris@90 100 delete fsWatcher;
jtkorhonen@0 101 }
jtkorhonen@0 102
jtkorhonen@0 103
Chris@64 104 QString MainWindow::getUserInfo() const
Chris@64 105 {
Chris@64 106 QSettings settings;
Chris@64 107 settings.beginGroup("User Information");
Chris@64 108 QString name = settings.value("name", getUserRealName()).toString();
Chris@64 109 QString email = settings.value("email", "").toString();
Chris@64 110
Chris@64 111 QString identifier;
Chris@64 112
Chris@64 113 if (email != "") {
Chris@64 114 identifier = QString("%1 <%2>").arg(name).arg(email);
Chris@64 115 } else {
Chris@64 116 identifier = name;
Chris@64 117 }
Chris@64 118
Chris@64 119 return identifier;
Chris@64 120 }
Chris@64 121
jtkorhonen@0 122 void MainWindow::about()
jtkorhonen@0 123 {
Chris@97 124 QMessageBox::about(this, tr("About EasyMercurial"),
Chris@97 125 tr("<qt><h2>About EasyMercurial</h2>"
Chris@97 126 "<p>EasyMercurial is a simple user interface for the "
Chris@97 127 "Mercurial version control system.</p>"
Chris@98 128 "<p>EasyMercurial is based on hgExplorer by "
Chris@97 129 "Jari Korhonen, with thanks.<br>EasyMercurial development carried out by "
Chris@97 130 "Chris Cannam for soundsoftware.ac.uk at the Centre for Digital Music, Queen Mary, University of London."
Chris@97 131 "<ul><li>Copyright &copy; 2010 Jari Korhonen</li>"
Chris@97 132 "<li>Copyright &copy; 2010 Chris Cannam</li>"
Chris@97 133 "<li>Copyright &copy; 2010 Queen Mary, University of London</li>"
Chris@97 134 "</ul>"
Chris@97 135 "<p> This program is free software; you can redistribute it and/or "
Chris@97 136 "modify it under the terms of the GNU General Public License as "
Chris@97 137 "published by the Free Software Foundation; either version 2 of the "
Chris@97 138 "License, or (at your option) any later version. See the file "
Chris@97 139 "COPYING included with this distribution for more information."));
jtkorhonen@0 140 }
jtkorhonen@0 141
Chris@94 142 void MainWindow::clearSelections()
Chris@94 143 {
Chris@98 144 hgTabs->clearSelections();
Chris@94 145 }
jtkorhonen@0 146
jtkorhonen@0 147 void MainWindow::hgStat()
jtkorhonen@0 148 {
Chris@109 149 QStringList params;
Chris@109 150 params << "stat" << "-ardum";
Chris@109 151 runner->requestAction(HgAction(ACT_STAT, workFolderPath, params));
jtkorhonen@0 152 }
jtkorhonen@0 153
Chris@109 154 void MainWindow::hgQueryPaths()
Chris@74 155 {
Chris@109 156 QStringList params;
Chris@109 157 params << "paths";
Chris@109 158 runner->requestAction(HgAction(ACT_QUERY_PATHS, workFolderPath, params));
Chris@74 159 }
Chris@74 160
Chris@109 161 void MainWindow::hgQueryBranch()
Chris@106 162 {
Chris@109 163 QStringList params;
Chris@109 164 params << "branch";
Chris@109 165 runner->requestAction(HgAction(ACT_QUERY_BRANCH, workFolderPath, params));
Chris@106 166 }
Chris@106 167
Chris@109 168 void MainWindow::hgQueryHeads()
jtkorhonen@0 169 {
Chris@109 170 QStringList params;
Chris@109 171 params << "heads";
Chris@109 172 // on empty repos, "hg heads" will fail -- we don't care about that.
Chris@109 173 runner->requestAction(HgAction(ACT_QUERY_HEADS, workFolderPath, params));
jtkorhonen@0 174 }
jtkorhonen@0 175
jtkorhonen@0 176 void MainWindow::hgLog()
jtkorhonen@0 177 {
Chris@90 178 //!!! This needs to be incremental, except when we pull or set new repo
Chris@109 179 QStringList params;
Chris@109 180 params << "log";
Chris@109 181 params << "--template";
Chris@109 182 params << "id: {rev}:{node|short}\\nauthor: {author}\\nbranch: {branches}\\ntag: {tag}\\ndatetime: {date|isodate}\\ntimestamp: {date|hgdate}\\nage: {date|age}\\nparents: {parents}\\ncomment: {desc|json}\\n\\n";
Chris@109 183
Chris@109 184 runner->requestAction(HgAction(ACT_LOG, workFolderPath, params));
Chris@109 185 }
Chris@109 186
Chris@109 187
Chris@109 188 void MainWindow::hgQueryParents()
Chris@109 189 {
Chris@109 190 QStringList params;
Chris@109 191 params << "parents";
Chris@109 192 runner->requestAction(HgAction(ACT_QUERY_PARENTS, workFolderPath, params));
Chris@109 193 }
Chris@109 194
Chris@109 195 void MainWindow::hgAnnotate()
Chris@109 196 {
Chris@109 197 QStringList params;
Chris@109 198 QString currentFile;//!!! = hgTabs -> getCurrentFileListLine();
Chris@109 199
Chris@109 200 if (!currentFile.isEmpty())
jtkorhonen@0 201 {
Chris@109 202 params << "annotate" << "--" << currentFile.mid(2); //Jump over status marker characters (e.g "M ")
jtkorhonen@0 203
Chris@109 204 runner->requestAction(HgAction(ACT_ANNOTATE, workFolderPath, params));
jtkorhonen@0 205 }
jtkorhonen@0 206 }
jtkorhonen@0 207
Chris@109 208 void MainWindow::hgResolveMark()
Chris@109 209 {
Chris@109 210 QStringList params;
Chris@109 211 QString currentFile;//!!! = hgTabs -> getCurrentFileListLine();
jtkorhonen@0 212
Chris@109 213 if (!currentFile.isEmpty())
jtkorhonen@0 214 {
Chris@109 215 params << "resolve" << "--mark" << "--" << currentFile.mid(2); //Jump over status marker characters (e.g "M ")
jtkorhonen@0 216
Chris@109 217 runner->requestAction(HgAction(ACT_RESOLVE_MARK, workFolderPath, params));
jtkorhonen@0 218 }
jtkorhonen@0 219 }
jtkorhonen@0 220
Chris@109 221 void MainWindow::hgResolveList()
Chris@109 222 {
Chris@109 223 QStringList params;
jtkorhonen@0 224
Chris@109 225 params << "resolve" << "--list";
Chris@109 226 runner->requestAction(HgAction(ACT_RESOLVE_LIST, workFolderPath, params));
Chris@109 227 }
Chris@109 228
Chris@109 229 void MainWindow::hgAdd()
jtkorhonen@0 230 {
Chris@109 231 QStringList params;
jtkorhonen@0 232
Chris@109 233 // hgExplorer permitted adding "all" files -- I'm not sure
Chris@109 234 // that one is a good idea, let's require the user to select
jtkorhonen@0 235
Chris@109 236 QStringList files = hgTabs->getSelectedAddableFiles();
Chris@109 237
Chris@109 238 if (!files.empty()) {
Chris@109 239 params << "add" << "--" << files;
Chris@109 240 runner->requestAction(HgAction(ACT_ADD, workFolderPath, params));
jtkorhonen@0 241 }
jtkorhonen@0 242 }
jtkorhonen@0 243
jtkorhonen@0 244
Chris@98 245 void MainWindow::hgRemove()
Chris@98 246 {
Chris@109 247 QStringList params;
Chris@98 248
Chris@109 249 QStringList files = hgTabs->getSelectedRemovableFiles();
Chris@98 250
Chris@109 251 //!!! todo: confirmation dialog (with file list in it) (or do we
Chris@109 252 // need that? all it does is move the files to the removed
Chris@109 253 // list... doesn't it?)
Chris@98 254
Chris@109 255 if (!files.empty()) {
Chris@109 256 params << "remove" << "--after" << "--force" << "--" << files;
Chris@109 257 runner->requestAction(HgAction(ACT_REMOVE, workFolderPath, params));
Chris@109 258 }
Chris@98 259
Chris@91 260 /*!!!
Chris@98 261 QString currentFile;//!!! = hgTabs -> getCurrentFileListLine();
Chris@98 262
Chris@98 263 if (!currentFile.isEmpty())
jtkorhonen@5 264 {
Chris@98 265 if (QMessageBox::Ok == QMessageBox::warning(this, "Remove file", "Really remove file " + currentFile.mid(2) + "?",
Chris@98 266 QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Cancel))
Chris@98 267 {
Chris@98 268 params << "remove" << "--after" << "--force" << "--" << currentFile.mid(2); //Jump over status marker characters (e.g "M ")
jtkorhonen@17 269
Chris@98 270 runner -> startHgCommand(workFolderPath, params);
Chris@98 271 runningAction = ACT_REMOVE;
jtkorhonen@17 272 }
jtkorhonen@5 273 }
Chris@98 274 */
jtkorhonen@0 275 }
jtkorhonen@0 276
jtkorhonen@0 277 void MainWindow::hgCommit()
jtkorhonen@0 278 {
Chris@109 279 QStringList params;
Chris@109 280 QString comment;
Chris@94 281
Chris@109 282 QStringList files = hgTabs->getSelectedCommittableFiles();
Chris@109 283 if (files.empty()) files = hgTabs->getAllCommittableFiles();
Chris@103 284
Chris@109 285 if (ConfirmCommentDialog::confirmAndGetLongComment
Chris@109 286 (this,
Chris@109 287 tr("Commit files"),
Chris@109 288 tr("<h2>Commit files</h2><p>About to commit the following files:"),
Chris@109 289 tr("<h2>Commit files</h2><p>About to commit %1 files."),
Chris@109 290 files,
Chris@109 291 comment)) {
Chris@103 292
Chris@109 293 if ((justMerged == false) && //!!! review usage of justMerged, and how it interacts with asynchronous request queue
Chris@109 294 !files.empty()) {
Chris@109 295 // User wants to commit selected file(s) (and this is not merge commit, which would fail if we selected files)
Chris@109 296 params << "commit" << "--message" << comment << "--user" << getUserInfo() << "--" << files;
Chris@109 297 } else {
Chris@109 298 // Commit all changes
Chris@109 299 params << "commit" << "--message" << comment << "--user" << getUserInfo();
jtkorhonen@0 300 }
Chris@109 301
Chris@109 302 runner->requestAction(HgAction(ACT_COMMIT, workFolderPath, params));
jtkorhonen@0 303 }
jtkorhonen@0 304 }
jtkorhonen@0 305
jtkorhonen@34 306 QString MainWindow::filterTag(QString tag)
jtkorhonen@34 307 {
jtkorhonen@34 308 for(int i = 0; i < tag.size(); i++)
jtkorhonen@34 309 {
jtkorhonen@34 310 if (tag[i].isLower() || tag[i].isUpper() || tag[i].isDigit() || (tag[i] == QChar('.')))
jtkorhonen@34 311 {
jtkorhonen@34 312 //ok
jtkorhonen@34 313 }
jtkorhonen@34 314 else
jtkorhonen@34 315 {
jtkorhonen@34 316 tag[i] = QChar('_');
jtkorhonen@34 317 }
jtkorhonen@34 318 }
jtkorhonen@34 319 return tag;
jtkorhonen@34 320 }
jtkorhonen@34 321
jtkorhonen@34 322
jtkorhonen@34 323 void MainWindow::hgTag()
jtkorhonen@34 324 {
Chris@109 325 QStringList params;
Chris@109 326 QString tag;
jtkorhonen@34 327
Chris@109 328 if (ConfirmCommentDialog::confirmAndGetShortComment
Chris@109 329 (this,
Chris@109 330 tr("Tag"),
Chris@109 331 tr("Enter tag:"),
Chris@109 332 tag)) {
Chris@109 333 if (!tag.isEmpty()) //!!! do something better if it is empty
Chris@109 334 {
Chris@109 335 params << "tag" << "--user" << getUserInfo() << filterTag(tag);
Chris@109 336
Chris@109 337 runner->requestAction(HgAction(ACT_TAG, workFolderPath, params));
jtkorhonen@34 338 }
jtkorhonen@34 339 }
jtkorhonen@34 340 }
jtkorhonen@34 341
jtkorhonen@34 342
jtkorhonen@34 343 void MainWindow::hgIgnore()
jtkorhonen@34 344 {
Chris@109 345 QString hgIgnorePath;
Chris@109 346 QStringList params;
Chris@109 347 QString editorName;
Chris@109 348
Chris@109 349 hgIgnorePath = workFolderPath;
Chris@109 350 hgIgnorePath += ".hgignore";
Chris@109 351
Chris@109 352 params << hgIgnorePath;
Chris@109 353
Chris@109 354 if ((getSystem() == "Linux"))
jtkorhonen@34 355 {
Chris@109 356 editorName = "gedit";
Chris@109 357 }
Chris@109 358 else
Chris@109 359 {
Chris@109 360 editorName = """C:\\Program Files\\Windows NT\\Accessories\\wordpad.exe""";
Chris@109 361 }
jtkorhonen@34 362
Chris@109 363 HgAction action(ACT_HG_IGNORE, workFolderPath, params);
Chris@109 364 action.executable = editorName;
jtkorhonen@34 365
Chris@109 366 runner->requestAction(action);
jtkorhonen@34 367 }
jtkorhonen@34 368
jtkorhonen@34 369
jtkorhonen@34 370
jtkorhonen@0 371 void MainWindow::hgFileDiff()
jtkorhonen@0 372 {
jtkorhonen@0 373 QStringList params;
Chris@91 374 /*!!!
Chris@98 375 QString currentFile = hgTabs -> getCurrentFileListLine();
jtkorhonen@0 376
jtkorhonen@0 377 if (!currentFile.isEmpty())
jtkorhonen@0 378 {
jtkorhonen@0 379 //Diff parent file against working folder file
mg@41 380 params << "kdiff3" << "--" << currentFile.mid(2);
Chris@62 381 runner -> startHgCommand(workFolderPath, params);
jtkorhonen@0 382 runningAction = ACT_FILEDIFF;
jtkorhonen@0 383 }
Chris@91 384 */
jtkorhonen@0 385 }
jtkorhonen@0 386
jtkorhonen@0 387
jtkorhonen@0 388 void MainWindow::hgFolderDiff()
jtkorhonen@0 389 {
Chris@109 390 QStringList params;
jtkorhonen@0 391
Chris@109 392 //Diff parent against working folder (folder diff)
Chris@109 393 params << "--config" << "extensions.extdiff=" << "extdiff" << "-p";
Chris@109 394
Chris@109 395 params << "kompare";
Chris@109 396
Chris@109 397 // params << "kdiff3";
Chris@109 398 runner->requestAction(HgAction(ACT_FOLDERDIFF, workFolderPath, params));
jtkorhonen@0 399 }
jtkorhonen@0 400
jtkorhonen@0 401
jtkorhonen@0 402 void MainWindow::hgChgSetDiff()
jtkorhonen@0 403 {
jtkorhonen@0 404 QStringList params;
jtkorhonen@0 405
jtkorhonen@0 406 //Diff 2 history log versions against each other
jtkorhonen@0 407 QString revA;
jtkorhonen@0 408 QString revB;
Chris@91 409 /*!!!
Chris@98 410 hgTabs -> getHistoryDiffRevisions(revA, revB);
jtkorhonen@0 411
jtkorhonen@0 412 if ((!revA.isEmpty()) && (!revB.isEmpty()))
jtkorhonen@0 413 {
jtkorhonen@0 414 params << "kdiff3" << "--rev" << revA << "--rev" << revB;
Chris@62 415 runner -> startHgCommand(workFolderPath, params);
jtkorhonen@0 416 runningAction = ACT_CHGSETDIFF;
jtkorhonen@0 417 }
jtkorhonen@0 418 else
jtkorhonen@0 419 {
jtkorhonen@0 420 QMessageBox::information(this, tr("Changeset diff"), tr("Please select two changesets from history list or heads list first."));
jtkorhonen@0 421 }
Chris@91 422 */
jtkorhonen@0 423 }
jtkorhonen@0 424
jtkorhonen@0 425
jtkorhonen@0 426
jtkorhonen@0 427 void MainWindow::hgUpdate()
jtkorhonen@0 428 {
Chris@109 429 QStringList params;
jtkorhonen@0 430
Chris@109 431 params << "update";
Chris@109 432
Chris@109 433 runner->requestAction(HgAction(ACT_UPDATE, workFolderPath, params));
jtkorhonen@0 434 }
jtkorhonen@0 435
jtkorhonen@0 436
jtkorhonen@0 437 void MainWindow::hgUpdateToRev()
jtkorhonen@0 438 {
jtkorhonen@0 439 QStringList params;
jtkorhonen@0 440 QString rev;
Chris@91 441 /*!!!
Chris@98 442 hgTabs -> getUpdateToRevRevision(rev);
jtkorhonen@0 443
Chris@98 444 hgTabs -> setCurrentIndex(WORKTAB);
jtkorhonen@0 445 enableDisableActions();
jtkorhonen@0 446
jtkorhonen@0 447 params << "update" << "--rev" << rev << "--clean";
jtkorhonen@0 448
Chris@62 449 runner -> startHgCommand(workFolderPath, params);
jtkorhonen@0 450
jtkorhonen@0 451 runningAction = ACT_UPDATE;
Chris@91 452 */
Chris@109 453
jtkorhonen@0 454 }
jtkorhonen@0 455
jtkorhonen@0 456
jtkorhonen@0 457 void MainWindow::hgRevert()
jtkorhonen@0 458 {
Chris@109 459 QStringList params;
Chris@109 460 QString comment;
Chris@98 461
Chris@109 462 QStringList files = hgTabs->getSelectedRevertableFiles();
Chris@109 463 if (files.empty()) files = hgTabs->getAllRevertableFiles();
Chris@109 464
Chris@109 465 if (ConfirmCommentDialog::confirmDangerousFilesAction
Chris@109 466 (this,
Chris@109 467 tr("Revert files"),
Chris@109 468 tr("<h2>Revert files</h2><p>About to revert the following files to their previous committed state. This will <b>throw away any changes</b> that you have made to these files but have not committed."),
Chris@109 469 tr("<h2>Revert files</h2><p>About to revert %1 files. This will <b>throw away any changes</b> that you have made to these files but have not committed."),
Chris@109 470 files)) {
Chris@109 471
Chris@98 472 if (files.empty()) {
Chris@98 473 params << "revert" << "--no-backup";
Chris@98 474 } else {
Chris@98 475 params << "revert" << "--no-backup" << "--" << files;
Chris@98 476 }
Chris@109 477
Chris@109 478 runner->requestAction(HgAction(ACT_REVERT, workFolderPath, params));
jtkorhonen@0 479 }
jtkorhonen@0 480 }
jtkorhonen@0 481
jtkorhonen@33 482 void MainWindow::hgRetryMerge()
jtkorhonen@33 483 {
Chris@109 484 QStringList params;
jtkorhonen@33 485
Chris@109 486 params << "resolve" << "--all";
Chris@109 487 runner->requestAction(HgAction(ACT_RETRY_MERGE, workFolderPath, params));
jtkorhonen@33 488 }
jtkorhonen@33 489
jtkorhonen@33 490
jtkorhonen@0 491 void MainWindow::hgMerge()
jtkorhonen@0 492 {
Chris@109 493 QStringList params;
jtkorhonen@0 494
Chris@109 495 params << "merge";
Chris@109 496
Chris@109 497 runner->requestAction(HgAction(ACT_MERGE, workFolderPath, params));
jtkorhonen@0 498 }
jtkorhonen@0 499
jtkorhonen@0 500
jtkorhonen@0 501 void MainWindow::hgCloneFromRemote()
jtkorhonen@0 502 {
Chris@109 503 QStringList params;
jtkorhonen@0 504
Chris@109 505 if (!QDir(workFolderPath).exists()) {
Chris@109 506 if (!QDir().mkpath(workFolderPath)) {
Chris@109 507 DEBUG << "hgCloneFromRemote: Failed to create target path "
Chris@109 508 << workFolderPath << endl;
Chris@109 509 //!!! report error
Chris@109 510 return;
Chris@104 511 }
Chris@109 512 }
Chris@104 513
Chris@109 514 params << "clone" << remoteRepoPath << workFolderPath;
Chris@109 515
Chris@109 516 hgTabs->setWorkFolderAndRepoNames(workFolderPath, remoteRepoPath);
jtkorhonen@0 517
Chris@109 518 runner->requestAction(HgAction(ACT_CLONEFROMREMOTE, workFolderPath, params));
jtkorhonen@0 519 }
jtkorhonen@0 520
jtkorhonen@0 521 void MainWindow::hgInit()
jtkorhonen@0 522 {
Chris@109 523 QStringList params;
jtkorhonen@0 524
Chris@109 525 params << "init";
Chris@109 526 params << workFolderPath;
jtkorhonen@0 527
Chris@109 528 runner->requestAction(HgAction(ACT_INIT, workFolderPath, params));
jtkorhonen@0 529 }
jtkorhonen@0 530
jtkorhonen@0 531 void MainWindow::hgIncoming()
jtkorhonen@0 532 {
Chris@109 533 QStringList params;
jtkorhonen@0 534
Chris@109 535 params << "incoming" << "--newest-first" << remoteRepoPath;
jtkorhonen@0 536
Chris@109 537 runner->requestAction(HgAction(ACT_INCOMING, workFolderPath, params));
jtkorhonen@0 538 }
jtkorhonen@0 539
jtkorhonen@0 540
jtkorhonen@0 541 void MainWindow::hgPull()
jtkorhonen@0 542 {
Chris@109 543 QStringList params;
jtkorhonen@0 544
Chris@109 545 params << "pull" << remoteRepoPath;
jtkorhonen@0 546
Chris@109 547 runner->requestAction(HgAction(ACT_PULL, workFolderPath, params));
jtkorhonen@0 548 }
jtkorhonen@0 549
jtkorhonen@0 550
jtkorhonen@0 551 void MainWindow::hgPush()
jtkorhonen@0 552 {
Chris@109 553 QStringList params;
jtkorhonen@0 554
Chris@109 555 params << "push" << remoteRepoPath;
jtkorhonen@0 556
Chris@109 557 runner->requestAction(HgAction(ACT_PUSH, workFolderPath, params));
jtkorhonen@0 558 }
jtkorhonen@0 559
jtkorhonen@28 560 QString MainWindow::listAllUpIpV4Addresses()
jtkorhonen@26 561 {
jtkorhonen@28 562 QString ret;
jtkorhonen@26 563 QList<QNetworkInterface> ifaces = QNetworkInterface::allInterfaces();
jtkorhonen@26 564
jtkorhonen@26 565 for (int i = 0; i < ifaces.count(); i++)
jtkorhonen@26 566 {
jtkorhonen@26 567 QNetworkInterface iface = ifaces.at(i);
jtkorhonen@26 568
jtkorhonen@26 569 if (iface.flags().testFlag(QNetworkInterface::IsUp) && !iface.flags().testFlag(QNetworkInterface::IsLoopBack))
jtkorhonen@26 570 {
jtkorhonen@26 571 for (int j=0; j<iface.addressEntries().count(); j++)
jtkorhonen@26 572 {
jtkorhonen@28 573 QHostAddress tmp = iface.addressEntries().at(j).ip();
jtkorhonen@28 574 if (QAbstractSocket::IPv4Protocol == tmp.protocol())
jtkorhonen@24 575 {
jtkorhonen@28 576 if (!ret.isEmpty())
jtkorhonen@28 577 {
jtkorhonen@28 578 ret += " ";
jtkorhonen@28 579 }
jtkorhonen@28 580 ret += tmp.toString();
jtkorhonen@24 581 }
jtkorhonen@24 582 }
jtkorhonen@22 583 }
jtkorhonen@17 584 }
jtkorhonen@28 585 return ret;
jtkorhonen@28 586 }
jtkorhonen@17 587
jtkorhonen@17 588
jtkorhonen@11 589 void MainWindow::hgServe()
jtkorhonen@11 590 {
Chris@109 591 QStringList params;
Chris@109 592 QString msg;
jtkorhonen@11 593
Chris@109 594 QString addrs = listAllUpIpV4Addresses();
Chris@109 595 QTextStream(&msg) << "Server running on address(es) (" << addrs << "), port 8000";
Chris@109 596 params << "serve";
jtkorhonen@11 597
Chris@109 598 runner->requestAction(HgAction(ACT_SERVE, workFolderPath, params));
Chris@109 599
Chris@109 600 QMessageBox::information(this, "Serve", msg, QMessageBox::Close);
Chris@109 601 //!!! runner -> killCurrentCommand();
jtkorhonen@11 602 }
jtkorhonen@11 603
Chris@64 604 void MainWindow::startupDialog()
Chris@64 605 {
Chris@64 606 StartupDialog *dlg = new StartupDialog(this);
Chris@65 607 if (dlg->exec()) firstStart = false;
Chris@64 608 }
jtkorhonen@11 609
Chris@69 610 void MainWindow::open()
Chris@69 611 {
Chris@86 612 bool done = false;
Chris@69 613
Chris@86 614 while (!done) {
Chris@69 615
Chris@86 616 MultiChoiceDialog *d = new MultiChoiceDialog
Chris@86 617 (tr("Open Repository"),
Chris@86 618 tr("<qt><big>What would you like to open?</big></qt>"),
Chris@86 619 this);
Chris@69 620
Chris@86 621 d->addChoice("remote",
Chris@86 622 tr("<qt><center><img src=\":images/browser-64.png\"><br>Remote repository</center></qt>"),
Chris@86 623 tr("Open a remote Mercurial repository, by cloning from its URL into a local folder."),
Chris@86 624 MultiChoiceDialog::UrlToDirectoryArg);
Chris@69 625
Chris@86 626 d->addChoice("local",
Chris@86 627 tr("<qt><center><img src=\":images/hglogo-64.png\"><br>Local repository</center></qt>"),
Chris@86 628 tr("Open an existing local Mercurial repository."),
Chris@86 629 MultiChoiceDialog::DirectoryArg);
Chris@69 630
Chris@86 631 d->addChoice("init",
Chris@86 632 tr("<qt><center><img src=\":images/hdd_unmount-64.png\"><br>File folder</center></qt>"),
Chris@86 633 tr("Open a local folder, by creating a Mercurial repository in it."),
Chris@86 634 MultiChoiceDialog::DirectoryArg);
Chris@79 635
Chris@86 636 d->setCurrentChoice("local");
Chris@86 637
Chris@86 638 if (d->exec() == QDialog::Accepted) {
Chris@86 639
Chris@86 640 QString choice = d->getCurrentChoice();
Chris@86 641 QString arg = d->getArgument().trimmed();
Chris@86 642
Chris@86 643 bool result = false;
Chris@86 644
Chris@86 645 if (choice == "local") {
Chris@86 646 result = openLocal(arg);
Chris@86 647 } else if (choice == "remote") {
Chris@86 648 result = openRemote(arg, d->getAdditionalArgument().trimmed());
Chris@86 649 } else if (choice == "init") {
Chris@86 650 result = openInit(arg);
Chris@86 651 }
Chris@86 652
Chris@86 653 if (result) {
Chris@86 654 enableDisableActions();
Chris@109 655 hgQueryPaths();
Chris@91 656 done = true;
Chris@91 657 }
Chris@86 658
Chris@86 659 } else {
Chris@86 660
Chris@86 661 // cancelled
Chris@86 662 done = true;
Chris@69 663 }
Chris@79 664
Chris@86 665 delete d;
Chris@69 666 }
Chris@69 667 }
Chris@69 668
Chris@79 669 bool MainWindow::complainAboutFilePath(QString arg)
Chris@79 670 {
Chris@79 671 QMessageBox::critical
Chris@79 672 (this, tr("File chosen"),
Chris@84 673 tr("<qt><b>Folder required</b><br><br>You asked to open \"%1\".<br>This is a file; to open a repository, you need to choose a folder.</qt>").arg(xmlEncode(arg)));
Chris@79 674 return false;
Chris@79 675 }
Chris@79 676
Chris@79 677 bool MainWindow::complainAboutUnknownFolder(QString arg)
Chris@79 678 {
Chris@79 679 QMessageBox::critical
Chris@79 680 (this, tr("Folder does not exist"),
Chris@84 681 tr("<qt><b>Folder does not exist</b><br><br>You asked to open \"%1\".<br>This folder does not exist, and it cannot be created because its parent does not exist either.</qt>").arg(xmlEncode(arg)));
Chris@84 682 return false;
Chris@84 683 }
Chris@84 684
Chris@84 685 bool MainWindow::complainAboutInitInRepo(QString arg)
Chris@84 686 {
Chris@84 687 QMessageBox::critical
Chris@84 688 (this, tr("Path is in existing repository"),
Chris@84 689 tr("<qt><b>Path is in an existing repository</b><br><br>You asked to initialise a repository at \"%1\".<br>This path is already inside an existing repository.</qt>").arg(xmlEncode(arg)));
Chris@84 690 return false;
Chris@84 691 }
Chris@84 692
Chris@84 693 bool MainWindow::complainAboutInitFile(QString arg)
Chris@84 694 {
Chris@84 695 QMessageBox::critical
Chris@84 696 (this, tr("Path is a file"),
Chris@84 697 tr("<qt><b>Path is a file</b><br><br>You asked to initialise a repository at \"%1\".<br>This is an existing file; it is only possible to initialise in folders.</qt>").arg(xmlEncode(arg)));
Chris@84 698 return false;
Chris@84 699 }
Chris@84 700
Chris@84 701 bool MainWindow::complainAboutCloneToExisting(QString arg)
Chris@84 702 {
Chris@84 703 QMessageBox::critical
Chris@84 704 (this, tr("Path is in existing repository"),
Chris@84 705 tr("<qt><b>Local path is in an existing repository</b><br><br>You asked to open a remote repository by cloning it to the local path \"%1\".<br>This path is already inside an existing repository.<br>Please provide a new folder name for the local repository.</qt>").arg(xmlEncode(arg)));
Chris@84 706 return false;
Chris@84 707 }
Chris@84 708
Chris@84 709 bool MainWindow::complainAboutCloneToFile(QString arg)
Chris@84 710 {
Chris@84 711 QMessageBox::critical
Chris@84 712 (this, tr("Path is a file"),
Chris@84 713 tr("<qt><b>Local path is a file</b><br><br>You asked to open a remote repository by cloning it to the local path \"%1\".<br>This path is an existing file.<br>Please provide a new folder name for the local repository.</qt>").arg(xmlEncode(arg)));
Chris@84 714 return false;
Chris@84 715 }
Chris@84 716
Chris@84 717 bool MainWindow::complainAboutCloneToExistingFolder(QString arg)
Chris@84 718 {
Chris@84 719 QMessageBox::critical
Chris@84 720 (this, tr("Folder exists"),
Chris@84 721 tr("<qt><b>Local folder already exists</b><br><br>You asked to open a remote repository by cloning it to the local path \"%1\".<br>This is the path of an existing folder.<br>Please provide a new folder name for the local repository.</qt>").arg(xmlEncode(arg)));
Chris@79 722 return false;
Chris@79 723 }
Chris@79 724
Chris@79 725 bool MainWindow::askToOpenParentRepo(QString arg, QString parent)
Chris@79 726 {
Chris@79 727 return (QMessageBox::question
Chris@84 728 (this, tr("Path is inside a repository"),
Chris@86 729 tr("<qt><b>Open the repository that contains this path?</b><br><br>You asked to open \"%1\".<br>This is not the root folder of a repository.<br>But it is inside a repository, whose root is at \"%2\". <br><br>Would you like to open that repository instead?</qt>")
Chris@79 730 .arg(xmlEncode(arg)).arg(xmlEncode(parent)),
Chris@79 731 QMessageBox::Ok | QMessageBox::Cancel,
Chris@79 732 QMessageBox::Ok)
Chris@79 733 == QMessageBox::Ok);
Chris@79 734 }
Chris@79 735
Chris@79 736 bool MainWindow::askToInitExisting(QString arg)
Chris@79 737 {
Chris@79 738 return (QMessageBox::question
Chris@84 739 (this, tr("Folder has no repository"),
Chris@84 740 tr("<qt><b>Initialise a repository here?</b><br><br>You asked to open \"%1\".<br>This folder does not contain a Mercurial repository.<br><br>Would you like to initialise a repository here?</qt>")
Chris@79 741 .arg(xmlEncode(arg)),
Chris@79 742 QMessageBox::Ok | QMessageBox::Cancel,
Chris@79 743 QMessageBox::Ok)
Chris@79 744 == QMessageBox::Ok);
Chris@79 745 }
Chris@79 746
Chris@79 747 bool MainWindow::askToInitNew(QString arg)
Chris@79 748 {
Chris@79 749 return (QMessageBox::question
Chris@84 750 (this, tr("Folder does not exist"),
Chris@84 751 tr("<qt><b>Initialise a new repository?</b><br><br>You asked to open \"%1\".<br>This folder does not yet exist.<br><br>Would you like to create the folder and initialise a new empty repository in it?</qt>")
Chris@84 752 .arg(xmlEncode(arg)),
Chris@84 753 QMessageBox::Ok | QMessageBox::Cancel,
Chris@84 754 QMessageBox::Ok)
Chris@84 755 == QMessageBox::Ok);
Chris@84 756 }
Chris@84 757
Chris@84 758 bool MainWindow::askToOpenInsteadOfInit(QString arg)
Chris@84 759 {
Chris@84 760 return (QMessageBox::question
Chris@84 761 (this, tr("Repository exists"),
Chris@84 762 tr("<qt><b>Open existing repository?</b><br><br>You asked to initialise a new repository at \"%1\".<br>This folder already contains a repository. Would you like to open it?</qt>")
Chris@79 763 .arg(xmlEncode(arg)),
Chris@79 764 QMessageBox::Ok | QMessageBox::Cancel,
Chris@79 765 QMessageBox::Ok)
Chris@79 766 == QMessageBox::Ok);
Chris@79 767 }
Chris@79 768
Chris@79 769 bool MainWindow::openLocal(QString local)
Chris@79 770 {
Chris@79 771 DEBUG << "open " << local << endl;
Chris@79 772
Chris@79 773 FolderStatus status = getFolderStatus(local);
Chris@79 774 QString containing = getContainingRepoFolder(local);
Chris@79 775
Chris@79 776 switch (status) {
Chris@79 777
Chris@79 778 case FolderHasRepo:
Chris@79 779 // fine
Chris@79 780 break;
Chris@79 781
Chris@79 782 case FolderExists:
Chris@79 783 if (containing != "") {
Chris@79 784 if (!askToOpenParentRepo(local, containing)) return false;
Chris@84 785 local = containing;
Chris@79 786 } else {
Chris@86 787 //!!! No -- this is likely to happen far more by accident
Chris@86 788 // than because the user actually wanted to init something.
Chris@86 789 // Don't ask, just politely reject.
Chris@79 790 if (!askToInitExisting(local)) return false;
Chris@79 791 return openInit(local);
Chris@79 792 }
Chris@79 793 break;
Chris@79 794
Chris@79 795 case FolderParentExists:
Chris@79 796 if (containing != "") {
Chris@79 797 if (!askToOpenParentRepo(local, containing)) return false;
Chris@84 798 local = containing;
Chris@79 799 } else {
Chris@79 800 if (!askToInitNew(local)) return false;
Chris@79 801 return openInit(local);
Chris@79 802 }
Chris@79 803 break;
Chris@79 804
Chris@79 805 case FolderUnknown:
Chris@84 806 if (containing != "") {
Chris@84 807 if (!askToOpenParentRepo(local, containing)) return false;
Chris@84 808 local = containing;
Chris@84 809 } else {
Chris@84 810 return complainAboutUnknownFolder(local);
Chris@84 811 }
Chris@84 812 break;
Chris@79 813
Chris@79 814 case FolderIsFile:
Chris@79 815 return complainAboutFilePath(local);
Chris@79 816 }
Chris@79 817
Chris@79 818 workFolderPath = local;
Chris@79 819 remoteRepoPath = "";
Chris@79 820 return true;
Chris@79 821 }
Chris@79 822
Chris@79 823 bool MainWindow::openRemote(QString remote, QString local)
Chris@79 824 {
Chris@79 825 DEBUG << "clone " << remote << " to " << local << endl;
Chris@84 826
Chris@84 827 FolderStatus status = getFolderStatus(local);
Chris@84 828 QString containing = getContainingRepoFolder(local);
Chris@84 829
Chris@84 830 DEBUG << "status = " << status << ", containing = " << containing << endl;
Chris@84 831
Chris@84 832 if (status == FolderHasRepo || containing != "") {
Chris@84 833 return complainAboutCloneToExisting(local);
Chris@84 834 }
Chris@84 835
Chris@84 836 if (status == FolderIsFile) {
Chris@84 837 return complainAboutCloneToFile(local);
Chris@84 838 }
Chris@84 839
Chris@84 840 if (status == FolderUnknown) {
Chris@84 841 return complainAboutUnknownFolder(local);
Chris@84 842 }
Chris@84 843
Chris@84 844 if (status == FolderExists) {
Chris@84 845 //!!! we can do better than this surely?
Chris@84 846 return complainAboutCloneToExistingFolder(local);
Chris@84 847 }
Chris@84 848
Chris@84 849 workFolderPath = local;
Chris@84 850 remoteRepoPath = remote;
Chris@84 851 hgCloneFromRemote();
Chris@84 852
Chris@79 853 return true;
Chris@79 854 }
Chris@79 855
Chris@84 856 bool MainWindow::openInit(QString local)
Chris@79 857 {
Chris@84 858 DEBUG << "openInit " << local << endl;
Chris@84 859
Chris@84 860 FolderStatus status = getFolderStatus(local);
Chris@84 861 QString containing = getContainingRepoFolder(local);
Chris@84 862
Chris@84 863 DEBUG << "status = " << status << ", containing = " << containing << endl;
Chris@84 864
Chris@84 865 if (status == FolderHasRepo) {
Chris@84 866 if (!askToOpenInsteadOfInit(local)) return false;
Chris@84 867 }
Chris@84 868
Chris@84 869 if (containing != "") {
Chris@84 870 return complainAboutInitInRepo(local);
Chris@84 871 }
Chris@84 872
Chris@84 873 if (status == FolderIsFile) {
Chris@84 874 return complainAboutInitFile(local);
Chris@84 875 }
Chris@84 876
Chris@84 877 if (status == FolderUnknown) {
Chris@84 878 return complainAboutUnknownFolder(local);
Chris@84 879 }
Chris@84 880
Chris@84 881 workFolderPath = local;
Chris@84 882 remoteRepoPath = "";
Chris@84 883 hgInit();
Chris@79 884 return true;
Chris@79 885 }
Chris@79 886
jtkorhonen@0 887 void MainWindow::settings()
jtkorhonen@0 888 {
Chris@69 889 /*!!!
jtkorhonen@0 890 SettingsDialog *settingsDlg = new SettingsDialog(this);
jtkorhonen@0 891 settingsDlg->setModal(true);
jtkorhonen@0 892 settingsDlg->exec();
Chris@98 893 hgTabs -> clearLists();
jtkorhonen@0 894 enableDisableActions();
jtkorhonen@0 895 hgStat();
Chris@69 896 */
jtkorhonen@0 897 }
jtkorhonen@0 898
jtkorhonen@2 899 #define STDOUT_NEEDS_BIG_WINDOW 512
jtkorhonen@2 900 #define SMALL_WND_W 500
jtkorhonen@2 901 #define SMALL_WND_H 300
jtkorhonen@2 902
jtkorhonen@2 903 #define BIG_WND_W 1024
jtkorhonen@2 904 #define BIG_WND_H 768
jtkorhonen@2 905
jtkorhonen@2 906
jtkorhonen@2 907 void MainWindow::presentLongStdoutToUser(QString stdo)
jtkorhonen@0 908 {
jtkorhonen@2 909 if (!stdo.isEmpty())
jtkorhonen@2 910 {
jtkorhonen@2 911 QDialog dlg;
jtkorhonen@0 912
jtkorhonen@2 913 if (stdo.length() > STDOUT_NEEDS_BIG_WINDOW)
jtkorhonen@2 914 {
jtkorhonen@2 915 dlg.setMinimumWidth(BIG_WND_W);
jtkorhonen@2 916 dlg.setMinimumHeight(BIG_WND_H);
jtkorhonen@2 917 }
jtkorhonen@2 918 else
jtkorhonen@2 919 {
jtkorhonen@2 920 dlg.setMinimumWidth(SMALL_WND_W);
jtkorhonen@2 921 dlg.setMinimumHeight(SMALL_WND_H);
jtkorhonen@2 922 }
jtkorhonen@0 923
jtkorhonen@2 924 QVBoxLayout *box = new QVBoxLayout;
jtkorhonen@2 925 QListWidget *list = new QListWidget;
jtkorhonen@2 926 list-> addItems(stdo.split("\n"));
jtkorhonen@2 927 QPushButton *btn = new QPushButton(tr("Ok"));
jtkorhonen@2 928 connect(btn, SIGNAL(clicked()), &dlg, SLOT(accept()));
jtkorhonen@0 929
jtkorhonen@2 930 box -> addWidget(list);
jtkorhonen@2 931 box -> addWidget(btn);
jtkorhonen@2 932 dlg.setLayout(box);
jtkorhonen@2 933
jtkorhonen@2 934 dlg.exec();
jtkorhonen@2 935 }
jtkorhonen@2 936 else
jtkorhonen@2 937 {
Chris@98 938 QMessageBox::information(this, tr("EasyMercurial"), tr("Mercurial command did not return any output."));
jtkorhonen@2 939 }
jtkorhonen@0 940 }
jtkorhonen@0 941
Chris@90 942 void MainWindow::updateFileSystemWatcher()
Chris@90 943 {
Chris@90 944 //!!! this needs to be incremental when something changes
Chris@90 945
Chris@90 946 delete fsWatcher;
Chris@90 947 fsWatcher = new QFileSystemWatcher();
Chris@90 948 std::deque<QString> pending;
Chris@90 949 pending.push_back(workFolderPath);
Chris@90 950 while (!pending.empty()) {
Chris@90 951 QString path = pending.front();
Chris@90 952 pending.pop_front();
Chris@90 953 fsWatcher->addPath(path);
Chris@90 954 DEBUG << "Added to file system watcher: " << path << endl;
Chris@90 955 QDir d(path);
Chris@90 956 if (d.exists()) {
Chris@90 957 d.setFilter(QDir::Files | QDir::Dirs |
Chris@90 958 QDir::NoDotAndDotDot | QDir::Readable);
Chris@90 959 foreach (QString entry, d.entryList()) {
Chris@90 960 if (entry == ".hg") continue;
Chris@90 961 QString entryPath = d.absoluteFilePath(entry);
Chris@90 962 pending.push_back(entryPath);
Chris@90 963 }
Chris@90 964 }
Chris@90 965 }
Chris@90 966 connect(fsWatcher, SIGNAL(directoryChanged(QString)),
Chris@90 967 this, SLOT(fsDirectoryChanged(QString)));
Chris@90 968 connect(fsWatcher, SIGNAL(fileChanged(QString)),
Chris@90 969 this, SLOT(fsFileChanged(QString)));
Chris@90 970 }
Chris@90 971
Chris@90 972 void MainWindow::fsDirectoryChanged(QString)
Chris@90 973 {
Chris@90 974 //!!! should just queue one of these!
Chris@90 975 hgStat();
Chris@90 976 }
Chris@90 977
Chris@90 978 void MainWindow::fsFileChanged(QString)
Chris@90 979 {
Chris@90 980 //!!! should just queue one of these!
Chris@90 981 hgStat();
Chris@90 982 }
Chris@90 983
Chris@109 984 void MainWindow::commandFailed(HgAction action, QString stderr)
Chris@62 985 {
Chris@62 986 DEBUG << "MainWindow::commandFailed" << endl;
Chris@109 987 // runner -> hideProgBar();
Chris@74 988
Chris@79 989 //!!! N.B hg incoming returns 1 even if successful, if there were no changes
Chris@62 990 }
Chris@62 991
Chris@109 992 void MainWindow::commandCompleted(HgAction completedAction, QString output)
jtkorhonen@0 993 {
jtkorhonen@0 994 bool shouldHgStat = false;
jtkorhonen@0 995
Chris@109 996 HGACTIONS action = completedAction.action;
Chris@109 997
Chris@109 998 if (action == ACT_NONE) return;
Chris@109 999
Chris@109 1000 switch(action) {
Chris@109 1001
Chris@109 1002 case ACT_QUERY_PATHS:
jtkorhonen@0 1003 {
Chris@109 1004 DEBUG << "stdout is " << output << endl;
Chris@109 1005 LogParser lp(output, "=");
Chris@109 1006 LogList ll = lp.parse();
Chris@109 1007 DEBUG << ll.size() << " results" << endl;
Chris@109 1008 if (!ll.empty()) {
Chris@109 1009 remoteRepoPath = lp.parse()[0]["default"].trimmed();
Chris@109 1010 DEBUG << "Set remote path to " << remoteRepoPath << endl;
Chris@109 1011 }
Chris@109 1012 MultiChoiceDialog::addRecentArgument("local", workFolderPath);
Chris@109 1013 MultiChoiceDialog::addRecentArgument("remote", remoteRepoPath);
Chris@109 1014 hgTabs->setWorkFolderAndRepoNames(workFolderPath, remoteRepoPath);
Chris@109 1015 enableDisableActions();
Chris@109 1016 break;
Chris@109 1017 }
jtkorhonen@0 1018
Chris@109 1019 case ACT_QUERY_BRANCH:
Chris@109 1020 currentBranch = output.trimmed();
Chris@109 1021 hgTabs->setBranch(currentBranch);
Chris@109 1022 break;
jtkorhonen@0 1023
Chris@109 1024 case ACT_STAT:
Chris@109 1025 hgTabs -> updateWorkFolderFileList(output);
Chris@109 1026 updateFileSystemWatcher();
Chris@109 1027 break;
Chris@109 1028
Chris@109 1029 case ACT_INCOMING:
Chris@109 1030 case ACT_ANNOTATE:
Chris@109 1031 case ACT_RESOLVE_LIST:
Chris@109 1032 case ACT_RESOLVE_MARK:
Chris@109 1033 presentLongStdoutToUser(output);
Chris@109 1034 shouldHgStat = true;
Chris@109 1035 break;
Chris@109 1036
Chris@109 1037 case ACT_PULL:
Chris@109 1038 QMessageBox::information(this, "Pull", output);
Chris@109 1039 shouldHgStat = true;
Chris@109 1040 break;
Chris@109 1041
Chris@109 1042 case ACT_PUSH:
Chris@109 1043 QMessageBox::information(this, "Push", output);
Chris@109 1044 shouldHgStat = true;
Chris@109 1045 break;
Chris@109 1046
Chris@109 1047 case ACT_INIT:
Chris@109 1048 MultiChoiceDialog::addRecentArgument("init", workFolderPath);
Chris@109 1049 MultiChoiceDialog::addRecentArgument("local", workFolderPath);
Chris@109 1050 enableDisableActions();
Chris@109 1051 shouldHgStat = true;
Chris@109 1052 break;
Chris@109 1053
Chris@109 1054 case ACT_CLONEFROMREMOTE:
Chris@109 1055 MultiChoiceDialog::addRecentArgument("local", workFolderPath);
Chris@109 1056 MultiChoiceDialog::addRecentArgument("remote", remoteRepoPath);
Chris@109 1057 MultiChoiceDialog::addRecentArgument("remote", workFolderPath, true);
Chris@109 1058 QMessageBox::information(this, "Clone", output);
Chris@109 1059 enableDisableActions();
Chris@109 1060 shouldHgStat = true;
Chris@109 1061 break;
Chris@109 1062
Chris@109 1063 case ACT_LOG:
Chris@109 1064 hgTabs -> updateLocalRepoHgLogList(output);
Chris@109 1065 break;
Chris@109 1066
Chris@109 1067 case ACT_QUERY_PARENTS:
Chris@109 1068 foreach (Changeset *cs, currentParents) delete cs;
Chris@109 1069 currentParents = Changeset::parseChangesets(output);
Chris@109 1070 break;
Chris@109 1071
Chris@109 1072 case ACT_QUERY_HEADS:
Chris@109 1073 foreach (Changeset *cs, currentHeads) delete cs;
Chris@109 1074 currentHeads = Changeset::parseChangesets(output);
Chris@109 1075 break;
Chris@109 1076
Chris@109 1077 case ACT_REMOVE:
Chris@109 1078 case ACT_ADD:
Chris@109 1079 case ACT_COMMIT:
Chris@109 1080 case ACT_FILEDIFF:
Chris@109 1081 case ACT_FOLDERDIFF:
Chris@109 1082 case ACT_CHGSETDIFF:
Chris@109 1083 case ACT_REVERT:
Chris@109 1084 case ACT_SERVE:
Chris@109 1085 case ACT_TAG:
Chris@109 1086 case ACT_HG_IGNORE:
Chris@109 1087 shouldHgStat = true;
Chris@109 1088 break;
Chris@109 1089
Chris@109 1090 case ACT_UPDATE:
Chris@109 1091 QMessageBox::information(this, tr("Update"), output);
Chris@109 1092 shouldHgStat = true;
Chris@109 1093 break;
Chris@109 1094
Chris@109 1095 case ACT_MERGE:
Chris@109 1096 QMessageBox::information(this, tr("Merge"), output);
Chris@109 1097 shouldHgStat = true;
Chris@109 1098 justMerged = true;
Chris@109 1099 break;
Chris@109 1100
Chris@109 1101 case ACT_RETRY_MERGE:
Chris@109 1102 QMessageBox::information(this, tr("Merge retry"), tr("Merge retry successful."));
Chris@109 1103 shouldHgStat = true;
Chris@109 1104 justMerged = true;
Chris@109 1105 break;
Chris@109 1106
Chris@109 1107 default:
Chris@109 1108 break;
Chris@109 1109 }
Chris@108 1110
Chris@109 1111 enableDisableActions();
Chris@74 1112
Chris@109 1113 // Typical sequence goes paths -> branch -> stat -> heads -> parents -> log
Chris@109 1114 if (action == ACT_QUERY_PATHS) {
Chris@109 1115 hgQueryBranch();
Chris@109 1116 } else if (action == ACT_QUERY_BRANCH) {
Chris@109 1117 hgStat();
Chris@109 1118 } else if (action == ACT_STAT) {
Chris@109 1119 hgQueryHeads();
Chris@109 1120 } else if (action == ACT_QUERY_HEADS) {
Chris@109 1121 hgQueryParents();
Chris@109 1122 } else if (action == ACT_QUERY_PARENTS) {
Chris@109 1123 hgLog();
Chris@109 1124 } else
Chris@109 1125 /* Move to commandFailed
Chris@109 1126 if ((runningAction == ACT_MERGE) && (exitCode != 0))
jtkorhonen@37 1127 {
Chris@106 1128 // If we had a failed merge, offer to retry
jtkorhonen@37 1129 if (QMessageBox::Ok == QMessageBox::information(this, tr("Retry merge ?"), tr("Merge attempt failed. retry ?"), QMessageBox::Ok | QMessageBox::Cancel))
jtkorhonen@37 1130 {
jtkorhonen@37 1131 runningAction = ACT_NONE;
jtkorhonen@37 1132 hgRetryMerge();
jtkorhonen@37 1133 }
jtkorhonen@37 1134 else
jtkorhonen@37 1135 {
jtkorhonen@37 1136 runningAction = ACT_NONE;
jtkorhonen@37 1137 hgStat();
jtkorhonen@37 1138 }
jtkorhonen@37 1139 }
jtkorhonen@0 1140 else
jtkorhonen@0 1141 {
Chris@109 1142 */
Chris@109 1143 if (shouldHgStat) {
Chris@109 1144 hgQueryPaths();
jtkorhonen@0 1145 }
jtkorhonen@0 1146 }
jtkorhonen@0 1147
jtkorhonen@0 1148 void MainWindow::connectActions()
jtkorhonen@0 1149 {
jtkorhonen@0 1150 connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
jtkorhonen@0 1151 connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
jtkorhonen@0 1152 connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
jtkorhonen@0 1153
Chris@109 1154 connect(hgStatAct, SIGNAL(triggered()), this, SLOT(hgQueryPaths()));
jtkorhonen@0 1155 connect(hgRemoveAct, SIGNAL(triggered()), this, SLOT(hgRemove()));
jtkorhonen@0 1156 connect(hgAddAct, SIGNAL(triggered()), this, SLOT(hgAdd()));
jtkorhonen@0 1157 connect(hgCommitAct, SIGNAL(triggered()), this, SLOT(hgCommit()));
jtkorhonen@0 1158 connect(hgFileDiffAct, SIGNAL(triggered()), this, SLOT(hgFileDiff()));
jtkorhonen@0 1159 connect(hgFolderDiffAct, SIGNAL(triggered()), this, SLOT(hgFolderDiff()));
jtkorhonen@0 1160 connect(hgChgSetDiffAct, SIGNAL(triggered()), this, SLOT(hgChgSetDiff()));
jtkorhonen@0 1161 connect(hgUpdateAct, SIGNAL(triggered()), this, SLOT(hgUpdate()));
jtkorhonen@0 1162 connect(hgRevertAct, SIGNAL(triggered()), this, SLOT(hgRevert()));
jtkorhonen@0 1163 connect(hgMergeAct, SIGNAL(triggered()), this, SLOT(hgMerge()));
jtkorhonen@33 1164 connect(hgRetryMergeAct, SIGNAL(triggered()), this, SLOT(hgRetryMerge()));
jtkorhonen@34 1165 connect(hgTagAct, SIGNAL(triggered()), this, SLOT(hgTag()));
jtkorhonen@34 1166 connect(hgIgnoreAct, SIGNAL(triggered()), this, SLOT(hgIgnore()));
jtkorhonen@0 1167
jtkorhonen@0 1168 connect(settingsAct, SIGNAL(triggered()), this, SLOT(settings()));
Chris@69 1169 connect(openAct, SIGNAL(triggered()), this, SLOT(open()));
jtkorhonen@0 1170
jtkorhonen@0 1171 connect(hgInitAct, SIGNAL(triggered()), this, SLOT(hgInit()));
jtkorhonen@0 1172 connect(hgCloneFromRemoteAct, SIGNAL(triggered()), this, SLOT(hgCloneFromRemote()));
jtkorhonen@0 1173 connect(hgIncomingAct, SIGNAL(triggered()), this, SLOT(hgIncoming()));
jtkorhonen@0 1174 connect(hgPullAct, SIGNAL(triggered()), this, SLOT(hgPull()));
jtkorhonen@0 1175 connect(hgPushAct, SIGNAL(triggered()), this, SLOT(hgPush()));
jtkorhonen@0 1176
Chris@109 1177 // connect(hgTabs, SIGNAL(currentChanged(int)), this, SLOT(tabChanged(int)));
jtkorhonen@0 1178
jtkorhonen@0 1179 connect(hgUpdateToRevAct, SIGNAL(triggered()), this, SLOT(hgUpdateToRev()));
jtkorhonen@0 1180 connect(hgAnnotateAct, SIGNAL(triggered()), this, SLOT(hgAnnotate()));
jtkorhonen@0 1181 connect(hgResolveListAct, SIGNAL(triggered()), this, SLOT(hgResolveList()));
jtkorhonen@0 1182 connect(hgResolveMarkAct, SIGNAL(triggered()), this, SLOT(hgResolveMark()));
jtkorhonen@11 1183 connect(hgServeAct, SIGNAL(triggered()), this, SLOT(hgServe()));
Chris@94 1184 connect(clearSelectionsAct, SIGNAL(triggered()), this, SLOT(clearSelections()));
jtkorhonen@0 1185 }
Chris@109 1186 /*!!!
jtkorhonen@0 1187 void MainWindow::tabChanged(int currTab)
jtkorhonen@0 1188 {
jtkorhonen@0 1189 tabPage = currTab;
jtkorhonen@32 1190
jtkorhonen@0 1191 }
Chris@109 1192 */
jtkorhonen@0 1193 void MainWindow::enableDisableActions()
jtkorhonen@0 1194 {
Chris@90 1195 DEBUG << "MainWindow::enableDisableActions" << endl;
Chris@90 1196
jtkorhonen@0 1197 QDir localRepoDir;
jtkorhonen@0 1198 QDir workFolderDir;
jtkorhonen@0 1199 bool workFolderExist;
jtkorhonen@0 1200 bool localRepoExist;
jtkorhonen@0 1201
jtkorhonen@0 1202 remoteRepoActionsEnabled = true;
Chris@90 1203 if (remoteRepoPath.isEmpty()) {
jtkorhonen@0 1204 remoteRepoActionsEnabled = false;
jtkorhonen@0 1205 }
jtkorhonen@0 1206
jtkorhonen@0 1207 localRepoActionsEnabled = true;
Chris@90 1208 if (workFolderPath.isEmpty()) {
jtkorhonen@0 1209 localRepoActionsEnabled = false;
jtkorhonen@0 1210 workFolderExist = false;
jtkorhonen@0 1211 }
jtkorhonen@0 1212
Chris@90 1213 if (!workFolderDir.exists(workFolderPath)) {
jtkorhonen@0 1214 localRepoActionsEnabled = false;
jtkorhonen@0 1215 workFolderExist = false;
Chris@90 1216 } else {
jtkorhonen@0 1217 workFolderExist = true;
jtkorhonen@0 1218 }
jtkorhonen@0 1219
Chris@90 1220 if (!localRepoDir.exists(workFolderPath + "/" + getHgDirName())) {
jtkorhonen@0 1221 localRepoActionsEnabled = false;
jtkorhonen@0 1222 localRepoExist = false;
jtkorhonen@0 1223 }
jtkorhonen@0 1224
jtkorhonen@0 1225 hgCloneFromRemoteAct -> setEnabled(remoteRepoActionsEnabled);
jtkorhonen@0 1226 hgIncomingAct -> setEnabled(remoteRepoActionsEnabled && remoteRepoActionsEnabled);
jtkorhonen@0 1227 hgPullAct -> setEnabled(remoteRepoActionsEnabled && remoteRepoActionsEnabled);
jtkorhonen@0 1228 hgPushAct -> setEnabled(remoteRepoActionsEnabled && remoteRepoActionsEnabled);
Chris@73 1229 /*
jtkorhonen@0 1230 if (tabPage != WORKTAB)
jtkorhonen@0 1231 {
jtkorhonen@0 1232 localRepoActionsEnabled = false;
jtkorhonen@0 1233 }
Chris@73 1234 */
jtkorhonen@0 1235 hgInitAct -> setEnabled((localRepoExist == false) && (workFolderExist==true));
jtkorhonen@0 1236 hgStatAct -> setEnabled(localRepoActionsEnabled);
jtkorhonen@0 1237 hgFileDiffAct -> setEnabled(localRepoActionsEnabled);
jtkorhonen@0 1238 hgFolderDiffAct -> setEnabled(localRepoActionsEnabled);
jtkorhonen@0 1239 hgRevertAct -> setEnabled(localRepoActionsEnabled);
jtkorhonen@0 1240 hgAddAct -> setEnabled(localRepoActionsEnabled);
jtkorhonen@0 1241 hgRemoveAct -> setEnabled(localRepoActionsEnabled);
jtkorhonen@0 1242 hgUpdateAct -> setEnabled(localRepoActionsEnabled);
jtkorhonen@0 1243 hgCommitAct -> setEnabled(localRepoActionsEnabled);
jtkorhonen@0 1244 hgMergeAct -> setEnabled(localRepoActionsEnabled);
jtkorhonen@33 1245 hgRetryMergeAct -> setEnabled(localRepoActionsEnabled);
jtkorhonen@2 1246 hgResolveListAct -> setEnabled(localRepoActionsEnabled);
jtkorhonen@2 1247 hgResolveMarkAct -> setEnabled(localRepoActionsEnabled);
jtkorhonen@2 1248 hgAnnotateAct -> setEnabled(localRepoActionsEnabled);
jtkorhonen@11 1249 hgServeAct -> setEnabled(localRepoActionsEnabled);
jtkorhonen@34 1250 hgTagAct -> setEnabled(localRepoActionsEnabled);
jtkorhonen@34 1251 hgIgnoreAct -> setEnabled(localRepoActionsEnabled);
jtkorhonen@0 1252
Chris@98 1253 //!!!hgTabs -> enableDisableOtherTabs(tabPage);
jtkorhonen@0 1254
Chris@90 1255 DEBUG << "localRepoActionsEnabled = " << localRepoActionsEnabled << endl;
Chris@98 1256 DEBUG << "canCommit = " << hgTabs->canCommit() << endl;
Chris@90 1257
Chris@90 1258 //!!! new stuff:
Chris@98 1259 hgAddAct->setEnabled(localRepoActionsEnabled && hgTabs->canAdd());
Chris@98 1260 hgRemoveAct->setEnabled(localRepoActionsEnabled && hgTabs->canRemove());
Chris@98 1261 hgCommitAct->setEnabled(localRepoActionsEnabled && hgTabs->canCommit());
Chris@98 1262 hgRevertAct->setEnabled(localRepoActionsEnabled && hgTabs->canCommit());
Chris@98 1263 hgFolderDiffAct->setEnabled(localRepoActionsEnabled && hgTabs->canDoDiff());
Chris@90 1264
Chris@108 1265 // A default merge makes sense if:
Chris@108 1266 // * there is only one parent (if there are two, we have an uncommitted merge) and
Chris@108 1267 // * there are exactly two heads that have the same branch as the current branch and
Chris@108 1268 // * our parent is one of those heads
Chris@108 1269 //
Chris@108 1270 // A default update makes sense if:
Chris@108 1271 // * there is only one parent and
Chris@108 1272 // * the parent is not one of the current heads
Chris@108 1273 //!!! test this
Chris@108 1274 bool canMerge = false;
Chris@108 1275 bool canUpdate = false;
Chris@108 1276 if (currentParents.size() == 1) {
Chris@108 1277 Changeset *parent = currentParents[0];
Chris@108 1278 int currentBranchHeads = 0;
Chris@108 1279 bool parentIsHead = false;
Chris@108 1280 foreach (Changeset *head, currentHeads) {
Chris@108 1281 DEBUG << "head branch " << head->branch() << ", current branch " << currentBranch << endl;
Chris@108 1282 if (head->isOnBranch(currentBranch)) {
Chris@108 1283 ++currentBranchHeads;
Chris@108 1284 if (parent->id() == head->id()) {
Chris@108 1285 parentIsHead = true;
Chris@108 1286 }
Chris@108 1287 }
Chris@108 1288 }
Chris@108 1289 if (currentBranchHeads == 2 && parentIsHead) {
Chris@108 1290 canMerge = true;
Chris@108 1291 }
Chris@108 1292 if (!parentIsHead) {
Chris@108 1293 canUpdate = true;
Chris@108 1294 DEBUG << "parent id = " << parent->id() << endl;
Chris@108 1295 DEBUG << " head ids "<<endl;
Chris@108 1296 foreach (Changeset *h, currentHeads) {
Chris@108 1297 DEBUG << "head id = " << h->id() << endl;
Chris@108 1298 }
Chris@108 1299 }
Chris@108 1300 }
Chris@108 1301 hgMergeAct->setEnabled(localRepoActionsEnabled && canMerge);
Chris@108 1302 hgUpdateAct->setEnabled(localRepoActionsEnabled && canUpdate);
jtkorhonen@0 1303 }
jtkorhonen@0 1304
jtkorhonen@0 1305 void MainWindow::createActions()
jtkorhonen@0 1306 {
jtkorhonen@0 1307 //File actions
jtkorhonen@0 1308 hgInitAct = new QAction(tr("Init local repository"), this);
jtkorhonen@0 1309 hgInitAct->setStatusTip(tr("Create an empty local repository in selected folder"));
jtkorhonen@0 1310
jtkorhonen@0 1311 hgCloneFromRemoteAct = new QAction(tr("Clone from remote"), this);
jtkorhonen@0 1312 hgCloneFromRemoteAct->setStatusTip(tr("Clone from remote repository into local repository in selected folder"));
jtkorhonen@0 1313
Chris@69 1314 openAct = new QAction(QIcon(":/images/fileopen.png"), tr("Open..."), this);
Chris@69 1315 openAct -> setStatusTip(tr("Open repository"));
Chris@69 1316 openAct -> setIconVisibleInMenu(true);
Chris@69 1317
jtkorhonen@0 1318 settingsAct = new QAction(QIcon(":/images/settings.png"), tr("Settings..."), this);
jtkorhonen@0 1319 settingsAct -> setStatusTip(tr("View and change application settings"));
jtkorhonen@0 1320 settingsAct -> setIconVisibleInMenu(true);
jtkorhonen@0 1321
jtkorhonen@0 1322 exitAct = new QAction(QIcon(":/images/exit.png"), tr("Exit"), this);
jtkorhonen@0 1323 exitAct->setShortcuts(QKeySequence::Quit);
jtkorhonen@0 1324 exitAct->setStatusTip(tr("Exit application"));
jtkorhonen@0 1325 exitAct -> setIconVisibleInMenu(true);
jtkorhonen@0 1326
jtkorhonen@0 1327 //Repository actions
Chris@61 1328 hgStatAct = new QAction(QIcon(":/images/status.png"), tr("Refresh"), this);
Chris@61 1329 hgStatAct->setStatusTip(tr("Refresh (info of) status of workfolder files"));
Chris@61 1330
Chris@61 1331 hgIncomingAct = new QAction(QIcon(":/images/incoming.png"), tr("Preview"), this);
jtkorhonen@0 1332 hgIncomingAct -> setStatusTip(tr("View info of changesets incoming to us from remote repository (on pull operation)"));
jtkorhonen@0 1333
Chris@61 1334 hgPullAct = new QAction(QIcon(":/images/pull.png"), tr("Pull"), this);
jtkorhonen@0 1335 hgPullAct -> setStatusTip(tr("Pull changesets from remote repository to local repository"));
jtkorhonen@0 1336
Chris@61 1337 hgPushAct = new QAction(QIcon(":/images/push.png"), tr("Push"), this);
jtkorhonen@0 1338 hgPushAct->setStatusTip(tr("Push local changesets to remote repository"));
jtkorhonen@0 1339
jtkorhonen@0 1340 //Workfolder actions
Chris@61 1341 hgFileDiffAct = new QAction(QIcon(":/images/diff.png"), tr("Diff"), this);
jtkorhonen@0 1342 hgFileDiffAct->setStatusTip(tr("Filediff: View differences between selected working folder file and local repository file"));
jtkorhonen@0 1343
Chris@99 1344 hgFolderDiffAct = new QAction(QIcon(":/images/folderdiff.png"), tr("Diff"), this);
jtkorhonen@0 1345 hgFolderDiffAct->setStatusTip(tr("Folderdiff: View all differences between working folder files and local repository files"));
jtkorhonen@0 1346
jtkorhonen@0 1347 hgChgSetDiffAct = new QAction(QIcon(":/images/chgsetdiff.png"), tr("View changesetdiff"), this);
jtkorhonen@0 1348 hgChgSetDiffAct->setStatusTip(tr("Change set diff: View differences between all files of 2 repository changesets"));
jtkorhonen@0 1349
Chris@61 1350 hgRevertAct = new QAction(QIcon(":/images/undo.png"), tr("Revert"), this);
jtkorhonen@0 1351 hgRevertAct->setStatusTip(tr("Undo selected working folder file changes (return to local repository version)"));
jtkorhonen@0 1352
Chris@61 1353 hgAddAct = new QAction(QIcon(":/images/add.png"), tr("Add"), this);
jtkorhonen@17 1354 hgAddAct -> setStatusTip(tr("Add working folder file(s) (selected or all yet untracked) to local repository (on next commit)"));
jtkorhonen@0 1355
Chris@61 1356 hgRemoveAct = new QAction(QIcon(":/images/remove.png"), tr("Remove"), this);
jtkorhonen@0 1357 hgRemoveAct -> setStatusTip(tr("Remove selected working folder file from local repository (on next commit)"));
jtkorhonen@0 1358
Chris@61 1359 hgUpdateAct = new QAction(QIcon(":/images/update.png"), tr("Update"), this);
jtkorhonen@0 1360 hgUpdateAct->setStatusTip(tr("Update working folder from local repository"));
jtkorhonen@0 1361
Chris@61 1362 hgCommitAct = new QAction(QIcon(":/images/commit.png"), tr("Commit"), this);
jtkorhonen@20 1363 hgCommitAct->setStatusTip(tr("Save selected file(s) or all changed files in working folder (and all subfolders) to local repository"));
jtkorhonen@0 1364
jtkorhonen@0 1365 hgMergeAct = new QAction(QIcon(":/images/merge.png"), tr("Merge"), this);
jtkorhonen@0 1366 hgMergeAct->setStatusTip(tr("Merge two local repository changesets to working folder"));
jtkorhonen@0 1367
jtkorhonen@0 1368 //Advanced actions
jtkorhonen@0 1369 hgUpdateToRevAct = new QAction(tr("Update to revision"), this);
jtkorhonen@0 1370 hgUpdateToRevAct -> setStatusTip(tr("Update working folder to version selected from history list"));
jtkorhonen@0 1371
jtkorhonen@0 1372 hgAnnotateAct = new QAction(tr("Annotate"), this);
jtkorhonen@0 1373 hgAnnotateAct -> setStatusTip(tr("Show line-by-line version information for selected file"));
jtkorhonen@0 1374
jtkorhonen@0 1375 hgResolveListAct = new QAction(tr("Resolve (list)"), this);
jtkorhonen@0 1376 hgResolveListAct -> setStatusTip(tr("Resolve (list): Show list of files needing merge"));
jtkorhonen@0 1377
jtkorhonen@0 1378 hgResolveMarkAct = new QAction(tr("Resolve (mark)"), this);
jtkorhonen@0 1379 hgResolveMarkAct -> setStatusTip(tr("Resolve (mark): Mark selected file status as resolved"));
jtkorhonen@0 1380
jtkorhonen@33 1381 hgRetryMergeAct = new QAction(tr("Retry merge"), this);
jtkorhonen@33 1382 hgRetryMergeAct -> setStatusTip(tr("Retry merge after failed merge attempt."));
jtkorhonen@33 1383
jtkorhonen@34 1384 hgTagAct = new QAction(tr("Tag revision"), this);
jtkorhonen@34 1385 hgTagAct -> setStatusTip(tr("Give decsriptive name (tag) to current workfolder parent revision."));
jtkorhonen@34 1386
jtkorhonen@34 1387 hgIgnoreAct = new QAction(tr("Edit .hgignore"), this);
jtkorhonen@34 1388 hgIgnoreAct -> setStatusTip(tr("Edit .hgignore file (file contains names of files that should be ignored by mercurial)"));
jtkorhonen@34 1389
jtkorhonen@11 1390 hgServeAct = new QAction(tr("Serve (via http)"), this);
jtkorhonen@11 1391 hgServeAct -> setStatusTip(tr("Serve local repository via http for workgroup access"));
jtkorhonen@11 1392
jtkorhonen@0 1393 //Help actions
jtkorhonen@0 1394 aboutAct = new QAction(tr("About"), this);
jtkorhonen@0 1395 aboutAct->setStatusTip(tr("Show the application's About box"));
jtkorhonen@0 1396
jtkorhonen@0 1397 aboutQtAct = new QAction(tr("About Qt"), this);
jtkorhonen@0 1398 aboutQtAct->setStatusTip(tr("Show the Qt library's About box"));
Chris@94 1399
Chris@94 1400 // Miscellaneous
Chris@94 1401 clearSelectionsAct = new QAction(tr("Clear selections"), this);
Chris@94 1402 clearSelectionsAct->setShortcut(Qt::Key_Escape);
jtkorhonen@0 1403 }
jtkorhonen@0 1404
jtkorhonen@0 1405 void MainWindow::createMenus()
jtkorhonen@0 1406 {
jtkorhonen@0 1407 fileMenu = menuBar()->addMenu(tr("File"));
jtkorhonen@0 1408 fileMenu -> addAction(hgInitAct);
jtkorhonen@0 1409 fileMenu -> addAction(hgCloneFromRemoteAct);
Chris@94 1410 fileMenu->addAction(clearSelectionsAct); //!!! can't live here!
jtkorhonen@0 1411 fileMenu -> addSeparator();
Chris@69 1412 fileMenu -> addAction(openAct);
jtkorhonen@0 1413 fileMenu -> addAction(settingsAct);
jtkorhonen@0 1414 fileMenu -> addSeparator();
jtkorhonen@0 1415 fileMenu -> addAction(exitAct);
jtkorhonen@0 1416
jtkorhonen@0 1417 advancedMenu = menuBar()->addMenu(tr("Advanced"));
jtkorhonen@0 1418 advancedMenu -> addAction(hgUpdateToRevAct);
jtkorhonen@0 1419 advancedMenu -> addSeparator();
jtkorhonen@0 1420 advancedMenu -> addAction(hgAnnotateAct);
jtkorhonen@0 1421 advancedMenu -> addSeparator();
jtkorhonen@33 1422 advancedMenu -> addAction(hgRetryMergeAct);
jtkorhonen@0 1423 advancedMenu -> addAction(hgResolveListAct);
jtkorhonen@0 1424 advancedMenu -> addAction(hgResolveMarkAct);
jtkorhonen@11 1425 advancedMenu -> addSeparator();
jtkorhonen@34 1426 advancedMenu -> addAction(hgTagAct);
jtkorhonen@34 1427 advancedMenu -> addSeparator();
jtkorhonen@34 1428 advancedMenu -> addAction(hgIgnoreAct);
jtkorhonen@34 1429 advancedMenu -> addSeparator();
jtkorhonen@11 1430 advancedMenu -> addAction(hgServeAct);
jtkorhonen@0 1431
jtkorhonen@0 1432 helpMenu = menuBar()->addMenu(tr("Help"));
jtkorhonen@0 1433 helpMenu->addAction(aboutAct);
jtkorhonen@0 1434 helpMenu->addAction(aboutQtAct);
jtkorhonen@0 1435 }
jtkorhonen@0 1436
jtkorhonen@0 1437 void MainWindow::createToolBars()
jtkorhonen@0 1438 {
jtkorhonen@0 1439 fileToolBar = addToolBar(tr("File"));
jtkorhonen@0 1440 fileToolBar -> setIconSize(QSize(MY_ICON_SIZE, MY_ICON_SIZE));
Chris@69 1441 fileToolBar -> addAction(openAct);
Chris@43 1442 fileToolBar -> addAction(hgStatAct);
jtkorhonen@0 1443 fileToolBar -> addSeparator();
Chris@61 1444 // fileToolBar -> addAction(hgChgSetDiffAct);
jtkorhonen@0 1445 fileToolBar -> setMovable(false);
jtkorhonen@0 1446
jtkorhonen@0 1447 repoToolBar = addToolBar(tr(REPOMENU_TITLE));
jtkorhonen@0 1448 repoToolBar -> setIconSize(QSize(MY_ICON_SIZE, MY_ICON_SIZE));
jtkorhonen@0 1449 repoToolBar->addAction(hgIncomingAct);
jtkorhonen@0 1450 repoToolBar->addAction(hgPullAct);
jtkorhonen@0 1451 repoToolBar->addAction(hgPushAct);
jtkorhonen@0 1452 repoToolBar -> setMovable(false);
jtkorhonen@0 1453
jtkorhonen@0 1454 workFolderToolBar = addToolBar(tr(WORKFOLDERMENU_TITLE));
jtkorhonen@0 1455 addToolBar(Qt::LeftToolBarArea, workFolderToolBar);
jtkorhonen@0 1456 workFolderToolBar -> setIconSize(QSize(MY_ICON_SIZE, MY_ICON_SIZE));
Chris@61 1457 // workFolderToolBar->addSeparator();
Chris@95 1458 // workFolderToolBar->addAction(hgFileDiffAct);
Chris@95 1459 workFolderToolBar->addAction(hgFolderDiffAct);
jtkorhonen@0 1460 workFolderToolBar->addSeparator();
jtkorhonen@0 1461 workFolderToolBar->addAction(hgRevertAct);
jtkorhonen@0 1462 workFolderToolBar->addAction(hgUpdateAct);
jtkorhonen@0 1463 workFolderToolBar->addAction(hgCommitAct);
jtkorhonen@0 1464 workFolderToolBar->addAction(hgMergeAct);
jtkorhonen@0 1465 workFolderToolBar->addSeparator();
jtkorhonen@0 1466 workFolderToolBar->addAction(hgAddAct);
jtkorhonen@0 1467 workFolderToolBar->addAction(hgRemoveAct);
jtkorhonen@0 1468 workFolderToolBar -> setMovable(false);
Chris@61 1469
Chris@61 1470 foreach (QToolButton *tb, findChildren<QToolButton *>()) {
Chris@61 1471 tb->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
Chris@61 1472 }
jtkorhonen@0 1473 }
jtkorhonen@0 1474
jtkorhonen@0 1475
jtkorhonen@0 1476 void MainWindow::createStatusBar()
jtkorhonen@0 1477 {
jtkorhonen@0 1478 statusBar()->showMessage(tr("Ready"));
jtkorhonen@0 1479 }
jtkorhonen@0 1480
Chris@69 1481
Chris@69 1482 //!!! review these:
Chris@69 1483
jtkorhonen@0 1484 void MainWindow::readSettings()
jtkorhonen@0 1485 {
jtkorhonen@0 1486 QDir workFolder;
jtkorhonen@0 1487
Chris@61 1488 QSettings settings;
jtkorhonen@0 1489
jtkorhonen@30 1490 remoteRepoPath = settings.value("remoterepopath", "").toString();
jtkorhonen@0 1491 workFolderPath = settings.value("workfolderpath", "").toString();
jtkorhonen@0 1492 if (!workFolder.exists(workFolderPath))
jtkorhonen@0 1493 {
jtkorhonen@0 1494 workFolderPath = "";
jtkorhonen@0 1495 }
jtkorhonen@0 1496
jtkorhonen@0 1497 QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
jtkorhonen@0 1498 QSize size = settings.value("size", QSize(400, 400)).toSize();
jtkorhonen@0 1499 firstStart = settings.value("firststart", QVariant(true)).toBool();
jtkorhonen@0 1500
Chris@109 1501 //!!! initialFileTypesBits = (unsigned char) settings.value("viewFileTypes", QVariant(DEFAULT_HG_STAT_BITS)).toInt();
jtkorhonen@0 1502 resize(size);
jtkorhonen@0 1503 move(pos);
jtkorhonen@0 1504 }
jtkorhonen@0 1505
jtkorhonen@17 1506
jtkorhonen@0 1507 void MainWindow::writeSettings()
jtkorhonen@0 1508 {
Chris@61 1509 QSettings settings;
jtkorhonen@0 1510 settings.setValue("pos", pos());
jtkorhonen@0 1511 settings.setValue("size", size());
jtkorhonen@0 1512 settings.setValue("remoterepopath", remoteRepoPath);
jtkorhonen@0 1513 settings.setValue("workfolderpath", workFolderPath);
jtkorhonen@0 1514 settings.setValue("firststart", firstStart);
Chris@98 1515 //!!!settings.setValue("viewFileTypes", hgTabs -> getFileTypesBits());
jtkorhonen@0 1516 }
jtkorhonen@0 1517
jtkorhonen@0 1518
jtkorhonen@0 1519
jtkorhonen@0 1520