Plugins/VcsPlugins/vcsMercurial/QueuesExtension/HgQueuesDefineGuardsDialog.py

changeset 1046
5dd14be5d6a1
child 1047
b41a36b201e4
equal deleted inserted replaced
1044:11aca34cce20 1046:5dd14be5d6a1
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2011 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a dialog to define guards for patches.
8 """
9
10 import os
11
12 from PyQt4.QtCore import pyqtSlot, Qt, QProcess, QTimer
13 from PyQt4.QtGui import QDialog, QDialogButtonBox, QAbstractButton, QListWidgetItem
14
15 from E5Gui import E5MessageBox
16
17 from .Ui_HgQueuesDefineGuardsDialog import Ui_HgQueuesDefineGuardsDialog
18
19 import Preferences
20 import UI.PixmapCache
21
22
23 class HgQueuesDefineGuardsDialog(QDialog, Ui_HgQueuesDefineGuardsDialog):
24 """
25 Class implementing a dialog to define guards for patches.
26 """
27 def __init__(self, vcs, patchesList, parent=None):
28 """
29 Constructor
30
31 @param vcs reference to the vcs object
32 @param patchesList list of patches (list of strings)
33 @param parent reference to the parent widget (QWidget)
34 """
35 QDialog.__init__(self, parent)
36 self.setupUi(self)
37
38 self.process = QProcess()
39 self.vcs = vcs
40
41 self.__patches = patchesList[:]
42 self.patchSelector.addItems([""] + self.__patches)
43
44 self.plusButton.setIcon(UI.PixmapCache.getIcon("plus.png"))
45 self.minusButton.setIcon(UI.PixmapCache.getIcon("minus.png"))
46
47 self.__dirtyList = False
48 self.__currentPatch = ""
49
50 def closeEvent(self, e):
51 """
52 Private slot implementing a close event handler.
53
54 @param e close event (QCloseEvent)
55 """
56 if self.process is not None and \
57 self.process.state() != QProcess.NotRunning:
58 self.process.terminate()
59 QTimer.singleShot(2000, self.process.kill)
60 self.process.waitForFinished(3000)
61
62 if self.__dirtyList:
63 res = E5MessageBox.question(self,
64 self.trUtf8("Unsaved Changes"),
65 self.trUtf8("""The guards list has been changed."""
66 """ Shall the changes be applied?"""),
67 E5MessageBox.StandardButtons(
68 E5MessageBox.Apply | \
69 E5MessageBox.Discard),
70 E5MessageBox.Apply)
71 if res == E5MessageBox.Apply:
72 self.__applyGuards()
73 else:
74 self.__dirtyList = False
75
76 e.accept()
77
78 def start(self, path):
79 """
80 Public slot to start the list command.
81
82 @param path name of directory to be listed (string)
83 """
84 dname, fname = self.vcs.splitPath(path)
85
86 # find the root of the repo
87 repodir = dname
88 while not os.path.isdir(os.path.join(repodir, self.vcs.adminDir)):
89 repodir = os.path.dirname(repodir)
90 if repodir == os.sep:
91 return
92
93 self.__repodir = repodir
94 self.on_patchSelector_activated("")
95
96 def __getGuards(self):
97 """
98 Private method to get a list of all guards defined.
99
100 @return list of guards (list of strings)
101 """
102 guardsList = []
103
104 ioEncoding = Preferences.getSystem("IOEncoding")
105 process = QProcess()
106 args = []
107 args.append("qselect")
108 args.append("--series")
109
110 process.setWorkingDirectory(self.__repodir)
111 process.start('hg', args)
112 procStarted = process.waitForStarted()
113 if procStarted:
114 finished = process.waitForFinished(30000)
115 if finished and process.exitCode() == 0:
116 output = \
117 str(process.readAllStandardOutput(), ioEncoding, 'replace')
118 for guard in output.splitlines():
119 guard = guard.strip()[1:]
120 if guard not in guardsList:
121 guardsList.append(guard)
122
123 return sorted(guardsList)
124
125 @pyqtSlot(str)
126 def on_patchSelector_activated(self, patch):
127 """
128 Private slot to get the list of guards defined for the given patch name.
129
130 @param patch selected patch name (empty for current patch)
131 """
132 if self.__dirtyList:
133 res = E5MessageBox.question(self,
134 self.trUtf8("Unsaved Changes"),
135 self.trUtf8("""The guards list has been changed."""
136 """ Shall the changes be applied?"""),
137 E5MessageBox.StandardButtons(
138 E5MessageBox.Apply | \
139 E5MessageBox.Discard),
140 E5MessageBox.Apply)
141 if res == E5MessageBox.Apply:
142 self.__applyGuards()
143 else:
144 self.__dirtyList = False
145
146 self.guardsList.clear()
147 self.patchNameLabel.setText("")
148
149 self.guardCombo.clear()
150 guardsList = self.__getGuards()
151 self.guardCombo.addItems(guardsList)
152 self.guardCombo.setEditText("")
153
154 ioEncoding = Preferences.getSystem("IOEncoding")
155 process = QProcess()
156 args = []
157 args.append("qguard")
158 if patch:
159 args.append(patch)
160
161 process.setWorkingDirectory(self.__repodir)
162 process.start('hg', args)
163 procStarted = process.waitForStarted()
164 if procStarted:
165 finished = process.waitForFinished(30000)
166 if finished and process.exitCode() == 0:
167 output = \
168 str(process.readAllStandardOutput(), ioEncoding, 'replace').strip()
169 if output:
170 patchName, guards = output.split(":", 1)
171 self.patchNameLabel.setText(patchName)
172 guardsList = guards.strip().split()
173 for guard in guardsList:
174 if guard.startswith("+"):
175 icon = UI.PixmapCache.getIcon("plus.png")
176 guard = guard[1:]
177 sign = "+"
178 elif guard.startswith("-"):
179 icon = UI.PixmapCache.getIcon("minus.png")
180 guard = guard[1:]
181 sign = "-"
182 else:
183 continue
184 itm = QListWidgetItem(icon, guard, self.guardsList)
185 itm.setData(Qt.UserRole, sign)
186
187 self.on_guardsList_itemSelectionChanged()
188
189 @pyqtSlot()
190 def on_guardsList_itemSelectionChanged(self):
191 """
192 Private slot to handle changes of the selection of guards.
193 """
194 self.removeButton.setEnabled(
195 len(self.guardsList.selectedItems()) > 0)
196
197 def __getGuard(self, guard):
198 """
199 Private method to get a reference to a named guard.
200
201 @param guard name of the guard (string)
202 @return reference to the guard item (QListWidgetItem)
203 """
204 items = self.guardsList.findItems(guard, Qt.MatchCaseSensitive)
205 if items:
206 return items[0]
207 else:
208 return None
209
210 @pyqtSlot(str)
211 def on_guardCombo_editTextChanged(self, txt):
212 """
213 Private slot to handle changes of the text of the guard combo.
214
215 @param txt contents of the guard combo line edit (string)
216 """
217 self.addButton.setEnabled(txt != "")
218
219 @pyqtSlot()
220 def on_addButton_clicked(self):
221 """
222 Private slot to add a guard definition to the list or change it.
223 """
224 guard = self.guardCombo.currentText()
225 if self.plusButton.isChecked():
226 sign = "+"
227 icon = UI.PixmapCache.getIcon("plus.png")
228 else:
229 sign = "-"
230 icon = UI.PixmapCache.getIcon("minus.png")
231
232 guardItem = self.__getGuard(guard)
233 if guardItem:
234 # guard already exists, remove it first
235 row = self.guardsList.row(guardItem)
236 itm = self.guardsList.takeItem(row)
237 del itm
238
239 itm = QListWidgetItem(icon, guard, self.guardsList)
240 itm.setData(Qt.UserRole, sign)
241 self.guardsList.sortItems()
242
243 self.__dirtyList = True
244
245 @pyqtSlot()
246 def on_removeButton_clicked(self):
247 """
248 Private slot to remove guard definitions from the list.
249 """
250 res = E5MessageBox.yesNo(self,
251 self.trUtf8("Remove Guards"),
252 self.trUtf8("""Do you really want to remove the selected guards?"""))
253 if res:
254 for guardItem in self.guardsList.selectedItems():
255 row = self.guardsList.row(guardItem)
256 itm = self.guardsList.takeItem(row)
257 del itm
258
259 self.__dirtyList = True
260
261 @pyqtSlot(QAbstractButton)
262 def on_buttonBox_clicked(self, button):
263 """
264 Private slot called by a button of the button box clicked.
265
266 @param button button that was clicked (QAbstractButton)
267 """
268 if button == self.buttonBox.button(QDialogButtonBox.Apply):
269 self.__applyGuards()
270 elif button == self.buttonBox.button(QDialogButtonBox.Close):
271 self.close()
272
273 @pyqtSlot()
274 def __applyGuards(self):
275 """
276 Private slot to apply the defined guards to the current patch.
277 """
278 if self.__dirtyList:
279 guardsList = []
280 for row in range(self.guardsList.count()):
281 itm = self.guardsList.item(row)
282 guard = itm.data(Qt.UserRole) + itm.text()
283 guardsList.append(guard)
284
285 ioEncoding = Preferences.getSystem("IOEncoding")
286 process = QProcess()
287 args = []
288 args.append("qguard")
289 args.append(self.patchNameLabel.text())
290 if guardsList:
291 args.append("--")
292 args.extend(guardsList)
293 else:
294 args.append("--none")
295
296 process.setWorkingDirectory(self.__repodir)
297 process.start('hg', args)
298 procStarted = process.waitForStarted()
299 if procStarted:
300 finished = process.waitForFinished(30000)
301 if finished:
302 if process.exitCode() == 0:
303 self.__dirtyList = False
304 self.on_patchSelector_activated(self.patchNameLabel.text())
305 else:
306 error = \
307 str(process.readAllStandardError(), ioEncoding, 'replace')
308 E5MessageBox.warning(self,
309 self.trUtf8("Apply Guard Definitions"),
310 self.trUtf8("""<p>The defined guards could not be"""
311 """ applied.</p><p>Reason: {0}</p>""")\
312 .format(error))
313
314 else:
315 E5MessageBox.warning(self,
316 self.trUtf8("Apply Guard Definitions"),
317 self.trUtf8("""The Mercurial process did not finish in time."""))

eric ide

mercurial