Plugins/VcsPlugins/vcsMercurial/HisteditExtension/HgHisteditPlanEditor.py

changeset 5283
06423d65a2b8
child 5291
e93d14b48c34
equal deleted inserted replaced
5282:898b0dda21e1 5283:06423d65a2b8
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2016 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a dialog to edit the history modification plan.
8 """
9
10 from PyQt5.QtCore import pyqtSlot, QCoreApplication
11 from PyQt5.QtWidgets import QDialog, QTreeWidgetItem, QComboBox
12
13 from E5Gui import E5MessageBox
14
15 from Ui_HgHisteditPlanEditor import Ui_HgHisteditPlanEditor
16
17 import UI.PixmapCache
18
19
20 class HgHisteditPlanActionComboBox(QComboBox):
21 """
22 Class implementing a combo box to select the action in the plan tree.
23 """
24 def __init__(self, item, column):
25 """
26 Constructor
27
28 @param item reference to the item
29 @type QTreeWidgetItem
30 @param column column number inside the tree widget item
31 @type int
32 """
33 super(HgHisteditPlanActionComboBox, self).__init__()
34
35 self.__item = item
36 self.__column = column
37
38 self.addItems(["pick", "drop", "mess", "fold", "roll", "edit"])
39 txt = self.__item.text(self.__column)
40 index = self.findText(txt)
41 if index > -1:
42 self.setCurrentIndex(index)
43
44 self.currentIndexChanged.connect(self.__changeItem)
45
46 @pyqtSlot(int)
47 def __changeItem(self, index):
48 """
49 Private slot to handle the selection of a plan action.
50
51 This method sets the text of the associated item for the specified
52 cell in order to be able to retrieve it with a call of the text()
53 method of the item.
54
55 @param index index of the selected action
56 @type int
57 """
58 self.__item.setText(self.__column, self.currentText())
59 self.__item.treeWidget().setCurrentItem(self.__item)
60
61 def showPopup(self):
62 """
63 Public method to show the list of items of the combo box.
64
65 This is reimplemented in order to set the associated item as the
66 current item of the tree widget.
67 """
68 self.__item.treeWidget().setCurrentItem(self.__item)
69 super(HgHisteditPlanActionComboBox, self).showPopup()
70
71
72 class HgHisteditPlanEditor(QDialog, Ui_HgHisteditPlanEditor):
73 """
74 Class implementing a dialog to edit the history modification plan.
75 """
76 def __init__(self, fileName, parent=None):
77 """
78 Constructor
79
80 @param fileName name of the file containing the history edit plan
81 to be edited
82 @type str
83 @param parent reference to the parent widget
84 @type QWidget
85 """
86 super(HgHisteditPlanEditor, self).__init__(parent)
87 self.setupUi(self)
88
89 self.upButton.setIcon(UI.PixmapCache.getIcon("1uparrow.png"))
90 self.downButton.setIcon(UI.PixmapCache.getIcon("1downarrow.png"))
91
92 self.planTreeWidget.headerItem().setText(
93 self.planTreeWidget.columnCount(), "")
94
95 self.__fileName = fileName
96 self.__readFile()
97
98 self.__updateButtons()
99
100 def __readFile(self):
101 """
102 Private method to read the file containing the edit plan and
103 populate the dialog.
104 """
105 try:
106 f = open(self.__fileName, "r")
107 txt = f.read()
108 f.close()
109 except (IOError, OSError) as err:
110 E5MessageBox.critical(
111 self,
112 self.tr("Edit Plan"),
113 self.tr("""<p>The file <b>{0}</b> could not be read.</p>"""
114 """<p>Reason: {1}</p>""").format(
115 self.__fileName, str(err)))
116 self.on_buttonBox_rejected()
117 return
118
119 infoLines = []
120 for line in txt.splitlines():
121 if line.startswith("#"):
122 infoLines.append(line[1:].lstrip())
123 else:
124 self.__createPlanItem(line)
125 self.infoEdit.setPlainText("\n".join(infoLines))
126
127 self.__resizeSections()
128
129 def __addActionCombo(self, item):
130 """
131 Private method to add an edit action combo to an item.
132
133 @param item reference to the tree widget item
134 @type QTreeWidgetItem
135 """
136 actionCombo = HgHisteditPlanActionComboBox(item, 0)
137 self.planTreeWidget.setItemWidget(item, 0, actionCombo)
138 item.setSizeHint(0, actionCombo.sizeHint())
139
140 def __createPlanItem(self, text):
141 """
142 Private method to create an edit plan tree item.
143 """
144 if not text.lstrip():
145 return
146
147 parts = text.split(" ", 3)
148 action = parts[0]
149 try:
150 rev = int(parts[2])
151 if len(parts) > 3:
152 summary = parts[3]
153 else:
154 summary = ""
155 except ValueError:
156 rev = -1
157 summary = " ".join(parts[2:])
158 if rev > -1:
159 revision = "{0:>7}:{1}".format(rev, parts[1])
160 else:
161 revision = parts[1]
162
163 itm = QTreeWidgetItem(self.planTreeWidget, [
164 action,
165 revision,
166 summary,
167 ])
168 self.__addActionCombo(itm)
169
170 def __resizeSections(self):
171 """
172 Private method to resize the tree widget sections.
173 """
174 for column in range(self.planTreeWidget.columnCount()):
175 self.planTreeWidget.resizeColumnToContents(column)
176 self.planTreeWidget.header().setStretchLastSection(True)
177
178 def __updateButtons(self):
179 """
180 Private method to set the enabled state of the up and down buttons.
181 """
182 if self.planTreeWidget.currentItem() is None:
183 self.upButton.setEnabled(False)
184 self.downButton.setEnabled(False)
185 else:
186 row = self.planTreeWidget.indexOfTopLevelItem(
187 self.planTreeWidget.currentItem())
188 self.upButton.setEnabled(row > 0)
189 self.downButton.setEnabled(
190 row < self.planTreeWidget.topLevelItemCount() - 1)
191
192 @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem)
193 def on_planTreeWidget_currentItemChanged(self, current, previous):
194 """
195 Private slot handling the change of the current edit plan item.
196
197 @param current reference to the current edit plan item
198 @type QTreeWidgetItem
199 @param previous reference to the previous current edit plan item
200 @type QTreeWidgetItem
201 """
202 self.__updateButtons()
203
204 @pyqtSlot()
205 def on_upButton_clicked(self):
206 """
207 Private slot to move the current entry up one line.
208 """
209 row = self.planTreeWidget.indexOfTopLevelItem(
210 self.planTreeWidget.currentItem())
211 if row > 0:
212 targetRow = row - 1
213 itm = self.planTreeWidget.takeTopLevelItem(row)
214 self.planTreeWidget.insertTopLevelItem(targetRow, itm)
215 self.__addActionCombo(itm)
216 self.planTreeWidget.setCurrentItem(itm)
217
218 @pyqtSlot()
219 def on_downButton_clicked(self):
220 """
221 Private slot to move the current entry down one line.
222 """
223 row = self.planTreeWidget.indexOfTopLevelItem(
224 self.planTreeWidget.currentItem())
225 if row < self.planTreeWidget.topLevelItemCount() - 1:
226 targetRow = row + 1
227 itm = self.planTreeWidget.takeTopLevelItem(row)
228 self.planTreeWidget.insertTopLevelItem(targetRow, itm)
229 self.__addActionCombo(itm)
230 self.planTreeWidget.setCurrentItem(itm)
231
232 @pyqtSlot()
233 def on_buttonBox_accepted(self):
234 """
235 Private slot called by the buttonBox accepted signal.
236 """
237 text = self.__assembleEditPlan()
238 try:
239 f = open(self.__fileName, "w")
240 f.write(text)
241 f.close()
242 except (IOError, OSError) as err:
243 E5MessageBox.critical(
244 self,
245 self.tr("Edit Plan"),
246 self.tr("""<p>The file <b>{0}</b> could not be read.</p>"""
247 """<p>Reason: {1}</p>""").format(
248 self.__fileName, str(err)))
249 self.on_buttonBox_rejected()
250 return
251
252 self.close()
253 QCoreApplication.exit(0)
254
255 @pyqtSlot()
256 def on_buttonBox_rejected(self):
257 """
258 Private slot called by the buttonBox rejected signal.
259 """
260 self.close()
261 QCoreApplication.exit(1)
262
263 def __assembleEditPlan(self):
264 """
265 Private method to assemble the edit plan into text suitable for the
266 histedit file.
267
268 @return assembled edit plan text
269 @rtype str
270 """
271 lines = []
272 for row in range(self.planTreeWidget.topLevelItemCount()):
273 itm = self.planTreeWidget.topLevelItem(row)
274 if ":" in itm.text(1):
275 rev, changeset = itm.text(1).split(":", 1)
276 rev = "{0} {1}".format(changeset.strip(), rev.strip())
277 else:
278 rev = itm.text(1).strip()
279
280 lines.append("{0} {1} {2}".format(itm.text(0).strip(), rev,
281 itm.text(2)))
282
283 return "\n".join(lines)

eric ide

mercurial