Tue, 21 Sep 2021 19:11:31 +0200
Continued implementing the VCS status widget for the left side.
--- a/eric7/Plugins/VcsPlugins/vcsGit/GitLogBrowserDialog.py Mon Sep 20 19:47:18 2021 +0200 +++ b/eric7/Plugins/VcsPlugins/vcsGit/GitLogBrowserDialog.py Tue Sep 21 19:11:31 2021 +0200 @@ -2341,5 +2341,5 @@ scheme, path = link.split(":", 1) if scheme == "sbsdiff" and "_" in path: commit1, commit2 = path.split("_", 1) - self.vcs.gitSbsDiff(self.__filename, + self.vcs.vcsSbsDiff(self.__filename, revisions=(commit1, commit2))
--- a/eric7/Plugins/VcsPlugins/vcsGit/GitStatusDialog.py Mon Sep 20 19:47:18 2021 +0200 +++ b/eric7/Plugins/VcsPlugins/vcsGit/GitStatusDialog.py Tue Sep 21 19:11:31 2021 +0200 @@ -234,18 +234,18 @@ self.__actionsMenu.addSeparator() self.__forgetAct = self.__actionsMenu.addAction( - self.tr("Forget missing"), self.__forget) + 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.tr("Restore Missing"), self.__restoreMissing) self.__restoreAct.setToolTip(self.tr( "Restores the selected missing files")) self.__actionsMenu.addSeparator() self.__editAct = self.__actionsMenu.addAction( - self.tr("Edit file"), self.__editConflict) + self.tr("Edit Conflict"), self.__editConflict) self.__editAct.setToolTip(self.tr( "Edit the selected conflicting file")) @@ -796,7 +796,7 @@ """ available/selected.""")) return - self.vcs.gitRevert(names) + self.vcs.vcsRevert(names) self.raise_() self.activateWindow() self.on_refreshButton_clicked() @@ -820,13 +820,13 @@ """ available/selected.""")) return - self.vcs.gitRevert(names) + self.vcs.vcsRevert(names) self.on_refreshButton_clicked() self.vcs.checkVCSStatus() def __editConflict(self): """ - Private slot to handle the Edit file context menu entry. + Private slot to handle the Edit Conflict context menu entry. """ itm = self.__getConflictingItems()[0] filename = os.path.join(self.__repodir, itm.text(self.__pathColumn)) @@ -860,7 +860,7 @@ def __sbsDiff(self): """ - Private slot to handle the Diff context menu entry. + Private slot to handle the Side-By-Side Diff context menu entry. """ itm = self.__getModifiedOnlyItems()[0] workModified = (itm.text(self.__statusWorkColumn) in @@ -878,7 +878,7 @@ ] result, ok = QInputDialog.getItem( None, - self.tr("Side-by-Side Difference"), + self.tr("Differences Side-by-Side"), self.tr("Select the compare method."), messages, 0, False) @@ -899,7 +899,7 @@ ] result, ok = QInputDialog.getItem( None, - self.tr("Side-by-Side Difference"), + self.tr("Differences Side-by-Side"), self.tr("Select the compare method."), messages, 0, False) @@ -913,7 +913,7 @@ else: revisions = ["HEAD", "Stage"] - self.vcs.gitSbsDiff(names[0], revisions=revisions) + self.vcs.vcsSbsDiff(names[0], revisions=revisions) def __getCommitableItems(self): """
--- a/eric7/Plugins/VcsPlugins/vcsGit/ProjectBrowserHelper.py Mon Sep 20 19:47:18 2021 +0200 +++ b/eric7/Plugins/VcsPlugins/vcsGit/ProjectBrowserHelper.py Tue Sep 21 19:11:31 2021 +0200 @@ -648,7 +648,7 @@ """ itm = self.browser.currentItem() fn = itm.fileName() - self.vcs.gitSbsDiff(fn) + self.vcs.vcsSbsDiff(fn) def __GitSbsExtendedDiff(self): """ @@ -659,7 +659,7 @@ """ itm = self.browser.currentItem() fn = itm.fileName() - self.vcs.gitSbsDiff(fn, extended=True) + self.vcs.vcsSbsDiff(fn, extended=True) def __GitUnstage(self): """ @@ -685,7 +685,7 @@ except AttributeError: name = itm.dirName() names.append(name) - self.vcs.gitRevert(names) + self.vcs.vcsRevert(names) def __GitBlame(self): """
--- a/eric7/Plugins/VcsPlugins/vcsGit/ProjectHelper.py Mon Sep 20 19:47:18 2021 +0200 +++ b/eric7/Plugins/VcsPlugins/vcsGit/ProjectHelper.py Tue Sep 21 19:11:31 2021 +0200 @@ -1738,7 +1738,7 @@ pfile = self.project.getProjectFile() lastModified = QFileInfo(pfile).lastModified().toString() shouldReopen = ( - self.vcs.gitRevert(self.project.getProjectPath()) or + self.vcs.vcsRevert(self.project.getProjectPath()) or QFileInfo(pfile).lastModified().toString() != lastModified ) if shouldReopen:
--- a/eric7/Plugins/VcsPlugins/vcsGit/git.py Mon Sep 20 19:47:18 2021 +0200 +++ b/eric7/Plugins/VcsPlugins/vcsGit/git.py Tue Sep 21 19:11:31 2021 +0200 @@ -669,6 +669,17 @@ return res + def vcsForget(self, name): + """ + Public method used to remove a file from the Mercurial repository. + + This will not remove the file from the project directory. + + @param name file/directory name to be removed + @type str or list of str + """ + self.vcsRemove(name, stageOnly=True) + def vcsMove(self, name, project, target=None, noDialog=False): """ Public method used to move a file/directory. @@ -845,13 +856,15 @@ return res - def gitRevert(self, name): + def vcsRevert(self, name): """ Public method used to revert changes made to a file/directory. - @param name file/directory name to be reverted (string) + @param name file/directory name to be reverted + @type str @return flag indicating, that the update contained an add - or delete (boolean) + or delete + @rtype bool """ args = self.initCommand("checkout") args.append("--") @@ -1568,7 +1581,7 @@ # return file contents with 'universal newlines' return output.replace('\r\n', '\n').replace('\r', '\n'), error - def gitSbsDiff(self, name, extended=False, revisions=None): + def vcsSbsDiff(self, name, extended=False, revisions=None): """ Public method used to view the difference of a file to the Git repository side-by-side.
--- a/eric7/Plugins/VcsPlugins/vcsMercurial/HgConflictsListDialog.py Mon Sep 20 19:47:18 2021 +0200 +++ b/eric7/Plugins/VcsPlugins/vcsMercurial/HgConflictsListDialog.py Tue Sep 21 19:11:31 2021 +0200 @@ -266,7 +266,7 @@ if itm.data(0, self.StatusRole) == "U" ] if names: - self.vcs.hgResolved(names) + self.vcs.vcsResolved(names) self.on_refreshButton_clicked() @pyqtSlot() @@ -280,7 +280,7 @@ if itm.data(0, self.StatusRole) == "R" ] if names: - self.vcs.hgResolved(names, unresolve=True) + self.vcs.vcsResolved(names, unresolve=True) self.on_refreshButton_clicked() @pyqtSlot()
--- a/eric7/Plugins/VcsPlugins/vcsMercurial/HgLogBrowserDialog.py Mon Sep 20 19:47:18 2021 +0200 +++ b/eric7/Plugins/VcsPlugins/vcsMercurial/HgLogBrowserDialog.py Tue Sep 21 19:11:31 2021 +0200 @@ -2704,4 +2704,4 @@ scheme, path = link.split(":", 1) if scheme == "sbsdiff" and "_" in path: rev1, rev2 = path.split("_", 1) - self.vcs.hgSbsDiff(self.__filename, revisions=(rev1, rev2)) + self.vcs.vcsSbsDiff(self.__filename, revisions=(rev1, rev2))
--- a/eric7/Plugins/VcsPlugins/vcsMercurial/HgStatusDialog.py Mon Sep 20 19:47:18 2021 +0200 +++ b/eric7/Plugins/VcsPlugins/vcsMercurial/HgStatusDialog.py Tue Sep 21 19:11:31 2021 +0200 @@ -168,11 +168,11 @@ self.__actionsMenu.addSeparator() self.__forgetAct = self.__actionsMenu.addAction( - self.tr("Forget missing"), self.__forget) + 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.tr("Restore Missing"), self.__restoreMissing) self.__restoreAct.setToolTip(self.tr( "Restores the selected missing files")) @@ -585,19 +585,19 @@ def __forget(self): """ - Private slot to handle the Remove context menu entry. + Private slot to handle the Forget Missing context menu entry. """ names = [os.path.join(self.__repoPath, itm.text(self.__pathColumn)) for itm in self.__getMissingItems()] if not names: EricMessageBox.information( self, - self.tr("Remove"), + self.tr("Forget Missing"), self.tr("""There are no missing entries""" """ available/selected.""")) return - self.vcs.hgForget(names) + self.vcs.vcsForget(names) self.on_refreshButton_clicked() def __revert(self): @@ -614,7 +614,7 @@ """ available/selected.""")) return - self.vcs.hgRevert(names) + self.vcs.vcsRevert(names) self.raise_() self.activateWindow() self.on_refreshButton_clicked() @@ -633,12 +633,12 @@ if not names: EricMessageBox.information( self, - self.tr("Revert"), + self.tr("Revert Missing"), self.tr("""There are no missing entries""" """ available/selected.""")) return - self.vcs.hgRevert(names) + self.vcs.vcsRevert(names) self.on_refreshButton_clicked() self.vcs.checkVCSStatus() @@ -664,26 +664,26 @@ def __sbsDiff(self): """ - Private slot to handle the Diff context menu entry. + Private slot to handle the Side-By-Side Diff context menu entry. """ names = [os.path.join(self.__repoPath, itm.text(self.__pathColumn)) for itm in self.__getModifiedItems()] if not names: EricMessageBox.information( self, - self.tr("Side-by-Side Diff"), + self.tr("Differences Side-By-Side"), self.tr("""There are no uncommitted changes""" """ available/selected.""")) return elif len(names) > 1: EricMessageBox.information( self, - self.tr("Side-by-Side Diff"), + self.tr("Differences Side-By-Side"), self.tr("""Only one file with uncommitted changes""" """ must be selected.""")) return - self.vcs.hgSbsDiff(names[0]) + self.vcs.vcsSbsDiff(names[0]) def __getCommitableItems(self): """
--- a/eric7/Plugins/VcsPlugins/vcsMercurial/ProjectBrowserHelper.py Mon Sep 20 19:47:18 2021 +0200 +++ b/eric7/Plugins/VcsPlugins/vcsMercurial/ProjectBrowserHelper.py Tue Sep 21 19:11:31 2021 +0200 @@ -691,7 +691,7 @@ except AttributeError: name = itm.dirName() names.append(name) - self.vcs.hgRevert(names) + self.vcs.vcsRevert(names) def __HgCopy(self): """ @@ -746,7 +746,7 @@ """ itm = self.browser.currentItem() fn = itm.fileName() - self.vcs.hgSbsDiff(fn) + self.vcs.vcsSbsDiff(fn) def __HgSbsExtendedDiff(self): """ @@ -757,7 +757,7 @@ """ itm = self.browser.currentItem() fn = itm.fileName() - self.vcs.hgSbsDiff(fn, extended=True) + self.vcs.vcsSbsDiff(fn, extended=True) def __HgAnnotate(self): """ @@ -779,7 +779,7 @@ names.append(itm.fileName()) except AttributeError: names.append(itm.dirName()) - self.vcs.hgResolved(names) + self.vcs.vcsResolved(names) def __HgUnresolved(self): """ @@ -792,7 +792,7 @@ names.append(itm.fileName()) except AttributeError: names.append(itm.dirName()) - self.vcs.hgResolved(names, unresolve=True) + self.vcs.vcsResolved(names, unresolve=True) def __HgReMerge(self): """ @@ -840,7 +840,7 @@ files) if dlg.exec() == QDialog.DialogCode.Accepted: - self.vcs.hgForget(names) + self.vcs.vcsForget(names) for fn in names: self._updateVCSStatus(fn)
--- a/eric7/Plugins/VcsPlugins/vcsMercurial/ProjectHelper.py Mon Sep 20 19:47:18 2021 +0200 +++ b/eric7/Plugins/VcsPlugins/vcsMercurial/ProjectHelper.py Tue Sep 21 19:11:31 2021 +0200 @@ -1723,14 +1723,14 @@ Private slot used to mark conflicts of the local project as being resolved. """ - self.vcs.hgResolved(self.project.ppath) + self.vcs.vcsResolved(self.project.ppath) def __hgUnresolved(self): """ Private slot used to mark conflicts of the local project as being unresolved. """ - self.vcs.hgResolved(self.project.ppath, unresolve=True) + self.vcs.vcsResolved(self.project.ppath, unresolve=True) def __hgCommitMerge(self): """ @@ -1943,7 +1943,7 @@ """ Private slot used to revert changes made to the local project. """ - shouldReopen = self.vcs.hgRevert(self.project.ppath) + shouldReopen = self.vcs.vcsRevert(self.project.ppath) if shouldReopen: res = EricMessageBox.yesNo( self.parent(),
--- a/eric7/Plugins/VcsPlugins/vcsMercurial/hg.py Mon Sep 20 19:47:18 2021 +0200 +++ b/eric7/Plugins/VcsPlugins/vcsMercurial/hg.py Tue Sep 21 19:11:31 2021 +0200 @@ -849,13 +849,15 @@ return True - def hgRevert(self, name): + def vcsRevert(self, name): """ Public method used to revert changes made to a file/directory. - @param name file/directory name to be reverted (string) + @param name file/directory name to be reverted + @type str @return flag indicating, that the update contained an add - or delete (boolean) + or delete + @rtype bool """ args = self.initCommand("revert") if not self.getPlugin().getPreferences("CreateBackup"): @@ -1494,7 +1496,7 @@ # return file contents with 'universal newlines' return output.replace('\r\n', '\n').replace('\r', '\n'), error - def hgSbsDiff(self, name, extended=False, revisions=None): + def vcsSbsDiff(self, name, extended=False, revisions=None): """ Public method used to view the difference of a file to the Mercurial repository side-by-side. @@ -1762,7 +1764,7 @@ self.conflictsDlg.raise_() self.conflictsDlg.start() - def hgResolved(self, name, unresolve=False): + def vcsResolved(self, name, unresolve=False): """ Public method used to resolve conflicts of a file/directory. @@ -2222,14 +2224,14 @@ if res: dia.exec() - def hgForget(self, name): + def vcsForget(self, name): """ Public method used to remove a file from the Mercurial repository. This will not remove the file from the project directory. - @param name file/directory name to be removed (string or list of - strings)) + @param name file/directory name to be removed + @type str or list of str """ args = self.initCommand("forget") args.append('-v')
--- a/eric7/Plugins/VcsPlugins/vcsPySvn/ProjectBrowserHelper.py Mon Sep 20 19:47:18 2021 +0200 +++ b/eric7/Plugins/VcsPlugins/vcsPySvn/ProjectBrowserHelper.py Tue Sep 21 19:11:31 2021 +0200 @@ -778,7 +778,7 @@ names.append(itm.fileName()) except AttributeError: names.append(itm.dirName()) - self.vcs.svnResolve(names) + self.vcs.vcsResolved(names) def __SVNListProps(self): """ @@ -856,7 +856,7 @@ """ itm = self.browser.currentItem() fn = itm.fileName() - self.vcs.svnSbsDiff(fn) + self.vcs.vcsSbsDiff(fn) def __SVNSbsExtendedDiff(self): """ @@ -867,7 +867,7 @@ """ itm = self.browser.currentItem() fn = itm.fileName() - self.vcs.svnSbsDiff(fn, extended=True) + self.vcs.vcsSbsDiff(fn, extended=True) def __SVNBlame(self): """
--- a/eric7/Plugins/VcsPlugins/vcsPySvn/ProjectHelper.py Mon Sep 20 19:47:18 2021 +0200 +++ b/eric7/Plugins/VcsPlugins/vcsPySvn/ProjectHelper.py Tue Sep 21 19:11:31 2021 +0200 @@ -609,7 +609,7 @@ """ Private slot used to resolve conflicts of the local project. """ - self.vcs.svnResolve(self.project.ppath) + self.vcs.vcsResolved(self.project.ppath) def __svnPropList(self): """
--- a/eric7/Plugins/VcsPlugins/vcsPySvn/SvnLogBrowserDialog.py Mon Sep 20 19:47:18 2021 +0200 +++ b/eric7/Plugins/VcsPlugins/vcsPySvn/SvnLogBrowserDialog.py Tue Sep 21 19:11:31 2021 +0200 @@ -397,7 +397,7 @@ @param peg_rev revision number to use as a reference (integer) """ if self.sbsCheckBox.isEnabled() and self.sbsCheckBox.isChecked(): - self.vcs.svnSbsDiff(self.filename, + self.vcs.vcsSbsDiff(self.filename, revisions=(str(rev1), str(rev2))) else: if self.diff is None:
--- a/eric7/Plugins/VcsPlugins/vcsPySvn/SvnStatusDialog.py Mon Sep 20 19:47:18 2021 +0200 +++ b/eric7/Plugins/VcsPlugins/vcsPySvn/SvnStatusDialog.py Tue Sep 21 19:11:31 2021 +0200 @@ -99,7 +99,7 @@ self.menuactions.append(self.menu.addAction( self.tr("Revert changes"), self.__revert)) self.menuactions.append(self.menu.addAction( - self.tr("Restore missing"), self.__restoreMissing)) + self.tr("Restore Missing"), self.__restoreMissing)) if pysvn.svn_version >= (1, 5, 0) and pysvn.version >= (1, 6, 0): self.menu.addSeparator() self.menuactions.append(self.menu.addAction( @@ -733,7 +733,7 @@ if not names: EricMessageBox.information( self, - self.tr("Revert"), + self.tr("Restore Missing"), self.tr("""There are no missing entries""" """ available/selected.""")) return @@ -784,7 +784,7 @@ """ must be selected.""")) return - self.vcs.svnSbsDiff(names[0]) + self.vcs.vcsSbsDiff(names[0]) def __lock(self): """
--- a/eric7/Plugins/VcsPlugins/vcsPySvn/subversion.py Mon Sep 20 19:47:18 2021 +0200 +++ b/eric7/Plugins/VcsPlugins/vcsPySvn/subversion.py Tue Sep 21 19:11:31 2021 +0200 @@ -1122,7 +1122,11 @@ """ Public method used to revert changes made to a file/directory. - @param name file/directory name to be reverted (string) + @param name file/directory name to be reverted + @type str + @return flag indicating, that the update contained an add + or delete + @rtype bool """ recurse = False if not isinstance(name, list): @@ -1167,6 +1171,20 @@ dlg.finish() dlg.exec() self.checkVCSStatus() + + return False + + def vcsForget(self, name): + """ + Public method used to remove a file from the repository. + + Note: svn does not support this operation. The method is implemented + as a NoOp. + + @param name file/directory name to be removed + @type str or list of str + """ + pass def vcsSwitch(self, name): """ @@ -1769,7 +1787,7 @@ url = "" return url - def svnResolve(self, name): + def vcsResolved(self, name): """ Public method used to resolve conflicts of a file/directory. @@ -2136,7 +2154,7 @@ return output, error - def svnSbsDiff(self, name, extended=False, revisions=None): + def vcsSbsDiff(self, name, extended=False, revisions=None): """ Public method used to view the difference of a file to the Mercurial repository side-by-side.
--- a/eric7/Plugins/VcsPlugins/vcsSubversion/ProjectBrowserHelper.py Mon Sep 20 19:47:18 2021 +0200 +++ b/eric7/Plugins/VcsPlugins/vcsSubversion/ProjectBrowserHelper.py Tue Sep 21 19:11:31 2021 +0200 @@ -773,7 +773,7 @@ names.append(itm.fileName()) except AttributeError: names.append(itm.dirName()) - self.vcs.svnResolve(names) + self.vcs.vcsResolved(names) def __SVNListProps(self): """ @@ -851,7 +851,7 @@ """ itm = self.browser.currentItem() fn = itm.fileName() - self.vcs.svnSbsDiff(fn) + self.vcs.vcsSbsDiff(fn) def __SVNSbsExtendedDiff(self): """ @@ -862,7 +862,7 @@ """ itm = self.browser.currentItem() fn = itm.fileName() - self.vcs.svnSbsDiff(fn, extended=True) + self.vcs.vcsSbsDiff(fn, extended=True) def __SVNBlame(self): """
--- a/eric7/Plugins/VcsPlugins/vcsSubversion/ProjectHelper.py Mon Sep 20 19:47:18 2021 +0200 +++ b/eric7/Plugins/VcsPlugins/vcsSubversion/ProjectHelper.py Tue Sep 21 19:11:31 2021 +0200 @@ -592,7 +592,7 @@ """ Private slot used to resolve conflicts of the local project. """ - self.vcs.svnResolve(self.project.ppath) + self.vcs.vcsResolved(self.project.ppath) def __svnPropList(self): """
--- a/eric7/Plugins/VcsPlugins/vcsSubversion/SvnLogBrowserDialog.py Mon Sep 20 19:47:18 2021 +0200 +++ b/eric7/Plugins/VcsPlugins/vcsSubversion/SvnLogBrowserDialog.py Tue Sep 21 19:11:31 2021 +0200 @@ -510,7 +510,7 @@ @param rev2 second revision number (integer) """ if self.sbsCheckBox.isEnabled() and self.sbsCheckBox.isChecked(): - self.vcs.svnSbsDiff(self.filename, + self.vcs.vcsSbsDiff(self.filename, revisions=(str(rev1), str(rev2))) else: if self.diff is None:
--- a/eric7/Plugins/VcsPlugins/vcsSubversion/SvnStatusDialog.py Mon Sep 20 19:47:18 2021 +0200 +++ b/eric7/Plugins/VcsPlugins/vcsSubversion/SvnStatusDialog.py Tue Sep 21 19:11:31 2021 +0200 @@ -880,7 +880,7 @@ """ must be selected.""")) return - self.vcs.svnSbsDiff(names[0]) + self.vcs.vcsSbsDiff(names[0]) def __lock(self): """
--- a/eric7/Plugins/VcsPlugins/vcsSubversion/subversion.py Mon Sep 20 19:47:18 2021 +0200 +++ b/eric7/Plugins/VcsPlugins/vcsSubversion/subversion.py Tue Sep 21 19:11:31 2021 +0200 @@ -1034,7 +1034,11 @@ """ Public method used to revert changes made to a file/directory. - @param name file/directory name to be reverted (string) + @param name file/directory name to be reverted + @type str + @return flag indicating, that the update contained an add + or delete + @rtype bool """ args = [] args.append('revert') @@ -1073,6 +1077,20 @@ if res: dia.exec() self.checkVCSStatus() + + return False + + def vcsForget(self, name): + """ + Public method used to remove a file from the repository. + + Note: svn does not support this operation. The method is implemented + as a NoOp. + + @param name file/directory name to be removed + @type str or list of str + """ + pass def vcsSwitch(self, name): """ @@ -1665,7 +1683,7 @@ return "" - def svnResolve(self, name): + def vcsResolved(self, name): """ Public method used to resolve conflicts of a file/directory. @@ -1990,7 +2008,7 @@ return output, error - def svnSbsDiff(self, name, extended=False, revisions=None): + def vcsSbsDiff(self, name, extended=False, revisions=None): """ Public method used to view the difference of a file to the Mercurial repository side-by-side.
--- a/eric7/UI/CompareDialog.py Mon Sep 20 19:47:18 2021 +0200 +++ b/eric7/UI/CompareDialog.py Tue Sep 21 19:11:31 2021 +0200 @@ -364,6 +364,9 @@ self.changedLabel.setText(self.tr('Changed: {0}').format(changed)) self.addedLabel.setText(self.tr('Added: {0}').format(added)) self.deletedLabel.setText(self.tr('Deleted: {0}').format(deleted)) + + # move to the first difference + self.downButton.click() def __moveTextToCurrentDiffPos(self): """
--- a/eric7/UI/UserInterface.py Mon Sep 20 19:47:18 2021 +0200 +++ b/eric7/UI/UserInterface.py Tue Sep 21 19:11:31 2021 +0200 @@ -955,7 +955,8 @@ # Create the VCS Status widget from VCS.StatusWidget import StatusWidget - self.__vcsStatusWidget = StatusWidget(self.project, self) + self.__vcsStatusWidget = StatusWidget( + self.project, self.viewmanager, self) def __createLayout(self): """
--- a/eric7/VCS/StatusWidget.py Mon Sep 20 19:47:18 2021 +0200 +++ b/eric7/VCS/StatusWidget.py Tue Sep 21 19:11:31 2021 +0200 @@ -13,7 +13,7 @@ from PyQt6.QtCore import pyqtSlot, Qt from PyQt6.QtWidgets import ( QWidget, QVBoxLayout, QHBoxLayout, QLabel, QSizePolicy, QListView, - QListWidget, QListWidgetItem, QToolButton, QAbstractItemView + QListWidget, QListWidgetItem, QToolButton, QAbstractItemView, QMenu ) from EricWidgets.EricApplication import ericApp @@ -21,6 +21,7 @@ import Preferences import UI.PixmapCache +import Utilities class StatusWidget(QWidget): @@ -29,12 +30,14 @@ """ StatusDataRole = Qt.ItemDataRole.UserRole + 1 - def __init__(self, project, parent=None): + def __init__(self, project, viewmanager, parent=None): """ Constructor @param project reference to the project object @type Project + @param viewmanager reference to the viewmanager object + @type ViewManager @param parent reference to the parent widget (defaults to None) @type QWidget (optional) """ @@ -42,6 +45,7 @@ self.setObjectName("VcsStatusWidget") self.__project = project + self.__vm = viewmanager self.__layout = QVBoxLayout() self.__layout.setObjectName("MainLayout") @@ -83,6 +87,15 @@ self.__reloadButton.clicked.connect(self.__reload) self.__topLayout.addWidget(self.__reloadButton) + self.__actionsButton = QToolButton(self) + self.__actionsButton.setIcon( + UI.PixmapCache.getIcon("actionsToolButton")) + self.__actionsButton.setToolTip( + self.tr("Select action from menu")) + self.__actionsButton.setPopupMode( + QToolButton.ToolButtonPopupMode.InstantPopup) + self.__topLayout.addWidget(self.__actionsButton) + self.__layout.addLayout(self.__topLayout) self.__statusList = QListWidget(self) @@ -92,6 +105,8 @@ self.__statusList.setTextElideMode(Qt.TextElideMode.ElideLeft) self.__statusList.setSelectionMode( QAbstractItemView.SelectionMode.ExtendedSelection) + self.__statusList.itemSelectionChanged.connect( + self.__updateButtonStates) self.__layout.addWidget(self.__statusList) self.setLayout(self.__layout) @@ -117,6 +132,10 @@ "!": self.tr("missing"), } + self.__initActionsMenu() + + self.__reset() + if self.__project.isOpen(): self.__projectOpened() else: @@ -129,6 +148,73 @@ self.__project.vcsStatusMonitorAllData.connect( self.__processStatusData) + def __initActionsMenu(self): + """ + Private method to initialize the actions menu. + """ + self.__actionsMenu = QMenu() + self.__actionsMenu.setToolTipsVisible(True) + self.__actionsMenu.aboutToShow.connect(self.__showActionsMenu) + + self.__commitAct = self.__actionsMenu.addAction( + UI.PixmapCache.getIcon("vcsCommit"), + 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( + UI.PixmapCache.getIcon("vcsAdd"), + self.tr("Add"), self.__addUntracked) + + self.__actionsMenu.addSeparator() + + self.__diffAct = self.__actionsMenu.addAction( + UI.PixmapCache.getIcon("vcsDiff"), + 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( + UI.PixmapCache.getIcon("vcsSbsDiff"), + 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( + UI.PixmapCache.getIcon("vcsRevert"), + 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.__forgetMissing) + 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() + + self.__editAct = self.__actionsMenu.addAction( + UI.PixmapCache.getIcon("open"), + self.tr("Edit Conflict"), self.__editConflict) + self.__editAct.setToolTip(self.tr( + "Edit the selected conflicting file")) + # TODO: add menu entry for 'Conflict Resolved' + + self.__actionsButton.setMenu(self.__actionsMenu) + @pyqtSlot() def __projectOpened(self): """ @@ -145,7 +231,7 @@ self.__reloadButton.setEnabled(False) - self.__statusList.clear() + self.__reset() @pyqtSlot(str) def __setInfoText(self, info): @@ -164,6 +250,28 @@ """ self.__project.checkVCSStatus() + def __reset(self): + """ + Private method to reset the widget to default. + """ + self.__statusList.clear() + + self.__commitToggleButton.setEnabled(False) + self.__commitButton.setEnabled(False) + self.__addButton.setEnabled(False) + + def __updateButtonStates(self): + """ + Private method to set the button states depending on the list state. + """ + modified = len(self.__getModifiedItems()) + unversioned = len(self.__getUnversionedItems()) + commitable = len(self.__getCommitableItems()) + + self.__commitToggleButton.setEnabled(modified) + self.__commitButton.setEnabled(commitable) + self.__addButton.setEnabled(unversioned) + @pyqtSlot(dict) def __processStatusData(self, data): """ @@ -187,7 +295,7 @@ @param data dictionary containing the status data @type dict """ - self.__statusList.clear() + self.__reset() for name, status in data.items(): if status: @@ -206,6 +314,8 @@ itm.flags() & ~Qt.ItemFlag.ItemIsUserCheckable) self.__statusList.sortItems(Qt.SortOrder.AscendingOrder) + + self.__updateButtonStates() @pyqtSlot() def __toggleCheckMark(self): @@ -223,6 +333,24 @@ else: itm.setCheckState(Qt.CheckState.Unchecked) + def __setCheckMark(self, checked): + """ + Private method to set or unset all check marks. + + @param checked check mark state to be set + @type bool + """ + for row in range(self.__statusList.count()): + itm = self.__statusList.item(row) + if ( + itm.flags() & Qt.ItemFlag.ItemIsUserCheckable == + Qt.ItemFlag.ItemIsUserCheckable + ): + if checked: + itm.setCheckState(Qt.CheckState.Checked) + else: + itm.setCheckState(Qt.CheckState.Unchecked) + @pyqtSlot() def __commit(self): """ @@ -259,17 +387,28 @@ self.__reload() @pyqtSlot() + def __commitSelectAll(self): + """ + Private slot to select all entries for commit. + """ + self.__setCheckMark(True) + + @pyqtSlot() + def __commitDeselectAll(self): + """ + Private slot to deselect all entries from commit. + """ + self.__setCheckMark(False) + + @pyqtSlot() def __addUntracked(self): """ Private slot to add the selected untracked entries. """ projectPath = self.__project.getProjectPath() - names = [ - os.path.join(projectPath, itm.text()) - for itm in self.__statusList.selectedItems() - if itm.data(self.StatusDataRole) == "?" - ] + names = [os.path.join(projectPath, itm.text()) + for itm in self.__getUnversionedItems()] if not names: EricMessageBox.information( @@ -282,3 +421,239 @@ vcs = self.__project.getVcs() vcs and vcs.vcsAdd(names) self.__reload() + + ########################################################################### + ## Menu handling methods + ########################################################################### + + def __showActionsMenu(self): + """ + Private slot to prepare the actions button menu before it is shown. + """ + modified = len(self.__getSelectedModifiedItems()) + unversioned = len(self.__getUnversionedItems()) + missing = len(self.__getMissingItems()) + commitable = len(self.__getCommitableItems()) + commitableUnselected = len(self.__getCommitableUnselectedItems()) + conflicting = len(self.__getSelectedConflictingItems()) + + self.__addAct.setEnabled(unversioned) + self.__diffAct.setEnabled(modified) + self.__sbsDiffAct.setEnabled(modified == 1) + self.__revertAct.setEnabled(modified) + self.__forgetAct.setEnabled(missing) + self.__restoreAct.setEnabled(missing) + self.__commitAct.setEnabled(commitable) + self.__commitSelectAct.setEnabled(commitableUnselected) + self.__commitDeselectAct.setEnabled(commitable) + self.__editAct.setEnabled(conflicting == 1) + + def __getCommitableItems(self): + """ + Private method to retrieve all entries the user wants to commit. + + @return list of all items, the user has checked + @rtype list of QListWidgetItem + """ + commitableItems = [] + for row in range(self.__statusList.count()): + itm = self.__statusList.item(row) + if ( + itm.checkState() == Qt.CheckState.Checked + ): + 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 + @rtype list of QListWidgetItem + """ + items = [] + for row in range(self.__statusList.count()): + itm = self.__statusList.item(row) + if ( + (itm.flags() & Qt.ItemFlag.ItemIsUserCheckable == + Qt.ItemFlag.ItemIsUserCheckable) and + itm.checkState() == Qt.CheckState.Unchecked + ): + items.append(itm) + return items + + def __getModifiedItems(self): + """ + Private method to retrieve all entries, that have a modified status. + + @return list of all items with a modified status + @rtype list of QListWidgetItem + """ + items = [] + for row in range(self.__statusList.count()): + itm = self.__statusList.item(row) + if itm.data(self.StatusDataRole) in "AMOR": + items.append(itm) + return items + + def __getSelectedModifiedItems(self): + """ + Private method to retrieve all selected entries, that have a modified + status. + + @return list of all selected entries with a modified status + @rtype list of QListWidgetItem + """ + return [itm for itm in self.__statusList.selectedItems() + if itm.data(self.StatusDataRole) in "AMOR"] + + def __getUnversionedItems(self): + """ + Private method to retrieve all entries, that have an unversioned + status. + + @return list of all items with an unversioned status + @rtype list of QListWidgetItem + """ + return [itm for itm in self.__statusList.selectedItems() + if itm.data(self.StatusDataRole) == "?"] + + def __getMissingItems(self): + """ + Private method to retrieve all entries, that have a missing status. + + @return list of all items with a missing status + @rtype list of QListWidgetItem + """ + return [itm for itm in self.__statusList.selectedItems() + if itm.data(self.StatusDataRole) == "!"] + + def __getSelectedConflictingItems(self): + """ + Private method to retrieve all selected entries, that have a conflict + status. + + @return list of all selected entries with a conflict status + @rtype list of QListWidgetItem + """ + return [itm for itm in self.__statusList.selectedItems() + if itm.data(self.StatusDataRole) == "Z"] + + @pyqtSlot() + def __diff(self): + """ + Private slot to handle the Diff action menu entry. + """ + projectPath = self.__project.getProjectPath() + + names = [os.path.join(projectPath, itm.text()) + for itm in self.__getSelectedModifiedItems()] + if not names: + EricMessageBox.information( + self, + self.tr("Differences"), + self.tr("""There are no uncommitted changes""" + """ available/selected.""")) + return + + vcs = self.__project.getVcs() + vcs and vcs.vcsDiff(names) + + @pyqtSlot() + def __sbsDiff(self): + """ + Private slot to handle the Side-By-Side Diff action menu entry. + """ + projectPath = self.__project.getProjectPath() + + names = [os.path.join(projectPath, itm.text()) + for itm in self.__getSelectedModifiedItems()] + if not names: + EricMessageBox.information( + self, + self.tr("Differences Side-By-Side"), + self.tr("""There are no uncommitted changes""" + """ available/selected.""")) + return + elif len(names) > 1: + EricMessageBox.information( + self, + self.tr("Differences Side-By-Side"), + self.tr("""Only one file with uncommitted changes""" + """ must be selected.""")) + return + + vcs = self.__project.getVcs() + vcs and vcs.vcsSbsDiff(names[0]) + + def __revert(self): + """ + Private slot to handle the Revert action menu entry. + """ + projectPath = self.__project.getProjectPath() + + names = [os.path.join(projectPath, itm.text()) + for itm in self.__getSelectedModifiedItems()] + if not names: + EricMessageBox.information( + self, + self.tr("Revert"), + self.tr("""There are no uncommitted changes""" + """ available/selected.""")) + return + + vcs = self.__project.getVcs() + vcs and vcs.vcsRevert(names) + self.__reload() + + def __forgetMissing(self): + """ + Private slot to handle the Forget action menu entry. + """ + projectPath = self.__project.getProjectPath() + + names = [os.path.join(projectPath, itm.text()) + for itm in self.__getMissingItems()] + if not names: + EricMessageBox.information( + self, + self.tr("Forget Missing"), + self.tr("""There are no missing entries""" + """ available/selected.""")) + return + + vcs = self.__project.getVcs() + vcs and vcs.vcsForget(names) + self.__reload() + + def __restoreMissing(self): + """ + Private slot to handle the Restore Missing context menu entry. + """ + projectPath = self.__project.getProjectPath() + + names = [os.path.join(projectPath, itm.text()) + for itm in self.__getMissingItems()] + if not names: + EricMessageBox.information( + self, + self.tr("Revert Missing"), + self.tr("""There are no missing entries""" + """ available/selected.""")) + return + + vcs = self.__project.getVcs() + vcs and vcs.vcsRevert(names) + self.__reload() + + def __editConflict(self): + """ + Private slot to handle the Edit Conflict action menu entry. + """ + projectPath = self.__project.getProjectPath() + + itm = self.__getSelectedConflictingItems()[0] + filename = os.path.join(projectPath, itm.text()) + if Utilities.MimeTypes.isTextFile(filename): + self.__vm.getEditor(filename)
--- a/eric7/VCS/VersionControl.py Mon Sep 20 19:47:18 2021 +0200 +++ b/eric7/VCS/VersionControl.py Tue Sep 21 19:11:31 2021 +0200 @@ -302,7 +302,23 @@ implemented by a subclass """ raise RuntimeError('Not implemented') + + def vcsSbsDiff(self, name, extended=False, revisions=None): + """ + Public method used to view the difference of a file to the Mercurial + repository side-by-side. + @param name file name to be diffed + @type str + @param extended flag indicating the extended variant + @type bool + @param revisions tuple of two revisions + @type tuple of two str + @exception RuntimeError to indicate that this method must be + implemented by a subclass + """ + raise RuntimeError('Not implemented') + def vcsStatus(self, name): """ Public method used to view the status of a file/directory in the vcs. @@ -327,12 +343,29 @@ """ Public method used to revert changes made to a file/directory. - @param name file/directory name to be reverted (string) + @param name file/directory name to be reverted + @type str + @return flag indicating, that the update contained an add + or delete + @rtype bool @exception RuntimeError to indicate that this method must be implemented by a subclass """ raise RuntimeError('Not implemented') + return False + + def vcsForget(self, name): + """ + Public method used to remove a file from the repository. + + @param name file/directory name to be removed + @type str or list of str + @exception RuntimeError to indicate that this method must be + implemented by a subclass + """ + raise RuntimeError('Not implemented') + def vcsSwitch(self, name): """ Public method used to switch a directory to a different tag/branch. @@ -579,7 +612,17 @@ for key in self.interestingDataKeys: if key in dictionary: self.otherData[key] = dictionary[key] + + def vcsResolved(self, name): + """ + Public method used to resolve conflicts of a file/directory. + @param name file/directory name to be resolved + @type str + """ + # default implementation just refreshes the status + self.checkVCSStatus() + ##################################################################### ## below are some utility methods #####################################################################