13 from PyQt4.QtGui import QWidget, QDialogButtonBox, QMenu, QHeaderView, QTreeWidgetItem, \ |
13 from PyQt4.QtGui import QWidget, QDialogButtonBox, QMenu, QHeaderView, QTreeWidgetItem, \ |
14 QLineEdit |
14 QLineEdit |
15 |
15 |
16 from E5Gui.E5Application import e5App |
16 from E5Gui.E5Application import e5App |
17 from E5Gui import E5MessageBox |
17 from E5Gui import E5MessageBox |
|
18 |
|
19 from .HgDiffDialog import HgDiffDialog |
18 |
20 |
19 from .Ui_HgStatusDialog import Ui_HgStatusDialog |
21 from .Ui_HgStatusDialog import Ui_HgStatusDialog |
20 |
22 |
21 import Preferences |
23 import Preferences |
22 |
24 |
32 @param parent parent widget (QWidget) |
34 @param parent parent widget (QWidget) |
33 """ |
35 """ |
34 QWidget.__init__(self, parent) |
36 QWidget.__init__(self, parent) |
35 self.setupUi(self) |
37 self.setupUi(self) |
36 |
38 |
37 self.__statusColumn = 0 |
39 self.__toBeCommittedColumn = 0 |
38 self.__pathColumn = 1 |
40 self.__statusColumn = 1 |
|
41 self.__pathColumn = 2 |
39 self.__lastColumn = self.statusList.columnCount() |
42 self.__lastColumn = self.statusList.columnCount() |
40 |
43 |
41 self.refreshButton = \ |
44 self.refreshButton = \ |
42 self.buttonBox.addButton(self.trUtf8("Refresh"), QDialogButtonBox.ActionRole) |
45 self.buttonBox.addButton(self.trUtf8("Refresh"), QDialogButtonBox.ActionRole) |
43 self.refreshButton.setToolTip(self.trUtf8("Press to refresh the status display")) |
46 self.refreshButton.setToolTip(self.trUtf8("Press to refresh the status display")) |
44 self.refreshButton.setEnabled(False) |
47 self.refreshButton.setEnabled(False) |
45 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False) |
48 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False) |
46 self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True) |
49 self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True) |
47 |
50 |
|
51 self.diff = None |
48 self.process = None |
52 self.process = None |
49 self.vcs = vcs |
53 self.vcs = vcs |
50 self.vcs.committed.connect(self.__committed) |
54 self.vcs.committed.connect(self.__committed) |
51 |
55 |
52 self.statusList.headerItem().setText(self.__lastColumn, "") |
56 self.statusList.headerItem().setText(self.__lastColumn, "") |
58 self.trUtf8("Commit changes to repository..."), self.__commit)) |
62 self.trUtf8("Commit changes to repository..."), self.__commit)) |
59 self.menu.addSeparator() |
63 self.menu.addSeparator() |
60 self.menuactions.append(self.menu.addAction( |
64 self.menuactions.append(self.menu.addAction( |
61 self.trUtf8("Add to repository"), self.__add)) |
65 self.trUtf8("Add to repository"), self.__add)) |
62 self.menuactions.append(self.menu.addAction( |
66 self.menuactions.append(self.menu.addAction( |
|
67 self.trUtf8("Show differences"), self.__diff)) |
|
68 self.menuactions.append(self.menu.addAction( |
63 self.trUtf8("Remove from repository"), self.__forget)) |
69 self.trUtf8("Remove from repository"), self.__forget)) |
64 self.menuactions.append(self.menu.addAction( |
70 self.menuactions.append(self.menu.addAction( |
65 self.trUtf8("Revert changes"), self.__revert)) |
71 self.trUtf8("Revert changes"), self.__revert)) |
|
72 self.menuactions.append(self.menu.addAction( |
|
73 self.trUtf8("Restore missing"), self.__restoreMissing)) |
66 self.menu.addSeparator() |
74 self.menu.addSeparator() |
67 self.menuactions.append(self.menu.addAction(self.trUtf8("Adjust column sizes"), |
75 self.menuactions.append(self.menu.addAction(self.trUtf8("Adjust column sizes"), |
68 self.__resizeColumns)) |
76 self.__resizeColumns)) |
69 for act in self.menuactions: |
77 for act in self.menuactions: |
70 act.setEnabled(False) |
78 act.setEnabled(False) |
115 Private method to generate a status item in the status list. |
123 Private method to generate a status item in the status list. |
116 |
124 |
117 @param status status indicator (string) |
125 @param status status indicator (string) |
118 @param path path of the file or directory (string) |
126 @param path path of the file or directory (string) |
119 """ |
127 """ |
|
128 statusText = self.status[status] |
120 itm = QTreeWidgetItem(self.statusList, [ |
129 itm = QTreeWidgetItem(self.statusList, [ |
121 self.status[status], |
130 "", |
|
131 statusText, |
122 path, |
132 path, |
123 ]) |
133 ]) |
124 |
134 |
125 itm.setTextAlignment(0, Qt.AlignHCenter) |
135 itm.setTextAlignment(1, Qt.AlignHCenter) |
126 itm.setTextAlignment(1, Qt.AlignLeft) |
136 itm.setTextAlignment(2, Qt.AlignLeft) |
127 |
137 |
|
138 if status in "AMR": |
|
139 itm.setCheckState(self.__toBeCommittedColumn, Qt.Checked) |
|
140 |
|
141 if statusText not in self.__statusFilters: |
|
142 self.__statusFilters.append(statusText) |
|
143 |
128 def closeEvent(self, e): |
144 def closeEvent(self, e): |
129 """ |
145 """ |
130 Private slot implementing a close event handler. |
146 Private slot implementing a close event handler. |
131 |
147 |
132 @param e close event (QCloseEvent) |
148 @param e close event (QCloseEvent) |
147 (string or list of strings) |
163 (string or list of strings) |
148 """ |
164 """ |
149 self.errorGroup.hide() |
165 self.errorGroup.hide() |
150 self.intercept = False |
166 self.intercept = False |
151 self.args = fn |
167 self.args = fn |
|
168 |
|
169 for act in self.menuactions: |
|
170 act.setEnabled(False) |
|
171 |
|
172 self.addButton.setEnabled(False) |
|
173 self.commitButton.setEnabled(False) |
|
174 self.diffButton.setEnabled(False) |
|
175 self.revertButton.setEnabled(False) |
|
176 self.forgetButton.setEnabled(False) |
|
177 self.restoreButton.setEnabled(False) |
|
178 |
|
179 self.statusFilterCombo.clear() |
|
180 self.__statusFilters = [] |
152 |
181 |
153 if self.process: |
182 if self.process: |
154 self.process.kill() |
183 self.process.kill() |
155 else: |
184 else: |
156 self.process = QProcess() |
185 self.process = QProcess() |
213 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True) |
242 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True) |
214 self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False) |
243 self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False) |
215 self.buttonBox.button(QDialogButtonBox.Close).setDefault(True) |
244 self.buttonBox.button(QDialogButtonBox.Close).setDefault(True) |
216 self.buttonBox.button(QDialogButtonBox.Close).setFocus(Qt.OtherFocusReason) |
245 self.buttonBox.button(QDialogButtonBox.Close).setFocus(Qt.OtherFocusReason) |
217 |
246 |
|
247 self.__statusFilters.sort() |
|
248 self.__statusFilters.insert(0, "<{0}>".format(self.trUtf8("all"))) |
|
249 self.statusFilterCombo.addItems(self.__statusFilters) |
|
250 |
218 for act in self.menuactions: |
251 for act in self.menuactions: |
219 act.setEnabled(True) |
252 act.setEnabled(True) |
220 |
253 |
221 self.process = None |
254 self.process = None |
222 |
255 |
223 self.statusList.doItemsLayout() |
256 self.statusList.doItemsLayout() |
224 self.__resort() |
257 self.__resort() |
225 self.__resizeColumns() |
258 self.__resizeColumns() |
|
259 |
|
260 self.__updateButtons() |
|
261 self.__updateCommitButton() |
226 |
262 |
227 def on_buttonBox_clicked(self, button): |
263 def on_buttonBox_clicked(self, button): |
228 """ |
264 """ |
229 Private slot called by a button of the button box clicked. |
265 Private slot called by a button of the button box clicked. |
230 |
266 |
340 |
376 |
341 self.inputGroup.setEnabled(True) |
377 self.inputGroup.setEnabled(True) |
342 self.inputGroup.show() |
378 self.inputGroup.show() |
343 self.refreshButton.setEnabled(False) |
379 self.refreshButton.setEnabled(False) |
344 |
380 |
345 for act in self.menuactions: |
|
346 act.setEnabled(False) |
|
347 |
|
348 self.statusList.clear() |
381 self.statusList.clear() |
349 |
382 |
350 self.start(self.args) |
383 self.start(self.args) |
|
384 |
|
385 def __updateButtons(self): |
|
386 """ |
|
387 Private method to update the VCS buttons status. |
|
388 """ |
|
389 modified = len(self.__getModifiedItems()) |
|
390 unversioned = len(self.__getUnversionedItems()) |
|
391 missing = len(self.__getMissingItems()) |
|
392 |
|
393 self.addButton.setEnabled(unversioned) |
|
394 self.diffButton.setEnabled(modified) |
|
395 self.revertButton.setEnabled(modified) |
|
396 self.forgetButton.setEnabled(missing) |
|
397 self.restoreButton.setEnabled(missing) |
|
398 |
|
399 def __updateCommitButton(self): |
|
400 """ |
|
401 Private method to update the Commit button status. |
|
402 """ |
|
403 commitable = len(self.__getCommitableItems()) |
|
404 self.commitButton.setEnabled(commitable) |
|
405 |
|
406 @pyqtSlot(str) |
|
407 def on_statusFilterCombo_activated(self, txt): |
|
408 """ |
|
409 Private slot to react to the selection of a status filter. |
|
410 |
|
411 @param txt selected status filter (string) |
|
412 """ |
|
413 if txt == "<{0}>".format(self.trUtf8("all")): |
|
414 for topIndex in range(self.statusList.topLevelItemCount()): |
|
415 topItem = self.statusList.topLevelItem(topIndex) |
|
416 topItem.setHidden(False) |
|
417 else: |
|
418 for topIndex in range(self.statusList.topLevelItemCount()): |
|
419 topItem = self.statusList.topLevelItem(topIndex) |
|
420 topItem.setHidden(topItem.text(self.__statusColumn) != txt) |
|
421 |
|
422 @pyqtSlot(QTreeWidgetItem, int) |
|
423 def on_statusList_itemChanged(self, item, column): |
|
424 """ |
|
425 Private slot to act upon item changes. |
|
426 |
|
427 @param item reference to the changed item (QTreeWidgetItem) |
|
428 @param column index of column that changed (integer) |
|
429 """ |
|
430 if column == self.__toBeCommittedColumn: |
|
431 self.__updateCommitButton() |
|
432 |
|
433 @pyqtSlot() |
|
434 def on_statusList_itemSelectionChanged(self): |
|
435 """ |
|
436 Private slot to act upon changes of selected items. |
|
437 """ |
|
438 self.__updateButtons() |
|
439 |
|
440 @pyqtSlot() |
|
441 def on_commitButton_clicked(self): |
|
442 """ |
|
443 Private slot to handle the press of the Commit button. |
|
444 """ |
|
445 self.__commit() |
|
446 |
|
447 @pyqtSlot() |
|
448 def on_addButton_clicked(self): |
|
449 """ |
|
450 Private slot to handle the press of the Add button. |
|
451 """ |
|
452 self.__add() |
|
453 |
|
454 @pyqtSlot() |
|
455 def on_diffButton_clicked(self): |
|
456 """ |
|
457 Private slot to handle the press of the Differences button. |
|
458 """ |
|
459 self.__diff() |
|
460 |
|
461 @pyqtSlot() |
|
462 def on_revertButton_clicked(self): |
|
463 """ |
|
464 Private slot to handle the press of the Revert button. |
|
465 """ |
|
466 self.__revert() |
|
467 |
|
468 @pyqtSlot() |
|
469 def on_forgetButton_clicked(self): |
|
470 """ |
|
471 Private slot to handle the press of the Forget button. |
|
472 """ |
|
473 self.__forget() |
|
474 |
|
475 @pyqtSlot() |
|
476 def on_restoreButton_clicked(self): |
|
477 """ |
|
478 Private slot to handle the press of the Restore button. |
|
479 """ |
|
480 self.__restoreMissing() |
351 |
481 |
352 ############################################################################ |
482 ############################################################################ |
353 ## Context menu handling methods |
483 ## Context menu handling methods |
354 ############################################################################ |
484 ############################################################################ |
355 |
485 |
364 def __commit(self): |
494 def __commit(self): |
365 """ |
495 """ |
366 Private slot to handle the Commit context menu entry. |
496 Private slot to handle the Commit context menu entry. |
367 """ |
497 """ |
368 names = [os.path.join(self.dname, itm.text(self.__pathColumn)) \ |
498 names = [os.path.join(self.dname, itm.text(self.__pathColumn)) \ |
369 for itm in self.__getModifiedItems()] |
499 for itm in self.__getCommitableItems()] |
370 if not names: |
500 if not names: |
371 E5MessageBox.information(self, |
501 E5MessageBox.information(self, |
372 self.trUtf8("Commit"), |
502 self.trUtf8("Commit"), |
373 self.trUtf8("""There are no uncommitted changes available/selected.""")) |
503 self.trUtf8("""There are no entries selected to be""" |
|
504 """ committed.""")) |
374 return |
505 return |
375 |
506 |
376 if Preferences.getVCS("AutoSaveFiles"): |
507 if Preferences.getVCS("AutoSaveFiles"): |
377 vm = e5App().getObject("ViewManager") |
508 vm = e5App().getObject("ViewManager") |
378 for name in names: |
509 for name in names: |
394 names = [os.path.join(self.dname, itm.text(self.__pathColumn)) \ |
525 names = [os.path.join(self.dname, itm.text(self.__pathColumn)) \ |
395 for itm in self.__getUnversionedItems()] |
526 for itm in self.__getUnversionedItems()] |
396 if not names: |
527 if not names: |
397 E5MessageBox.information(self, |
528 E5MessageBox.information(self, |
398 self.trUtf8("Add"), |
529 self.trUtf8("Add"), |
399 self.trUtf8("""There are no unversioned entries available/selected.""")) |
530 self.trUtf8("""There are no unversioned entries""" |
|
531 """ available/selected.""")) |
400 return |
532 return |
401 |
533 |
402 self.vcs.vcsAdd(names) |
534 self.vcs.vcsAdd(names) |
403 self.on_refreshButton_clicked() |
535 self.on_refreshButton_clicked() |
404 |
536 |
414 names = [os.path.join(self.dname, itm.text(self.__pathColumn)) \ |
546 names = [os.path.join(self.dname, itm.text(self.__pathColumn)) \ |
415 for itm in self.__getMissingItems()] |
547 for itm in self.__getMissingItems()] |
416 if not names: |
548 if not names: |
417 E5MessageBox.information(self, |
549 E5MessageBox.information(self, |
418 self.trUtf8("Remove"), |
550 self.trUtf8("Remove"), |
419 self.trUtf8("""There are no missing entries available/selected.""")) |
551 self.trUtf8("""There are no missing entries""" |
|
552 """ available/selected.""")) |
420 return |
553 return |
421 |
554 |
422 self.vcs.hgForget(names) |
555 self.vcs.hgForget(names) |
423 self.on_refreshButton_clicked() |
556 self.on_refreshButton_clicked() |
424 |
557 |
429 names = [os.path.join(self.dname, itm.text(self.__pathColumn)) \ |
562 names = [os.path.join(self.dname, itm.text(self.__pathColumn)) \ |
430 for itm in self.__getModifiedItems()] |
563 for itm in self.__getModifiedItems()] |
431 if not names: |
564 if not names: |
432 E5MessageBox.information(self, |
565 E5MessageBox.information(self, |
433 self.trUtf8("Revert"), |
566 self.trUtf8("Revert"), |
434 self.trUtf8("""There are no uncommitted changes available/selected.""")) |
567 self.trUtf8("""There are no uncommitted changes""" |
|
568 """ available/selected.""")) |
435 return |
569 return |
436 |
570 |
437 self.vcs.vcsRevert(names) |
571 self.vcs.vcsRevert(names) |
438 self.on_refreshButton_clicked() |
572 self.on_refreshButton_clicked() |
439 |
573 |
440 project = e5App().getObject("Project") |
574 project = e5App().getObject("Project") |
441 for name in names: |
575 for name in names: |
442 project.getModel().updateVCSStatus(name) |
576 project.getModel().updateVCSStatus(name) |
443 self.vcs.checkVCSStatus() |
577 self.vcs.checkVCSStatus() |
|
578 |
|
579 def __restoreMissing(self): |
|
580 """ |
|
581 Private slot to handle the Restore Missing context menu entry. |
|
582 """ |
|
583 names = [os.path.join(self.dname, itm.text(self.__pathColumn)) |
|
584 for itm in self.__getMissingItems()] |
|
585 if not names: |
|
586 E5MessageBox.information(self, |
|
587 self.trUtf8("Revert"), |
|
588 self.trUtf8("""There are no missing entries""" |
|
589 """ available/selected.""")) |
|
590 return |
|
591 |
|
592 self.vcs.vcsRevert(names) |
|
593 self.on_refreshButton_clicked() |
|
594 self.vcs.checkVCSStatus() |
|
595 |
|
596 def __diff(self): |
|
597 """ |
|
598 Private slot to handle the Diff context menu entry. |
|
599 """ |
|
600 names = [os.path.join(self.dname, itm.text(self.__pathColumn)) |
|
601 for itm in self.__getModifiedItems()] |
|
602 if not names: |
|
603 E5MessageBox.information(self, |
|
604 self.trUtf8("Differences"), |
|
605 self.trUtf8("""There are no uncommitted changes""" |
|
606 """ available/selected.""")) |
|
607 return |
|
608 |
|
609 if self.diff is None: |
|
610 self.diff = HgDiffDialog(self.vcs) |
|
611 self.diff.show() |
|
612 self.diff.start(names) |
|
613 |
|
614 def __getCommitableItems(self): |
|
615 """ |
|
616 Private method to retrieve all entries the user wants to commit. |
|
617 |
|
618 @return list of all items, the user has checked |
|
619 """ |
|
620 commitableItems = [] |
|
621 for index in range(self.statusList.topLevelItemCount()): |
|
622 itm = self.statusList.topLevelItem(index) |
|
623 if itm.checkState(self.__toBeCommittedColumn) == Qt.Checked: |
|
624 commitableItems.append(itm) |
|
625 return commitableItems |
444 |
626 |
445 def __getModifiedItems(self): |
627 def __getModifiedItems(self): |
446 """ |
628 """ |
447 Private method to retrieve all entries, that have a modified status. |
629 Private method to retrieve all entries, that have a modified status. |
448 |
630 |