18 from E5Gui.E5Application import e5App |
18 from E5Gui.E5Application import e5App |
19 from E5Gui import E5MessageBox |
19 from E5Gui import E5MessageBox |
20 |
20 |
21 from .SvnConst import svnStatusMap |
21 from .SvnConst import svnStatusMap |
22 from .SvnDialogMixin import SvnDialogMixin |
22 from .SvnDialogMixin import SvnDialogMixin |
|
23 from .SvnDiffDialog import SvnDiffDialog |
|
24 |
23 from .Ui_SvnStatusDialog import Ui_SvnStatusDialog |
25 from .Ui_SvnStatusDialog import Ui_SvnStatusDialog |
24 |
26 |
25 import Preferences |
27 import Preferences |
26 |
28 |
27 class SvnStatusDialog(QWidget, SvnDialogMixin, Ui_SvnStatusDialog): |
29 class SvnStatusDialog(QWidget, SvnDialogMixin, Ui_SvnStatusDialog): |
38 """ |
40 """ |
39 QWidget.__init__(self, parent) |
41 QWidget.__init__(self, parent) |
40 self.setupUi(self) |
42 self.setupUi(self) |
41 SvnDialogMixin.__init__(self) |
43 SvnDialogMixin.__init__(self) |
42 |
44 |
43 self.__changelistColumn = 0 |
45 self.__toBeCommittedColumn = 0 |
44 self.__statusColumn = 1 |
46 self.__changelistColumn = 1 |
45 self.__propStatusColumn = 2 |
47 self.__statusColumn = 2 |
46 self.__lockedColumn = 3 |
48 self.__propStatusColumn = 3 |
47 self.__historyColumn = 4 |
49 self.__lockedColumn = 4 |
48 self.__switchedColumn = 5 |
50 self.__historyColumn = 5 |
49 self.__lockinfoColumn = 6 |
51 self.__switchedColumn = 6 |
50 self.__upToDateColumn = 7 |
52 self.__lockinfoColumn = 7 |
51 self.__pathColumn = 11 |
53 self.__upToDateColumn = 8 |
|
54 self.__pathColumn = 12 |
52 self.__lastColumn = self.statusList.columnCount() |
55 self.__lastColumn = self.statusList.columnCount() |
53 |
56 |
54 self.refreshButton = \ |
57 self.refreshButton = \ |
55 self.buttonBox.addButton(self.trUtf8("Refresh"), |
58 self.buttonBox.addButton(self.trUtf8("Refresh"), |
56 QDialogButtonBox.ActionRole) |
59 QDialogButtonBox.ActionRole) |
58 self.trUtf8("Press to refresh the status display")) |
61 self.trUtf8("Press to refresh the status display")) |
59 self.refreshButton.setEnabled(False) |
62 self.refreshButton.setEnabled(False) |
60 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False) |
63 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False) |
61 self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True) |
64 self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True) |
62 |
65 |
|
66 self.diff = None |
63 self.vcs = vcs |
67 self.vcs = vcs |
64 self.vcs.committed.connect(self.__committed) |
68 self.vcs.committed.connect(self.__committed) |
65 |
69 |
66 self.statusList.headerItem().setText(self.__lastColumn, "") |
70 self.statusList.headerItem().setText(self.__lastColumn, "") |
67 self.statusList.header().setSortIndicator(self.__pathColumn, |
71 self.statusList.header().setSortIndicator(self.__pathColumn, |
75 self.trUtf8("Commit changes to repository..."), self.__commit)) |
79 self.trUtf8("Commit changes to repository..."), self.__commit)) |
76 self.menu.addSeparator() |
80 self.menu.addSeparator() |
77 self.menuactions.append(self.menu.addAction( |
81 self.menuactions.append(self.menu.addAction( |
78 self.trUtf8("Add to repository"), self.__add)) |
82 self.trUtf8("Add to repository"), self.__add)) |
79 self.menuactions.append(self.menu.addAction( |
83 self.menuactions.append(self.menu.addAction( |
|
84 self.trUtf8("Show differences"), self.__diff)) |
|
85 self.menuactions.append(self.menu.addAction( |
80 self.trUtf8("Revert changes"), self.__revert)) |
86 self.trUtf8("Revert changes"), self.__revert)) |
|
87 self.menuactions.append(self.menu.addAction( |
|
88 self.trUtf8("Restore missing"), self.__restoreMissing)) |
81 if pysvn.svn_version >= (1, 5, 0) and pysvn.version >= (1, 6, 0): |
89 if pysvn.svn_version >= (1, 5, 0) and pysvn.version >= (1, 6, 0): |
82 self.menu.addSeparator() |
90 self.menu.addSeparator() |
83 self.menuactions.append(self.menu.addAction( |
91 self.menuactions.append(self.menu.addAction( |
84 self.trUtf8("Add to Changelist"), self.__addToChangelist)) |
92 self.trUtf8("Add to Changelist"), self.__addToChangelist)) |
85 self.menuactions.append(self.menu.addAction( |
93 self.menuactions.append(self.menu.addAction( |
112 self.trUtf8(svnStatusMap[pysvn.wc_status_kind.added]), |
120 self.trUtf8(svnStatusMap[pysvn.wc_status_kind.added]), |
113 self.trUtf8(svnStatusMap[pysvn.wc_status_kind.deleted]), |
121 self.trUtf8(svnStatusMap[pysvn.wc_status_kind.deleted]), |
114 self.trUtf8(svnStatusMap[pysvn.wc_status_kind.modified]) |
122 self.trUtf8(svnStatusMap[pysvn.wc_status_kind.modified]) |
115 ] |
123 ] |
116 |
124 |
|
125 self.missingIndicators = [ |
|
126 self.trUtf8(svnStatusMap[pysvn.wc_status_kind.missing]), |
|
127 ] |
|
128 |
117 self.unversionedIndicators = [ |
129 self.unversionedIndicators = [ |
118 self.trUtf8(svnStatusMap[pysvn.wc_status_kind.unversioned]) |
130 self.trUtf8(svnStatusMap[pysvn.wc_status_kind.unversioned]), |
119 ] |
131 ] |
120 |
132 |
121 self.lockedIndicators = [ |
133 self.lockedIndicators = [ |
122 self.trUtf8('locked') |
134 self.trUtf8('locked'), |
123 ] |
135 ] |
124 |
136 |
125 self.stealBreakLockIndicators = [ |
137 self.stealBreakLockIndicators = [ |
126 self.trUtf8('other lock'), |
138 self.trUtf8('other lock'), |
127 self.trUtf8('stolen lock'), |
139 self.trUtf8('stolen lock'), |
128 self.trUtf8('broken lock') |
140 self.trUtf8('broken lock'), |
129 ] |
141 ] |
130 |
142 |
131 self.unlockedIndicators = [ |
143 self.unlockedIndicators = [ |
132 self.trUtf8('not locked') |
144 self.trUtf8('not locked'), |
133 ] |
145 ] |
134 |
146 |
135 self.lockinfo = { |
147 self.lockinfo = { |
136 ' ' : self.trUtf8('not locked'), |
148 ' ' : self.trUtf8('not locked'), |
137 'L' : self.trUtf8('locked'), |
149 'L' : self.trUtf8('locked'), |
186 @param revision revision (integer) |
198 @param revision revision (integer) |
187 @param change revision of last change (integer) |
199 @param change revision of last change (integer) |
188 @param author author of the last change (string) |
200 @param author author of the last change (string) |
189 @param path path of the file or directory (string) |
201 @param path path of the file or directory (string) |
190 """ |
202 """ |
|
203 statusText = self.trUtf8(svnStatusMap[status]) |
191 itm = QTreeWidgetItem(self.statusList, [ |
204 itm = QTreeWidgetItem(self.statusList, [ |
|
205 "", |
192 changelist, |
206 changelist, |
193 self.trUtf8(svnStatusMap[status]), |
207 statusText, |
194 self.trUtf8(svnStatusMap[propStatus]), |
208 self.trUtf8(svnStatusMap[propStatus]), |
195 self.yesno[locked], |
209 self.yesno[locked], |
196 self.yesno[history], |
210 self.yesno[history], |
197 self.yesno[switched], |
211 self.yesno[switched], |
198 self.lockinfo[lockinfo], |
212 self.lockinfo[lockinfo], |
201 "{0:7}".format(str(change)), |
215 "{0:7}".format(str(change)), |
202 author, |
216 author, |
203 path, |
217 path, |
204 ]) |
218 ]) |
205 |
219 |
206 itm.setTextAlignment(0, Qt.AlignLeft) |
220 itm.setTextAlignment(1, Qt.AlignLeft) |
207 itm.setTextAlignment(1, Qt.AlignHCenter) |
|
208 itm.setTextAlignment(2, Qt.AlignHCenter) |
221 itm.setTextAlignment(2, Qt.AlignHCenter) |
209 itm.setTextAlignment(3, Qt.AlignHCenter) |
222 itm.setTextAlignment(3, Qt.AlignHCenter) |
210 itm.setTextAlignment(4, Qt.AlignHCenter) |
223 itm.setTextAlignment(4, Qt.AlignHCenter) |
211 itm.setTextAlignment(5, Qt.AlignHCenter) |
224 itm.setTextAlignment(5, Qt.AlignHCenter) |
212 itm.setTextAlignment(6, Qt.AlignHCenter) |
225 itm.setTextAlignment(6, Qt.AlignHCenter) |
213 itm.setTextAlignment(7, Qt.AlignHCenter) |
226 itm.setTextAlignment(7, Qt.AlignHCenter) |
214 itm.setTextAlignment(8, Qt.AlignRight) |
227 itm.setTextAlignment(8, Qt.AlignHCenter) |
215 itm.setTextAlignment(9, Qt.AlignRight) |
228 itm.setTextAlignment(9, Qt.AlignRight) |
216 itm.setTextAlignment(10, Qt.AlignLeft) |
229 itm.setTextAlignment(10, Qt.AlignRight) |
217 itm.setTextAlignment(11, Qt.AlignLeft) |
230 itm.setTextAlignment(11, Qt.AlignLeft) |
|
231 itm.setTextAlignment(12, Qt.AlignLeft) |
|
232 |
|
233 if status in [pysvn.wc_status_kind.added, |
|
234 pysvn.wc_status_kind.deleted, |
|
235 pysvn.wc_status_kind.modified] or \ |
|
236 propStatus in [pysvn.wc_status_kind.added, |
|
237 pysvn.wc_status_kind.deleted, |
|
238 pysvn.wc_status_kind.modified]: |
|
239 itm.setCheckState(self.__toBeCommittedColumn, Qt.Checked) |
|
240 |
|
241 if statusText not in self.__statusFilters: |
|
242 self.__statusFilters.append(statusText) |
218 |
243 |
219 def start(self, fn): |
244 def start(self, fn): |
220 """ |
245 """ |
221 Public slot to start the svn status command. |
246 Public slot to start the svn status command. |
222 |
247 |
223 @param fn filename(s)/directoryname(s) to show the status of |
248 @param fn filename(s)/directoryname(s) to show the status of |
224 (string or list of strings) |
249 (string or list of strings) |
225 """ |
250 """ |
226 self.errorGroup.hide() |
251 self.errorGroup.hide() |
|
252 |
|
253 for act in self.menuactions: |
|
254 act.setEnabled(False) |
|
255 |
|
256 self.addButton.setEnabled(False) |
|
257 self.commitButton.setEnabled(False) |
|
258 self.diffButton.setEnabled(False) |
|
259 self.revertButton.setEnabled(False) |
|
260 self.restoreButton.setEnabled(False) |
|
261 |
|
262 self.statusFilterCombo.clear() |
|
263 self.__statusFilters = [] |
227 |
264 |
228 QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) |
265 QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) |
229 QApplication.processEvents() |
266 QApplication.processEvents() |
230 |
267 |
231 self.args = fn |
268 self.args = fn |
243 opts = self.vcs.options['global'] + self.vcs.options['status'] |
280 opts = self.vcs.options['global'] + self.vcs.options['status'] |
244 verbose = "--verbose" in opts |
281 verbose = "--verbose" in opts |
245 recurse = "--non-recursive" not in opts |
282 recurse = "--non-recursive" not in opts |
246 update = "--show-updates" in opts |
283 update = "--show-updates" in opts |
247 |
284 |
|
285 hideChangelistColumn = True |
248 hidePropertyStatusColumn = True |
286 hidePropertyStatusColumn = True |
249 hideLockColumns = True |
287 hideLockColumns = True |
250 hideUpToDateColumn = True |
288 hideUpToDateColumn = True |
251 hideHistoryColumn = True |
289 hideHistoryColumn = True |
252 hideSwitchedColumn = True |
290 hideSwitchedColumn = True |
264 else: |
302 else: |
265 depth = pysvn.depth.immediate |
303 depth = pysvn.depth.immediate |
266 changelists = self.client.get_changelist(name, depth=depth) |
304 changelists = self.client.get_changelist(name, depth=depth) |
267 for entry in changelists: |
305 for entry in changelists: |
268 changelistsDict[entry[0]] = entry[1] |
306 changelistsDict[entry[0]] = entry[1] |
269 self.statusList.setColumnHidden(self.__changelistColumn, |
307 hideChangelistColumn = hideChangelistColumn and \ |
270 len(changelistsDict) == 0) |
308 len(changelistsDict) == 0 |
271 |
309 |
272 # step 2: determine status of files |
310 # step 2: determine status of files |
273 allFiles = self.client.status(name, recurse = recurse, |
311 allFiles = self.client.status(name, recurse = recurse, |
274 get_all=verbose, ignore=True, |
312 get_all=verbose, ignore=True, |
275 update = update) |
313 update = update) |
368 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True) |
408 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True) |
369 self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False) |
409 self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False) |
370 self.buttonBox.button(QDialogButtonBox.Close).setDefault(True) |
410 self.buttonBox.button(QDialogButtonBox.Close).setDefault(True) |
371 |
411 |
372 self.refreshButton.setEnabled(True) |
412 self.refreshButton.setEnabled(True) |
|
413 self.__updateButtons() |
|
414 self.__updateCommitButton() |
|
415 |
|
416 self.__statusFilters.sort() |
|
417 self.__statusFilters.insert(0, "<{0}>".format(self.trUtf8("all"))) |
|
418 self.statusFilterCombo.addItems(self.__statusFilters) |
373 |
419 |
374 for act in self.menuactions: |
420 for act in self.menuactions: |
375 act.setEnabled(True) |
421 act.setEnabled(True) |
376 |
422 |
377 self.statusList.doItemsLayout() |
423 self.statusList.doItemsLayout() |
420 """ |
463 """ |
421 self.errorGroup.show() |
464 self.errorGroup.show() |
422 self.errors.insertPlainText(msg) |
465 self.errors.insertPlainText(msg) |
423 self.errors.ensureCursorVisible() |
466 self.errors.ensureCursorVisible() |
424 |
467 |
|
468 def __updateButtons(self): |
|
469 """ |
|
470 Private method to update the VCS buttons status. |
|
471 """ |
|
472 modified = len(self.__getModifiedItems()) |
|
473 unversioned = len(self.__getUnversionedItems()) |
|
474 missing = len(self.__getMissingItems()) |
|
475 |
|
476 self.addButton.setEnabled(unversioned) |
|
477 self.diffButton.setEnabled(modified) |
|
478 self.revertButton.setEnabled(modified) |
|
479 self.restoreButton.setEnabled(missing) |
|
480 |
|
481 def __updateCommitButton(self): |
|
482 """ |
|
483 Private method to update the Commit button status. |
|
484 """ |
|
485 commitable = len(self.__getCommitableItems()) |
|
486 self.commitButton.setEnabled(commitable) |
|
487 |
|
488 @pyqtSlot(str) |
|
489 def on_statusFilterCombo_activated(self, txt): |
|
490 """ |
|
491 Private slot to react to the selection of a status filter. |
|
492 |
|
493 @param txt selected status filter (string) |
|
494 """ |
|
495 if txt == "<{0}>".format(self.trUtf8("all")): |
|
496 for topIndex in range(self.statusList.topLevelItemCount()): |
|
497 topItem = self.statusList.topLevelItem(topIndex) |
|
498 topItem.setHidden(False) |
|
499 else: |
|
500 for topIndex in range(self.statusList.topLevelItemCount()): |
|
501 topItem = self.statusList.topLevelItem(topIndex) |
|
502 topItem.setHidden(topItem.text(self.__statusColumn) != txt) |
|
503 |
|
504 @pyqtSlot(QTreeWidgetItem, int) |
|
505 def on_statusList_itemChanged(self, item, column): |
|
506 """ |
|
507 Private slot to act upon item changes. |
|
508 |
|
509 @param item reference to the changed item (QTreeWidgetItem) |
|
510 @param column index of column that changed (integer) |
|
511 """ |
|
512 if column == self.__toBeCommittedColumn: |
|
513 self.__updateCommitButton() |
|
514 |
|
515 @pyqtSlot() |
|
516 def on_statusList_itemSelectionChanged(self): |
|
517 """ |
|
518 Private slot to act upon changes of selected items. |
|
519 """ |
|
520 self.__updateButtons() |
|
521 |
|
522 @pyqtSlot() |
|
523 def on_commitButton_clicked(self): |
|
524 """ |
|
525 Private slot to handle the press of the Commit button. |
|
526 """ |
|
527 self.__commit() |
|
528 |
|
529 @pyqtSlot() |
|
530 def on_addButton_clicked(self): |
|
531 """ |
|
532 Private slot to handle the press of the Add button. |
|
533 """ |
|
534 self.__add() |
|
535 |
|
536 @pyqtSlot() |
|
537 def on_diffButton_clicked(self): |
|
538 """ |
|
539 Private slot to handle the press of the Differences button. |
|
540 """ |
|
541 self.__diff() |
|
542 |
|
543 @pyqtSlot() |
|
544 def on_revertButton_clicked(self): |
|
545 """ |
|
546 Private slot to handle the press of the Revert button. |
|
547 """ |
|
548 self.__revert() |
|
549 |
|
550 @pyqtSlot() |
|
551 def on_restoreButton_clicked(self): |
|
552 """ |
|
553 Private slot to handle the press of the Restore button. |
|
554 """ |
|
555 self.__restoreMissing() |
|
556 |
425 ########################################################################### |
557 ########################################################################### |
426 ## Context menu handling methods |
558 ## Context menu handling methods |
427 ########################################################################### |
559 ########################################################################### |
428 |
560 |
429 def __showContextMenu(self, coord): |
561 def __showContextMenu(self, coord): |
436 |
568 |
437 def __commit(self): |
569 def __commit(self): |
438 """ |
570 """ |
439 Private slot to handle the Commit context menu entry. |
571 Private slot to handle the Commit context menu entry. |
440 """ |
572 """ |
441 names = [os.path.join(self.dname, itm.text(self.__pathColumn)) \ |
573 names = [os.path.join(self.dname, itm.text(self.__pathColumn)) |
442 for itm in self.__getModifiedItems()] |
574 for itm in self.__getCommitableItems()] |
443 if not names: |
575 if not names: |
444 E5MessageBox.information(self, |
576 E5MessageBox.information(self, |
445 self.trUtf8("Commit"), |
577 self.trUtf8("Commit"), |
446 self.trUtf8("""There are no uncommitted changes""" |
578 self.trUtf8("""There are no entries selected to be""" |
447 """ available/selected.""")) |
579 """ committed.""")) |
448 return |
580 return |
449 |
581 |
450 if Preferences.getVCS("AutoSaveFiles"): |
582 if Preferences.getVCS("AutoSaveFiles"): |
451 vm = e5App().getObject("ViewManager") |
583 vm = e5App().getObject("ViewManager") |
452 for name in names: |
584 for name in names: |
501 project = e5App().getObject("Project") |
633 project = e5App().getObject("Project") |
502 for name in names: |
634 for name in names: |
503 project.getModel().updateVCSStatus(name) |
635 project.getModel().updateVCSStatus(name) |
504 self.vcs.checkVCSStatus() |
636 self.vcs.checkVCSStatus() |
505 |
637 |
|
638 def __restoreMissing(self): |
|
639 """ |
|
640 Private slot to handle the Restore Missing context menu entry. |
|
641 """ |
|
642 names = [os.path.join(self.dname, itm.text(self.__pathColumn)) |
|
643 for itm in self.__getMissingItems()] |
|
644 if not names: |
|
645 E5MessageBox.information(self, |
|
646 self.trUtf8("Revert"), |
|
647 self.trUtf8("""There are no missing entries""" |
|
648 """ available/selected.""")) |
|
649 return |
|
650 |
|
651 self.vcs.vcsRevert(names) |
|
652 self.on_refreshButton_clicked() |
|
653 self.vcs.checkVCSStatus() |
|
654 |
|
655 def __diff(self): |
|
656 """ |
|
657 Private slot to handle the Diff context menu entry. |
|
658 """ |
|
659 names = [os.path.join(self.dname, itm.text(self.__pathColumn)) |
|
660 for itm in self.__getModifiedItems()] |
|
661 if not names: |
|
662 E5MessageBox.information(self, |
|
663 self.trUtf8("Differences"), |
|
664 self.trUtf8("""There are no uncommitted changes""" |
|
665 """ available/selected.""")) |
|
666 return |
|
667 |
|
668 if self.diff is None: |
|
669 self.diff = SvnDiffDialog(self.vcs) |
|
670 self.diff.show() |
|
671 QApplication.processEvents() |
|
672 self.diff.start(names) |
|
673 |
506 def __lock(self): |
674 def __lock(self): |
507 """ |
675 """ |
508 Private slot to handle the Lock context menu entry. |
676 Private slot to handle the Lock context menu entry. |
509 """ |
677 """ |
510 names = [os.path.join(self.dname, itm.text(self.__pathColumn)) \ |
678 names = [os.path.join(self.dname, itm.text(self.__pathColumn)) \ |
603 ) |
771 ) |
604 return |
772 return |
605 self.vcs.svnRemoveFromChangelist(names) |
773 self.vcs.svnRemoveFromChangelist(names) |
606 self.on_refreshButton_clicked() |
774 self.on_refreshButton_clicked() |
607 |
775 |
|
776 def __getCommitableItems(self): |
|
777 """ |
|
778 Private method to retrieve all entries the user wants to commit. |
|
779 |
|
780 @return list of all items, the user has checked |
|
781 """ |
|
782 commitableItems = [] |
|
783 for index in range(self.statusList.topLevelItemCount()): |
|
784 itm = self.statusList.topLevelItem(index) |
|
785 if itm.checkState(self.__toBeCommittedColumn) == Qt.Checked: |
|
786 commitableItems.append(itm) |
|
787 return commitableItems |
|
788 |
608 def __getModifiedItems(self): |
789 def __getModifiedItems(self): |
609 """ |
790 """ |
610 Private method to retrieve all entries, that have a modified status. |
791 Private method to retrieve all entries, that have a modified status. |
611 |
792 |
612 @return list of all items with a modified status |
793 @return list of all items with a modified status |
629 for itm in self.statusList.selectedItems(): |
810 for itm in self.statusList.selectedItems(): |
630 if itm.text(self.__statusColumn) in self.unversionedIndicators: |
811 if itm.text(self.__statusColumn) in self.unversionedIndicators: |
631 unversionedItems.append(itm) |
812 unversionedItems.append(itm) |
632 return unversionedItems |
813 return unversionedItems |
633 |
814 |
|
815 def __getMissingItems(self): |
|
816 """ |
|
817 Private method to retrieve all entries, that have a missing status. |
|
818 |
|
819 @return list of all items with a missing status |
|
820 """ |
|
821 missingItems = [] |
|
822 for itm in self.statusList.selectedItems(): |
|
823 if itm.text(self.__statusColumn) in self.missingIndicators: |
|
824 missingItems.append(itm) |
|
825 return missingItems |
|
826 |
634 def __getLockActionItems(self, indicators): |
827 def __getLockActionItems(self, indicators): |
635 """ |
828 """ |
636 Private method to retrieve all entries, that have a locked status. |
829 Private method to retrieve all entries, that have a locked status. |
637 |
830 |
638 @return list of all items with a locked status |
831 @return list of all items with a locked status |