RefactoringRope/HistoryDialog.py

Sun, 17 Sep 2017 17:03:16 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sun, 17 Sep 2017 17:03:16 +0200
branch
server_client_variant
changeset 168
53d76b4fc1ac
parent 151
5260100b6700
child 170
05ef7c12a6d4
permissions
-rw-r--r--

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()

eric ide

mercurial