Sun, 17 Sep 2017 17:03:16 +0200
Implemented the distributed History dialog and moved the Undo/Redo functions to this dialog.
# -*- coding: utf-8 -*- # Copyright (c) 2010 - 2017 Detlev Offenbach <detlev@die-offenbachs.de> # """ Module implementing the History dialog. """ from __future__ import unicode_literals from PyQt5.QtCore import pyqtSlot, Qt, QItemSelectionModel from PyQt5.QtGui import QBrush, QColor, QTextCursor from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QListWidgetItem, \ QAbstractButton from E5Gui.E5Application import e5App from E5Gui import E5MessageBox from Ui_HistoryDialog import Ui_HistoryDialog import Globals import Utilities class HistoryDialog(QDialog, Ui_HistoryDialog): """ Class implementing the History dialog. """ ChangeIDRole = Qt.UserRole def __init__(self, refactoring, filename="", parent=None): """ Constructor @param refactoring reference to the main refactoring object @type Refactoring @param filename name of the file to show the history for @type str @param parent reference to the parent widget @type QWidget """ QDialog.__init__(self, parent) self.setupUi(self) self.setWindowFlags(Qt.Window) if Globals.isWindowsPlatform(): self.previewEdit.setFontFamily("Lucida Console") else: self.previewEdit.setFontFamily("Monospace") self.formats = {} self.formats[' '] = self.previewEdit.currentCharFormat() charFormat = self.previewEdit.currentCharFormat() charFormat.setBackground(QBrush(QColor(190, 237, 190))) self.formats['+'] = charFormat charFormat = self.previewEdit.currentCharFormat() charFormat.setBackground(QBrush(QColor(237, 190, 190))) self.formats['-'] = charFormat charFormat = self.previewEdit.currentCharFormat() charFormat.setBackground(QBrush(QColor(190, 190, 237))) self.formats['@'] = charFormat charFormat = self.previewEdit.currentCharFormat() charFormat.setBackground(QBrush(QColor(124, 124, 124))) self.formats['?'] = charFormat charFormat = self.previewEdit.currentCharFormat() charFormat.setBackground(QBrush(QColor(190, 190, 190))) self.formats['='] = charFormat self.__refactoring = refactoring self.__filename = filename if not filename: self.header.setText(self.tr("<b>Project History</b>")) else: self.header.setText(self.tr("<b>File History: {0}</b>").format( filename)) self.__undoButton = self.buttonBox.addButton( self.tr("&Undo"), QDialogButtonBox.ActionRole) self.__redoButton = self.buttonBox.addButton( self.tr("&Redo"), QDialogButtonBox.ActionRole) self.__refreshButton = self.buttonBox.addButton( self.tr("Re&fresh"), QDialogButtonBox.ActionRole) self.__clearButton = self.buttonBox.addButton( self.tr("&Clear History"), QDialogButtonBox.ActionRole) # populate the list self.__refreshHistories() def __appendText(self, txt, charFormat): """ Private method to append text to the end of the preview pane. @param txt text to insert @type str @param charFormat text format to be used @type QTextCharFormat """ tc = self.previewEdit.textCursor() tc.movePosition(QTextCursor.End) self.previewEdit.setTextCursor(tc) self.previewEdit.setCurrentCharFormat(charFormat) self.previewEdit.insertPlainText(txt) @pyqtSlot(QAbstractButton) def on_buttonBox_clicked(self, button): """ Private slot handling the selection of a dialog button. @param button reference to the button clicked @type QAbstractButton """ if button == QDialogButtonBox.Close: self.close() elif button == self.__undoButton: self.__undoChanges() elif button == self.__redoButton: self.__redoChanges() elif button == self.__refreshButton: self.__refreshHistories() elif button == self.__clearButton: self.__clearHistory() def __currentItemChanged(self, current): """ Private method to request change data of an item. @param current reference to the item to get change data for @type QListWidgetItem """ if current is None: return self.previewEdit.clear() changeId = current.data(HistoryDialog.ChangeIDRole) self.__refactoring.sendJson("History", { "Subcommand": "GetChange", "Id": changeId, }) @pyqtSlot(QListWidgetItem, QListWidgetItem) def on_redoChangesList_currentItemChanged(self, current, previous): """ Private slot handling a change of the current redo change. @param current reference to the new current redo item @type QListWidgetItem @param previous reference to the previous current redo item @type QListWidgetItem """ self.__redoButton.setEnabled(current is not None) self.__currentItemChanged(current) @pyqtSlot(QListWidgetItem) def on_redoChangesList_itemClicked(self, item): """ Private slot handling a click on a redo entry. @param item reference to the clicked item @type QListWidgetItem """ self.__currentItemChanged(item) @pyqtSlot(QListWidgetItem, QListWidgetItem) def on_undoChangesList_currentItemChanged(self, current, previous): """ Private slot handling a change of the current undo change. @param current reference to the new current undo item @type QListWidgetItem @param previous reference to the previous current undo item @type QListWidgetItem """ self.__undoButton.setEnabled(current is not None) self.__currentItemChanged(current) @pyqtSlot(QListWidgetItem) def on_undoChangesList_itemClicked(self, item): """ Private slot handling a click on an undo entry. @param item reference to the clicked item @type QListWidgetItem """ self.__currentItemChanged(item) def __undoChanges(self): """ Private method to undo the selected set of changes. """ currentUndoItem = self.undoChangesList.currentItem() change = currentUndoItem.text() changeId = currentUndoItem.data(HistoryDialog.ChangeIDRole) res = E5MessageBox.yesNo( None, self.tr("Undo refactorings"), self.tr("""Shall all refactorings up to <b>{0}</b>""" """ be undone?""") .format(Utilities.html_encode(change))) if res: if not self.__refactoring.confirmAllBuffersSaved(): return self.__refactoring.sendJson("History", { "Subcommand": "Undo", "Id": changeId, }) def __redoChanges(self): """ Private method to redo the selected set of changes. """ currentRedoItem = self.redoChangesList.currentItem() change = currentRedoItem.text() changeId = currentRedoItem.data(HistoryDialog.ChangeIDRole) res = E5MessageBox.yesNo( None, self.tr("Redo refactorings"), self.tr("""Shall all refactorings up to <b>{0}</b>""" """ be redone?""") .format(Utilities.html_encode(change))) if res: if not self.__refactoring.confirmAllBuffersSaved(): return self.__refactoring.sendJson("History", { "Subcommand": "Redo", "Id": changeId, }) def __refreshHistories(self): """ Private method to refresh the undo and redo history lists. """ self.__undoButton.setEnabled(False) self.__redoButton.setEnabled(False) self.__refreshButton.setEnabled(False) self.__clearButton.setEnabled(False) self.undoChangesList.clear() self.redoChangesList.clear() self.previewEdit.clear() self.__refactoring.sendJson("History", { "Subcommand": "Get", "Filename": self.__filename }) def __clearHistory(self): """ Private method to clear the refactoring history. """ res = E5MessageBox.yesNo( None, self.tr("Clear History"), self.tr("Do you really want to clear the refactoring history?")) if res: self.sendJson("History", { "Subcommand": "Clear", }) self.historyCleared() def historyCleared(self): """ Public method to indicate, that the refactoring history was cleared through the menu. """ self.__refreshHistories() def processHistoryCommand(self, data): """ Public method to process the data sent by the refactoring client. @param data dictionary containing the history data @type dict """ subcommand = data["Subcommand"] if subcommand == "Histories": for change, changeId in data["Undo"]: itm = QListWidgetItem(change, self.undoChangesList) itm.setData(HistoryDialog.ChangeIDRole, changeId) for change, changeId in data["Redo"]: itm = QListWidgetItem(change, self.redoChangesList) itm.setData(HistoryDialog.ChangeIDRole, changeId) if self.undoChangesList.count() > 0: self.undoChangesList.setCurrentItem( self.undoChangesList.item(0), QItemSelectionModel.Select) elif self.redoChangesList.count() > 0: self.redoChangesList.setCurrentItem( self.redoChangesList.item(0), QItemSelectionModel.Select) self.__refreshButton.setEnabled(True) if self.undoChangesList.count() > 0 or \ self.redoChangesList.count() > 0: self.__clearButton.setEnabled(True) elif subcommand == "ChangeDescription": for line in data["Description"].splitlines(True): try: charFormat = self.formats[line[0]] except (IndexError, KeyError): charFormat = self.formats[' '] self.__appendText(line, charFormat) elif subcommand in ["Undo", "Redo"]: self.__refactoring.refreshEditors(data["ChangedFiles"]) p = e5App().getObject("Project") if p.isDirty(): p.saveProject() self.raise_() self.__refreshHistories()