1# -*- coding: utf-8 -*- 2 3# Copyright (c) 2011 - 2021 Detlev Offenbach <detlev@die-offenbachs.de> 4# 5 6""" 7Module implementing a dialog to define guards for patches. 8""" 9 10from PyQt5.QtCore import pyqtSlot, Qt, QCoreApplication 11from PyQt5.QtWidgets import ( 12 QDialog, QDialogButtonBox, QAbstractButton, QListWidgetItem 13) 14 15from E5Gui import E5MessageBox 16 17from .Ui_HgQueuesDefineGuardsDialog import Ui_HgQueuesDefineGuardsDialog 18 19import UI.PixmapCache 20 21 22class HgQueuesDefineGuardsDialog(QDialog, Ui_HgQueuesDefineGuardsDialog): 23 """ 24 Class implementing a dialog to define guards for patches. 25 """ 26 def __init__(self, vcs, extension, patchesList, parent=None): 27 """ 28 Constructor 29 30 @param vcs reference to the vcs object 31 @param extension reference to the extension module (Queues) 32 @param patchesList list of patches (list of strings) 33 @param parent reference to the parent widget (QWidget) 34 """ 35 super().__init__(parent) 36 self.setupUi(self) 37 self.setWindowFlags(Qt.WindowType.Window) 38 39 self.vcs = vcs 40 self.extension = extension 41 self.__hgClient = vcs.getClient() 42 43 self.__patches = patchesList[:] 44 self.patchSelector.addItems([""] + self.__patches) 45 46 self.plusButton.setIcon(UI.PixmapCache.getIcon("plus")) 47 self.minusButton.setIcon(UI.PixmapCache.getIcon("minus")) 48 49 self.__dirtyList = False 50 self.__currentPatch = "" 51 52 self.show() 53 QCoreApplication.processEvents() 54 55 def closeEvent(self, e): 56 """ 57 Protected slot implementing a close event handler. 58 59 @param e close event (QCloseEvent) 60 """ 61 if self.__hgClient.isExecuting(): 62 self.__hgClient.cancel() 63 64 if self.__dirtyList: 65 res = E5MessageBox.question( 66 self, 67 self.tr("Unsaved Changes"), 68 self.tr("""The guards list has been changed.""" 69 """ Shall the changes be applied?"""), 70 E5MessageBox.StandardButtons( 71 E5MessageBox.Apply | 72 E5MessageBox.Discard), 73 E5MessageBox.Apply) 74 if res == E5MessageBox.Apply: 75 self.__applyGuards() 76 else: 77 self.__dirtyList = False 78 79 e.accept() 80 81 def start(self): 82 """ 83 Public slot to start the list command. 84 """ 85 self.on_patchSelector_activated(0) 86 87 @pyqtSlot(int) 88 def on_patchSelector_activated(self, index): 89 """ 90 Private slot to get the list of guards defined for the given patch 91 name. 92 93 @param index index of the selected entry 94 @type int 95 """ 96 patch = self.patchSelector.itemText(index) 97 if self.__dirtyList: 98 res = E5MessageBox.question( 99 self, 100 self.tr("Unsaved Changes"), 101 self.tr("""The guards list has been changed.""" 102 """ Shall the changes be applied?"""), 103 E5MessageBox.StandardButtons( 104 E5MessageBox.Apply | 105 E5MessageBox.Discard), 106 E5MessageBox.Apply) 107 if res == E5MessageBox.Apply: 108 self.__applyGuards() 109 else: 110 self.__dirtyList = False 111 112 self.guardsList.clear() 113 self.patchNameLabel.setText("") 114 115 self.guardCombo.clear() 116 guardsList = self.extension.getGuardsList() 117 self.guardCombo.addItems(guardsList) 118 self.guardCombo.setEditText("") 119 120 args = self.vcs.initCommand("qguard") 121 if patch: 122 args.append(patch) 123 124 output = self.__hgClient.runcommand(args)[0] 125 126 if output: 127 patchName, guards = output.split(":", 1) 128 self.patchNameLabel.setText(patchName) 129 guardsList = guards.strip().split() 130 for guard in guardsList: 131 if guard.startswith("+"): 132 icon = UI.PixmapCache.getIcon("plus") 133 guard = guard[1:] 134 sign = "+" 135 elif guard.startswith("-"): 136 icon = UI.PixmapCache.getIcon("minus") 137 guard = guard[1:] 138 sign = "-" 139 else: 140 continue 141 itm = QListWidgetItem(icon, guard, self.guardsList) 142 itm.setData(Qt.ItemDataRole.UserRole, sign) 143 144 self.on_guardsList_itemSelectionChanged() 145 146 @pyqtSlot() 147 def on_guardsList_itemSelectionChanged(self): 148 """ 149 Private slot to handle changes of the selection of guards. 150 """ 151 self.removeButton.setEnabled( 152 len(self.guardsList.selectedItems()) > 0) 153 154 def __getGuard(self, guard): 155 """ 156 Private method to get a reference to a named guard. 157 158 @param guard name of the guard (string) 159 @return reference to the guard item (QListWidgetItem) 160 """ 161 items = self.guardsList.findItems( 162 guard, Qt.MatchFlag.MatchCaseSensitive) 163 if items: 164 return items[0] 165 else: 166 return None 167 168 @pyqtSlot(str) 169 def on_guardCombo_editTextChanged(self, txt): 170 """ 171 Private slot to handle changes of the text of the guard combo. 172 173 @param txt contents of the guard combo line edit (string) 174 """ 175 self.addButton.setEnabled(txt != "") 176 177 @pyqtSlot() 178 def on_addButton_clicked(self): 179 """ 180 Private slot to add a guard definition to the list or change it. 181 """ 182 guard = self.guardCombo.currentText() 183 if self.plusButton.isChecked(): 184 sign = "+" 185 icon = UI.PixmapCache.getIcon("plus") 186 else: 187 sign = "-" 188 icon = UI.PixmapCache.getIcon("minus") 189 190 guardItem = self.__getGuard(guard) 191 if guardItem: 192 # guard already exists, remove it first 193 row = self.guardsList.row(guardItem) 194 itm = self.guardsList.takeItem(row) 195 del itm 196 197 itm = QListWidgetItem(icon, guard, self.guardsList) 198 itm.setData(Qt.ItemDataRole.UserRole, sign) 199 self.guardsList.sortItems() 200 201 self.__dirtyList = True 202 203 @pyqtSlot() 204 def on_removeButton_clicked(self): 205 """ 206 Private slot to remove guard definitions from the list. 207 """ 208 res = E5MessageBox.yesNo( 209 self, 210 self.tr("Remove Guards"), 211 self.tr( 212 """Do you really want to remove the selected guards?""")) 213 if res: 214 for guardItem in self.guardsList.selectedItems(): 215 row = self.guardsList.row(guardItem) 216 itm = self.guardsList.takeItem(row) # __IGNORE_WARNING__ 217 del itm 218 219 self.__dirtyList = True 220 221 @pyqtSlot(QAbstractButton) 222 def on_buttonBox_clicked(self, button): 223 """ 224 Private slot called by a button of the button box clicked. 225 226 @param button button that was clicked (QAbstractButton) 227 """ 228 if button == self.buttonBox.button( 229 QDialogButtonBox.StandardButton.Apply 230 ): 231 self.__applyGuards() 232 elif button == self.buttonBox.button( 233 QDialogButtonBox.StandardButton.Close 234 ): 235 self.close() 236 237 @pyqtSlot() 238 def __applyGuards(self): 239 """ 240 Private slot to apply the defined guards to the current patch. 241 """ 242 if self.__dirtyList: 243 guardsList = [] 244 for row in range(self.guardsList.count()): 245 itm = self.guardsList.item(row) 246 guard = itm.data(Qt.ItemDataRole.UserRole) + itm.text() 247 guardsList.append(guard) 248 249 args = self.vcs.initCommand("qguard") 250 args.append(self.patchNameLabel.text()) 251 if guardsList: 252 args.append("--") 253 args.extend(guardsList) 254 else: 255 args.append("--none") 256 257 error = self.__hgClient.runcommand(args)[1] 258 259 if error: 260 E5MessageBox.warning( 261 self, 262 self.tr("Apply Guard Definitions"), 263 self.tr("""<p>The defined guards could not be""" 264 """ applied.</p><p>Reason: {0}</p>""") 265 .format(error)) 266 else: 267 self.__dirtyList = False 268 index = self.patchSelector.findText(self.patchNameLabel.text()) 269 if index == -1: 270 index = 0 271 self.on_patchSelector_activated(index) 272