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