|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2014 - 2021 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing a dialog to enter some user data. |
|
8 """ |
|
9 |
|
10 import os |
|
11 from configparser import ConfigParser |
|
12 import contextlib |
|
13 |
|
14 from PyQt5.QtCore import pyqtSlot, Qt, QEvent |
|
15 from PyQt5.QtWidgets import QDialog, QTreeWidgetItem |
|
16 |
|
17 from E5Gui.E5PathPicker import E5PathPickerModes |
|
18 from E5Gui import E5MessageBox |
|
19 |
|
20 import Globals |
|
21 |
|
22 from .HgUtilities import getConfigPath |
|
23 from .HgUserConfigHostFingerprintDialog import ( |
|
24 HgUserConfigHostFingerprintDialog |
|
25 ) |
|
26 from .HgUserConfigHostMinimumProtocolDialog import ( |
|
27 HgUserConfigHostMinimumProtocolDialog |
|
28 ) |
|
29 |
|
30 from .Ui_HgUserConfigDialog import Ui_HgUserConfigDialog |
|
31 |
|
32 import UI.PixmapCache |
|
33 |
|
34 |
|
35 class HgUserConfigDialog(QDialog, Ui_HgUserConfigDialog): |
|
36 """ |
|
37 Class implementing a dialog to enter some user data. |
|
38 """ |
|
39 def __init__(self, version=(0, 0, 0), parent=None): |
|
40 """ |
|
41 Constructor |
|
42 |
|
43 @param version Mercurial version info |
|
44 @type tuple of three integers |
|
45 @param parent reference to the parent widget |
|
46 @type QWidget |
|
47 """ |
|
48 super().__init__(parent) |
|
49 self.setupUi(self) |
|
50 |
|
51 self.__version = version |
|
52 |
|
53 self.__minimumProtocols = { |
|
54 "tls1.0": self.tr("TLS 1.0"), |
|
55 "tls1.1": self.tr("TLS 1.1"), |
|
56 "tls1.2": self.tr("TLS 1.2"), |
|
57 } |
|
58 |
|
59 self.lfUserCachePicker.setMode(E5PathPickerModes.DirectoryMode) |
|
60 if Globals.isLinuxPlatform(): |
|
61 self.lfUserCachePicker.setDefaultDirectory(os.path.expanduser( |
|
62 "~/.cache/largefiles")) |
|
63 elif Globals.isMacPlatform(): |
|
64 self.lfUserCachePicker.setDefaultDirectory(os.path.expanduser( |
|
65 "~/Library/Caches/largefiles")) |
|
66 else: |
|
67 self.lfUserCachePicker.setDefaultDirectory(os.path.expanduser( |
|
68 "~\\AppData\\Local\\largefiles")) |
|
69 |
|
70 self.fpAddButton.setIcon(UI.PixmapCache.getIcon("plus")) |
|
71 self.fpDeleteButton.setIcon(UI.PixmapCache.getIcon("minus")) |
|
72 self.fpEditButton.setIcon(UI.PixmapCache.getIcon("edit")) |
|
73 |
|
74 self.protocolAddButton.setIcon(UI.PixmapCache.getIcon("plus")) |
|
75 self.protocolDeleteButton.setIcon(UI.PixmapCache.getIcon("minus")) |
|
76 self.protocolEditButton.setIcon(UI.PixmapCache.getIcon("edit")) |
|
77 |
|
78 self.minimumProtocolComboBox.addItem(self.tr("Default"), "") |
|
79 for protocol in sorted(self.__minimumProtocols.keys()): |
|
80 self.minimumProtocolComboBox.addItem( |
|
81 self.__minimumProtocols[protocol], protocol) |
|
82 |
|
83 self.fingerprintsList.headerItem().setText( |
|
84 self.fingerprintsList.columnCount(), "") |
|
85 self.protocolsList.headerItem().setText( |
|
86 self.protocolsList.columnCount(), "") |
|
87 |
|
88 if self.__version < (3, 9, 0): |
|
89 self.disableTls10WarningCheckBox.setEnabled(False) |
|
90 self.minimumProtocolComboBox.setEnabled(False) |
|
91 self.minimumProtcolGroupBox.setEnabled(False) |
|
92 |
|
93 self.tabWidget.setCurrentIndex(0) |
|
94 |
|
95 self.__editor = None |
|
96 |
|
97 self.__config = None |
|
98 self.readUserConfig() |
|
99 |
|
100 self.__updateFingerprintsButtons() |
|
101 self.__updateProtocolsButtons() |
|
102 |
|
103 def writeUserConfig(self): |
|
104 """ |
|
105 Public method to write the user configuration file. |
|
106 """ |
|
107 if self.__config is None: |
|
108 self.__config = ConfigParser() |
|
109 |
|
110 ################################################################### |
|
111 ## ui section |
|
112 ################################################################### |
|
113 if "ui" not in self.__config: |
|
114 self.__config["ui"] = {} |
|
115 self.__config["ui"]["username"] = "{0} <{1}>".format( |
|
116 self.userNameEdit.text(), |
|
117 self.emailEdit.text(), |
|
118 ) |
|
119 ################################################################### |
|
120 ## extensions section |
|
121 ################################################################### |
|
122 if "extensions" not in self.__config: |
|
123 self.__config["extensions"] = {} |
|
124 |
|
125 if self.gpgCheckBox.isChecked(): |
|
126 self.__config["extensions"]["gpg"] = "" |
|
127 else: |
|
128 if "gpg" in self.__config["extensions"]: |
|
129 del self.__config["extensions"]["gpg"] |
|
130 self.__config["extensions"]["#gpg"] = "" |
|
131 |
|
132 if self.purgeCheckBox.isChecked(): |
|
133 self.__config["extensions"]["purge"] = "" |
|
134 else: |
|
135 if "purge" in self.__config["extensions"]: |
|
136 del self.__config["extensions"]["purge"] |
|
137 self.__config["extensions"]["#purge"] = "" |
|
138 |
|
139 if self.queuesCheckBox.isChecked(): |
|
140 self.__config["extensions"]["mq"] = "" |
|
141 else: |
|
142 if "mq" in self.__config["extensions"]: |
|
143 del self.__config["extensions"]["mq"] |
|
144 self.__config["extensions"]["#mq"] = "" |
|
145 |
|
146 if self.rebaseCheckBox.isChecked(): |
|
147 self.__config["extensions"]["rebase"] = "" |
|
148 else: |
|
149 if "rebase" in self.__config["extensions"]: |
|
150 del self.__config["extensions"]["rebase"] |
|
151 self.__config["extensions"]["#rebase"] = "" |
|
152 |
|
153 if self.shelveCheckBox.isChecked(): |
|
154 self.__config["extensions"]["shelve"] = "" |
|
155 else: |
|
156 if "shelve" in self.__config["extensions"]: |
|
157 del self.__config["extensions"]["shelve"] |
|
158 self.__config["extensions"]["#shelve"] = "" |
|
159 |
|
160 if self.stripCheckBox.isChecked(): |
|
161 self.__config["extensions"]["strip"] = "" |
|
162 else: |
|
163 if "strip" in self.__config["extensions"]: |
|
164 del self.__config["extensions"]["strip"] |
|
165 self.__config["extensions"]["#strip"] = "" |
|
166 |
|
167 if self.histeditCheckBox.isChecked(): |
|
168 self.__config["extensions"]["histedit"] = "" |
|
169 else: |
|
170 if "histedit" in self.__config["extensions"]: |
|
171 del self.__config["extensions"]["histedit"] |
|
172 self.__config["extensions"]["#histedit"] = "" |
|
173 |
|
174 if self.largefilesCheckBox.isChecked(): |
|
175 self.__config["extensions"]["largefiles"] = "" |
|
176 ############################################################### |
|
177 ## largefiles section |
|
178 ############################################################### |
|
179 if "largefiles" not in self.__config: |
|
180 self.__config["largefiles"] = {} |
|
181 self.__config["largefiles"]["minsize"] = ( |
|
182 str(self.lfFileSizeSpinBox.value()) |
|
183 ) |
|
184 lfFilePatterns = self.lfFilePatternsEdit.text() |
|
185 if lfFilePatterns: |
|
186 self.__config["largefiles"]["patterns"] = lfFilePatterns |
|
187 elif "patterns" in self.__config["largefiles"]: |
|
188 del self.__config["largefiles"]["patterns"] |
|
189 lfUserCache = self.lfUserCachePicker.text() |
|
190 if lfUserCache: |
|
191 self.__config["largefiles"]["usercache"] = lfUserCache |
|
192 elif "usercache" in self.__config["largefiles"]: |
|
193 del self.__config["largefiles"]["usercache"] |
|
194 else: |
|
195 if "largefiles" in self.__config["extensions"]: |
|
196 del self.__config["extensions"]["largefiles"] |
|
197 self.__config["extensions"]["#largefiles"] = "" |
|
198 |
|
199 if self.closeheadCheckBox.isChecked() and self.__version >= (4, 8, 0): |
|
200 self.__config["extensions"]["closehead"] = "" |
|
201 else: |
|
202 if "closehead" in self.__config["extensions"]: |
|
203 del self.__config["extensions"]["closehead"] |
|
204 self.__config["extensions"]["#closehead"] = "" |
|
205 ################################################################### |
|
206 ## http_proxy section |
|
207 ################################################################### |
|
208 if self.proxyHostEdit.text(): |
|
209 self.__config["http_proxy"] = { |
|
210 "host": self.proxyHostEdit.text(), |
|
211 "user": self.proxyUserEdit.text(), |
|
212 "passwd": self.proxyPasswordEdit.text() |
|
213 } |
|
214 if self.proxyBypassEdit.text(): |
|
215 self.__config["http_proxy"]["no"] = ( |
|
216 self.proxyBypassEdit.text() |
|
217 ) |
|
218 else: |
|
219 if "http_proxy" in self.__config: |
|
220 del self.__config["http_proxy"] |
|
221 ################################################################### |
|
222 ## hostfingerprints/hostsecurity section |
|
223 ################################################################### |
|
224 if self.__version < (3, 9, 0): |
|
225 # |
|
226 # delete hostsecurity section |
|
227 # |
|
228 if "hostsecurity" in self.__config: |
|
229 del self.__config["hostsecurity"] |
|
230 |
|
231 # |
|
232 # hostfingerprints section |
|
233 # |
|
234 if self.fingerprintsList.topLevelItemCount() > 0: |
|
235 self.__config["hostfingerprints"] = {} |
|
236 for row in range(self.fingerprintsList.topLevelItemCount()): |
|
237 itm = self.fingerprintsList.topLevelItem(row) |
|
238 fingerprint = itm.text(1) |
|
239 if fingerprint.startswith("sha1:"): |
|
240 fingerprint = fingerprint[5:] |
|
241 self.__config["hostfingerprints"][itm.text(0)] = ( |
|
242 fingerprint |
|
243 ) |
|
244 else: |
|
245 if "hostfingerprints" in self.__config: |
|
246 del self.__config["hostfingerprints"] |
|
247 else: |
|
248 # |
|
249 # delete hostfingerprints section |
|
250 # |
|
251 if "hostfingerprints" in self.__config: |
|
252 del self.__config["hostfingerprints"] |
|
253 |
|
254 # |
|
255 # hostsecurity section |
|
256 # |
|
257 if "hostsecurity" not in self.__config: |
|
258 self.__config["hostsecurity"] = {} |
|
259 |
|
260 if self.fingerprintsList.topLevelItemCount() > 0: |
|
261 self.__clearFingerprints() |
|
262 fingerprints = self.__assembleFingerprints() |
|
263 for host in fingerprints: |
|
264 key = "{0}:fingerprints".format(host) |
|
265 self.__config["hostsecurity"][key] = ( |
|
266 ", ".join(fingerprints[host]) |
|
267 ) |
|
268 else: |
|
269 self.__clearFingerprints() |
|
270 |
|
271 if self.disableTls10WarningCheckBox.isChecked(): |
|
272 disabletls10warning = "true" |
|
273 else: |
|
274 disabletls10warning = "false" |
|
275 self.__config["hostsecurity"]["disabletls10warning"] = ( |
|
276 disabletls10warning |
|
277 ) |
|
278 |
|
279 if self.minimumProtocolComboBox.currentIndex() == 0: |
|
280 self.__config.remove_option("hostsecurity", "minimumprotocol") |
|
281 else: |
|
282 minimumProtocol = self.minimumProtocolComboBox.itemData( |
|
283 self.minimumProtocolComboBox.currentIndex()) |
|
284 self.__config["hostsecurity"]["minimumprotocol"] = ( |
|
285 minimumProtocol |
|
286 ) |
|
287 |
|
288 if self.protocolsList.topLevelItemCount() > 0: |
|
289 self.__clearMinimumProtocols() |
|
290 minimumProtocols = self.__assembleMinimumProtocols() |
|
291 for host in minimumProtocols: |
|
292 key = "{0}:minimumprotocol".format(host) |
|
293 self.__config["hostsecurity"][key] = minimumProtocols[host] |
|
294 else: |
|
295 self.__clearMinimumProtocols() |
|
296 |
|
297 if len(self.__config.options("hostsecurity")) == 0: |
|
298 del self.__config["hostsecurity"] |
|
299 ################################################################### |
|
300 |
|
301 cfgFile = getConfigPath() |
|
302 with open(cfgFile, "w") as configFile: |
|
303 self.__config.write(configFile) |
|
304 |
|
305 def readUserConfig(self): |
|
306 """ |
|
307 Public method to read the user configuration file. |
|
308 """ |
|
309 cfgFile = getConfigPath() |
|
310 |
|
311 self.__config = ConfigParser(delimiters=("=",)) |
|
312 if self.__config.read(cfgFile): |
|
313 # step 1: extract user name and email |
|
314 with contextlib.suppress(KeyError): |
|
315 username = self.__config["ui"]["username"].strip() |
|
316 if "<" in username and username.endswith(">"): |
|
317 name, email = username[:-1].rsplit("<", 1) |
|
318 else: |
|
319 name = username |
|
320 email = "" |
|
321 self.userNameEdit.setText(name.strip()), |
|
322 self.emailEdit.setText(email.strip()), |
|
323 |
|
324 # step 2: extract extensions information |
|
325 if "extensions" in self.__config: |
|
326 self.gpgCheckBox.setChecked( |
|
327 "gpg" in self.__config["extensions"]) |
|
328 self.purgeCheckBox.setChecked( |
|
329 "purge" in self.__config["extensions"]) |
|
330 self.queuesCheckBox.setChecked( |
|
331 "mq" in self.__config["extensions"]) |
|
332 self.rebaseCheckBox.setChecked( |
|
333 "rebase" in self.__config["extensions"]) |
|
334 self.shelveCheckBox.setChecked( |
|
335 "shelve" in self.__config["extensions"]) |
|
336 self.largefilesCheckBox.setChecked( |
|
337 "largefiles" in self.__config["extensions"]) |
|
338 self.stripCheckBox.setChecked( |
|
339 "strip" in self.__config["extensions"]) |
|
340 self.histeditCheckBox.setChecked( |
|
341 "histedit" in self.__config["extensions"]) |
|
342 self.closeheadCheckBox.setChecked( |
|
343 "closehead" in self.__config["extensions"]) |
|
344 self.closeheadCheckBox.setEnabled(self.__version >= (4, 8, 0)) |
|
345 |
|
346 # step 3: extract large files information |
|
347 if "largefiles" in self.__config: |
|
348 if "minsize" in self.__config["largefiles"]: |
|
349 self.lfFileSizeSpinBox.setValue( |
|
350 self.__config.getint("largefiles", "minsize")) |
|
351 if "patterns" in self.__config["largefiles"]: |
|
352 self.lfFilePatternsEdit.setText( |
|
353 self.__config["largefiles"]["patterns"]) |
|
354 if "usercache" in self.__config["largefiles"]: |
|
355 self.lfUserCachePicker.setText( |
|
356 self.__config["largefiles"]["usercache"]) |
|
357 |
|
358 # step 4: extract http proxy information |
|
359 if "http_proxy" in self.__config: |
|
360 if "host" in self.__config["http_proxy"]: |
|
361 self.proxyHostEdit.setText( |
|
362 self.__config["http_proxy"]["host"]) |
|
363 if "user" in self.__config["http_proxy"]: |
|
364 self.proxyUserEdit.setText( |
|
365 self.__config["http_proxy"]["user"]) |
|
366 if "passwd" in self.__config["http_proxy"]: |
|
367 self.proxyPasswordEdit.setText( |
|
368 self.__config["http_proxy"]["passwd"]) |
|
369 if "no" in self.__config["http_proxy"]: |
|
370 self.proxyBypassEdit.setText( |
|
371 self.__config["http_proxy"]["no"]) |
|
372 |
|
373 # step 5a: extract host fingerprints |
|
374 if "hostfingerprints" in self.__config: |
|
375 for host in self.__config.options("hostfingerprints"): |
|
376 if self.__version < (3, 9, 0): |
|
377 QTreeWidgetItem(self.fingerprintsList, [ |
|
378 host, |
|
379 self.__config["hostfingerprints"][host] |
|
380 ]) |
|
381 else: |
|
382 # convert to hostsecurity fingerprint |
|
383 QTreeWidgetItem(self.fingerprintsList, [ |
|
384 host, |
|
385 "sha1:" + self.__config["hostfingerprints"][host] |
|
386 ]) |
|
387 |
|
388 # step 5b: extract hostsecurity fingerprints |
|
389 if "hostsecurity" in self.__config: |
|
390 for key in self.__config.options("hostsecurity"): |
|
391 if key.endswith(":fingerprints"): |
|
392 host = key.replace(":fingerprints", "") |
|
393 fingerprints = ( |
|
394 self.__config["hostsecurity"][key].split(",") |
|
395 ) |
|
396 for fingerprint in fingerprints: |
|
397 if self.__version < (3, 9, 0): |
|
398 # downgrade from a newer version |
|
399 if fingerprint.startswith("sha1:"): |
|
400 fingerprint = fingerprint[5:] |
|
401 else: |
|
402 # Mercurial < 3.9.0 supports sha1 |
|
403 # fingerprints only |
|
404 continue |
|
405 QTreeWidgetItem(self.fingerprintsList, [ |
|
406 host, |
|
407 fingerprint.replace("\\", "").strip() |
|
408 ]) |
|
409 |
|
410 elif key == "disabletls10warning": |
|
411 self.disableTls10WarningCheckBox.setChecked( |
|
412 self.__config.getboolean( |
|
413 "hostsecurity", "disabletls10warning")) |
|
414 |
|
415 elif key == "minimumprotocol": |
|
416 minimumProtocol = self.__config["hostsecurity"][key] |
|
417 index = self.minimumProtocolComboBox.findData( |
|
418 minimumProtocol) |
|
419 if index == -1: |
|
420 index = 0 |
|
421 self.minimumProtocolComboBox.setCurrentIndex(index) |
|
422 |
|
423 elif key.endswith(":minimumprotocol"): |
|
424 host = key.replace(":minimumprotocol", "") |
|
425 protocol = self.__config["hostsecurity"][key].strip() |
|
426 if protocol in self.__minimumProtocols: |
|
427 itm = QTreeWidgetItem(self.protocolsList, [ |
|
428 host, |
|
429 self.__minimumProtocols[protocol] |
|
430 ]) |
|
431 itm.setData(1, Qt.ItemDataRole.UserRole, protocol) |
|
432 |
|
433 self.__finalizeFingerprintsColumns() |
|
434 self.__finalizeProtocolsColumns() |
|
435 |
|
436 @pyqtSlot() |
|
437 def accept(self): |
|
438 """ |
|
439 Public slot to accept the dialog. |
|
440 """ |
|
441 self.writeUserConfig() |
|
442 |
|
443 super().accept() |
|
444 |
|
445 def __clearDialog(self): |
|
446 """ |
|
447 Private method to clear the data of the dialog. |
|
448 """ |
|
449 self.userNameEdit.clear() |
|
450 self.emailEdit.clear() |
|
451 |
|
452 self.gpgCheckBox.setChecked(False) |
|
453 self.purgeCheckBox.setChecked(False) |
|
454 self.queuesCheckBox.setChecked(False) |
|
455 self.rebaseCheckBox.setChecked(False) |
|
456 self.shelveCheckBox.setChecked(False) |
|
457 self.stripCheckBox.setChecked(False) |
|
458 self.largefilesCheckBox.setChecked(False) |
|
459 self.lfFileSizeSpinBox.setValue(10) |
|
460 self.lfFilePatternsEdit.clear() |
|
461 self.lfUserCachePicker.clear() |
|
462 |
|
463 self.proxyHostEdit.clear() |
|
464 self.proxyUserEdit.clear() |
|
465 self.proxyPasswordEdit.clear() |
|
466 self.proxyBypassEdit.clear() |
|
467 |
|
468 self.fingerprintsList.clear() |
|
469 self.__finalizeFingerprintsColumns() |
|
470 self.__updateFingerprintsButtons() |
|
471 |
|
472 self.protocolsList.clear() |
|
473 self.__finalizeProtocolsColumns() |
|
474 self.__updateProtocolsButtons() |
|
475 |
|
476 ####################################################################### |
|
477 ## Methods and slots for the host fingerprint handling below |
|
478 ####################################################################### |
|
479 |
|
480 def __clearFingerprints(self): |
|
481 """ |
|
482 Private method to clear the fingerprints from the hostsecurity section. |
|
483 """ |
|
484 if "hostsecurity" in self.__config: |
|
485 for key in self.__config.options("hostsecurity"): |
|
486 if key.endswith(":fingerprints"): |
|
487 self.__config.remove_option("hostsecurity", key) |
|
488 |
|
489 def __assembleFingerprints(self): |
|
490 """ |
|
491 Private method to assemble a list of host fingerprints. |
|
492 |
|
493 @return dictionary with list of fingerprints per host |
|
494 @rtype dict with str as key and list of str as value |
|
495 """ |
|
496 hostFingerprints = {} |
|
497 for row in range(self.fingerprintsList.topLevelItemCount()): |
|
498 itm = self.fingerprintsList.topLevelItem(row) |
|
499 host = itm.text(0) |
|
500 fingerprint = itm.text(1) |
|
501 if host in hostFingerprints: |
|
502 hostFingerprints[host].append(fingerprint) |
|
503 else: |
|
504 hostFingerprints[host] = [fingerprint] |
|
505 return hostFingerprints |
|
506 |
|
507 @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem) |
|
508 def on_fingerprintsList_currentItemChanged(self, current, previous): |
|
509 """ |
|
510 Private slot handling a change of the current fingerprints item. |
|
511 |
|
512 @param current reference to the current item |
|
513 @type QTreeWidgetItem |
|
514 @param previous reference to the previous current item |
|
515 @type QTreeWidgetItem |
|
516 """ |
|
517 self.__updateFingerprintsButtons() |
|
518 |
|
519 @pyqtSlot() |
|
520 def on_fpAddButton_clicked(self): |
|
521 """ |
|
522 Private slot to add a fingerprints entry. |
|
523 """ |
|
524 dlg = HgUserConfigHostFingerprintDialog(self, version=self.__version) |
|
525 if dlg.exec() == QDialog.DialogCode.Accepted: |
|
526 host, fingerprint = dlg.getData() |
|
527 itm = QTreeWidgetItem(self.fingerprintsList, [host, fingerprint]) |
|
528 self.__finalizeFingerprintsColumns() |
|
529 self.fingerprintsList.setCurrentItem(itm) |
|
530 self.fingerprintsList.scrollToItem(itm) |
|
531 |
|
532 @pyqtSlot() |
|
533 def on_fpDeleteButton_clicked(self): |
|
534 """ |
|
535 Private slot to delete the current fingerprints item. |
|
536 """ |
|
537 itm = self.fingerprintsList.currentItem() |
|
538 if itm is not None: |
|
539 host = itm.text(0) |
|
540 yes = E5MessageBox.yesNo( |
|
541 self, |
|
542 self.tr("Delete Host Fingerprint"), |
|
543 self.tr("""<p>Shall the fingerprint for host <b>{0}</b>""" |
|
544 """ really be deleted?</p>""").format(host)) |
|
545 if yes: |
|
546 self.fingerprintsList.takeTopLevelItem( |
|
547 self.fingerprintsList.indexOfTopLevelItem(itm)) |
|
548 del itm |
|
549 self.__finalizeFingerprintsColumns() |
|
550 |
|
551 @pyqtSlot() |
|
552 def on_fpEditButton_clicked(self): |
|
553 """ |
|
554 Private slot to edit the current fingerprints item. |
|
555 """ |
|
556 itm = self.fingerprintsList.currentItem() |
|
557 if itm is not None: |
|
558 host = itm.text(0) |
|
559 fingerprint = itm.text(1) |
|
560 dlg = HgUserConfigHostFingerprintDialog(self, host, fingerprint, |
|
561 version=self.__version) |
|
562 if dlg.exec() == QDialog.DialogCode.Accepted: |
|
563 host, fingerprint = dlg.getData() |
|
564 itm.setText(0, host) |
|
565 itm.setText(1, fingerprint) |
|
566 self.__finalizeFingerprintsColumns() |
|
567 self.fingerprintsList.scrollToItem(itm) |
|
568 |
|
569 def __finalizeFingerprintsColumns(self): |
|
570 """ |
|
571 Private method to resize and sort the host fingerprints columns. |
|
572 """ |
|
573 for col in range(self.fingerprintsList.columnCount()): |
|
574 self.fingerprintsList.resizeColumnToContents(col) |
|
575 self.fingerprintsList.sortItems(0, Qt.SortOrder.AscendingOrder) |
|
576 |
|
577 def __updateFingerprintsButtons(self): |
|
578 """ |
|
579 Private slot to update the host fingerprints edit buttons. |
|
580 """ |
|
581 enable = self.fingerprintsList.currentItem() is not None |
|
582 self.fpDeleteButton.setEnabled(enable) |
|
583 self.fpEditButton.setEnabled(enable) |
|
584 |
|
585 ####################################################################### |
|
586 ## Methods and slots for the host minimum protocol handling below |
|
587 ####################################################################### |
|
588 |
|
589 def __clearMinimumProtocols(self): |
|
590 """ |
|
591 Private method to clear the minimum protocols from the hostsecurity |
|
592 section. |
|
593 """ |
|
594 if "hostsecurity" in self.__config: |
|
595 for key in self.__config.options("hostsecurity"): |
|
596 if key.endswith(":minimumprotocol"): |
|
597 self.__config.remove_option("hostsecurity", key) |
|
598 |
|
599 def __assembleMinimumProtocols(self): |
|
600 """ |
|
601 Private method to assemble a list of host minimum protocols. |
|
602 |
|
603 @return dictionary with list of minimum protocol per host |
|
604 @rtype dict with str as key and str as value |
|
605 """ |
|
606 minimumProtocols = {} |
|
607 for row in range(self.protocolsList.topLevelItemCount()): |
|
608 itm = self.protocolsList.topLevelItem(row) |
|
609 host = itm.text(0) |
|
610 minimumProtocol = itm.data(1, Qt.ItemDataRole.UserRole) |
|
611 minimumProtocols[host] = minimumProtocol |
|
612 return minimumProtocols |
|
613 |
|
614 @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem) |
|
615 def on_protocolsList_currentItemChanged(self, current, previous): |
|
616 """ |
|
617 Private slot handling a change of the current minimum protocol item. |
|
618 |
|
619 @param current reference to the current item |
|
620 @type QTreeWidgetItem |
|
621 @param previous reference to the previous current item |
|
622 @type QTreeWidgetItem |
|
623 """ |
|
624 self.__updateProtocolsButtons() |
|
625 |
|
626 @pyqtSlot() |
|
627 def on_protocolAddButton_clicked(self): |
|
628 """ |
|
629 Private slot to add a minimum protocol entry. |
|
630 """ |
|
631 dlg = HgUserConfigHostMinimumProtocolDialog(self.__minimumProtocols, |
|
632 self) |
|
633 if dlg.exec() == QDialog.DialogCode.Accepted: |
|
634 host, protocol = dlg.getData() |
|
635 itm = QTreeWidgetItem(self.protocolsList, [ |
|
636 host, |
|
637 self.__minimumProtocols[protocol] |
|
638 ]) |
|
639 itm.setData(1, Qt.ItemDataRole.UserRole, protocol) |
|
640 self.__finalizeProtocolsColumns() |
|
641 self.protocolsList.setCurrentItem(itm) |
|
642 self.protocolsList.scrollToItem(itm) |
|
643 |
|
644 @pyqtSlot() |
|
645 def on_protocolDeleteButton_clicked(self): |
|
646 """ |
|
647 Private slot to delete the current minimum protocol item. |
|
648 """ |
|
649 itm = self.protocolsList.currentItem() |
|
650 if itm is not None: |
|
651 host = itm.text(0) |
|
652 yes = E5MessageBox.yesNo( |
|
653 self, |
|
654 self.tr("Delete Host Minimum Protocol"), |
|
655 self.tr("""<p>Shall the minimum protocol entry for host""" |
|
656 """ <b>{0}</b> really be deleted?</p>""").format(host)) |
|
657 if yes: |
|
658 self.protocolsList.takeTopLevelItem( |
|
659 self.protocolsList.indexOfTopLevelItem(itm)) |
|
660 del itm |
|
661 self.__finalizeProtocolsColumns() |
|
662 |
|
663 @pyqtSlot() |
|
664 def on_protocolEditButton_clicked(self): |
|
665 """ |
|
666 Private slot to edit the current minimum protocol item. |
|
667 """ |
|
668 itm = self.protocolsList.currentItem() |
|
669 if itm is not None: |
|
670 host = itm.text(0) |
|
671 protocol = itm.data(1, Qt.ItemDataRole.UserRole) |
|
672 dlg = HgUserConfigHostMinimumProtocolDialog( |
|
673 self.__minimumProtocols, self, host, protocol) |
|
674 if dlg.exec() == QDialog.DialogCode.Accepted: |
|
675 host, protocol = dlg.getData() |
|
676 itm.setText(0, host) |
|
677 itm.setText(1, self.__minimumProtocols[protocol]) |
|
678 itm.setData(1, Qt.ItemDataRole.UserRole, protocol) |
|
679 self.__finalizeProtocolsColumns() |
|
680 self.protocolsList.scrollToItem(itm) |
|
681 |
|
682 def __finalizeProtocolsColumns(self): |
|
683 """ |
|
684 Private method to resize and sort the host fingerprints columns. |
|
685 """ |
|
686 for col in range(self.protocolsList.columnCount()): |
|
687 self.protocolsList.resizeColumnToContents(col) |
|
688 self.protocolsList.sortItems(0, Qt.SortOrder.AscendingOrder) |
|
689 |
|
690 def __updateProtocolsButtons(self): |
|
691 """ |
|
692 Private slot to update the host minimum protocol edit buttons. |
|
693 """ |
|
694 enable = self.protocolsList.currentItem() is not None |
|
695 self.protocolDeleteButton.setEnabled(enable) |
|
696 self.protocolEditButton.setEnabled(enable) |
|
697 |
|
698 ####################################################################### |
|
699 ## Slot to edit the user configuration in an editor below |
|
700 ####################################################################### |
|
701 |
|
702 @pyqtSlot() |
|
703 def on_editorButton_clicked(self): |
|
704 """ |
|
705 Private slot to open the user configuration file in a text editor. |
|
706 """ |
|
707 from QScintilla.MiniEditor import MiniEditor |
|
708 cfgFile = getConfigPath() |
|
709 |
|
710 yes = E5MessageBox.yesNo( |
|
711 self, |
|
712 self.tr("Edit User Configuration"), |
|
713 self.tr("""You will loose all changes made in this dialog.""" |
|
714 """ Shall the data be saved first?"""), |
|
715 icon=E5MessageBox.Warning, |
|
716 yesDefault=True) |
|
717 if yes: |
|
718 self.writeUserConfig() |
|
719 |
|
720 self.__editor = MiniEditor(cfgFile, "Properties", self) |
|
721 self.__editor.setWindowModality(Qt.WindowModality.WindowModal) |
|
722 self.__editor.installEventFilter(self) |
|
723 self.__editor.show() |
|
724 |
|
725 def eventFilter(self, watched, event): |
|
726 """ |
|
727 Public method called to filter the event queue. |
|
728 |
|
729 @param watched reference to the object being watched |
|
730 @type QObject |
|
731 @param event event to be handled |
|
732 @type QEvent |
|
733 @return flag indicating, if we handled the event |
|
734 @rtype bool |
|
735 """ |
|
736 if watched is self.__editor and event.type() == QEvent.Type.Close: |
|
737 self.__editor.closeEvent(event) |
|
738 if event.isAccepted(): |
|
739 self.__clearDialog() |
|
740 self.readUserConfig() |
|
741 return True |
|
742 |
|
743 return False |