diff -r 37089cbeb1b9 -r e07d1df4c64a Plugins/VcsPlugins/vcsMercurial/HgStatusDialog.py --- a/Plugins/VcsPlugins/vcsMercurial/HgStatusDialog.py Mon Feb 13 19:08:26 2017 +0100 +++ b/Plugins/VcsPlugins/vcsMercurial/HgStatusDialog.py Tue Feb 14 19:57:58 2017 +0100 @@ -16,10 +16,10 @@ import os -from PyQt5.QtCore import pyqtSlot, Qt, QProcess, QTimer, QSize -from PyQt5.QtGui import QTextCursor +from PyQt5.QtCore import pyqtSlot, qVersion, Qt, QProcess, QTimer, QSize +from PyQt5.QtGui import QTextCursor, QCursor from PyQt5.QtWidgets import QWidget, QDialogButtonBox, QMenu, QHeaderView, \ - QTreeWidgetItem, QLineEdit + QTreeWidgetItem, QLineEdit, QToolTip from E5Gui.E5Application import e5App from E5Gui import E5MessageBox @@ -30,10 +30,9 @@ from .HgDiffGenerator import HgDiffGenerator import Preferences +import UI.PixmapCache -# TODO: convert action buttons to a tool button with menu and delete status -# list context menu (i.e. make it the action menu) class HgStatusDialog(QWidget, Ui_HgStatusDialog): """ Class implementing a dialog to show the output of the hg status command @@ -76,8 +75,6 @@ self.process.readyReadStandardOutput.connect(self.__readStdout) self.process.readyReadStandardError.connect(self.__readStderr) - self.diffSplitter.setSizes([300, 300]) - self.statusList.headerItem().setText(self.__lastColumn, "") self.statusList.header().setSortIndicator( self.__pathColumn, Qt.AscendingOrder) @@ -92,86 +89,6 @@ self.__selectedName = "" - if mq: - self.buttonsLine.setVisible(False) - self.addButton.setVisible(False) - self.diffButton.setVisible(False) - self.sbsDiffButton.setVisible(False) - self.revertButton.setVisible(False) - self.forgetButton.setVisible(False) - self.restoreButton.setVisible(False) - - self.diffEdit.setVisible(False) - - self.menuactions = [] - self.lfActions = [] - self.menu = QMenu() - if not mq: - self.__commitAct = self.menu.addAction( - self.tr("Commit changes to repository..."), self.__commit) - self.menuactions.append(self.__commitAct) - self.menuactions.append(self.menu.addAction( - self.tr("Select all for commit"), self.__commitSelectAll)) - self.menuactions.append(self.menu.addAction( - self.tr("Deselect all from commit"), - self.__commitDeselectAll)) - self.menu.addSeparator() - self.__addAct = self.menu.addAction( - self.tr("Add to repository"), self.__add) - self.menuactions.append(self.__addAct) - self.lfActions.append(self.menu.addAction( - self.tr("Add as Large File"), - lambda: self.__lfAdd("large"))) - self.lfActions.append(self.menu.addAction( - self.tr("Add as Normal File"), - lambda: self.__lfAdd("normal"))) - self.menu.addSeparator() - self.__diffAct = self.menu.addAction( - self.tr("Show differences"), self.__diff) - self.menuactions.append(self.__diffAct) - self.__sbsDiffAct = self.menu.addAction( - self.tr("Show differences side-by-side"), self.__sbsDiff) - self.menuactions.append(self.__sbsDiffAct) - self.menu.addSeparator() - self.__revertAct = self.menu.addAction( - self.tr("Revert changes"), self.__revert) - self.menuactions.append(self.__revertAct) - self.__forgetAct = self.menu.addAction( - self.tr("Forget missing"), self.__forget) - self.menuactions.append(self.__forgetAct) - self.__restoreAct = self.menu.addAction( - self.tr("Restore missing"), self.__restoreMissing) - self.menuactions.append(self.__restoreAct) - self.menu.addSeparator() - self.menuactions.append(self.menu.addAction( - self.tr("Adjust column sizes"), self.__resizeColumns)) - for act in self.menuactions: - act.setEnabled(False) - for act in self.lfActions: - act.setEnabled(False) - - self.statusList.setContextMenuPolicy(Qt.CustomContextMenu) - self.statusList.customContextMenuRequested.connect( - self.__showContextMenu) - - if not mq: - self.__lfAddActions = [] - self.__addButtonMenu = QMenu() - self.__addButtonMenu.addAction(self.tr("Add"), self.__add) - self.__lfAddActions.append( - self.__addButtonMenu.addAction(self.tr("Add as Large File"), - lambda: self.__lfAdd("large"))) - self.__lfAddActions.append( - self.__addButtonMenu.addAction(self.tr("Add as Normal File"), - lambda: self.__lfAdd("normal"))) - self.__addButtonMenu.aboutToShow.connect(self.__showAddMenu) - if self.vcs.isExtensionActive("largefiles"): - self.addButton.setMenu(self.__addButtonMenu) - - if not mq: - self.vcs.activeExtensionsChanged.connect( - self.__activeExtensionsChanged) - self.modifiedIndicators = [ self.tr('added'), self.tr('modified'), @@ -195,6 +112,105 @@ '?': self.tr('not tracked'), '!': self.tr('missing'), } + + self.__initActionsMenu() + + if mq: + self.diffLabel.setVisible(False) + self.diffEdit.setVisible(False) + self.actionsButton.setEnabled(False) + self.diffSplitter.setSizes([600, 0]) + else: + self.diffSplitter.setSizes([300, 300]) + + def __initActionsMenu(self): + """ + Private method to initialize the actions menu. + """ + self.__actionsMenu = QMenu() + self.__actionsMenu.setTearOffEnabled(True) + if qVersion() >= "5.1.0": + self.__actionsMenu.setToolTipsVisible(True) + else: + self.__actionsMenu.hovered.connect(self.__actionsMenuHovered) + self.__actionsMenu.aboutToShow.connect(self.__showActionsMenu) + + self.__commitAct = self.__actionsMenu.addAction( + self.tr("Commit"), self.__commit) + self.__commitAct.setToolTip(self.tr("Commit the selected changes")) + self.__commitSelectAct = self.__actionsMenu.addAction( + self.tr("Select all for commit"), self.__commitSelectAll) + self.__commitDeselectAct = self.__actionsMenu.addAction( + self.tr("Unselect all from commit"), self.__commitDeselectAll) + + self.__actionsMenu.addSeparator() + + self.__addAct = self.__actionsMenu.addAction( + self.tr("Add"), self.__add) + self.__addAct.setToolTip(self.tr("Add the selected files")) + self.__lfAddLargeAct = self.__actionsMenu.addAction( + self.tr("Add as Large Files"), lambda: self.__lfAdd("large")) + self.__lfAddLargeAct.setToolTip(self.tr( + "Add the selected files as a large files using the 'Large Files'" + " extension")) + self.__lfAddNormalAct = self.__actionsMenu.addAction( + self.tr("Add as Normal Files"), lambda: self.__lfAdd("normal")) + self.__lfAddNormalAct.setToolTip(self.tr( + "Add the selected files as a normal files using the 'Large Files'" + " extension")) + + self.__actionsMenu.addSeparator() + + self.__diffAct = self.__actionsMenu.addAction( + self.tr("Differences"), self.__diff) + self.__diffAct.setToolTip(self.tr( + "Shows the differences of the selected entry in a" + " separate dialog")) + self.__sbsDiffAct = self.__actionsMenu.addAction( + self.tr("Differences Side-By-Side"), self.__sbsDiff) + self.__sbsDiffAct.setToolTip(self.tr( + "Shows the differences of the selected entry side-by-side in" + " a separate dialog")) + + self.__actionsMenu.addSeparator() + + self.__revertAct = self.__actionsMenu.addAction( + self.tr("Revert"), self.__revert) + self.__revertAct.setToolTip(self.tr( + "Reverts the changes of the selected files")) + + self.__actionsMenu.addSeparator() + + self.__forgetAct = self.__actionsMenu.addAction( + self.tr("Forget missing"), self.__forget) + self.__forgetAct.setToolTip(self.tr( + "Forgets about the selected missing files")) + self.__restoreAct = self.__actionsMenu.addAction( + self.tr("Restore missing"), self.__restoreMissing) + self.__restoreAct.setToolTip(self.tr( + "Restores the selected missing files")) + + self.__actionsMenu.addSeparator() + + act = self.__actionsMenu.addAction( + self.tr("Adjust column sizes"), self.__resizeColumns) + act.setToolTip(self.tr( + "Adjusts the width of all columns to their contents")) + + self.actionsButton.setIcon( + UI.PixmapCache.getIcon("actionsToolButton.png")) + self.actionsButton.setMenu(self.__actionsMenu) + + def __actionsMenuHovered(self, action): + """ + Private slot to show the tooltip for an action menu entry. + + @param action action to show tooltip for + @type QAction + """ + QToolTip.showText( + QCursor.pos(), action.toolTip(), + self.__actionsMenu, self.__actionsMenu.actionGeometry(action)) def closeEvent(self, e): """ @@ -252,17 +268,6 @@ if diffSplitterState is not None: self.diffSplitter.restoreState(diffSplitterState) - def __activeExtensionsChanged(self): - """ - Private slot handling a change in the activated extensions. - """ - if self.vcs.isExtensionActive("largefiles"): - if self.addButton.menu() is None: - self.addButton.setMenu(self.__addButtonMenu) - else: - if self.addButton.menu() is not None: - self.addButton.setMenu(None) - def __resort(self): """ Private method to resort the tree. @@ -315,18 +320,7 @@ self.intercept = False self.args = fn - for act in self.menuactions: - act.setEnabled(False) - for act in self.lfActions: - act.setEnabled(False) - - self.addButton.setEnabled(False) - self.commitButton.setEnabled(False) - self.diffButton.setEnabled(False) - self.sbsDiffButton.setEnabled(False) - self.revertButton.setEnabled(False) - self.forgetButton.setEnabled(False) - self.restoreButton.setEnabled(False) + self.actionsButton.setEnabled(False) self.statusFilterCombo.clear() self.__statusFilters = [] @@ -427,15 +421,12 @@ self.__statusFilters.insert(0, "<{0}>".format(self.tr("all"))) self.statusFilterCombo.addItems(self.__statusFilters) - for act in self.menuactions: - act.setEnabled(True) + if not self.__mq: + self.actionsButton.setEnabled(True) self.__resort() self.__resizeColumns() - self.__updateButtons() - self.__updateCommitButton() - self.__refreshDiff() def on_buttonBox_clicked(self, button): @@ -578,28 +569,6 @@ self.start(self.args) - def __updateButtons(self): - """ - Private method to update the VCS buttons status. - """ - modified = len(self.__getModifiedItems()) - unversioned = len(self.__getUnversionedItems()) - missing = len(self.__getMissingItems()) - - self.addButton.setEnabled(unversioned) - self.diffButton.setEnabled(modified) - self.sbsDiffButton.setEnabled(modified == 1) - self.revertButton.setEnabled(modified) - self.forgetButton.setEnabled(missing) - self.restoreButton.setEnabled(missing) - - def __updateCommitButton(self): - """ - Private method to update the Commit button status. - """ - commitable = len(self.__getCommitableItems()) - self.commitButton.setEnabled(commitable) - @pyqtSlot(str) def on_statusFilterCombo_activated(self, txt): """ @@ -616,88 +585,26 @@ topItem = self.statusList.topLevelItem(topIndex) topItem.setHidden(topItem.text(self.__statusColumn) != txt) - @pyqtSlot(QTreeWidgetItem, int) - def on_statusList_itemChanged(self, item, column): - """ - Private slot to act upon item changes. - - @param item reference to the changed item (QTreeWidgetItem) - @param column index of column that changed (integer) - """ - if column == self.__toBeCommittedColumn: - self.__updateCommitButton() - @pyqtSlot() def on_statusList_itemSelectionChanged(self): """ Private slot to act upon changes of selected items. """ - self.__updateButtons() self.__generateDiffs() - @pyqtSlot() - def on_commitButton_clicked(self): - """ - Private slot to handle the press of the Commit button. - """ - self.__commit() - - @pyqtSlot() - def on_addButton_clicked(self): - """ - Private slot to handle the press of the Add button. - """ - self.__add() - - @pyqtSlot() - def on_diffButton_clicked(self): - """ - Private slot to handle the press of the Differences button. - """ - self.__diff() - - @pyqtSlot() - def on_sbsDiffButton_clicked(self): - """ - Private slot to handle the press of the Side-by-Side Diff button. - """ - self.__sbsDiff() - - @pyqtSlot() - def on_revertButton_clicked(self): - """ - Private slot to handle the press of the Revert button. - """ - self.__revert() - - @pyqtSlot() - def on_forgetButton_clicked(self): - """ - Private slot to handle the press of the Forget button. - """ - self.__forget() - - @pyqtSlot() - def on_restoreButton_clicked(self): - """ - Private slot to handle the press of the Restore button. - """ - self.__restoreMissing() - ########################################################################### - ## Context menu handling methods + ## Menu handling methods ########################################################################### - def __showContextMenu(self, coord): + def __showActionsMenu(self): """ - Private slot to show the context menu of the status list. - - @param coord the position of the mouse pointer (QPoint) + Private slot to prepare the actions button menu before it is shown. """ modified = len(self.__getModifiedItems()) unversioned = len(self.__getUnversionedItems()) missing = len(self.__getMissingItems()) commitable = len(self.__getCommitableItems()) + commitableUnselected = len(self.__getCommitableUnselectedItems()) self.__addAct.setEnabled(unversioned) self.__diffAct.setEnabled(modified) @@ -706,22 +613,15 @@ self.__forgetAct.setEnabled(missing) self.__restoreAct.setEnabled(missing) self.__commitAct.setEnabled(commitable) + self.__commitSelectAct.setEnabled(commitableUnselected) + self.__commitDeselectAct.setEnabled(commitable) if self.vcs.isExtensionActive("largefiles"): - enable = len(self.__getUnversionedItems()) > 0 + enable = bool(unversioned) else: enable = False - for act in self.lfActions: - act.setEnabled(enable) - self.menu.popup(self.statusList.mapToGlobal(coord)) - - def __showAddMenu(self): - """ - Private slot to prepare the Add button menu before it is shown. - """ - enable = self.vcs.isExtensionActive("largefiles") - for act in self.__lfAddActions: - act.setEnabled(enable) + self.__lfAddLargeAct.setEnabled(enable) + self.__lfAddNormalAct.setEnabled(enable) def __commit(self): """ @@ -928,6 +828,21 @@ commitableItems.append(itm) return commitableItems + def __getCommitableUnselectedItems(self): + """ + Private method to retrieve all entries the user may commit but hasn't + selected. + + @return list of all items, the user has checked + """ + items = [] + for index in range(self.statusList.topLevelItemCount()): + itm = self.statusList.topLevelItem(index) + if itm.flags() & Qt.ItemIsUserCheckable and \ + itm.checkState(self.__toBeCommittedColumn) == Qt.Unchecked: + items.append(itm) + return items + def __getModifiedItems(self): """ Private method to retrieve all entries, that have a modified status.