RefactoringRope/HistoryDialog.py

branch
server_client_variant
changeset 168
53d76b4fc1ac
parent 151
5260100b6700
child 170
05ef7c12a6d4
equal deleted inserted replaced
167:3c8e875d0326 168:53d76b4fc1ac
7 Module implementing the History dialog. 7 Module implementing the History dialog.
8 """ 8 """
9 9
10 from __future__ import unicode_literals 10 from __future__ import unicode_literals
11 11
12 from PyQt5.QtCore import Qt, pyqtSlot 12 from PyQt5.QtCore import pyqtSlot, Qt, QItemSelectionModel
13 from PyQt5.QtWidgets import QDialogButtonBox, QListWidgetItem, QApplication 13 from PyQt5.QtGui import QBrush, QColor, QTextCursor
14 from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QListWidgetItem, \
15 QAbstractButton
14 16
15 from E5Gui.E5Application import e5App 17 from E5Gui.E5Application import e5App
16 from E5Gui import E5MessageBox 18 from E5Gui import E5MessageBox
17 19
18 from PreviewDialogBase import PreviewDialogBase 20 from Ui_HistoryDialog import Ui_HistoryDialog
19 21
22 import Globals
20 import Utilities 23 import Utilities
21 24
22 25
23 class HistoryDialog(PreviewDialogBase): 26 class HistoryDialog(QDialog, Ui_HistoryDialog):
24 """ 27 """
25 Class implementing the History dialog. 28 Class implementing the History dialog.
26 """ 29 """
27 ChangeIDRole = Qt.UserRole 30 ChangeIDRole = Qt.UserRole
28 31
29 def __init__(self, refactoring, changes, isUndo, parent=None): 32 def __init__(self, refactoring, filename="", parent=None):
30 """ 33 """
31 Constructor 34 Constructor
32 35
33 @param refactoring reference to the main refactoring object 36 @param refactoring reference to the main refactoring object
34 (Refactoring) 37 @type Refactoring
35 @param changes list of ChangeSet objects 38 @param filename name of the file to show the history for
36 (list of rope.base.change.ChangeSet) 39 @type str
37 @param isUndo flag indicating an undo history dialog (boolean) 40 @param parent reference to the parent widget
38 @param parent reference to the parent widget (QWidget) 41 @type QWidget
39 """ 42 """
40 PreviewDialogBase.__init__(self, parent) 43 QDialog.__init__(self, parent)
44 self.setupUi(self)
45 self.setWindowFlags(Qt.Window)
46
47 if Globals.isWindowsPlatform():
48 self.previewEdit.setFontFamily("Lucida Console")
49 else:
50 self.previewEdit.setFontFamily("Monospace")
51
52 self.formats = {}
53 self.formats[' '] = self.previewEdit.currentCharFormat()
54 charFormat = self.previewEdit.currentCharFormat()
55 charFormat.setBackground(QBrush(QColor(190, 237, 190)))
56 self.formats['+'] = charFormat
57 charFormat = self.previewEdit.currentCharFormat()
58 charFormat.setBackground(QBrush(QColor(237, 190, 190)))
59 self.formats['-'] = charFormat
60 charFormat = self.previewEdit.currentCharFormat()
61 charFormat.setBackground(QBrush(QColor(190, 190, 237)))
62 self.formats['@'] = charFormat
63 charFormat = self.previewEdit.currentCharFormat()
64 charFormat.setBackground(QBrush(QColor(124, 124, 124)))
65 self.formats['?'] = charFormat
66 charFormat = self.previewEdit.currentCharFormat()
67 charFormat.setBackground(QBrush(QColor(190, 190, 190)))
68 self.formats['='] = charFormat
41 69
42 self.__refactoring = refactoring 70 self.__refactoring = refactoring
43 self.__isUndo = isUndo 71 self.__filename = filename
44 72
45 if self.__isUndo: 73 if not filename:
46 self.__actionButton = self.buttonBox.addButton( 74 self.header.setText(self.tr("<b>Project History</b>"))
47 self.tr("&Undo"),
48 QDialogButtonBox.AcceptRole)
49 self.description.setText(self.tr("Undoable Changes"))
50 title = self.tr("Undo History")
51 else: 75 else:
52 self.__actionButton = self.buttonBox.addButton( 76 self.header.setText(self.tr("<b>File History: {0}</b>").format(
53 self.tr("&Redo"), 77 filename))
54 QDialogButtonBox.AcceptRole) 78
55 self.description.setText(self.tr("Redoable Changes")) 79 self.__undoButton = self.buttonBox.addButton(
56 title = self.tr("Redo History") 80 self.tr("&Undo"), QDialogButtonBox.ActionRole)
57 self.buttonBox.addButton(QDialogButtonBox.Close) 81 self.__redoButton = self.buttonBox.addButton(
58 self.setWindowTitle(title) 82 self.tr("&Redo"), QDialogButtonBox.ActionRole)
83 self.__refreshButton = self.buttonBox.addButton(
84 self.tr("Re&fresh"), QDialogButtonBox.ActionRole)
85 self.__clearButton = self.buttonBox.addButton(
86 self.tr("&Clear History"), QDialogButtonBox.ActionRole)
59 87
60 # populate the list 88 # populate the list
61 self.__changes = {} 89 self.__refreshHistories()
62 for change in changes: 90
63 self.__changes[id(change)] = change 91 def __appendText(self, txt, charFormat):
64 itm = QListWidgetItem(str(change), self.changesList) 92 """
65 itm.setData(HistoryDialog.ChangeIDRole, id(change)) 93 Private method to append text to the end of the preview pane.
66 if self.changesList.count() > 0: 94
67 self.changesList.item(0).setSelected(True) 95 @param txt text to insert
68 96 @type str
69 @pyqtSlot(QListWidgetItem, QListWidgetItem) 97 @param charFormat text format to be used
70 def on_changesList_currentItemChanged(self, current, previous): 98 @type QTextCharFormat
71 """ 99 """
72 Private slot called when a change is selected. 100 tc = self.previewEdit.textCursor()
73 101 tc.movePosition(QTextCursor.End)
74 @param current reference to the new current item (QListWidgetItem) 102 self.previewEdit.setTextCursor(tc)
75 @param previous reference to the old current item (QListWidgetItem) 103 self.previewEdit.setCurrentCharFormat(charFormat)
104 self.previewEdit.insertPlainText(txt)
105
106 @pyqtSlot(QAbstractButton)
107 def on_buttonBox_clicked(self, button):
108 """
109 Private slot handling the selection of a dialog button.
110
111 @param button reference to the button clicked
112 @type QAbstractButton
113 """
114 if button == QDialogButtonBox.Close:
115 self.close()
116 elif button == self.__undoButton:
117 self.__undoChanges()
118 elif button == self.__redoButton:
119 self.__redoChanges()
120 elif button == self.__refreshButton:
121 self.__refreshHistories()
122 elif button == self.__clearButton:
123 self.__clearHistory()
124
125 def __currentItemChanged(self, current):
126 """
127 Private method to request change data of an item.
128
129 @param current reference to the item to get change data for
130 @type QListWidgetItem
76 """ 131 """
77 if current is None: 132 if current is None:
78 return 133 return
79 134
80 self.previewEdit.clear() 135 self.previewEdit.clear()
81 changeId = current.data(HistoryDialog.ChangeIDRole) 136 changeId = current.data(HistoryDialog.ChangeIDRole)
82 change = self.__changes[changeId] 137 self.__refactoring.sendJson("History", {
83 for line in change.get_description().splitlines(True): 138 "Subcommand": "GetChange",
84 try: 139 "Id": changeId,
85 charFormat = self.formats[line[0]] 140 })
86 except (IndexError, KeyError): 141
87 charFormat = self.formats[' '] 142 @pyqtSlot(QListWidgetItem, QListWidgetItem)
88 self._appendText(line, charFormat) 143 def on_redoChangesList_currentItemChanged(self, current, previous):
89 144 """
90 def accept(self): 145 Private slot handling a change of the current redo change.
91 """ 146
92 Public slot to undo the selected set of changes. 147 @param current reference to the new current redo item
93 """ 148 @type QListWidgetItem
94 changeId = self.changesList.currentItem()\ 149 @param previous reference to the previous current redo item
95 .data(HistoryDialog.ChangeIDRole) 150 @type QListWidgetItem
96 change = self.__changes[changeId] 151 """
97 152 self.__redoButton.setEnabled(current is not None)
98 if self.__isUndo: 153 self.__currentItemChanged(current)
99 res = E5MessageBox.yesNo( 154
100 None, 155 @pyqtSlot(QListWidgetItem)
101 self.tr("Undo refactorings"), 156 def on_redoChangesList_itemClicked(self, item):
102 self.tr("""Shall all refactorings up to <b>{0}</b>""" 157 """
103 """ be undone?""") 158 Private slot handling a click on a redo entry.
104 .format(Utilities.html_encode(str(change)))) 159
105 else: 160 @param item reference to the clicked item
106 res = E5MessageBox.yesNo( 161 @type QListWidgetItem
107 None, 162 """
108 self.tr("Redo refactorings"), 163 self.__currentItemChanged(item)
109 self.tr("""Shall all refactorings up to <b>{0}</b>""" 164
110 """ be redone?""") 165 @pyqtSlot(QListWidgetItem, QListWidgetItem)
111 .format(Utilities.html_encode(str(change)))) 166 def on_undoChangesList_currentItemChanged(self, current, previous):
167 """
168 Private slot handling a change of the current undo change.
169
170 @param current reference to the new current undo item
171 @type QListWidgetItem
172 @param previous reference to the previous current undo item
173 @type QListWidgetItem
174 """
175 self.__undoButton.setEnabled(current is not None)
176 self.__currentItemChanged(current)
177
178 @pyqtSlot(QListWidgetItem)
179 def on_undoChangesList_itemClicked(self, item):
180 """
181 Private slot handling a click on an undo entry.
182
183 @param item reference to the clicked item
184 @type QListWidgetItem
185 """
186 self.__currentItemChanged(item)
187
188 def __undoChanges(self):
189 """
190 Private method to undo the selected set of changes.
191 """
192 currentUndoItem = self.undoChangesList.currentItem()
193 change = currentUndoItem.text()
194 changeId = currentUndoItem.data(HistoryDialog.ChangeIDRole)
195 res = E5MessageBox.yesNo(
196 None,
197 self.tr("Undo refactorings"),
198 self.tr("""Shall all refactorings up to <b>{0}</b>"""
199 """ be undone?""")
200 .format(Utilities.html_encode(change)))
112 if res: 201 if res:
113 if not self.__refactoring.confirmAllBuffersSaved(): 202 if not self.__refactoring.confirmAllBuffersSaved():
114 return 203 return
115 204
116 from ProgressHandle import ProgressHandle 205 self.__refactoring.sendJson("History", {
117 handle = ProgressHandle(change.description, False, self) 206 "Subcommand": "Undo",
118 handle.show() 207 "Id": changeId,
119 QApplication.processEvents() 208 })
120 if self.__isUndo: 209
121 self.__refactoring.getProject().history.undo( 210 def __redoChanges(self):
122 change, task_handle=handle) 211 """
123 else: 212 Private method to redo the selected set of changes.
124 self.__refactoring.getProject().history.redo( 213 """
125 change, task_handle=handle) 214 currentRedoItem = self.redoChangesList.currentItem()
126 handle.reset() 215 change = currentRedoItem.text()
127 216 changeId = currentRedoItem.data(HistoryDialog.ChangeIDRole)
128 self.__refactoring.refreshEditors(change) 217 res = E5MessageBox.yesNo(
218 None,
219 self.tr("Redo refactorings"),
220 self.tr("""Shall all refactorings up to <b>{0}</b>"""
221 """ be redone?""")
222 .format(Utilities.html_encode(change)))
223 if res:
224 if not self.__refactoring.confirmAllBuffersSaved():
225 return
226
227 self.__refactoring.sendJson("History", {
228 "Subcommand": "Redo",
229 "Id": changeId,
230 })
231
232 def __refreshHistories(self):
233 """
234 Private method to refresh the undo and redo history lists.
235 """
236 self.__undoButton.setEnabled(False)
237 self.__redoButton.setEnabled(False)
238 self.__refreshButton.setEnabled(False)
239 self.__clearButton.setEnabled(False)
240
241 self.undoChangesList.clear()
242 self.redoChangesList.clear()
243 self.previewEdit.clear()
244
245 self.__refactoring.sendJson("History", {
246 "Subcommand": "Get",
247 "Filename": self.__filename
248 })
249
250 def __clearHistory(self):
251 """
252 Private method to clear the refactoring history.
253 """
254 res = E5MessageBox.yesNo(
255 None,
256 self.tr("Clear History"),
257 self.tr("Do you really want to clear the refactoring history?"))
258 if res:
259 self.sendJson("History", {
260 "Subcommand": "Clear",
261 })
262
263 self.historyCleared()
264
265 def historyCleared(self):
266 """
267 Public method to indicate, that the refactoring history was cleared
268 through the menu.
269 """
270 self.__refreshHistories()
271
272 def processHistoryCommand(self, data):
273 """
274 Public method to process the data sent by the refactoring client.
275
276 @param data dictionary containing the history data
277 @type dict
278 """
279 subcommand = data["Subcommand"]
280 if subcommand == "Histories":
281 for change, changeId in data["Undo"]:
282 itm = QListWidgetItem(change, self.undoChangesList)
283 itm.setData(HistoryDialog.ChangeIDRole, changeId)
284 for change, changeId in data["Redo"]:
285 itm = QListWidgetItem(change, self.redoChangesList)
286 itm.setData(HistoryDialog.ChangeIDRole, changeId)
287 if self.undoChangesList.count() > 0:
288 self.undoChangesList.setCurrentItem(
289 self.undoChangesList.item(0),
290 QItemSelectionModel.Select)
291 elif self.redoChangesList.count() > 0:
292 self.redoChangesList.setCurrentItem(
293 self.redoChangesList.item(0),
294 QItemSelectionModel.Select)
295
296 self.__refreshButton.setEnabled(True)
297 if self.undoChangesList.count() > 0 or \
298 self.redoChangesList.count() > 0:
299 self.__clearButton.setEnabled(True)
300
301 elif subcommand == "ChangeDescription":
302 for line in data["Description"].splitlines(True):
303 try:
304 charFormat = self.formats[line[0]]
305 except (IndexError, KeyError):
306 charFormat = self.formats[' ']
307 self.__appendText(line, charFormat)
308
309 elif subcommand in ["Undo", "Redo"]:
310 self.__refactoring.refreshEditors(data["ChangedFiles"])
129 p = e5App().getObject("Project") 311 p = e5App().getObject("Project")
130 if p.isDirty(): 312 if p.isDirty():
131 p.saveProject() 313 p.saveProject()
132 314
133 PreviewDialogBase.accept(self) 315 self.raise_()
134 else: 316 self.__refreshHistories()
135 self.reject()

eric ide

mercurial