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>
|
Chris@125
|
32 #include <QRegExp>
|
Chris@199
|
33 #include <QShortcut>
|
jtkorhonen@0
|
34
|
Chris@53
|
35 #include "mainwindow.h"
|
Chris@69
|
36 #include "multichoicedialog.h"
|
Chris@64
|
37 #include "startupdialog.h"
|
Chris@53
|
38 #include "colourset.h"
|
Chris@62
|
39 #include "debug.h"
|
Chris@74
|
40 #include "logparser.h"
|
Chris@103
|
41 #include "confirmcommentdialog.h"
|
Chris@125
|
42 #include "incomingdialog.h"
|
Chris@175
|
43 #include "settingsdialog.h"
|
Chris@53
|
44
|
jtkorhonen@0
|
45
|
Chris@172
|
46 MainWindow::MainWindow(QString myDirPath) :
|
Chris@172
|
47 m_myDirPath(myDirPath)
|
jtkorhonen@0
|
48 {
|
Chris@197
|
49 setWindowIcon(QIcon(":images/easyhg-icon.png"));
|
Chris@197
|
50
|
jtkorhonen@0
|
51 QString wndTitle;
|
jtkorhonen@0
|
52
|
Chris@199
|
53 showAllFiles = false;
|
Chris@199
|
54
|
Chris@90
|
55 fsWatcher = 0;
|
Chris@133
|
56 commitsSincePush = 0;
|
Chris@163
|
57 shouldHgStat = true;
|
Chris@90
|
58
|
jtkorhonen@0
|
59 createActions();
|
jtkorhonen@0
|
60 createMenus();
|
jtkorhonen@0
|
61 createToolBars();
|
jtkorhonen@0
|
62 createStatusBar();
|
jtkorhonen@0
|
63
|
Chris@172
|
64 runner = new HgRunner(myDirPath, this);
|
Chris@109
|
65 connect(runner, SIGNAL(commandCompleted(HgAction, QString)),
|
Chris@109
|
66 this, SLOT(commandCompleted(HgAction, QString)));
|
Chris@109
|
67 connect(runner, SIGNAL(commandFailed(HgAction, QString)),
|
Chris@109
|
68 this, SLOT(commandFailed(HgAction, QString)));
|
jtkorhonen@0
|
69 statusBar()->addPermanentWidget(runner);
|
jtkorhonen@0
|
70
|
Chris@61
|
71 setWindowTitle(tr("EasyMercurial"));
|
jtkorhonen@0
|
72
|
jtkorhonen@0
|
73 remoteRepoPath = "";
|
jtkorhonen@0
|
74 workFolderPath = "";
|
jtkorhonen@0
|
75
|
jtkorhonen@0
|
76 readSettings();
|
jtkorhonen@0
|
77
|
jtkorhonen@33
|
78 justMerged = false;
|
Chris@98
|
79 hgTabs = new HgTabWidget((QWidget *) this, remoteRepoPath, workFolderPath);
|
Chris@141
|
80 connectTabsSignals();
|
Chris@98
|
81 setCentralWidget(hgTabs);
|
jtkorhonen@0
|
82
|
Chris@98
|
83 connect(hgTabs, SIGNAL(selectionChanged()),
|
Chris@95
|
84 this, SLOT(enableDisableActions()));
|
Chris@199
|
85 connect(hgTabs, SIGNAL(showAllChanged(bool)),
|
Chris@199
|
86 this, SLOT(showAllChanged(bool)));
|
Chris@95
|
87
|
jtkorhonen@0
|
88 setUnifiedTitleAndToolBarOnMac(true);
|
jtkorhonen@0
|
89 connectActions();
|
Chris@120
|
90 clearState();
|
jtkorhonen@0
|
91 enableDisableActions();
|
jtkorhonen@0
|
92
|
Chris@64
|
93 if (firstStart) {
|
Chris@64
|
94 startupDialog();
|
jtkorhonen@0
|
95 }
|
jtkorhonen@0
|
96
|
Chris@179
|
97 (void)findDiffBinaryName();
|
Chris@179
|
98 (void)findMergeBinaryName();
|
Chris@179
|
99 (void)findEditorBinaryName();
|
Chris@112
|
100
|
Chris@64
|
101 ColourSet *cs = ColourSet::instance();
|
Chris@64
|
102 cs->clearDefaultNames();
|
Chris@64
|
103 cs->addDefaultName("");
|
Chris@153
|
104 cs->addDefaultName("default");
|
Chris@64
|
105 cs->addDefaultName(getUserInfo());
|
Chris@62
|
106
|
Chris@72
|
107 if (workFolderPath == "") {
|
Chris@72
|
108 open();
|
Chris@72
|
109 }
|
Chris@72
|
110
|
Chris@175
|
111 hgTest();
|
jtkorhonen@0
|
112 }
|
jtkorhonen@0
|
113
|
jtkorhonen@0
|
114
|
jtkorhonen@0
|
115 void MainWindow::closeEvent(QCloseEvent *)
|
jtkorhonen@0
|
116 {
|
jtkorhonen@0
|
117 writeSettings();
|
Chris@90
|
118 delete fsWatcher;
|
jtkorhonen@0
|
119 }
|
jtkorhonen@0
|
120
|
jtkorhonen@0
|
121
|
Chris@64
|
122 QString MainWindow::getUserInfo() const
|
Chris@64
|
123 {
|
Chris@64
|
124 QSettings settings;
|
Chris@64
|
125 settings.beginGroup("User Information");
|
Chris@64
|
126 QString name = settings.value("name", getUserRealName()).toString();
|
Chris@64
|
127 QString email = settings.value("email", "").toString();
|
Chris@64
|
128
|
Chris@64
|
129 QString identifier;
|
Chris@64
|
130
|
Chris@64
|
131 if (email != "") {
|
Chris@64
|
132 identifier = QString("%1 <%2>").arg(name).arg(email);
|
Chris@64
|
133 } else {
|
Chris@64
|
134 identifier = name;
|
Chris@64
|
135 }
|
Chris@64
|
136
|
Chris@64
|
137 return identifier;
|
Chris@64
|
138 }
|
Chris@64
|
139
|
jtkorhonen@0
|
140 void MainWindow::about()
|
jtkorhonen@0
|
141 {
|
Chris@97
|
142 QMessageBox::about(this, tr("About EasyMercurial"),
|
Chris@97
|
143 tr("<qt><h2>About EasyMercurial</h2>"
|
Chris@97
|
144 "<p>EasyMercurial is a simple user interface for the "
|
Chris@186
|
145 "Mercurial</a> version control system.</p>"
|
Chris@186
|
146 "<h4>Credits and Copyright</h4>"
|
Chris@186
|
147 "<p>Development carried out by Chris Cannam for "
|
Chris@186
|
148 "SoundSoftware.ac.uk at the Centre for Digital Music, "
|
Chris@186
|
149 "Queen Mary, University of London.</p>"
|
Chris@186
|
150 "<p>EasyMercurial is based on HgExplorer by "
|
Chris@186
|
151 "Jari Korhonen, with thanks.</p>"
|
Chris@186
|
152 "<p style=\"margin-left: 2em;\">"
|
Chris@186
|
153 "Copyright © 2010 Queen Mary, University of London.<br>"
|
Chris@186
|
154 "Copyright © 2010 Jari Korhonen.<br>"
|
Chris@186
|
155 "Copyright © 2010 Chris Cannam."
|
Chris@186
|
156 "</p>"
|
Chris@186
|
157 "<p style=\"margin-left: 2em;\">"
|
Chris@186
|
158 "This program requires Mercurial, by Matt Mackall and others.<br>"
|
Chris@186
|
159 "This program uses Qt by Nokia.<br>"
|
Chris@186
|
160 "This program uses Nuvola icons by David Vignoni.<br>"
|
Chris@186
|
161 "This program may use KDiff3 by Joachim Eibl.<br>"
|
Chris@186
|
162 "This program may use PyQt by River Bank Computing.<br>"
|
Chris@186
|
163 "Packaging for Mercurial and other dependencies on Windows is derived from TortoiseHg by Steve Borho and others."
|
Chris@186
|
164 "</p>"
|
Chris@186
|
165 "<h4>License</h4>"
|
Chris@186
|
166 "<p>This program is free software; you can redistribute it and/or "
|
Chris@97
|
167 "modify it under the terms of the GNU General Public License as "
|
Chris@97
|
168 "published by the Free Software Foundation; either version 2 of the "
|
Chris@97
|
169 "License, or (at your option) any later version. See the file "
|
Chris@186
|
170 "COPYING included with this distribution for more information.</p>"));
|
jtkorhonen@0
|
171 }
|
jtkorhonen@0
|
172
|
Chris@94
|
173 void MainWindow::clearSelections()
|
Chris@94
|
174 {
|
Chris@98
|
175 hgTabs->clearSelections();
|
Chris@94
|
176 }
|
jtkorhonen@0
|
177
|
Chris@199
|
178 void MainWindow::showAllChanged(bool s)
|
Chris@199
|
179 {
|
Chris@199
|
180 showAllFiles = s;
|
Chris@199
|
181 hgQueryPaths();
|
Chris@199
|
182 }
|
Chris@199
|
183
|
Chris@120
|
184 void MainWindow::hgRefresh()
|
Chris@120
|
185 {
|
Chris@120
|
186 clearState();
|
Chris@120
|
187 hgQueryPaths();
|
Chris@120
|
188 }
|
Chris@120
|
189
|
Chris@175
|
190 void MainWindow::hgTest()
|
Chris@175
|
191 {
|
Chris@175
|
192 QStringList params;
|
Chris@175
|
193 params << "--version";
|
Chris@175
|
194 runner->requestAction(HgAction(ACT_TEST_HG, m_myDirPath, params));
|
Chris@175
|
195 }
|
Chris@175
|
196
|
Chris@200
|
197 void MainWindow::hgTestExtension()
|
Chris@200
|
198 {
|
Chris@200
|
199 QStringList params;
|
Chris@200
|
200 params << "--version";
|
Chris@200
|
201 runner->requestAction(HgAction(ACT_TEST_HG_EXT, m_myDirPath, params));
|
Chris@200
|
202 }
|
Chris@200
|
203
|
jtkorhonen@0
|
204 void MainWindow::hgStat()
|
jtkorhonen@0
|
205 {
|
Chris@109
|
206 QStringList params;
|
Chris@199
|
207
|
Chris@199
|
208 if (showAllFiles) {
|
Chris@199
|
209 params << "stat" << "-A";
|
Chris@199
|
210 } else {
|
Chris@199
|
211 params << "stat" << "-ardum";
|
Chris@199
|
212 }
|
Chris@153
|
213
|
Chris@163
|
214 lastStatOutput = "";
|
Chris@163
|
215
|
Chris@153
|
216 // annoyingly, hg stat actually modifies the working directory --
|
Chris@153
|
217 // it creates files called hg-checklink and hg-checkexec to test
|
Chris@153
|
218 // properties of the filesystem
|
Chris@153
|
219 if (fsWatcher) fsWatcher->blockSignals(true);
|
Chris@153
|
220
|
Chris@109
|
221 runner->requestAction(HgAction(ACT_STAT, workFolderPath, params));
|
jtkorhonen@0
|
222 }
|
jtkorhonen@0
|
223
|
Chris@109
|
224 void MainWindow::hgQueryPaths()
|
Chris@74
|
225 {
|
Chris@198
|
226 // Quickest is to just read the file -- but fall back on hg
|
Chris@198
|
227 // command if we get confused
|
Chris@198
|
228
|
Chris@198
|
229 QFileInfo hgrc(workFolderPath + "/.hg/hgrc");
|
Chris@198
|
230
|
Chris@198
|
231 if (hgrc.exists()) {
|
Chris@198
|
232
|
Chris@198
|
233 QSettings s(hgrc.canonicalFilePath(), QSettings::IniFormat);
|
Chris@198
|
234 s.beginGroup("paths");
|
Chris@198
|
235 remoteRepoPath = s.value("default").toString();
|
Chris@198
|
236
|
Chris@198
|
237 // We have to do this here, because commandCompleted won't be called
|
Chris@198
|
238 MultiChoiceDialog::addRecentArgument("local", workFolderPath);
|
Chris@198
|
239 MultiChoiceDialog::addRecentArgument("remote", remoteRepoPath);
|
Chris@198
|
240 hgTabs->setWorkFolderAndRepoNames(workFolderPath, remoteRepoPath);
|
Chris@198
|
241
|
Chris@198
|
242 hgQueryBranch();
|
Chris@198
|
243 return;
|
Chris@198
|
244 }
|
Chris@198
|
245
|
Chris@109
|
246 QStringList params;
|
Chris@109
|
247 params << "paths";
|
Chris@109
|
248 runner->requestAction(HgAction(ACT_QUERY_PATHS, workFolderPath, params));
|
Chris@74
|
249 }
|
Chris@74
|
250
|
Chris@109
|
251 void MainWindow::hgQueryBranch()
|
Chris@106
|
252 {
|
Chris@198
|
253 // Quickest is to just read the file -- but fall back on hg
|
Chris@198
|
254 // command if we get confused
|
Chris@198
|
255
|
Chris@198
|
256 QFile hgbr(workFolderPath + "/.hg/branch");
|
Chris@198
|
257
|
Chris@198
|
258 if (hgbr.exists() && hgbr.open(QFile::ReadOnly)) {
|
Chris@198
|
259
|
Chris@198
|
260 QByteArray ba = hgbr.readLine();
|
Chris@198
|
261 currentBranch = QString::fromUtf8(ba).trimmed();
|
Chris@198
|
262
|
Chris@198
|
263 // We have to do this here, because commandCompleted won't be called
|
Chris@198
|
264 hgStat();
|
Chris@198
|
265 return;
|
Chris@198
|
266 }
|
Chris@198
|
267
|
Chris@109
|
268 QStringList params;
|
Chris@109
|
269 params << "branch";
|
Chris@109
|
270 runner->requestAction(HgAction(ACT_QUERY_BRANCH, workFolderPath, params));
|
Chris@106
|
271 }
|
Chris@106
|
272
|
Chris@109
|
273 void MainWindow::hgQueryHeads()
|
jtkorhonen@0
|
274 {
|
Chris@109
|
275 QStringList params;
|
Chris@137
|
276 // On empty repos, "hg heads" will fail -- we don't care about
|
Chris@137
|
277 // that. Use --closed option so as to include closed branches;
|
Chris@137
|
278 // otherwise we'll be stuck if the user updates into one, and our
|
Chris@137
|
279 // incremental log will end up with spurious stuff in it because
|
Chris@137
|
280 // we won't be pruning at the ends of closed branches
|
Chris@137
|
281 params << "heads" << "--closed";
|
Chris@109
|
282 runner->requestAction(HgAction(ACT_QUERY_HEADS, workFolderPath, params));
|
jtkorhonen@0
|
283 }
|
jtkorhonen@0
|
284
|
jtkorhonen@0
|
285 void MainWindow::hgLog()
|
jtkorhonen@0
|
286 {
|
Chris@109
|
287 QStringList params;
|
Chris@109
|
288 params << "log";
|
Chris@109
|
289 params << "--template";
|
Chris@125
|
290 params << Changeset::getLogTemplate();
|
Chris@109
|
291
|
Chris@109
|
292 runner->requestAction(HgAction(ACT_LOG, workFolderPath, params));
|
Chris@109
|
293 }
|
Chris@109
|
294
|
Chris@150
|
295 void MainWindow::hgLogIncremental(QStringList prune)
|
Chris@120
|
296 {
|
Chris@120
|
297 QStringList params;
|
Chris@120
|
298 params << "log";
|
Chris@120
|
299
|
Chris@150
|
300 foreach (QString p, prune) {
|
Chris@153
|
301 params << "--prune" << Changeset::hashOf(p);
|
Chris@120
|
302 }
|
Chris@120
|
303
|
Chris@120
|
304 params << "--template";
|
Chris@125
|
305 params << Changeset::getLogTemplate();
|
Chris@120
|
306
|
Chris@120
|
307 runner->requestAction(HgAction(ACT_LOG_INCREMENTAL, workFolderPath, params));
|
Chris@120
|
308 }
|
Chris@109
|
309
|
Chris@109
|
310 void MainWindow::hgQueryParents()
|
Chris@109
|
311 {
|
Chris@109
|
312 QStringList params;
|
Chris@109
|
313 params << "parents";
|
Chris@109
|
314 runner->requestAction(HgAction(ACT_QUERY_PARENTS, workFolderPath, params));
|
Chris@109
|
315 }
|
Chris@109
|
316
|
Chris@109
|
317 void MainWindow::hgAnnotate()
|
Chris@109
|
318 {
|
Chris@109
|
319 QStringList params;
|
Chris@109
|
320 QString currentFile;//!!! = hgTabs -> getCurrentFileListLine();
|
Chris@109
|
321
|
Chris@109
|
322 if (!currentFile.isEmpty())
|
jtkorhonen@0
|
323 {
|
Chris@109
|
324 params << "annotate" << "--" << currentFile.mid(2); //Jump over status marker characters (e.g "M ")
|
jtkorhonen@0
|
325
|
Chris@109
|
326 runner->requestAction(HgAction(ACT_ANNOTATE, workFolderPath, params));
|
jtkorhonen@0
|
327 }
|
jtkorhonen@0
|
328 }
|
jtkorhonen@0
|
329
|
Chris@109
|
330 void MainWindow::hgResolveList()
|
Chris@109
|
331 {
|
Chris@109
|
332 QStringList params;
|
jtkorhonen@0
|
333
|
Chris@109
|
334 params << "resolve" << "--list";
|
Chris@109
|
335 runner->requestAction(HgAction(ACT_RESOLVE_LIST, workFolderPath, params));
|
Chris@109
|
336 }
|
Chris@109
|
337
|
Chris@109
|
338 void MainWindow::hgAdd()
|
jtkorhonen@0
|
339 {
|
Chris@109
|
340 QStringList params;
|
jtkorhonen@0
|
341
|
Chris@109
|
342 // hgExplorer permitted adding "all" files -- I'm not sure
|
Chris@109
|
343 // that one is a good idea, let's require the user to select
|
jtkorhonen@0
|
344
|
Chris@109
|
345 QStringList files = hgTabs->getSelectedAddableFiles();
|
Chris@109
|
346
|
Chris@109
|
347 if (!files.empty()) {
|
Chris@109
|
348 params << "add" << "--" << files;
|
Chris@109
|
349 runner->requestAction(HgAction(ACT_ADD, workFolderPath, params));
|
jtkorhonen@0
|
350 }
|
jtkorhonen@0
|
351 }
|
jtkorhonen@0
|
352
|
jtkorhonen@0
|
353
|
Chris@98
|
354 void MainWindow::hgRemove()
|
Chris@98
|
355 {
|
Chris@109
|
356 QStringList params;
|
Chris@98
|
357
|
Chris@109
|
358 QStringList files = hgTabs->getSelectedRemovableFiles();
|
Chris@98
|
359
|
Chris@109
|
360 //!!! todo: confirmation dialog (with file list in it) (or do we
|
Chris@109
|
361 // need that? all it does is move the files to the removed
|
Chris@109
|
362 // list... doesn't it?)
|
Chris@98
|
363
|
Chris@109
|
364 if (!files.empty()) {
|
Chris@109
|
365 params << "remove" << "--after" << "--force" << "--" << files;
|
Chris@109
|
366 runner->requestAction(HgAction(ACT_REMOVE, workFolderPath, params));
|
Chris@109
|
367 }
|
jtkorhonen@0
|
368 }
|
jtkorhonen@0
|
369
|
jtkorhonen@0
|
370 void MainWindow::hgCommit()
|
jtkorhonen@0
|
371 {
|
Chris@109
|
372 QStringList params;
|
Chris@109
|
373 QString comment;
|
Chris@94
|
374
|
Chris@157
|
375 if (justMerged) {
|
Chris@157
|
376 comment = mergeCommitComment;
|
Chris@157
|
377 }
|
Chris@157
|
378
|
Chris@109
|
379 QStringList files = hgTabs->getSelectedCommittableFiles();
|
Chris@127
|
380 QStringList reportFiles = files;
|
Chris@127
|
381 if (reportFiles.empty()) reportFiles = hgTabs->getAllCommittableFiles();
|
Chris@103
|
382
|
Chris@155
|
383 QString cf(tr("Commit files"));
|
Chris@155
|
384
|
Chris@109
|
385 if (ConfirmCommentDialog::confirmAndGetLongComment
|
Chris@109
|
386 (this,
|
Chris@155
|
387 cf,
|
Chris@155
|
388 tr("<h3>%1</h3><p>%2").arg(cf)
|
Chris@155
|
389 .arg(tr("You are about to commit the following files:")),
|
Chris@155
|
390 tr("<h3>%1</h3><p>%2").arg(cf)
|
Chris@168
|
391 .arg(tr("You are about to commit %n file(s).", "", reportFiles.size())),
|
Chris@127
|
392 reportFiles,
|
Chris@193
|
393 comment,
|
Chris@193
|
394 tr("Commit"))) {
|
Chris@103
|
395
|
Chris@157
|
396 if (!justMerged && !files.empty()) {
|
Chris@157
|
397 // User wants to commit selected file(s) (and this is not
|
Chris@157
|
398 // merge commit, which would fail if we selected files)
|
Chris@157
|
399 params << "commit" << "--message" << comment
|
Chris@157
|
400 << "--user" << getUserInfo() << "--" << files;
|
Chris@109
|
401 } else {
|
Chris@109
|
402 // Commit all changes
|
Chris@157
|
403 params << "commit" << "--message" << comment
|
Chris@157
|
404 << "--user" << getUserInfo();
|
jtkorhonen@0
|
405 }
|
Chris@109
|
406
|
Chris@109
|
407 runner->requestAction(HgAction(ACT_COMMIT, workFolderPath, params));
|
Chris@173
|
408 mergeCommitComment = "";
|
jtkorhonen@0
|
409 }
|
jtkorhonen@0
|
410 }
|
jtkorhonen@0
|
411
|
jtkorhonen@34
|
412 QString MainWindow::filterTag(QString tag)
|
jtkorhonen@34
|
413 {
|
jtkorhonen@34
|
414 for(int i = 0; i < tag.size(); i++)
|
jtkorhonen@34
|
415 {
|
jtkorhonen@34
|
416 if (tag[i].isLower() || tag[i].isUpper() || tag[i].isDigit() || (tag[i] == QChar('.')))
|
jtkorhonen@34
|
417 {
|
jtkorhonen@34
|
418 //ok
|
jtkorhonen@34
|
419 }
|
jtkorhonen@34
|
420 else
|
jtkorhonen@34
|
421 {
|
jtkorhonen@34
|
422 tag[i] = QChar('_');
|
jtkorhonen@34
|
423 }
|
jtkorhonen@34
|
424 }
|
jtkorhonen@34
|
425 return tag;
|
jtkorhonen@34
|
426 }
|
jtkorhonen@34
|
427
|
jtkorhonen@34
|
428
|
Chris@164
|
429 void MainWindow::hgTag(QString id)
|
jtkorhonen@34
|
430 {
|
Chris@109
|
431 QStringList params;
|
Chris@109
|
432 QString tag;
|
jtkorhonen@34
|
433
|
Chris@109
|
434 if (ConfirmCommentDialog::confirmAndGetShortComment
|
Chris@109
|
435 (this,
|
Chris@109
|
436 tr("Tag"),
|
Chris@109
|
437 tr("Enter tag:"),
|
Chris@193
|
438 tag,
|
Chris@193
|
439 tr("Add Tag"))) {
|
Chris@164
|
440 if (!tag.isEmpty()) {//!!! do something better if it is empty
|
Chris@164
|
441
|
Chris@164
|
442 params << "tag" << "--user" << getUserInfo();
|
Chris@164
|
443 params << "--rev" << Changeset::hashOf(id) << filterTag(tag);
|
Chris@109
|
444
|
Chris@109
|
445 runner->requestAction(HgAction(ACT_TAG, workFolderPath, params));
|
jtkorhonen@34
|
446 }
|
jtkorhonen@34
|
447 }
|
jtkorhonen@34
|
448 }
|
jtkorhonen@34
|
449
|
jtkorhonen@34
|
450
|
jtkorhonen@34
|
451 void MainWindow::hgIgnore()
|
jtkorhonen@34
|
452 {
|
Chris@109
|
453 QString hgIgnorePath;
|
Chris@109
|
454 QStringList params;
|
Chris@178
|
455
|
Chris@109
|
456 hgIgnorePath = workFolderPath;
|
Chris@178
|
457 hgIgnorePath += "/.hgignore";
|
Chris@109
|
458
|
Chris@109
|
459 params << hgIgnorePath;
|
Chris@179
|
460
|
Chris@179
|
461 QString editor = findEditorBinaryName();
|
Chris@112
|
462
|
Chris@179
|
463 if (editor == "") {
|
Chris@179
|
464 DEBUG << "Failed to find a text editor" << endl;
|
Chris@179
|
465 //!!! visible error!
|
Chris@179
|
466 return;
|
Chris@179
|
467 }
|
Chris@179
|
468
|
Chris@179
|
469 HgAction action(ACT_HG_IGNORE, workFolderPath, params);
|
Chris@179
|
470 action.executable = editor;
|
Chris@179
|
471
|
Chris@179
|
472 runner->requestAction(action);
|
Chris@179
|
473 }
|
Chris@179
|
474
|
Chris@179
|
475 QString MainWindow::findDiffBinaryName()
|
Chris@179
|
476 {
|
Chris@179
|
477 QSettings settings;
|
Chris@179
|
478 settings.beginGroup("Locations");
|
Chris@179
|
479 QString diff = settings.value("extdiffbinary", "").toString();
|
Chris@179
|
480 if (diff == "") {
|
Chris@179
|
481 QStringList bases;
|
Chris@179
|
482 bases << "opendiff" << "kompare" << "kdiff3" << "meld";
|
Chris@179
|
483 bool found = false;
|
Chris@179
|
484 foreach (QString base, bases) {
|
Chris@179
|
485 diff = findInPath(base, m_myDirPath, true);
|
Chris@179
|
486 if (diff != base && diff != base + ".exe") {
|
Chris@179
|
487 found = true;
|
Chris@179
|
488 break;
|
Chris@179
|
489 }
|
Chris@179
|
490 }
|
Chris@179
|
491 if (found) {
|
Chris@179
|
492 settings.setValue("extdiffbinary", diff);
|
Chris@179
|
493 } else {
|
Chris@179
|
494 diff = "";
|
Chris@179
|
495 }
|
Chris@179
|
496 }
|
Chris@179
|
497 return diff;
|
Chris@179
|
498 }
|
Chris@179
|
499
|
Chris@179
|
500 QString MainWindow::findMergeBinaryName()
|
Chris@179
|
501 {
|
Chris@179
|
502 QSettings settings;
|
Chris@179
|
503 settings.beginGroup("Locations");
|
Chris@195
|
504 QVariant v = settings.value("mergebinary");
|
Chris@195
|
505 if (v != QVariant()) {
|
Chris@195
|
506 return v.toString(); // even if empty: user may have specified no external tool
|
Chris@195
|
507 }
|
Chris@195
|
508 QString merge;
|
Chris@195
|
509 QStringList bases;
|
Chris@195
|
510 bases << "fmdiff3" << "meld" << "diffuse" << "kdiff3";
|
Chris@195
|
511 bool found = false;
|
Chris@195
|
512 foreach (QString base, bases) {
|
Chris@195
|
513 merge = findInPath(base, m_myDirPath, true);
|
Chris@195
|
514 if (merge != base && merge != base + ".exe") {
|
Chris@195
|
515 found = true;
|
Chris@195
|
516 break;
|
Chris@179
|
517 }
|
Chris@195
|
518 }
|
Chris@195
|
519 if (found) {
|
Chris@195
|
520 settings.setValue("mergebinary", merge);
|
Chris@195
|
521 } else {
|
Chris@195
|
522 merge = "";
|
Chris@179
|
523 }
|
Chris@179
|
524 return merge;
|
Chris@179
|
525 }
|
Chris@179
|
526
|
Chris@179
|
527 QString MainWindow::findEditorBinaryName()
|
Chris@179
|
528 {
|
Chris@178
|
529 QSettings settings;
|
Chris@178
|
530 settings.beginGroup("Locations");
|
Chris@178
|
531 QString editor = settings.value("editorbinary", "").toString();
|
Chris@178
|
532 if (editor == "") {
|
Chris@178
|
533 QStringList bases;
|
Chris@178
|
534 bases
|
Chris@178
|
535 #if defined Q_OS_WIN32
|
Chris@178
|
536 << "wordpad.exe"
|
Chris@178
|
537 << "C:\\Program Files\\Windows NT\\Accessories\\wordpad.exe"
|
Chris@178
|
538 << "notepad.exe"
|
Chris@178
|
539 #elif defined Q_OS_MAC
|
Chris@178
|
540 << "textedit"
|
Chris@178
|
541 #else
|
Chris@178
|
542 << "gedit" << "kate"
|
Chris@178
|
543 #endif
|
Chris@178
|
544 ;
|
Chris@178
|
545 bool found = false;
|
Chris@178
|
546 foreach (QString base, bases) {
|
Chris@178
|
547 editor = findInPath(base, m_myDirPath, true);
|
Chris@178
|
548 if (editor != base && editor != base + ".exe") {
|
Chris@178
|
549 found = true;
|
Chris@178
|
550 break;
|
Chris@178
|
551 }
|
Chris@178
|
552 }
|
Chris@178
|
553 if (found) {
|
Chris@178
|
554 settings.setValue("editorbinary", editor);
|
Chris@178
|
555 } else {
|
Chris@178
|
556 editor = "";
|
Chris@178
|
557 }
|
Chris@178
|
558 }
|
Chris@179
|
559 return editor;
|
Chris@163
|
560 }
|
Chris@163
|
561
|
Chris@168
|
562 void MainWindow::hgShowSummary()
|
Chris@168
|
563 {
|
Chris@168
|
564 QStringList params;
|
Chris@168
|
565
|
Chris@168
|
566 params << "diff" << "--stat";
|
Chris@168
|
567
|
Chris@168
|
568 runner->requestAction(HgAction(ACT_DIFF_SUMMARY, workFolderPath, params));
|
Chris@168
|
569 }
|
Chris@168
|
570
|
jtkorhonen@0
|
571 void MainWindow::hgFolderDiff()
|
jtkorhonen@0
|
572 {
|
Chris@179
|
573 QString diff = findDiffBinaryName();
|
Chris@179
|
574 if (diff == "") return;
|
Chris@112
|
575
|
Chris@109
|
576 QStringList params;
|
jtkorhonen@0
|
577
|
Chris@112
|
578 // Diff parent against working folder (folder diff)
|
Chris@112
|
579
|
Chris@148
|
580 params << "--config" << "extensions.extdiff=" << "extdiff";
|
Chris@179
|
581 params << "--program" << diff;
|
Chris@109
|
582
|
Chris@153
|
583 params << hgTabs->getSelectedCommittableFiles(); // may be none: whole dir
|
Chris@153
|
584
|
Chris@109
|
585 runner->requestAction(HgAction(ACT_FOLDERDIFF, workFolderPath, params));
|
jtkorhonen@0
|
586 }
|
jtkorhonen@0
|
587
|
jtkorhonen@0
|
588
|
Chris@148
|
589 void MainWindow::hgDiffToCurrent(QString id)
|
jtkorhonen@0
|
590 {
|
Chris@179
|
591 QString diff = findDiffBinaryName();
|
Chris@179
|
592 if (diff == "") return;
|
Chris@163
|
593
|
Chris@148
|
594 QStringList params;
|
jtkorhonen@0
|
595
|
Chris@148
|
596 // Diff given revision against working folder
|
jtkorhonen@0
|
597
|
Chris@148
|
598 params << "--config" << "extensions.extdiff=" << "extdiff";
|
Chris@179
|
599 params << "--program" << diff;
|
Chris@153
|
600 params << "--rev" << Changeset::hashOf(id);
|
Chris@148
|
601
|
Chris@148
|
602 runner->requestAction(HgAction(ACT_FOLDERDIFF, workFolderPath, params));
|
jtkorhonen@0
|
603 }
|
jtkorhonen@0
|
604
|
jtkorhonen@0
|
605
|
Chris@148
|
606 void MainWindow::hgDiffToParent(QString child, QString parent)
|
Chris@148
|
607 {
|
Chris@179
|
608 QString diff = findDiffBinaryName();
|
Chris@179
|
609 if (diff == "") return;
|
Chris@163
|
610
|
Chris@148
|
611 QStringList params;
|
Chris@148
|
612
|
Chris@148
|
613 // Diff given revision against working folder
|
Chris@148
|
614
|
Chris@148
|
615 params << "--config" << "extensions.extdiff=" << "extdiff";
|
Chris@179
|
616 params << "--program" << diff;
|
Chris@153
|
617 params << "--rev" << Changeset::hashOf(parent)
|
Chris@153
|
618 << "--rev" << Changeset::hashOf(child);
|
Chris@148
|
619
|
Chris@148
|
620 runner->requestAction(HgAction(ACT_CHGSETDIFF, workFolderPath, params));
|
Chris@148
|
621 }
|
Chris@148
|
622
|
jtkorhonen@0
|
623
|
jtkorhonen@0
|
624 void MainWindow::hgUpdate()
|
jtkorhonen@0
|
625 {
|
Chris@109
|
626 QStringList params;
|
jtkorhonen@0
|
627
|
Chris@109
|
628 params << "update";
|
Chris@109
|
629
|
Chris@109
|
630 runner->requestAction(HgAction(ACT_UPDATE, workFolderPath, params));
|
jtkorhonen@0
|
631 }
|
jtkorhonen@0
|
632
|
jtkorhonen@0
|
633
|
Chris@148
|
634 void MainWindow::hgUpdateToRev(QString id)
|
jtkorhonen@0
|
635 {
|
Chris@148
|
636 QStringList params;
|
jtkorhonen@0
|
637
|
Chris@153
|
638 params << "update" << "--rev" << Changeset::hashOf(id) << "--check";
|
jtkorhonen@0
|
639
|
Chris@148
|
640 runner->requestAction(HgAction(ACT_UPDATE, workFolderPath, params));
|
jtkorhonen@0
|
641 }
|
jtkorhonen@0
|
642
|
jtkorhonen@0
|
643
|
jtkorhonen@0
|
644 void MainWindow::hgRevert()
|
jtkorhonen@0
|
645 {
|
Chris@109
|
646 QStringList params;
|
Chris@109
|
647 QString comment;
|
Chris@98
|
648
|
Chris@109
|
649 QStringList files = hgTabs->getSelectedRevertableFiles();
|
Chris@109
|
650 if (files.empty()) files = hgTabs->getAllRevertableFiles();
|
Chris@155
|
651
|
Chris@155
|
652 QString rf(tr("Revert files"));
|
Chris@109
|
653
|
Chris@109
|
654 if (ConfirmCommentDialog::confirmDangerousFilesAction
|
Chris@109
|
655 (this,
|
Chris@155
|
656 rf,
|
Chris@155
|
657 tr("<h3>%1</h3><p>%2").arg(rf)
|
Chris@155
|
658 .arg(tr("You are about to <b>revert</b> the following files to their previous committed state.<br><br>This will <b>throw away any changes</b> that you have made to these files but have not committed:")),
|
Chris@155
|
659 tr("<h3>%1</h3><p>%2").arg(rf)
|
Chris@155
|
660 .arg(tr("You are about to <b>revert</b> %n file(s).<br><br>This will <b>throw away any changes</b> that you have made to these files but have not committed.", "", files.size())),
|
Chris@193
|
661 files,
|
Chris@193
|
662 tr("Revert"))) {
|
Chris@163
|
663
|
Chris@163
|
664 lastRevertedFiles = files;
|
Chris@109
|
665
|
Chris@98
|
666 if (files.empty()) {
|
Chris@98
|
667 params << "revert" << "--no-backup";
|
Chris@98
|
668 } else {
|
Chris@164
|
669 params << "revert" << "--" << files;
|
Chris@98
|
670 }
|
Chris@163
|
671
|
Chris@163
|
672 //!!! This is problematic. If you've got an uncommitted
|
Chris@163
|
673 //!!! merge, you can't revert it without declaring which
|
Chris@163
|
674 //!!! parent of the merge you want to revert to (reasonably
|
Chris@163
|
675 //!!! enough). We're OK if we just did the merge in easyhg a
|
Chris@163
|
676 //!!! moment ago, because we have a record of which parent was
|
Chris@163
|
677 //!!! the target -- but if you exit and restart, we've lost
|
Chris@163
|
678 //!!! that record and it doesn't appear to be possible to get
|
Chris@163
|
679 //!!! it back from Hg. Even if you just switched from one
|
Chris@163
|
680 //!!! repo to another, the record is lost. What to do?
|
Chris@163
|
681
|
Chris@163
|
682 if (justMerged && mergeTargetRevision != "") {
|
Chris@163
|
683 params << "--rev" << mergeTargetRevision;
|
Chris@163
|
684 }
|
Chris@109
|
685
|
Chris@109
|
686 runner->requestAction(HgAction(ACT_REVERT, workFolderPath, params));
|
jtkorhonen@0
|
687 }
|
jtkorhonen@0
|
688 }
|
jtkorhonen@0
|
689
|
Chris@163
|
690
|
Chris@163
|
691 void MainWindow::hgMarkResolved(QStringList files)
|
Chris@163
|
692 {
|
Chris@163
|
693 QStringList params;
|
Chris@163
|
694
|
Chris@163
|
695 params << "resolve" << "--mark";
|
Chris@163
|
696
|
Chris@163
|
697 if (files.empty()) {
|
Chris@163
|
698 params << "--all";
|
Chris@163
|
699 } else {
|
Chris@164
|
700 params << "--" << files;
|
Chris@163
|
701 }
|
Chris@163
|
702
|
Chris@163
|
703 runner->requestAction(HgAction(ACT_RESOLVE_MARK, workFolderPath, params));
|
Chris@163
|
704 }
|
Chris@163
|
705
|
Chris@163
|
706
|
jtkorhonen@33
|
707 void MainWindow::hgRetryMerge()
|
jtkorhonen@33
|
708 {
|
Chris@109
|
709 QStringList params;
|
jtkorhonen@33
|
710
|
Chris@163
|
711 params << "resolve";
|
Chris@163
|
712
|
Chris@179
|
713 QString merge = findMergeBinaryName();
|
Chris@179
|
714 if (merge != "") {
|
Chris@179
|
715 params << "--tool" << merge;
|
Chris@163
|
716 }
|
Chris@163
|
717
|
Chris@163
|
718 QStringList files = hgTabs->getSelectedUnresolvedFiles();
|
Chris@163
|
719 if (files.empty()) {
|
Chris@163
|
720 params << "--all";
|
Chris@163
|
721 } else {
|
Chris@164
|
722 params << "--" << files;
|
Chris@163
|
723 }
|
Chris@163
|
724
|
Chris@109
|
725 runner->requestAction(HgAction(ACT_RETRY_MERGE, workFolderPath, params));
|
Chris@163
|
726
|
Chris@163
|
727 mergeCommitComment = tr("Merge");
|
jtkorhonen@33
|
728 }
|
jtkorhonen@33
|
729
|
jtkorhonen@33
|
730
|
jtkorhonen@0
|
731 void MainWindow::hgMerge()
|
jtkorhonen@0
|
732 {
|
Chris@163
|
733 if (hgTabs->canResolve()) {
|
Chris@163
|
734 hgRetryMerge();
|
Chris@163
|
735 return;
|
Chris@163
|
736 }
|
Chris@163
|
737
|
Chris@109
|
738 QStringList params;
|
jtkorhonen@0
|
739
|
Chris@109
|
740 params << "merge";
|
Chris@163
|
741
|
Chris@179
|
742 QString merge = findMergeBinaryName();
|
Chris@179
|
743 if (merge != "") {
|
Chris@179
|
744 params << "--tool" << merge;
|
Chris@163
|
745 }
|
Chris@163
|
746
|
Chris@163
|
747 if (currentParents.size() == 1) {
|
Chris@163
|
748 mergeTargetRevision = currentParents[0]->id();
|
Chris@163
|
749 }
|
Chris@163
|
750
|
Chris@109
|
751 runner->requestAction(HgAction(ACT_MERGE, workFolderPath, params));
|
Chris@157
|
752
|
Chris@157
|
753 mergeCommitComment = tr("Merge");
|
jtkorhonen@0
|
754 }
|
jtkorhonen@0
|
755
|
jtkorhonen@0
|
756
|
Chris@148
|
757 void MainWindow::hgMergeFrom(QString id)
|
Chris@148
|
758 {
|
Chris@148
|
759 QStringList params;
|
Chris@148
|
760
|
Chris@148
|
761 params << "merge";
|
Chris@153
|
762 params << "--rev" << Changeset::hashOf(id);
|
Chris@163
|
763
|
Chris@179
|
764 QString merge = findMergeBinaryName();
|
Chris@179
|
765 if (merge != "") {
|
Chris@179
|
766 params << "--tool" << merge;
|
Chris@163
|
767 }
|
Chris@148
|
768
|
Chris@148
|
769 runner->requestAction(HgAction(ACT_MERGE, workFolderPath, params));
|
Chris@157
|
770
|
Chris@157
|
771 mergeCommitComment = "";
|
Chris@157
|
772
|
Chris@157
|
773 foreach (Changeset *cs, currentHeads) {
|
Chris@157
|
774 if (cs->id() == id && !cs->isOnBranch(currentBranch)) {
|
Chris@157
|
775 if (cs->branch() == "" || cs->branch() == "default") {
|
Chris@157
|
776 mergeCommitComment = tr("Merge from the default branch");
|
Chris@157
|
777 } else {
|
Chris@157
|
778 mergeCommitComment = tr("Merge from branch \"%1\"").arg(cs->branch());
|
Chris@157
|
779 }
|
Chris@157
|
780 }
|
Chris@157
|
781 }
|
Chris@157
|
782
|
Chris@157
|
783 if (mergeCommitComment == "") {
|
Chris@157
|
784 mergeCommitComment = tr("Merge from %1").arg(id);
|
Chris@157
|
785 }
|
Chris@148
|
786 }
|
Chris@148
|
787
|
Chris@148
|
788
|
jtkorhonen@0
|
789 void MainWindow::hgCloneFromRemote()
|
jtkorhonen@0
|
790 {
|
Chris@109
|
791 QStringList params;
|
jtkorhonen@0
|
792
|
Chris@109
|
793 if (!QDir(workFolderPath).exists()) {
|
Chris@109
|
794 if (!QDir().mkpath(workFolderPath)) {
|
Chris@109
|
795 DEBUG << "hgCloneFromRemote: Failed to create target path "
|
Chris@109
|
796 << workFolderPath << endl;
|
Chris@109
|
797 //!!! report error
|
Chris@109
|
798 return;
|
Chris@104
|
799 }
|
Chris@109
|
800 }
|
Chris@104
|
801
|
Chris@109
|
802 params << "clone" << remoteRepoPath << workFolderPath;
|
Chris@109
|
803
|
Chris@109
|
804 hgTabs->setWorkFolderAndRepoNames(workFolderPath, remoteRepoPath);
|
Chris@113
|
805 hgTabs->updateWorkFolderFileList("");
|
jtkorhonen@0
|
806
|
Chris@109
|
807 runner->requestAction(HgAction(ACT_CLONEFROMREMOTE, workFolderPath, params));
|
jtkorhonen@0
|
808 }
|
jtkorhonen@0
|
809
|
jtkorhonen@0
|
810 void MainWindow::hgInit()
|
jtkorhonen@0
|
811 {
|
Chris@109
|
812 QStringList params;
|
jtkorhonen@0
|
813
|
Chris@109
|
814 params << "init";
|
Chris@109
|
815 params << workFolderPath;
|
jtkorhonen@0
|
816
|
Chris@109
|
817 runner->requestAction(HgAction(ACT_INIT, workFolderPath, params));
|
jtkorhonen@0
|
818 }
|
jtkorhonen@0
|
819
|
jtkorhonen@0
|
820 void MainWindow::hgIncoming()
|
jtkorhonen@0
|
821 {
|
Chris@109
|
822 QStringList params;
|
jtkorhonen@0
|
823
|
Chris@109
|
824 params << "incoming" << "--newest-first" << remoteRepoPath;
|
Chris@125
|
825 params << "--template" << Changeset::getLogTemplate();
|
jtkorhonen@0
|
826
|
Chris@109
|
827 runner->requestAction(HgAction(ACT_INCOMING, workFolderPath, params));
|
jtkorhonen@0
|
828 }
|
jtkorhonen@0
|
829
|
jtkorhonen@0
|
830 void MainWindow::hgPull()
|
jtkorhonen@0
|
831 {
|
Chris@193
|
832 if (ConfirmCommentDialog::confirm
|
Chris@126
|
833 (this, tr("Confirm pull"),
|
Chris@126
|
834 format3(tr("Confirm pull from remote repository"),
|
Chris@192
|
835 tr("You are about to pull changes from the following remote repository:"),
|
Chris@126
|
836 remoteRepoPath),
|
Chris@194
|
837 tr("Pull"))) {
|
jtkorhonen@0
|
838
|
Chris@126
|
839 QStringList params;
|
Chris@126
|
840 params << "pull" << remoteRepoPath;
|
Chris@126
|
841 runner->requestAction(HgAction(ACT_PULL, workFolderPath, params));
|
Chris@126
|
842 }
|
jtkorhonen@0
|
843 }
|
jtkorhonen@0
|
844
|
jtkorhonen@0
|
845 void MainWindow::hgPush()
|
jtkorhonen@0
|
846 {
|
Chris@193
|
847 if (ConfirmCommentDialog::confirm
|
Chris@126
|
848 (this, tr("Confirm push"),
|
Chris@126
|
849 format3(tr("Confirm push to remote repository"),
|
Chris@192
|
850 tr("You are about to push your changes to the following remote repository:"),
|
Chris@126
|
851 remoteRepoPath),
|
Chris@194
|
852 tr("Push"))) {
|
jtkorhonen@0
|
853
|
Chris@126
|
854 QStringList params;
|
Chris@154
|
855 params << "push" << "--new-branch" << remoteRepoPath;
|
Chris@126
|
856 runner->requestAction(HgAction(ACT_PUSH, workFolderPath, params));
|
Chris@126
|
857 }
|
jtkorhonen@0
|
858 }
|
jtkorhonen@0
|
859
|
Chris@182
|
860 QStringList MainWindow::listAllUpIpV4Addresses()
|
jtkorhonen@26
|
861 {
|
Chris@182
|
862 QStringList ret;
|
jtkorhonen@26
|
863 QList<QNetworkInterface> ifaces = QNetworkInterface::allInterfaces();
|
jtkorhonen@26
|
864
|
Chris@182
|
865 for (int i = 0; i < ifaces.count(); i++) {
|
jtkorhonen@26
|
866 QNetworkInterface iface = ifaces.at(i);
|
Chris@182
|
867 if (iface.flags().testFlag(QNetworkInterface::IsUp)
|
Chris@182
|
868 && !iface.flags().testFlag(QNetworkInterface::IsLoopBack)) {
|
Chris@182
|
869 for (int j=0; j<iface.addressEntries().count(); j++) {
|
jtkorhonen@28
|
870 QHostAddress tmp = iface.addressEntries().at(j).ip();
|
Chris@182
|
871 if (QAbstractSocket::IPv4Protocol == tmp.protocol()) {
|
Chris@182
|
872 ret.push_back(tmp.toString());
|
jtkorhonen@24
|
873 }
|
jtkorhonen@24
|
874 }
|
jtkorhonen@22
|
875 }
|
jtkorhonen@17
|
876 }
|
jtkorhonen@28
|
877 return ret;
|
jtkorhonen@28
|
878 }
|
jtkorhonen@17
|
879
|
Chris@120
|
880 void MainWindow::clearState()
|
Chris@120
|
881 {
|
Chris@120
|
882 foreach (Changeset *cs, currentParents) delete cs;
|
Chris@120
|
883 currentParents.clear();
|
Chris@120
|
884 foreach (Changeset *cs, currentHeads) delete cs;
|
Chris@120
|
885 currentHeads.clear();
|
Chris@120
|
886 currentBranch = "";
|
Chris@163
|
887 lastStatOutput = "";
|
Chris@163
|
888 lastRevertedFiles.clear();
|
Chris@163
|
889 mergeTargetRevision = "";
|
Chris@163
|
890 mergeCommitComment = "";
|
Chris@173
|
891 stateUnknown = true;
|
Chris@120
|
892 needNewLog = true;
|
Chris@199
|
893 if (fsWatcher) {
|
Chris@199
|
894 delete fsWatcher;
|
Chris@199
|
895 fsWatcher = 0;
|
Chris@199
|
896 }
|
Chris@120
|
897 }
|
jtkorhonen@17
|
898
|
jtkorhonen@11
|
899 void MainWindow::hgServe()
|
jtkorhonen@11
|
900 {
|
Chris@109
|
901 QStringList params;
|
Chris@109
|
902 QString msg;
|
jtkorhonen@11
|
903
|
Chris@182
|
904 QStringList addrs = listAllUpIpV4Addresses();
|
Chris@182
|
905
|
Chris@182
|
906 if (addrs.empty()) {
|
Chris@182
|
907 QMessageBox::critical
|
Chris@182
|
908 (this, tr("Serve"), tr("Failed to identify an active IPv4 address"));
|
Chris@182
|
909 return;
|
Chris@182
|
910 }
|
Chris@182
|
911
|
Chris@182
|
912 //!!! should find available port as well
|
Chris@182
|
913
|
Chris@182
|
914 QTextStream ts(&msg);
|
Chris@182
|
915 ts << QString("<qt><p>%1</p>")
|
Chris@182
|
916 .arg(tr("Running temporary server at %n address(es):", "", addrs.size()));
|
Chris@182
|
917 foreach (QString addr, addrs) {
|
Chris@182
|
918 ts << QString("<pre> http://%1:8000</pre>").arg(xmlEncode(addr));
|
Chris@182
|
919 }
|
Chris@182
|
920 ts << tr("<p>Press Close to stop the server and return.</p>");
|
Chris@182
|
921 ts.flush();
|
Chris@182
|
922
|
Chris@109
|
923 params << "serve";
|
jtkorhonen@11
|
924
|
Chris@109
|
925 runner->requestAction(HgAction(ACT_SERVE, workFolderPath, params));
|
Chris@109
|
926
|
Chris@182
|
927 QMessageBox::information(this, tr("Serve"), msg, QMessageBox::Close);
|
Chris@182
|
928
|
Chris@182
|
929 runner->killCurrentActions();
|
jtkorhonen@11
|
930 }
|
jtkorhonen@11
|
931
|
Chris@64
|
932 void MainWindow::startupDialog()
|
Chris@64
|
933 {
|
Chris@64
|
934 StartupDialog *dlg = new StartupDialog(this);
|
Chris@65
|
935 if (dlg->exec()) firstStart = false;
|
Chris@64
|
936 }
|
jtkorhonen@11
|
937
|
Chris@69
|
938 void MainWindow::open()
|
Chris@69
|
939 {
|
Chris@86
|
940 bool done = false;
|
Chris@69
|
941
|
Chris@86
|
942 while (!done) {
|
Chris@69
|
943
|
Chris@86
|
944 MultiChoiceDialog *d = new MultiChoiceDialog
|
Chris@86
|
945 (tr("Open Repository"),
|
Chris@86
|
946 tr("<qt><big>What would you like to open?</big></qt>"),
|
Chris@86
|
947 this);
|
Chris@69
|
948
|
Chris@86
|
949 d->addChoice("remote",
|
Chris@86
|
950 tr("<qt><center><img src=\":images/browser-64.png\"><br>Remote repository</center></qt>"),
|
Chris@86
|
951 tr("Open a remote Mercurial repository, by cloning from its URL into a local folder."),
|
Chris@86
|
952 MultiChoiceDialog::UrlToDirectoryArg);
|
Chris@69
|
953
|
Chris@86
|
954 d->addChoice("local",
|
Chris@86
|
955 tr("<qt><center><img src=\":images/hglogo-64.png\"><br>Local repository</center></qt>"),
|
Chris@86
|
956 tr("Open an existing local Mercurial repository."),
|
Chris@86
|
957 MultiChoiceDialog::DirectoryArg);
|
Chris@69
|
958
|
Chris@86
|
959 d->addChoice("init",
|
Chris@86
|
960 tr("<qt><center><img src=\":images/hdd_unmount-64.png\"><br>File folder</center></qt>"),
|
Chris@86
|
961 tr("Open a local folder, by creating a Mercurial repository in it."),
|
Chris@86
|
962 MultiChoiceDialog::DirectoryArg);
|
Chris@79
|
963
|
Chris@86
|
964 d->setCurrentChoice("local");
|
Chris@86
|
965
|
Chris@86
|
966 if (d->exec() == QDialog::Accepted) {
|
Chris@86
|
967
|
Chris@86
|
968 QString choice = d->getCurrentChoice();
|
Chris@86
|
969 QString arg = d->getArgument().trimmed();
|
Chris@86
|
970
|
Chris@86
|
971 bool result = false;
|
Chris@86
|
972
|
Chris@86
|
973 if (choice == "local") {
|
Chris@86
|
974 result = openLocal(arg);
|
Chris@86
|
975 } else if (choice == "remote") {
|
Chris@86
|
976 result = openRemote(arg, d->getAdditionalArgument().trimmed());
|
Chris@86
|
977 } else if (choice == "init") {
|
Chris@86
|
978 result = openInit(arg);
|
Chris@86
|
979 }
|
Chris@86
|
980
|
Chris@86
|
981 if (result) {
|
Chris@86
|
982 enableDisableActions();
|
Chris@120
|
983 clearState();
|
Chris@109
|
984 hgQueryPaths();
|
Chris@91
|
985 done = true;
|
Chris@91
|
986 }
|
Chris@86
|
987
|
Chris@86
|
988 } else {
|
Chris@86
|
989
|
Chris@86
|
990 // cancelled
|
Chris@86
|
991 done = true;
|
Chris@69
|
992 }
|
Chris@79
|
993
|
Chris@86
|
994 delete d;
|
Chris@69
|
995 }
|
Chris@69
|
996 }
|
Chris@69
|
997
|
Chris@182
|
998 void MainWindow::changeRemoteRepo()
|
Chris@182
|
999 {
|
Chris@183
|
1000 // This will involve rewriting the local .hgrc
|
Chris@183
|
1001
|
Chris@184
|
1002 QDir hgDir(workFolderPath + "/.hg");
|
Chris@184
|
1003 if (!hgDir.exists()) {
|
Chris@184
|
1004 //!!! visible error!
|
Chris@184
|
1005 return;
|
Chris@184
|
1006 }
|
Chris@184
|
1007
|
Chris@183
|
1008 QFileInfo hgrc(workFolderPath + "/.hg/hgrc");
|
Chris@184
|
1009 if (hgrc.exists() && !hgrc.isWritable()) {
|
Chris@183
|
1010 //!!! visible error!
|
Chris@183
|
1011 return;
|
Chris@183
|
1012 }
|
Chris@183
|
1013
|
Chris@183
|
1014 MultiChoiceDialog *d = new MultiChoiceDialog
|
Chris@183
|
1015 (tr("Change Remote Location"),
|
Chris@183
|
1016 tr("<qt><big>Change the remote location</big></qt>"),
|
Chris@183
|
1017 this);
|
Chris@183
|
1018
|
Chris@183
|
1019 d->addChoice("remote",
|
Chris@183
|
1020 tr("<qt><center><img src=\":images/browser-64.png\"><br>Remote repository</center></qt>"),
|
Chris@183
|
1021 tr("Provide a new URL to use for push and pull actions from the current local repository."),
|
Chris@183
|
1022 MultiChoiceDialog::UrlArg);
|
Chris@183
|
1023
|
Chris@183
|
1024 if (d->exec() == QDialog::Accepted) {
|
Chris@183
|
1025 QSettings s(hgrc.canonicalFilePath(), QSettings::IniFormat);
|
Chris@183
|
1026 s.beginGroup("paths");
|
Chris@183
|
1027 s.setValue("default", d->getArgument());
|
Chris@186
|
1028 stateUnknown = true;
|
Chris@183
|
1029 hgQueryPaths();
|
Chris@183
|
1030 }
|
Chris@183
|
1031
|
Chris@183
|
1032 delete d;
|
Chris@182
|
1033 }
|
Chris@182
|
1034
|
Chris@145
|
1035 void MainWindow::open(QString local)
|
Chris@145
|
1036 {
|
Chris@145
|
1037 if (openLocal(local)) {
|
Chris@145
|
1038 enableDisableActions();
|
Chris@145
|
1039 clearState();
|
Chris@145
|
1040 hgQueryPaths();
|
Chris@145
|
1041 }
|
Chris@145
|
1042 }
|
Chris@145
|
1043
|
Chris@79
|
1044 bool MainWindow::complainAboutFilePath(QString arg)
|
Chris@79
|
1045 {
|
Chris@79
|
1046 QMessageBox::critical
|
Chris@79
|
1047 (this, tr("File chosen"),
|
Chris@84
|
1048 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
|
1049 return false;
|
Chris@79
|
1050 }
|
Chris@79
|
1051
|
Chris@79
|
1052 bool MainWindow::complainAboutUnknownFolder(QString arg)
|
Chris@79
|
1053 {
|
Chris@79
|
1054 QMessageBox::critical
|
Chris@79
|
1055 (this, tr("Folder does not exist"),
|
Chris@84
|
1056 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
|
1057 return false;
|
Chris@84
|
1058 }
|
Chris@84
|
1059
|
Chris@84
|
1060 bool MainWindow::complainAboutInitInRepo(QString arg)
|
Chris@84
|
1061 {
|
Chris@84
|
1062 QMessageBox::critical
|
Chris@84
|
1063 (this, tr("Path is in existing repository"),
|
Chris@84
|
1064 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
|
1065 return false;
|
Chris@84
|
1066 }
|
Chris@84
|
1067
|
Chris@84
|
1068 bool MainWindow::complainAboutInitFile(QString arg)
|
Chris@84
|
1069 {
|
Chris@84
|
1070 QMessageBox::critical
|
Chris@84
|
1071 (this, tr("Path is a file"),
|
Chris@84
|
1072 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
|
1073 return false;
|
Chris@84
|
1074 }
|
Chris@84
|
1075
|
Chris@84
|
1076 bool MainWindow::complainAboutCloneToExisting(QString arg)
|
Chris@84
|
1077 {
|
Chris@84
|
1078 QMessageBox::critical
|
Chris@84
|
1079 (this, tr("Path is in existing repository"),
|
Chris@84
|
1080 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
|
1081 return false;
|
Chris@84
|
1082 }
|
Chris@84
|
1083
|
Chris@84
|
1084 bool MainWindow::complainAboutCloneToFile(QString arg)
|
Chris@84
|
1085 {
|
Chris@84
|
1086 QMessageBox::critical
|
Chris@84
|
1087 (this, tr("Path is a file"),
|
Chris@84
|
1088 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
|
1089 return false;
|
Chris@84
|
1090 }
|
Chris@84
|
1091
|
Chris@84
|
1092 bool MainWindow::complainAboutCloneToExistingFolder(QString arg)
|
Chris@84
|
1093 {
|
Chris@84
|
1094 QMessageBox::critical
|
Chris@84
|
1095 (this, tr("Folder exists"),
|
Chris@84
|
1096 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
|
1097 return false;
|
Chris@79
|
1098 }
|
Chris@79
|
1099
|
Chris@79
|
1100 bool MainWindow::askToOpenParentRepo(QString arg, QString parent)
|
Chris@79
|
1101 {
|
Chris@79
|
1102 return (QMessageBox::question
|
Chris@84
|
1103 (this, tr("Path is inside a repository"),
|
Chris@86
|
1104 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
|
1105 .arg(xmlEncode(arg)).arg(xmlEncode(parent)),
|
Chris@79
|
1106 QMessageBox::Ok | QMessageBox::Cancel,
|
Chris@79
|
1107 QMessageBox::Ok)
|
Chris@79
|
1108 == QMessageBox::Ok);
|
Chris@79
|
1109 }
|
Chris@79
|
1110
|
Chris@79
|
1111 bool MainWindow::askToInitExisting(QString arg)
|
Chris@79
|
1112 {
|
Chris@79
|
1113 return (QMessageBox::question
|
Chris@84
|
1114 (this, tr("Folder has no repository"),
|
Chris@84
|
1115 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
|
1116 .arg(xmlEncode(arg)),
|
Chris@79
|
1117 QMessageBox::Ok | QMessageBox::Cancel,
|
Chris@79
|
1118 QMessageBox::Ok)
|
Chris@79
|
1119 == QMessageBox::Ok);
|
Chris@79
|
1120 }
|
Chris@79
|
1121
|
Chris@79
|
1122 bool MainWindow::askToInitNew(QString arg)
|
Chris@79
|
1123 {
|
Chris@79
|
1124 return (QMessageBox::question
|
Chris@84
|
1125 (this, tr("Folder does not exist"),
|
Chris@84
|
1126 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
|
1127 .arg(xmlEncode(arg)),
|
Chris@84
|
1128 QMessageBox::Ok | QMessageBox::Cancel,
|
Chris@84
|
1129 QMessageBox::Ok)
|
Chris@84
|
1130 == QMessageBox::Ok);
|
Chris@84
|
1131 }
|
Chris@84
|
1132
|
Chris@84
|
1133 bool MainWindow::askToOpenInsteadOfInit(QString arg)
|
Chris@84
|
1134 {
|
Chris@84
|
1135 return (QMessageBox::question
|
Chris@84
|
1136 (this, tr("Repository exists"),
|
Chris@84
|
1137 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
|
1138 .arg(xmlEncode(arg)),
|
Chris@79
|
1139 QMessageBox::Ok | QMessageBox::Cancel,
|
Chris@79
|
1140 QMessageBox::Ok)
|
Chris@79
|
1141 == QMessageBox::Ok);
|
Chris@79
|
1142 }
|
Chris@79
|
1143
|
Chris@79
|
1144 bool MainWindow::openLocal(QString local)
|
Chris@79
|
1145 {
|
Chris@79
|
1146 DEBUG << "open " << local << endl;
|
Chris@79
|
1147
|
Chris@79
|
1148 FolderStatus status = getFolderStatus(local);
|
Chris@79
|
1149 QString containing = getContainingRepoFolder(local);
|
Chris@79
|
1150
|
Chris@79
|
1151 switch (status) {
|
Chris@79
|
1152
|
Chris@79
|
1153 case FolderHasRepo:
|
Chris@79
|
1154 // fine
|
Chris@79
|
1155 break;
|
Chris@79
|
1156
|
Chris@79
|
1157 case FolderExists:
|
Chris@79
|
1158 if (containing != "") {
|
Chris@79
|
1159 if (!askToOpenParentRepo(local, containing)) return false;
|
Chris@84
|
1160 local = containing;
|
Chris@79
|
1161 } else {
|
Chris@86
|
1162 //!!! No -- this is likely to happen far more by accident
|
Chris@86
|
1163 // than because the user actually wanted to init something.
|
Chris@86
|
1164 // Don't ask, just politely reject.
|
Chris@79
|
1165 if (!askToInitExisting(local)) return false;
|
Chris@79
|
1166 return openInit(local);
|
Chris@79
|
1167 }
|
Chris@79
|
1168 break;
|
Chris@79
|
1169
|
Chris@79
|
1170 case FolderParentExists:
|
Chris@79
|
1171 if (containing != "") {
|
Chris@79
|
1172 if (!askToOpenParentRepo(local, containing)) return false;
|
Chris@84
|
1173 local = containing;
|
Chris@79
|
1174 } else {
|
Chris@79
|
1175 if (!askToInitNew(local)) return false;
|
Chris@79
|
1176 return openInit(local);
|
Chris@79
|
1177 }
|
Chris@79
|
1178 break;
|
Chris@79
|
1179
|
Chris@79
|
1180 case FolderUnknown:
|
Chris@84
|
1181 if (containing != "") {
|
Chris@84
|
1182 if (!askToOpenParentRepo(local, containing)) return false;
|
Chris@84
|
1183 local = containing;
|
Chris@84
|
1184 } else {
|
Chris@84
|
1185 return complainAboutUnknownFolder(local);
|
Chris@84
|
1186 }
|
Chris@84
|
1187 break;
|
Chris@79
|
1188
|
Chris@79
|
1189 case FolderIsFile:
|
Chris@79
|
1190 return complainAboutFilePath(local);
|
Chris@79
|
1191 }
|
Chris@79
|
1192
|
Chris@79
|
1193 workFolderPath = local;
|
Chris@79
|
1194 remoteRepoPath = "";
|
Chris@79
|
1195 return true;
|
Chris@79
|
1196 }
|
Chris@79
|
1197
|
Chris@79
|
1198 bool MainWindow::openRemote(QString remote, QString local)
|
Chris@79
|
1199 {
|
Chris@79
|
1200 DEBUG << "clone " << remote << " to " << local << endl;
|
Chris@84
|
1201
|
Chris@84
|
1202 FolderStatus status = getFolderStatus(local);
|
Chris@84
|
1203 QString containing = getContainingRepoFolder(local);
|
Chris@84
|
1204
|
Chris@84
|
1205 DEBUG << "status = " << status << ", containing = " << containing << endl;
|
Chris@84
|
1206
|
Chris@84
|
1207 if (status == FolderHasRepo || containing != "") {
|
Chris@84
|
1208 return complainAboutCloneToExisting(local);
|
Chris@84
|
1209 }
|
Chris@84
|
1210
|
Chris@84
|
1211 if (status == FolderIsFile) {
|
Chris@84
|
1212 return complainAboutCloneToFile(local);
|
Chris@84
|
1213 }
|
Chris@84
|
1214
|
Chris@84
|
1215 if (status == FolderUnknown) {
|
Chris@84
|
1216 return complainAboutUnknownFolder(local);
|
Chris@84
|
1217 }
|
Chris@84
|
1218
|
Chris@84
|
1219 if (status == FolderExists) {
|
Chris@84
|
1220 //!!! we can do better than this surely?
|
Chris@84
|
1221 return complainAboutCloneToExistingFolder(local);
|
Chris@84
|
1222 }
|
Chris@84
|
1223
|
Chris@84
|
1224 workFolderPath = local;
|
Chris@84
|
1225 remoteRepoPath = remote;
|
Chris@84
|
1226 hgCloneFromRemote();
|
Chris@84
|
1227
|
Chris@79
|
1228 return true;
|
Chris@79
|
1229 }
|
Chris@79
|
1230
|
Chris@84
|
1231 bool MainWindow::openInit(QString local)
|
Chris@79
|
1232 {
|
Chris@84
|
1233 DEBUG << "openInit " << local << endl;
|
Chris@84
|
1234
|
Chris@84
|
1235 FolderStatus status = getFolderStatus(local);
|
Chris@84
|
1236 QString containing = getContainingRepoFolder(local);
|
Chris@84
|
1237
|
Chris@84
|
1238 DEBUG << "status = " << status << ", containing = " << containing << endl;
|
Chris@84
|
1239
|
Chris@84
|
1240 if (status == FolderHasRepo) {
|
Chris@84
|
1241 if (!askToOpenInsteadOfInit(local)) return false;
|
Chris@84
|
1242 }
|
Chris@84
|
1243
|
Chris@84
|
1244 if (containing != "") {
|
Chris@84
|
1245 return complainAboutInitInRepo(local);
|
Chris@84
|
1246 }
|
Chris@84
|
1247
|
Chris@84
|
1248 if (status == FolderIsFile) {
|
Chris@84
|
1249 return complainAboutInitFile(local);
|
Chris@84
|
1250 }
|
Chris@84
|
1251
|
Chris@84
|
1252 if (status == FolderUnknown) {
|
Chris@84
|
1253 return complainAboutUnknownFolder(local);
|
Chris@84
|
1254 }
|
Chris@84
|
1255
|
Chris@84
|
1256 workFolderPath = local;
|
Chris@84
|
1257 remoteRepoPath = "";
|
Chris@84
|
1258 hgInit();
|
Chris@79
|
1259 return true;
|
Chris@79
|
1260 }
|
Chris@79
|
1261
|
jtkorhonen@0
|
1262 void MainWindow::settings()
|
jtkorhonen@0
|
1263 {
|
jtkorhonen@0
|
1264 SettingsDialog *settingsDlg = new SettingsDialog(this);
|
jtkorhonen@0
|
1265 settingsDlg->exec();
|
jtkorhonen@0
|
1266 }
|
jtkorhonen@0
|
1267
|
jtkorhonen@2
|
1268 #define STDOUT_NEEDS_BIG_WINDOW 512
|
jtkorhonen@2
|
1269 #define SMALL_WND_W 500
|
jtkorhonen@2
|
1270 #define SMALL_WND_H 300
|
jtkorhonen@2
|
1271
|
jtkorhonen@2
|
1272 #define BIG_WND_W 1024
|
jtkorhonen@2
|
1273 #define BIG_WND_H 768
|
jtkorhonen@2
|
1274
|
jtkorhonen@2
|
1275
|
jtkorhonen@2
|
1276 void MainWindow::presentLongStdoutToUser(QString stdo)
|
jtkorhonen@0
|
1277 {
|
jtkorhonen@2
|
1278 if (!stdo.isEmpty())
|
jtkorhonen@2
|
1279 {
|
jtkorhonen@2
|
1280 QDialog dlg;
|
jtkorhonen@0
|
1281
|
jtkorhonen@2
|
1282 if (stdo.length() > STDOUT_NEEDS_BIG_WINDOW)
|
jtkorhonen@2
|
1283 {
|
jtkorhonen@2
|
1284 dlg.setMinimumWidth(BIG_WND_W);
|
jtkorhonen@2
|
1285 dlg.setMinimumHeight(BIG_WND_H);
|
jtkorhonen@2
|
1286 }
|
jtkorhonen@2
|
1287 else
|
jtkorhonen@2
|
1288 {
|
jtkorhonen@2
|
1289 dlg.setMinimumWidth(SMALL_WND_W);
|
jtkorhonen@2
|
1290 dlg.setMinimumHeight(SMALL_WND_H);
|
jtkorhonen@2
|
1291 }
|
jtkorhonen@0
|
1292
|
jtkorhonen@2
|
1293 QVBoxLayout *box = new QVBoxLayout;
|
jtkorhonen@2
|
1294 QListWidget *list = new QListWidget;
|
jtkorhonen@2
|
1295 list-> addItems(stdo.split("\n"));
|
jtkorhonen@2
|
1296 QPushButton *btn = new QPushButton(tr("Ok"));
|
jtkorhonen@2
|
1297 connect(btn, SIGNAL(clicked()), &dlg, SLOT(accept()));
|
jtkorhonen@0
|
1298
|
jtkorhonen@2
|
1299 box -> addWidget(list);
|
jtkorhonen@2
|
1300 box -> addWidget(btn);
|
jtkorhonen@2
|
1301 dlg.setLayout(box);
|
jtkorhonen@2
|
1302
|
jtkorhonen@2
|
1303 dlg.exec();
|
jtkorhonen@2
|
1304 }
|
jtkorhonen@2
|
1305 else
|
jtkorhonen@2
|
1306 {
|
Chris@98
|
1307 QMessageBox::information(this, tr("EasyMercurial"), tr("Mercurial command did not return any output."));
|
jtkorhonen@2
|
1308 }
|
jtkorhonen@0
|
1309 }
|
jtkorhonen@0
|
1310
|
Chris@90
|
1311 void MainWindow::updateFileSystemWatcher()
|
Chris@90
|
1312 {
|
Chris@199
|
1313 bool justCreated = false;
|
Chris@199
|
1314 if (!fsWatcher) {
|
Chris@199
|
1315 fsWatcher = new QFileSystemWatcher();
|
Chris@199
|
1316 justCreated = true;
|
Chris@199
|
1317 }
|
Chris@199
|
1318
|
Chris@199
|
1319 // QFileSystemWatcher will refuse to add a file or directory to
|
Chris@199
|
1320 // its watch list that it is already watching -- fine, that's what
|
Chris@199
|
1321 // we want -- but it prints a warning when this happens, which is
|
Chris@199
|
1322 // annoying because it would be the normal case for us. So we'll
|
Chris@199
|
1323 // check for duplicates ourselves.
|
Chris@199
|
1324 QSet<QString> alreadyWatched;
|
Chris@199
|
1325 QStringList dl(fsWatcher->directories());
|
Chris@199
|
1326 foreach (QString d, dl) alreadyWatched.insert(d);
|
Chris@199
|
1327
|
Chris@90
|
1328 std::deque<QString> pending;
|
Chris@90
|
1329 pending.push_back(workFolderPath);
|
Chris@199
|
1330
|
Chris@90
|
1331 while (!pending.empty()) {
|
Chris@199
|
1332
|
Chris@90
|
1333 QString path = pending.front();
|
Chris@90
|
1334 pending.pop_front();
|
Chris@199
|
1335 if (!alreadyWatched.contains(path)) {
|
Chris@199
|
1336 fsWatcher->addPath(path);
|
Chris@199
|
1337 DEBUG << "Added to file system watcher: " << path << endl;
|
Chris@199
|
1338 }
|
Chris@199
|
1339
|
Chris@90
|
1340 QDir d(path);
|
Chris@90
|
1341 if (d.exists()) {
|
Chris@199
|
1342 d.setFilter(QDir::Dirs | QDir::NoDotAndDotDot |
|
Chris@199
|
1343 QDir::Readable | QDir::NoSymLinks);
|
Chris@90
|
1344 foreach (QString entry, d.entryList()) {
|
Chris@199
|
1345 if (entry.startsWith('.')) continue;
|
Chris@90
|
1346 QString entryPath = d.absoluteFilePath(entry);
|
Chris@90
|
1347 pending.push_back(entryPath);
|
Chris@90
|
1348 }
|
Chris@90
|
1349 }
|
Chris@90
|
1350 }
|
Chris@199
|
1351
|
Chris@199
|
1352 if (justCreated) {
|
Chris@199
|
1353 connect(fsWatcher, SIGNAL(directoryChanged(QString)),
|
Chris@199
|
1354 this, SLOT(fsDirectoryChanged(QString)));
|
Chris@199
|
1355 connect(fsWatcher, SIGNAL(fileChanged(QString)),
|
Chris@199
|
1356 this, SLOT(fsFileChanged(QString)));
|
Chris@199
|
1357 }
|
Chris@90
|
1358 }
|
Chris@90
|
1359
|
Chris@122
|
1360 void MainWindow::fsDirectoryChanged(QString d)
|
Chris@90
|
1361 {
|
Chris@122
|
1362 DEBUG << "MainWindow::fsDirectoryChanged " << d << endl;
|
Chris@90
|
1363 hgStat();
|
Chris@90
|
1364 }
|
Chris@90
|
1365
|
Chris@122
|
1366 void MainWindow::fsFileChanged(QString f)
|
Chris@90
|
1367 {
|
Chris@122
|
1368 DEBUG << "MainWindow::fsFileChanged " << f << endl;
|
Chris@90
|
1369 hgStat();
|
Chris@90
|
1370 }
|
Chris@90
|
1371
|
Chris@125
|
1372 QString MainWindow::format3(QString head, QString intro, QString code)
|
Chris@125
|
1373 {
|
Chris@196
|
1374 code = xmlEncode(code).replace("\n", "<br>")
|
Chris@196
|
1375 #ifndef Q_OS_WIN32
|
Chris@196
|
1376 // The hard hyphen comes out funny on Windows
|
Chris@196
|
1377 .replace("-", "‑")
|
Chris@196
|
1378 #endif
|
Chris@196
|
1379 .replace(" ", " ");
|
Chris@125
|
1380 if (intro == "") {
|
Chris@168
|
1381 return QString("<qt><h3>%1</h3><p><code>%2</code></p>")
|
Chris@168
|
1382 .arg(head).arg(code);
|
Chris@126
|
1383 } else if (code == "") {
|
Chris@126
|
1384 return QString("<qt><h3>%1</h3><p>%2</p>")
|
Chris@126
|
1385 .arg(head).arg(intro);
|
Chris@125
|
1386 } else {
|
Chris@168
|
1387 return QString("<qt><h3>%1</h3><p>%2</p><p><code>%3</code></p>")
|
Chris@168
|
1388 .arg(head).arg(intro).arg(code);
|
Chris@125
|
1389 }
|
Chris@125
|
1390 }
|
Chris@125
|
1391
|
Chris@120
|
1392 void MainWindow::showIncoming(QString output)
|
Chris@120
|
1393 {
|
Chris@120
|
1394 runner->hide();
|
Chris@125
|
1395 IncomingDialog *d = new IncomingDialog(this, output);
|
Chris@125
|
1396 d->exec();
|
Chris@125
|
1397 delete d;
|
Chris@125
|
1398 }
|
Chris@125
|
1399
|
Chris@125
|
1400 int MainWindow::extractChangeCount(QString text)
|
Chris@125
|
1401 {
|
Chris@125
|
1402 QRegExp re("added (\\d+) ch\\w+ with (\\d+) ch\\w+ to (\\d+) f\\w+");
|
Chris@125
|
1403 if (re.indexIn(text) >= 0) {
|
Chris@125
|
1404 return re.cap(1).toInt();
|
Chris@125
|
1405 } else if (text.contains("no changes")) {
|
Chris@125
|
1406 return 0;
|
Chris@125
|
1407 } else {
|
Chris@125
|
1408 return -1; // unknown
|
Chris@125
|
1409 }
|
Chris@120
|
1410 }
|
Chris@120
|
1411
|
Chris@120
|
1412 void MainWindow::showPushResult(QString output)
|
Chris@120
|
1413 {
|
Chris@125
|
1414 QString report;
|
Chris@125
|
1415 int n = extractChangeCount(output);
|
Chris@125
|
1416 if (n > 0) {
|
Chris@125
|
1417 report = tr("Pushed %n changeset(s)", "", n);
|
Chris@125
|
1418 } else if (n == 0) {
|
Chris@125
|
1419 report = tr("No changes to push");
|
Chris@125
|
1420 } else {
|
Chris@125
|
1421 report = tr("Push complete");
|
Chris@125
|
1422 }
|
Chris@125
|
1423 report = format3(report, tr("The push command output was:"), output);
|
Chris@120
|
1424 runner->hide();
|
Chris@125
|
1425 QMessageBox::information(this, "Push complete", report);
|
Chris@120
|
1426 }
|
Chris@120
|
1427
|
Chris@120
|
1428 void MainWindow::showPullResult(QString output)
|
Chris@120
|
1429 {
|
Chris@125
|
1430 QString report;
|
Chris@125
|
1431 int n = extractChangeCount(output);
|
Chris@125
|
1432 if (n > 0) {
|
Chris@125
|
1433 report = tr("Pulled %n changeset(s)", "", n);
|
Chris@125
|
1434 } else if (n == 0) {
|
Chris@125
|
1435 report = tr("No changes to pull");
|
Chris@125
|
1436 } else {
|
Chris@125
|
1437 report = tr("Pull complete");
|
Chris@125
|
1438 }
|
Chris@125
|
1439 report = format3(report, tr("The pull command output was:"), output);
|
Chris@120
|
1440 runner->hide();
|
Chris@125
|
1441
|
Chris@125
|
1442 //!!! and something about updating
|
Chris@125
|
1443
|
Chris@125
|
1444 QMessageBox::information(this, "Pull complete", report);
|
Chris@120
|
1445 }
|
Chris@120
|
1446
|
Chris@174
|
1447 void MainWindow::reportNewRemoteHeads(QString output)
|
Chris@174
|
1448 {
|
Chris@174
|
1449 bool headsAreLocal = false;
|
Chris@174
|
1450
|
Chris@174
|
1451 if (currentParents.size() == 1) {
|
Chris@174
|
1452 int currentBranchHeads = 0;
|
Chris@174
|
1453 bool parentIsHead = false;
|
Chris@174
|
1454 Changeset *parent = currentParents[0];
|
Chris@174
|
1455 foreach (Changeset *head, currentHeads) {
|
Chris@174
|
1456 if (head->isOnBranch(currentBranch)) {
|
Chris@174
|
1457 ++currentBranchHeads;
|
Chris@174
|
1458 }
|
Chris@174
|
1459 if (parent->id() == head->id()) {
|
Chris@174
|
1460 parentIsHead = true;
|
Chris@174
|
1461 }
|
Chris@174
|
1462 }
|
Chris@174
|
1463 if (currentBranchHeads == 2 && parentIsHead) {
|
Chris@174
|
1464 headsAreLocal = true;
|
Chris@174
|
1465 }
|
Chris@174
|
1466 }
|
Chris@174
|
1467
|
Chris@174
|
1468 if (headsAreLocal) {
|
Chris@174
|
1469 QMessageBox::warning
|
Chris@174
|
1470 (this, tr("Push failed"),
|
Chris@174
|
1471 format3(tr("Push failed"),
|
Chris@174
|
1472 tr("Your local repository could not be pushed to the remote repository.<br><br>You may need to merge the changes locally first.<br><br>The output of the push command was:"),
|
Chris@174
|
1473 output));
|
Chris@174
|
1474 } else {
|
Chris@174
|
1475 QMessageBox::warning
|
Chris@174
|
1476 (this, tr("Push failed"),
|
Chris@174
|
1477 format3(tr("Push failed"),
|
Chris@174
|
1478 tr("Your local repository could not be pushed to the remote repository.<br><br>The remote repository may have been changed by someone else since you last pushed. Try pulling and merging their changes into your local repository first.<br><br>The output of the push command was:"),
|
Chris@174
|
1479 output));
|
Chris@174
|
1480 }
|
Chris@174
|
1481 }
|
Chris@174
|
1482
|
Chris@143
|
1483 void MainWindow::commandFailed(HgAction action, QString output)
|
Chris@62
|
1484 {
|
Chris@62
|
1485 DEBUG << "MainWindow::commandFailed" << endl;
|
Chris@74
|
1486
|
Chris@113
|
1487 // Some commands we just have to ignore bad return values from:
|
Chris@113
|
1488
|
Chris@113
|
1489 switch(action.action) {
|
Chris@113
|
1490 case ACT_NONE:
|
Chris@113
|
1491 // uh huh
|
Chris@113
|
1492 return;
|
Chris@175
|
1493 case ACT_TEST_HG:
|
Chris@175
|
1494 QMessageBox::warning
|
Chris@175
|
1495 (this, tr("Failed to run Mercurial"),
|
Chris@175
|
1496 format3(tr("Failed to run Mercurial"),
|
Chris@200
|
1497 tr("The Mercurial program either could not be found or failed to run.<br>Check that the Mercurial program path is correct in Settings.<br><br>%1").arg(output == "" ? QString("") : tr("The test command said:")),
|
Chris@200
|
1498 output));
|
Chris@200
|
1499 settings();
|
Chris@200
|
1500 return;
|
Chris@200
|
1501 case ACT_TEST_HG_EXT:
|
Chris@200
|
1502 QMessageBox::warning
|
Chris@200
|
1503 (this, tr("Failed to run Mercurial"),
|
Chris@200
|
1504 format3(tr("Failed to run Mercurial with extension enabled"),
|
Chris@200
|
1505 tr("The Mercurial program failed to run with the EasyMercurial interaction extension enabled.<br>This may indicate an installation problem with EasyMercurial.<br><br>You may be able to continue working if you switch off “Use EasyHg Mercurial Extension” in Settings. Note that remote repositories that require authentication may not work if you do this.<br><br>%1").arg(output == "" ? QString("") : tr("The test command said:")),
|
Chris@175
|
1506 output));
|
Chris@175
|
1507 settings();
|
Chris@175
|
1508 return;
|
Chris@113
|
1509 case ACT_INCOMING:
|
Chris@113
|
1510 // returns non-zero code if the check was successful but there
|
Chris@113
|
1511 // are no changes pending
|
Chris@143
|
1512 if (output.trimmed() == "") showIncoming("");
|
Chris@113
|
1513 return;
|
Chris@162
|
1514 case ACT_QUERY_HEADS:
|
Chris@162
|
1515 // fails if repo is empty; we don't care (if there's a genuine
|
Chris@162
|
1516 // problem, something else will fail too). Need to do this,
|
Chris@162
|
1517 // otherwise empty repo state will not be reflected properly
|
Chris@162
|
1518 // (since heads/log procedure never completes for empty repo)
|
Chris@162
|
1519 enableDisableActions();
|
Chris@162
|
1520 return;
|
Chris@113
|
1521 case ACT_FOLDERDIFF:
|
Chris@113
|
1522 case ACT_CHGSETDIFF:
|
Chris@113
|
1523 // external program, unlikely to be anything useful in stderr
|
Chris@113
|
1524 // and some return with failure codes when something as basic
|
Chris@113
|
1525 // as the user closing the window via the wm happens
|
Chris@113
|
1526 return;
|
Chris@174
|
1527 case ACT_PUSH:
|
Chris@174
|
1528 if (output.contains("creates new remote heads")) {
|
Chris@174
|
1529 reportNewRemoteHeads(output);
|
Chris@174
|
1530 return;
|
Chris@174
|
1531 }
|
Chris@199
|
1532 case ACT_STAT:
|
Chris@199
|
1533 if (fsWatcher) fsWatcher->blockSignals(false);
|
Chris@199
|
1534 break; // go on and report
|
Chris@113
|
1535 default:
|
Chris@114
|
1536 break;
|
Chris@113
|
1537 }
|
Chris@113
|
1538
|
Chris@113
|
1539 QString command = action.executable;
|
Chris@113
|
1540 if (command == "") command = "hg";
|
Chris@113
|
1541 foreach (QString arg, action.params) {
|
Chris@113
|
1542 command += " " + arg;
|
Chris@113
|
1543 }
|
Chris@113
|
1544
|
Chris@113
|
1545 QString message = tr("<qt><h3>Command failed</h3>"
|
Chris@113
|
1546 "<p>The following command failed:</p>"
|
Chris@113
|
1547 "<code>%1</code>"
|
Chris@113
|
1548 "%2</qt>")
|
Chris@113
|
1549 .arg(command)
|
Chris@143
|
1550 .arg((output.trimmed() != "") ?
|
Chris@113
|
1551 tr("<p>Its output said:</p><code>%1</code>")
|
Chris@143
|
1552 .arg(xmlEncode(output.left(800))
|
Chris@113
|
1553 .replace("\n", "<br>"))
|
Chris@113
|
1554 : "");
|
Chris@113
|
1555
|
Chris@113
|
1556 QMessageBox::warning(this, tr("Command failed"), message);
|
Chris@62
|
1557 }
|
Chris@62
|
1558
|
Chris@109
|
1559 void MainWindow::commandCompleted(HgAction completedAction, QString output)
|
jtkorhonen@0
|
1560 {
|
Chris@109
|
1561 HGACTIONS action = completedAction.action;
|
Chris@109
|
1562
|
Chris@109
|
1563 if (action == ACT_NONE) return;
|
Chris@109
|
1564
|
Chris@150
|
1565 bool headsChanged = false;
|
Chris@150
|
1566 QStringList oldHeadIds;
|
Chris@150
|
1567
|
Chris@150
|
1568 switch (action) {
|
Chris@109
|
1569
|
Chris@175
|
1570 case ACT_TEST_HG:
|
Chris@175
|
1571 break;
|
Chris@175
|
1572
|
Chris@200
|
1573 case ACT_TEST_HG_EXT:
|
Chris@200
|
1574 break;
|
Chris@200
|
1575
|
Chris@109
|
1576 case ACT_QUERY_PATHS:
|
jtkorhonen@0
|
1577 {
|
Chris@109
|
1578 DEBUG << "stdout is " << output << endl;
|
Chris@109
|
1579 LogParser lp(output, "=");
|
Chris@109
|
1580 LogList ll = lp.parse();
|
Chris@109
|
1581 DEBUG << ll.size() << " results" << endl;
|
Chris@109
|
1582 if (!ll.empty()) {
|
Chris@109
|
1583 remoteRepoPath = lp.parse()[0]["default"].trimmed();
|
Chris@109
|
1584 DEBUG << "Set remote path to " << remoteRepoPath << endl;
|
Chris@109
|
1585 }
|
Chris@109
|
1586 MultiChoiceDialog::addRecentArgument("local", workFolderPath);
|
Chris@109
|
1587 MultiChoiceDialog::addRecentArgument("remote", remoteRepoPath);
|
Chris@109
|
1588 hgTabs->setWorkFolderAndRepoNames(workFolderPath, remoteRepoPath);
|
Chris@109
|
1589 break;
|
Chris@109
|
1590 }
|
jtkorhonen@0
|
1591
|
Chris@109
|
1592 case ACT_QUERY_BRANCH:
|
Chris@109
|
1593 currentBranch = output.trimmed();
|
Chris@109
|
1594 break;
|
jtkorhonen@0
|
1595
|
Chris@109
|
1596 case ACT_STAT:
|
Chris@163
|
1597 lastStatOutput = output;
|
Chris@109
|
1598 updateFileSystemWatcher();
|
Chris@199
|
1599 if (fsWatcher) fsWatcher->blockSignals(false);
|
Chris@109
|
1600 break;
|
Chris@163
|
1601
|
Chris@163
|
1602 case ACT_RESOLVE_LIST:
|
Chris@163
|
1603 if (output != "") {
|
Chris@163
|
1604 // Remove lines beginning with R (they are resolved,
|
Chris@163
|
1605 // and the file stat parser treats R as removed)
|
Chris@163
|
1606 QStringList outList = output.split('\n');
|
Chris@163
|
1607 QStringList winnowed;
|
Chris@163
|
1608 foreach (QString line, outList) {
|
Chris@163
|
1609 if (!line.startsWith("R ")) winnowed.push_back(line);
|
Chris@163
|
1610 }
|
Chris@163
|
1611 output = winnowed.join("\n");
|
Chris@163
|
1612 }
|
Chris@163
|
1613 DEBUG << "lastStatOutput = " << lastStatOutput << endl;
|
Chris@199
|
1614 DEBUG << "resolve output = " << output << endl;
|
Chris@163
|
1615 hgTabs->updateWorkFolderFileList(lastStatOutput + output);
|
Chris@163
|
1616 break;
|
Chris@163
|
1617
|
Chris@163
|
1618 case ACT_RESOLVE_MARK:
|
Chris@163
|
1619 shouldHgStat = true;
|
Chris@163
|
1620 break;
|
Chris@109
|
1621
|
Chris@109
|
1622 case ACT_INCOMING:
|
Chris@120
|
1623 showIncoming(output);
|
Chris@120
|
1624 break;
|
Chris@120
|
1625
|
Chris@109
|
1626 case ACT_ANNOTATE:
|
Chris@109
|
1627 presentLongStdoutToUser(output);
|
Chris@109
|
1628 shouldHgStat = true;
|
Chris@109
|
1629 break;
|
Chris@109
|
1630
|
Chris@109
|
1631 case ACT_PULL:
|
Chris@120
|
1632 showPullResult(output);
|
Chris@109
|
1633 shouldHgStat = true;
|
Chris@109
|
1634 break;
|
Chris@109
|
1635
|
Chris@109
|
1636 case ACT_PUSH:
|
Chris@120
|
1637 showPushResult(output);
|
Chris@109
|
1638 break;
|
Chris@109
|
1639
|
Chris@109
|
1640 case ACT_INIT:
|
Chris@109
|
1641 MultiChoiceDialog::addRecentArgument("init", workFolderPath);
|
Chris@109
|
1642 MultiChoiceDialog::addRecentArgument("local", workFolderPath);
|
Chris@109
|
1643 enableDisableActions();
|
Chris@109
|
1644 shouldHgStat = true;
|
Chris@109
|
1645 break;
|
Chris@109
|
1646
|
Chris@109
|
1647 case ACT_CLONEFROMREMOTE:
|
Chris@109
|
1648 MultiChoiceDialog::addRecentArgument("local", workFolderPath);
|
Chris@109
|
1649 MultiChoiceDialog::addRecentArgument("remote", remoteRepoPath);
|
Chris@109
|
1650 MultiChoiceDialog::addRecentArgument("remote", workFolderPath, true);
|
Chris@109
|
1651 QMessageBox::information(this, "Clone", output);
|
Chris@109
|
1652 enableDisableActions();
|
Chris@109
|
1653 shouldHgStat = true;
|
Chris@109
|
1654 break;
|
Chris@109
|
1655
|
Chris@109
|
1656 case ACT_LOG:
|
Chris@120
|
1657 hgTabs->setNewLog(output);
|
Chris@120
|
1658 needNewLog = false;
|
Chris@120
|
1659 break;
|
Chris@120
|
1660
|
Chris@120
|
1661 case ACT_LOG_INCREMENTAL:
|
Chris@120
|
1662 hgTabs->addIncrementalLog(output);
|
Chris@109
|
1663 break;
|
Chris@109
|
1664
|
Chris@109
|
1665 case ACT_QUERY_PARENTS:
|
Chris@152
|
1666 {
|
Chris@109
|
1667 foreach (Changeset *cs, currentParents) delete cs;
|
Chris@109
|
1668 currentParents = Changeset::parseChangesets(output);
|
Chris@152
|
1669 QStringList parentIds = Changeset::getIds(currentParents);
|
Chris@153
|
1670 hgTabs->setCurrent(parentIds, currentBranch);
|
Chris@152
|
1671 }
|
Chris@109
|
1672 break;
|
Chris@109
|
1673
|
Chris@109
|
1674 case ACT_QUERY_HEADS:
|
Chris@150
|
1675 {
|
Chris@150
|
1676 oldHeadIds = Changeset::getIds(currentHeads);
|
Chris@150
|
1677 Changesets newHeads = Changeset::parseChangesets(output);
|
Chris@150
|
1678 QStringList newHeadIds = Changeset::getIds(newHeads);
|
Chris@150
|
1679 if (oldHeadIds != newHeadIds) {
|
Chris@150
|
1680 DEBUG << "Heads changed, will prompt an incremental log if appropriate" << endl;
|
Chris@150
|
1681 headsChanged = true;
|
Chris@150
|
1682 foreach (Changeset *cs, currentHeads) delete cs;
|
Chris@150
|
1683 currentHeads = newHeads;
|
Chris@150
|
1684 }
|
Chris@150
|
1685 }
|
Chris@109
|
1686 break;
|
Chris@130
|
1687
|
Chris@130
|
1688 case ACT_COMMIT:
|
Chris@130
|
1689 hgTabs->clearSelections();
|
Chris@163
|
1690 justMerged = false;
|
Chris@130
|
1691 shouldHgStat = true;
|
Chris@130
|
1692 break;
|
Chris@163
|
1693
|
Chris@163
|
1694 case ACT_REVERT:
|
Chris@163
|
1695 hgMarkResolved(lastRevertedFiles);
|
Chris@163
|
1696 justMerged = false;
|
Chris@163
|
1697 break;
|
Chris@109
|
1698
|
Chris@109
|
1699 case ACT_REMOVE:
|
Chris@109
|
1700 case ACT_ADD:
|
Chris@116
|
1701 hgTabs->clearSelections();
|
Chris@116
|
1702 shouldHgStat = true;
|
Chris@116
|
1703 break;
|
Chris@116
|
1704
|
Chris@164
|
1705 case ACT_TAG:
|
Chris@164
|
1706 needNewLog = true;
|
Chris@164
|
1707 shouldHgStat = true;
|
Chris@164
|
1708 break;
|
Chris@164
|
1709
|
Chris@168
|
1710 case ACT_DIFF_SUMMARY:
|
Chris@168
|
1711 QMessageBox::information(this, tr("Change summary"),
|
Chris@168
|
1712 format3(tr("Summary of uncommitted changes"),
|
Chris@168
|
1713 "",
|
Chris@168
|
1714 output));
|
Chris@168
|
1715 break;
|
Chris@168
|
1716
|
Chris@109
|
1717 case ACT_FOLDERDIFF:
|
Chris@109
|
1718 case ACT_CHGSETDIFF:
|
Chris@109
|
1719 case ACT_SERVE:
|
Chris@109
|
1720 case ACT_HG_IGNORE:
|
Chris@109
|
1721 shouldHgStat = true;
|
Chris@109
|
1722 break;
|
Chris@109
|
1723
|
Chris@109
|
1724 case ACT_UPDATE:
|
Chris@162
|
1725 QMessageBox::information(this, tr("Update"), tr("<qt><h3>Update successful</h3><p>%1</p>").arg(xmlEncode(output)));
|
Chris@109
|
1726 shouldHgStat = true;
|
Chris@109
|
1727 break;
|
Chris@109
|
1728
|
Chris@109
|
1729 case ACT_MERGE:
|
Chris@196
|
1730 //!!! use format3?
|
Chris@196
|
1731 QMessageBox::information(this, tr("Merge"), tr("<qt><h3>Merge successful</h3><pre>%1</pre>").arg(xmlEncode(output)));
|
Chris@109
|
1732 shouldHgStat = true;
|
Chris@109
|
1733 justMerged = true;
|
Chris@109
|
1734 break;
|
Chris@109
|
1735
|
Chris@109
|
1736 case ACT_RETRY_MERGE:
|
Chris@163
|
1737 QMessageBox::information(this, tr("Resolved"),
|
Chris@163
|
1738 tr("<qt><h3>Merge resolved</h3><p>Merge resolved successfully.</p>"));
|
Chris@109
|
1739 shouldHgStat = true;
|
Chris@109
|
1740 justMerged = true;
|
Chris@109
|
1741 break;
|
Chris@109
|
1742
|
Chris@109
|
1743 default:
|
Chris@109
|
1744 break;
|
Chris@109
|
1745 }
|
Chris@108
|
1746
|
Chris@121
|
1747 // Sequence when no full log required:
|
Chris@163
|
1748 // paths -> branch -> stat -> resolve-list -> heads ->
|
Chris@150
|
1749 // incremental-log (only if heads changed) -> parents
|
Chris@150
|
1750 //
|
Chris@121
|
1751 // Sequence when full log required:
|
Chris@163
|
1752 // paths -> branch -> stat -> resolve-list -> heads -> parents -> log
|
Chris@150
|
1753 //
|
Chris@150
|
1754 // Note we want to call enableDisableActions only once, at the end
|
Chris@150
|
1755 // of whichever sequence is in use.
|
Chris@150
|
1756
|
Chris@156
|
1757 bool noMore = false;
|
Chris@156
|
1758
|
Chris@150
|
1759 switch (action) {
|
Chris@175
|
1760
|
Chris@175
|
1761 case ACT_TEST_HG:
|
Chris@200
|
1762 hgTestExtension();
|
Chris@200
|
1763 break;
|
Chris@200
|
1764
|
Chris@200
|
1765 case ACT_TEST_HG_EXT:
|
Chris@175
|
1766 hgQueryPaths();
|
Chris@175
|
1767 break;
|
Chris@150
|
1768
|
Chris@150
|
1769 case ACT_QUERY_PATHS:
|
Chris@109
|
1770 hgQueryBranch();
|
Chris@150
|
1771 break;
|
Chris@150
|
1772
|
Chris@150
|
1773 case ACT_QUERY_BRANCH:
|
Chris@109
|
1774 hgStat();
|
Chris@150
|
1775 break;
|
Chris@150
|
1776
|
Chris@150
|
1777 case ACT_STAT:
|
Chris@163
|
1778 hgResolveList();
|
Chris@163
|
1779 break;
|
Chris@163
|
1780
|
Chris@163
|
1781 case ACT_RESOLVE_LIST:
|
Chris@150
|
1782 hgQueryHeads();
|
Chris@150
|
1783 break;
|
Chris@150
|
1784
|
Chris@150
|
1785 case ACT_QUERY_HEADS:
|
Chris@150
|
1786 if (headsChanged && !needNewLog) {
|
Chris@150
|
1787 hgLogIncremental(oldHeadIds);
|
Chris@121
|
1788 } else {
|
Chris@150
|
1789 hgQueryParents();
|
Chris@121
|
1790 }
|
Chris@150
|
1791 break;
|
Chris@150
|
1792
|
Chris@150
|
1793 case ACT_LOG_INCREMENTAL:
|
Chris@109
|
1794 hgQueryParents();
|
Chris@150
|
1795 break;
|
Chris@150
|
1796
|
Chris@150
|
1797 case ACT_QUERY_PARENTS:
|
Chris@120
|
1798 if (needNewLog) {
|
Chris@120
|
1799 hgLog();
|
Chris@150
|
1800 } else {
|
Chris@150
|
1801 // we're done
|
Chris@156
|
1802 noMore = true;
|
Chris@120
|
1803 }
|
Chris@150
|
1804 break;
|
Chris@150
|
1805
|
Chris@150
|
1806 case ACT_LOG:
|
Chris@150
|
1807 // we're done
|
Chris@156
|
1808 noMore = true;
|
Chris@198
|
1809 break;
|
Chris@150
|
1810
|
Chris@150
|
1811 default:
|
Chris@109
|
1812 if (shouldHgStat) {
|
Chris@163
|
1813 shouldHgStat = false;
|
Chris@109
|
1814 hgQueryPaths();
|
Chris@150
|
1815 } else {
|
Chris@156
|
1816 noMore = true;
|
jtkorhonen@0
|
1817 }
|
Chris@150
|
1818 break;
|
Chris@150
|
1819 }
|
Chris@156
|
1820
|
Chris@156
|
1821 if (noMore) {
|
Chris@173
|
1822 stateUnknown = false;
|
Chris@156
|
1823 enableDisableActions();
|
Chris@156
|
1824 hgTabs->updateHistory();
|
Chris@156
|
1825 }
|
jtkorhonen@0
|
1826 }
|
jtkorhonen@0
|
1827
|
jtkorhonen@0
|
1828 void MainWindow::connectActions()
|
jtkorhonen@0
|
1829 {
|
jtkorhonen@0
|
1830 connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
|
jtkorhonen@0
|
1831 connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
|
jtkorhonen@0
|
1832
|
Chris@120
|
1833 connect(hgRefreshAct, SIGNAL(triggered()), this, SLOT(hgRefresh()));
|
jtkorhonen@0
|
1834 connect(hgRemoveAct, SIGNAL(triggered()), this, SLOT(hgRemove()));
|
jtkorhonen@0
|
1835 connect(hgAddAct, SIGNAL(triggered()), this, SLOT(hgAdd()));
|
jtkorhonen@0
|
1836 connect(hgCommitAct, SIGNAL(triggered()), this, SLOT(hgCommit()));
|
jtkorhonen@0
|
1837 connect(hgFolderDiffAct, SIGNAL(triggered()), this, SLOT(hgFolderDiff()));
|
jtkorhonen@0
|
1838 connect(hgUpdateAct, SIGNAL(triggered()), this, SLOT(hgUpdate()));
|
jtkorhonen@0
|
1839 connect(hgRevertAct, SIGNAL(triggered()), this, SLOT(hgRevert()));
|
jtkorhonen@0
|
1840 connect(hgMergeAct, SIGNAL(triggered()), this, SLOT(hgMerge()));
|
jtkorhonen@34
|
1841 connect(hgIgnoreAct, SIGNAL(triggered()), this, SLOT(hgIgnore()));
|
jtkorhonen@0
|
1842
|
jtkorhonen@0
|
1843 connect(settingsAct, SIGNAL(triggered()), this, SLOT(settings()));
|
Chris@69
|
1844 connect(openAct, SIGNAL(triggered()), this, SLOT(open()));
|
Chris@182
|
1845 connect(changeRemoteRepoAct, SIGNAL(triggered()), this, SLOT(changeRemoteRepo()));
|
jtkorhonen@0
|
1846
|
jtkorhonen@0
|
1847 connect(hgIncomingAct, SIGNAL(triggered()), this, SLOT(hgIncoming()));
|
jtkorhonen@0
|
1848 connect(hgPullAct, SIGNAL(triggered()), this, SLOT(hgPull()));
|
jtkorhonen@0
|
1849 connect(hgPushAct, SIGNAL(triggered()), this, SLOT(hgPush()));
|
jtkorhonen@0
|
1850
|
jtkorhonen@0
|
1851 connect(hgAnnotateAct, SIGNAL(triggered()), this, SLOT(hgAnnotate()));
|
jtkorhonen@11
|
1852 connect(hgServeAct, SIGNAL(triggered()), this, SLOT(hgServe()));
|
jtkorhonen@0
|
1853 }
|
Chris@141
|
1854
|
Chris@141
|
1855 void MainWindow::connectTabsSignals()
|
Chris@141
|
1856 {
|
Chris@141
|
1857 connect(hgTabs, SIGNAL(commit()),
|
Chris@141
|
1858 this, SLOT(hgCommit()));
|
Chris@141
|
1859
|
Chris@141
|
1860 connect(hgTabs, SIGNAL(revert()),
|
Chris@141
|
1861 this, SLOT(hgRevert()));
|
Chris@141
|
1862
|
Chris@141
|
1863 connect(hgTabs, SIGNAL(diffWorkingFolder()),
|
Chris@141
|
1864 this, SLOT(hgFolderDiff()));
|
Chris@168
|
1865
|
Chris@168
|
1866 connect(hgTabs, SIGNAL(showSummary()),
|
Chris@168
|
1867 this, SLOT(hgShowSummary()));
|
Chris@148
|
1868
|
Chris@141
|
1869 connect(hgTabs, SIGNAL(updateTo(QString)),
|
Chris@148
|
1870 this, SLOT(hgUpdateToRev(QString)));
|
Chris@141
|
1871
|
Chris@141
|
1872 connect(hgTabs, SIGNAL(diffToCurrent(QString)),
|
Chris@148
|
1873 this, SLOT(hgDiffToCurrent(QString)));
|
Chris@141
|
1874
|
Chris@148
|
1875 connect(hgTabs, SIGNAL(diffToParent(QString, QString)),
|
Chris@148
|
1876 this, SLOT(hgDiffToParent(QString, QString)));
|
Chris@141
|
1877
|
Chris@141
|
1878 connect(hgTabs, SIGNAL(mergeFrom(QString)),
|
Chris@148
|
1879 this, SLOT(hgMergeFrom(QString)));
|
Chris@164
|
1880
|
Chris@141
|
1881 connect(hgTabs, SIGNAL(tag(QString)),
|
Chris@148
|
1882 this, SLOT(hgTag(QString)));
|
Chris@141
|
1883 }
|
Chris@141
|
1884
|
jtkorhonen@0
|
1885 void MainWindow::enableDisableActions()
|
jtkorhonen@0
|
1886 {
|
Chris@90
|
1887 DEBUG << "MainWindow::enableDisableActions" << endl;
|
Chris@90
|
1888
|
Chris@115
|
1889 //!!! should also do things like set the status texts for the
|
Chris@115
|
1890 //!!! actions appropriately by context
|
Chris@115
|
1891
|
jtkorhonen@0
|
1892 QDir localRepoDir;
|
jtkorhonen@0
|
1893 QDir workFolderDir;
|
Chris@145
|
1894 bool workFolderExist = true;
|
Chris@145
|
1895 bool localRepoExist = true;
|
jtkorhonen@0
|
1896
|
jtkorhonen@0
|
1897 remoteRepoActionsEnabled = true;
|
Chris@90
|
1898 if (remoteRepoPath.isEmpty()) {
|
jtkorhonen@0
|
1899 remoteRepoActionsEnabled = false;
|
jtkorhonen@0
|
1900 }
|
jtkorhonen@0
|
1901
|
jtkorhonen@0
|
1902 localRepoActionsEnabled = true;
|
Chris@90
|
1903 if (workFolderPath.isEmpty()) {
|
jtkorhonen@0
|
1904 localRepoActionsEnabled = false;
|
jtkorhonen@0
|
1905 workFolderExist = false;
|
jtkorhonen@0
|
1906 }
|
jtkorhonen@0
|
1907
|
Chris@90
|
1908 if (!workFolderDir.exists(workFolderPath)) {
|
jtkorhonen@0
|
1909 localRepoActionsEnabled = false;
|
jtkorhonen@0
|
1910 workFolderExist = false;
|
Chris@90
|
1911 } else {
|
jtkorhonen@0
|
1912 workFolderExist = true;
|
jtkorhonen@0
|
1913 }
|
jtkorhonen@0
|
1914
|
Chris@112
|
1915 if (!localRepoDir.exists(workFolderPath + "/.hg")) {
|
jtkorhonen@0
|
1916 localRepoActionsEnabled = false;
|
jtkorhonen@0
|
1917 localRepoExist = false;
|
jtkorhonen@0
|
1918 }
|
jtkorhonen@0
|
1919
|
jtkorhonen@0
|
1920 hgIncomingAct -> setEnabled(remoteRepoActionsEnabled && remoteRepoActionsEnabled);
|
jtkorhonen@0
|
1921 hgPullAct -> setEnabled(remoteRepoActionsEnabled && remoteRepoActionsEnabled);
|
jtkorhonen@0
|
1922 hgPushAct -> setEnabled(remoteRepoActionsEnabled && remoteRepoActionsEnabled);
|
Chris@169
|
1923
|
Chris@179
|
1924 bool haveDiff = false;
|
Chris@179
|
1925 QSettings settings;
|
Chris@179
|
1926 settings.beginGroup("Locations");
|
Chris@179
|
1927 if (settings.value("extdiffbinary", "").toString() != "") {
|
Chris@179
|
1928 haveDiff = true;
|
Chris@179
|
1929 }
|
Chris@179
|
1930 settings.endGroup();
|
Chris@112
|
1931
|
Chris@120
|
1932 hgRefreshAct -> setEnabled(localRepoActionsEnabled);
|
Chris@112
|
1933 hgFolderDiffAct -> setEnabled(localRepoActionsEnabled && haveDiff);
|
jtkorhonen@0
|
1934 hgRevertAct -> setEnabled(localRepoActionsEnabled);
|
jtkorhonen@0
|
1935 hgAddAct -> setEnabled(localRepoActionsEnabled);
|
jtkorhonen@0
|
1936 hgRemoveAct -> setEnabled(localRepoActionsEnabled);
|
jtkorhonen@0
|
1937 hgUpdateAct -> setEnabled(localRepoActionsEnabled);
|
jtkorhonen@0
|
1938 hgCommitAct -> setEnabled(localRepoActionsEnabled);
|
jtkorhonen@0
|
1939 hgMergeAct -> setEnabled(localRepoActionsEnabled);
|
jtkorhonen@2
|
1940 hgAnnotateAct -> setEnabled(localRepoActionsEnabled);
|
jtkorhonen@11
|
1941 hgServeAct -> setEnabled(localRepoActionsEnabled);
|
jtkorhonen@34
|
1942 hgIgnoreAct -> setEnabled(localRepoActionsEnabled);
|
jtkorhonen@0
|
1943
|
Chris@90
|
1944 DEBUG << "localRepoActionsEnabled = " << localRepoActionsEnabled << endl;
|
Chris@98
|
1945 DEBUG << "canCommit = " << hgTabs->canCommit() << endl;
|
Chris@90
|
1946
|
Chris@98
|
1947 hgAddAct->setEnabled(localRepoActionsEnabled && hgTabs->canAdd());
|
Chris@98
|
1948 hgRemoveAct->setEnabled(localRepoActionsEnabled && hgTabs->canRemove());
|
Chris@98
|
1949 hgCommitAct->setEnabled(localRepoActionsEnabled && hgTabs->canCommit());
|
Chris@163
|
1950 hgRevertAct->setEnabled(localRepoActionsEnabled && hgTabs->canRevert());
|
Chris@163
|
1951 hgFolderDiffAct->setEnabled(localRepoActionsEnabled && hgTabs->canDiff());
|
Chris@90
|
1952
|
Chris@108
|
1953 // A default merge makes sense if:
|
Chris@108
|
1954 // * there is only one parent (if there are two, we have an uncommitted merge) and
|
Chris@108
|
1955 // * there are exactly two heads that have the same branch as the current branch and
|
Chris@108
|
1956 // * our parent is one of those heads
|
Chris@108
|
1957 //
|
Chris@108
|
1958 // A default update makes sense if:
|
Chris@108
|
1959 // * there is only one parent and
|
Chris@108
|
1960 // * the parent is not one of the current heads
|
Chris@156
|
1961
|
Chris@108
|
1962 bool canMerge = false;
|
Chris@108
|
1963 bool canUpdate = false;
|
Chris@156
|
1964 bool haveMerge = false;
|
Chris@162
|
1965 bool emptyRepo = false;
|
Chris@156
|
1966 int currentBranchHeads = 0;
|
Chris@156
|
1967
|
Chris@108
|
1968 if (currentParents.size() == 1) {
|
Chris@156
|
1969 bool parentIsHead = false;
|
Chris@108
|
1970 Changeset *parent = currentParents[0];
|
Chris@108
|
1971 foreach (Changeset *head, currentHeads) {
|
Chris@108
|
1972 DEBUG << "head branch " << head->branch() << ", current branch " << currentBranch << endl;
|
Chris@108
|
1973 if (head->isOnBranch(currentBranch)) {
|
Chris@108
|
1974 ++currentBranchHeads;
|
Chris@108
|
1975 if (parent->id() == head->id()) {
|
Chris@108
|
1976 parentIsHead = true;
|
Chris@108
|
1977 }
|
Chris@108
|
1978 }
|
Chris@108
|
1979 }
|
Chris@108
|
1980 if (currentBranchHeads == 2 && parentIsHead) {
|
Chris@108
|
1981 canMerge = true;
|
Chris@108
|
1982 }
|
Chris@108
|
1983 if (!parentIsHead) {
|
Chris@108
|
1984 canUpdate = true;
|
Chris@108
|
1985 DEBUG << "parent id = " << parent->id() << endl;
|
Chris@108
|
1986 DEBUG << " head ids "<<endl;
|
Chris@108
|
1987 foreach (Changeset *h, currentHeads) {
|
Chris@108
|
1988 DEBUG << "head id = " << h->id() << endl;
|
Chris@108
|
1989 }
|
Chris@108
|
1990 }
|
Chris@162
|
1991 } else if (currentParents.size() == 0) {
|
Chris@162
|
1992 emptyRepo = true;
|
Chris@156
|
1993 } else {
|
Chris@156
|
1994 haveMerge = true;
|
Chris@163
|
1995 justMerged = true;
|
Chris@108
|
1996 }
|
Chris@156
|
1997
|
Chris@163
|
1998 hgMergeAct->setEnabled(localRepoActionsEnabled &&
|
Chris@163
|
1999 (canMerge || hgTabs->canResolve()));
|
Chris@163
|
2000 hgUpdateAct->setEnabled(localRepoActionsEnabled &&
|
Chris@172
|
2001 (canUpdate && !hgTabs->haveChangesToCommit()));
|
Chris@115
|
2002
|
Chris@115
|
2003 // Set the state field on the file status widget
|
Chris@115
|
2004
|
Chris@115
|
2005 QString branchText;
|
Chris@115
|
2006 if (currentBranch == "" || currentBranch == "default") {
|
Chris@115
|
2007 branchText = tr("the default branch");
|
Chris@115
|
2008 } else {
|
Chris@115
|
2009 branchText = tr("branch \"%1\"").arg(currentBranch);
|
Chris@115
|
2010 }
|
Chris@156
|
2011
|
Chris@173
|
2012 if (stateUnknown) {
|
Chris@173
|
2013 hgTabs->setState(tr("(Examining repository)"));
|
Chris@173
|
2014 } else if (emptyRepo) {
|
Chris@162
|
2015 hgTabs->setState(tr("Nothing committed to this repository yet"));
|
Chris@162
|
2016 } else if (canMerge) {
|
Chris@156
|
2017 hgTabs->setState(tr("<b>Awaiting merge</b> on %1").arg(branchText));
|
Chris@163
|
2018 } else if (!hgTabs->getAllUnresolvedFiles().empty()) {
|
Chris@163
|
2019 hgTabs->setState(tr("Have unresolved files following merge on %1").arg(branchText));
|
Chris@156
|
2020 } else if (haveMerge) {
|
Chris@157
|
2021 hgTabs->setState(tr("Have merged but not yet committed on %1").arg(branchText));
|
Chris@156
|
2022 } else if (canUpdate) {
|
Chris@172
|
2023 if (hgTabs->haveChangesToCommit()) {
|
Chris@163
|
2024 // have uncommitted changes
|
Chris@163
|
2025 hgTabs->setState(tr("On %1. Not at the head of the branch").arg(branchText));
|
Chris@163
|
2026 } else {
|
Chris@163
|
2027 // no uncommitted changes
|
Chris@163
|
2028 hgTabs->setState(tr("On %1. Not at the head of the branch: consider updating").arg(branchText));
|
Chris@163
|
2029 }
|
Chris@156
|
2030 } else if (currentBranchHeads > 1) {
|
Chris@156
|
2031 hgTabs->setState(tr("At one of %n heads of %1", "", currentBranchHeads).arg(branchText));
|
Chris@115
|
2032 } else {
|
Chris@115
|
2033 hgTabs->setState(tr("At the head of %1").arg(branchText));
|
Chris@115
|
2034 }
|
jtkorhonen@0
|
2035 }
|
jtkorhonen@0
|
2036
|
jtkorhonen@0
|
2037 void MainWindow::createActions()
|
jtkorhonen@0
|
2038 {
|
jtkorhonen@0
|
2039 //File actions
|
Chris@69
|
2040 openAct = new QAction(QIcon(":/images/fileopen.png"), tr("Open..."), this);
|
Chris@199
|
2041 openAct -> setStatusTip(tr("Open an existing repository or working folder"));
|
Chris@69
|
2042
|
Chris@182
|
2043 changeRemoteRepoAct = new QAction(tr("Change Remote Location..."), this);
|
Chris@182
|
2044 changeRemoteRepoAct->setStatusTip(tr("Change the default remote repository for pull and push actions"));
|
Chris@182
|
2045
|
jtkorhonen@0
|
2046 settingsAct = new QAction(QIcon(":/images/settings.png"), tr("Settings..."), this);
|
jtkorhonen@0
|
2047 settingsAct -> setStatusTip(tr("View and change application settings"));
|
jtkorhonen@0
|
2048
|
Chris@169
|
2049 exitAct = new QAction(QIcon(":/images/exit.png"), tr("Quit"), this);
|
jtkorhonen@0
|
2050 exitAct->setShortcuts(QKeySequence::Quit);
|
Chris@169
|
2051 exitAct->setStatusTip(tr("Quit EasyMercurial"));
|
jtkorhonen@0
|
2052
|
jtkorhonen@0
|
2053 //Repository actions
|
Chris@120
|
2054 hgRefreshAct = new QAction(QIcon(":/images/status.png"), tr("Refresh"), this);
|
Chris@178
|
2055 hgRefreshAct->setStatusTip(tr("Refresh the window to show the current state of the working folder"));
|
Chris@61
|
2056
|
Chris@61
|
2057 hgIncomingAct = new QAction(QIcon(":/images/incoming.png"), tr("Preview"), this);
|
Chris@169
|
2058 hgIncomingAct -> setStatusTip(tr("See what changes are available in the remote repository waiting to be pulled"));
|
jtkorhonen@0
|
2059
|
Chris@61
|
2060 hgPullAct = new QAction(QIcon(":/images/pull.png"), tr("Pull"), this);
|
Chris@169
|
2061 hgPullAct -> setStatusTip(tr("Pull changes from the remote repository to the local repository"));
|
jtkorhonen@0
|
2062
|
Chris@61
|
2063 hgPushAct = new QAction(QIcon(":/images/push.png"), tr("Push"), this);
|
Chris@169
|
2064 hgPushAct->setStatusTip(tr("Push changes from the local repository to the remote repository"));
|
jtkorhonen@0
|
2065
|
jtkorhonen@0
|
2066 //Workfolder actions
|
Chris@99
|
2067 hgFolderDiffAct = new QAction(QIcon(":/images/folderdiff.png"), tr("Diff"), this);
|
Chris@169
|
2068 hgFolderDiffAct->setStatusTip(tr("See what has changed in the working folder compared with the last committed state"));
|
jtkorhonen@0
|
2069
|
Chris@61
|
2070 hgRevertAct = new QAction(QIcon(":/images/undo.png"), tr("Revert"), this);
|
Chris@169
|
2071 hgRevertAct->setStatusTip(tr("Throw away your changes and return to the last committed state"));
|
jtkorhonen@0
|
2072
|
Chris@61
|
2073 hgAddAct = new QAction(QIcon(":/images/add.png"), tr("Add"), this);
|
Chris@169
|
2074 hgAddAct -> setStatusTip(tr("Mark the selected file(s) to be added on the next commit"));
|
jtkorhonen@0
|
2075
|
Chris@169
|
2076 //!!! needs to be modified for number
|
Chris@61
|
2077 hgRemoveAct = new QAction(QIcon(":/images/remove.png"), tr("Remove"), this);
|
Chris@169
|
2078 hgRemoveAct -> setStatusTip(tr("Mark the selected file(s) to be removed from version control on the next commit"));
|
jtkorhonen@0
|
2079
|
Chris@61
|
2080 hgUpdateAct = new QAction(QIcon(":/images/update.png"), tr("Update"), this);
|
Chris@169
|
2081 hgUpdateAct->setStatusTip(tr("Update the working folder to the head of the current repository branch"));
|
jtkorhonen@0
|
2082
|
Chris@169
|
2083 //!!! needs to be modified when files selected
|
Chris@61
|
2084 hgCommitAct = new QAction(QIcon(":/images/commit.png"), tr("Commit"), this);
|
Chris@169
|
2085 hgCommitAct->setStatusTip(tr("Commit your changes to the local repository"));
|
jtkorhonen@0
|
2086
|
jtkorhonen@0
|
2087 hgMergeAct = new QAction(QIcon(":/images/merge.png"), tr("Merge"), this);
|
Chris@169
|
2088 hgMergeAct->setStatusTip(tr("Merge the two independent sets of changes in the local repository into the working folder"));
|
jtkorhonen@0
|
2089
|
jtkorhonen@0
|
2090 //Advanced actions
|
Chris@169
|
2091 //!!! needs to be modified for number
|
jtkorhonen@0
|
2092 hgAnnotateAct = new QAction(tr("Annotate"), this);
|
jtkorhonen@0
|
2093 hgAnnotateAct -> setStatusTip(tr("Show line-by-line version information for selected file"));
|
jtkorhonen@0
|
2094
|
Chris@182
|
2095 hgIgnoreAct = new QAction(tr("Edit .hgignore File"), this);
|
Chris@169
|
2096 hgIgnoreAct -> setStatusTip(tr("Edit the .hgignore file, containing the names of files that should be ignored by Mercurial"));
|
jtkorhonen@34
|
2097
|
Chris@182
|
2098 hgServeAct = new QAction(tr("Serve via HTTP"), this);
|
jtkorhonen@11
|
2099 hgServeAct -> setStatusTip(tr("Serve local repository via http for workgroup access"));
|
jtkorhonen@11
|
2100
|
jtkorhonen@0
|
2101 //Help actions
|
Chris@190
|
2102 aboutAct = new QAction(tr("About EasyMercurial"), this);
|
Chris@94
|
2103
|
Chris@94
|
2104 // Miscellaneous
|
Chris@199
|
2105 QShortcut *clearSelectionsShortcut = new QShortcut(Qt::Key_Escape, this);
|
Chris@199
|
2106 connect(clearSelectionsShortcut, SIGNAL(activated()),
|
Chris@199
|
2107 this, SLOT(clearSelections()));
|
jtkorhonen@0
|
2108 }
|
jtkorhonen@0
|
2109
|
jtkorhonen@0
|
2110 void MainWindow::createMenus()
|
jtkorhonen@0
|
2111 {
|
jtkorhonen@0
|
2112 fileMenu = menuBar()->addMenu(tr("File"));
|
Chris@169
|
2113
|
Chris@69
|
2114 fileMenu -> addAction(openAct);
|
Chris@182
|
2115 fileMenu -> addAction(changeRemoteRepoAct);
|
Chris@191
|
2116 fileMenu -> addSeparator();
|
Chris@191
|
2117
|
Chris@191
|
2118 advancedMenu = fileMenu->addMenu(tr("Advanced"));
|
Chris@191
|
2119
|
jtkorhonen@0
|
2120 fileMenu -> addAction(settingsAct);
|
Chris@191
|
2121
|
jtkorhonen@0
|
2122 fileMenu -> addSeparator();
|
jtkorhonen@0
|
2123 fileMenu -> addAction(exitAct);
|
jtkorhonen@0
|
2124
|
jtkorhonen@34
|
2125 advancedMenu -> addAction(hgIgnoreAct);
|
Chris@199
|
2126 advancedMenu -> addSeparator();
|
jtkorhonen@11
|
2127 advancedMenu -> addAction(hgServeAct);
|
jtkorhonen@0
|
2128
|
jtkorhonen@0
|
2129 helpMenu = menuBar()->addMenu(tr("Help"));
|
jtkorhonen@0
|
2130 helpMenu->addAction(aboutAct);
|
jtkorhonen@0
|
2131 }
|
jtkorhonen@0
|
2132
|
jtkorhonen@0
|
2133 void MainWindow::createToolBars()
|
jtkorhonen@0
|
2134 {
|
jtkorhonen@0
|
2135 fileToolBar = addToolBar(tr("File"));
|
jtkorhonen@0
|
2136 fileToolBar -> setIconSize(QSize(MY_ICON_SIZE, MY_ICON_SIZE));
|
Chris@69
|
2137 fileToolBar -> addAction(openAct);
|
Chris@120
|
2138 fileToolBar -> addAction(hgRefreshAct);
|
jtkorhonen@0
|
2139 fileToolBar -> addSeparator();
|
jtkorhonen@0
|
2140 fileToolBar -> setMovable(false);
|
jtkorhonen@0
|
2141
|
jtkorhonen@0
|
2142 repoToolBar = addToolBar(tr(REPOMENU_TITLE));
|
jtkorhonen@0
|
2143 repoToolBar -> setIconSize(QSize(MY_ICON_SIZE, MY_ICON_SIZE));
|
jtkorhonen@0
|
2144 repoToolBar->addAction(hgIncomingAct);
|
jtkorhonen@0
|
2145 repoToolBar->addAction(hgPullAct);
|
jtkorhonen@0
|
2146 repoToolBar->addAction(hgPushAct);
|
jtkorhonen@0
|
2147 repoToolBar -> setMovable(false);
|
jtkorhonen@0
|
2148
|
jtkorhonen@0
|
2149 workFolderToolBar = addToolBar(tr(WORKFOLDERMENU_TITLE));
|
jtkorhonen@0
|
2150 addToolBar(Qt::LeftToolBarArea, workFolderToolBar);
|
jtkorhonen@0
|
2151 workFolderToolBar -> setIconSize(QSize(MY_ICON_SIZE, MY_ICON_SIZE));
|
Chris@95
|
2152 workFolderToolBar->addAction(hgFolderDiffAct);
|
jtkorhonen@0
|
2153 workFolderToolBar->addSeparator();
|
jtkorhonen@0
|
2154 workFolderToolBar->addAction(hgRevertAct);
|
jtkorhonen@0
|
2155 workFolderToolBar->addAction(hgUpdateAct);
|
jtkorhonen@0
|
2156 workFolderToolBar->addAction(hgCommitAct);
|
jtkorhonen@0
|
2157 workFolderToolBar->addAction(hgMergeAct);
|
jtkorhonen@0
|
2158 workFolderToolBar->addSeparator();
|
jtkorhonen@0
|
2159 workFolderToolBar->addAction(hgAddAct);
|
jtkorhonen@0
|
2160 workFolderToolBar->addAction(hgRemoveAct);
|
jtkorhonen@0
|
2161 workFolderToolBar -> setMovable(false);
|
Chris@61
|
2162
|
Chris@61
|
2163 foreach (QToolButton *tb, findChildren<QToolButton *>()) {
|
Chris@61
|
2164 tb->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
|
Chris@61
|
2165 }
|
jtkorhonen@0
|
2166 }
|
jtkorhonen@0
|
2167
|
jtkorhonen@0
|
2168
|
jtkorhonen@0
|
2169 void MainWindow::createStatusBar()
|
jtkorhonen@0
|
2170 {
|
jtkorhonen@0
|
2171 statusBar()->showMessage(tr("Ready"));
|
jtkorhonen@0
|
2172 }
|
jtkorhonen@0
|
2173
|
Chris@69
|
2174
|
Chris@69
|
2175 //!!! review these:
|
Chris@69
|
2176
|
jtkorhonen@0
|
2177 void MainWindow::readSettings()
|
jtkorhonen@0
|
2178 {
|
jtkorhonen@0
|
2179 QDir workFolder;
|
jtkorhonen@0
|
2180
|
Chris@61
|
2181 QSettings settings;
|
jtkorhonen@0
|
2182
|
jtkorhonen@30
|
2183 remoteRepoPath = settings.value("remoterepopath", "").toString();
|
jtkorhonen@0
|
2184 workFolderPath = settings.value("workfolderpath", "").toString();
|
jtkorhonen@0
|
2185 if (!workFolder.exists(workFolderPath))
|
jtkorhonen@0
|
2186 {
|
jtkorhonen@0
|
2187 workFolderPath = "";
|
jtkorhonen@0
|
2188 }
|
jtkorhonen@0
|
2189
|
jtkorhonen@0
|
2190 QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
|
jtkorhonen@0
|
2191 QSize size = settings.value("size", QSize(400, 400)).toSize();
|
jtkorhonen@0
|
2192 firstStart = settings.value("firststart", QVariant(true)).toBool();
|
jtkorhonen@0
|
2193
|
Chris@109
|
2194 //!!! initialFileTypesBits = (unsigned char) settings.value("viewFileTypes", QVariant(DEFAULT_HG_STAT_BITS)).toInt();
|
jtkorhonen@0
|
2195 resize(size);
|
jtkorhonen@0
|
2196 move(pos);
|
jtkorhonen@0
|
2197 }
|
jtkorhonen@0
|
2198
|
jtkorhonen@17
|
2199
|
jtkorhonen@0
|
2200 void MainWindow::writeSettings()
|
jtkorhonen@0
|
2201 {
|
Chris@61
|
2202 QSettings settings;
|
jtkorhonen@0
|
2203 settings.setValue("pos", pos());
|
jtkorhonen@0
|
2204 settings.setValue("size", size());
|
jtkorhonen@0
|
2205 settings.setValue("remoterepopath", remoteRepoPath);
|
jtkorhonen@0
|
2206 settings.setValue("workfolderpath", workFolderPath);
|
jtkorhonen@0
|
2207 settings.setValue("firststart", firstStart);
|
Chris@98
|
2208 //!!!settings.setValue("viewFileTypes", hgTabs -> getFileTypesBits());
|
jtkorhonen@0
|
2209 }
|
jtkorhonen@0
|
2210
|
jtkorhonen@0
|
2211
|
jtkorhonen@0
|
2212
|
jtkorhonen@0
|
2213
|