eric6/WebBrowser/QtHelp/QtHelpDocumentationDialog.py

changeset 7231
0dcb92a9687d
parent 7229
53054eb5b15a
child 7235
4f23ea4af43c
equal deleted inserted replaced
7230:2ee6af6381c8 7231:0dcb92a9687d
5 5
6 """ 6 """
7 Module implementing a dialog to manage the QtHelp documentation database. 7 Module implementing a dialog to manage the QtHelp documentation database.
8 """ 8 """
9 9
10 import sqlite3
10 11
11 from PyQt5.QtCore import pyqtSlot, Qt, QItemSelectionModel 12 from PyQt5.QtCore import pyqtSlot, Qt, QItemSelectionModel
12 from PyQt5.QtWidgets import QDialog 13 from PyQt5.QtWidgets import QDialog, QTreeWidgetItem, QListWidgetItem, \
14 QInputDialog, QLineEdit
13 from PyQt5.QtHelp import QHelpEngineCore 15 from PyQt5.QtHelp import QHelpEngineCore
14 16
15 from E5Gui import E5MessageBox, E5FileDialog 17 from E5Gui import E5MessageBox, E5FileDialog
16 from E5Gui.E5Application import e5App 18 from E5Gui.E5Application import e5App
17 19
30 @param parent reference to the parent widget (QWidget) 32 @param parent reference to the parent widget (QWidget)
31 """ 33 """
32 super(QtHelpDocumentationDialog, self).__init__(parent) 34 super(QtHelpDocumentationDialog, self).__init__(parent)
33 self.setupUi(self) 35 self.setupUi(self)
34 36
35 self.removeButton.setEnabled(False)
36
37 self.__engine = engine 37 self.__engine = engine
38 self.__mw = parent 38 self.__mw = parent
39 39
40 self.__initDocumentsTab()
41 self.__initFiltersTab()
42
43 self.tabWidget.setCurrentIndex(0)
44
45 @pyqtSlot(int)
46 def on_tabWidget_currentChanged(self, index):
47 """
48 Private slot handling a change of the current tab.
49
50 @param index index of the current tab
51 @type int
52 """
53 if index != 1 and \
54 (self.__hasChangedFilters() or self.__removedAttributes):
55 yes = E5MessageBox.yesNo(
56 self,
57 self.tr("Unsaved Filter Changes"),
58 self.tr("""The page contains unsaved changes. Shall they be"""
59 """ saved?"""),
60 yesDefault=True)
61 if yes:
62 self.on_applyFilterChangesButton_clicked()
63
64 ##################################################################
65 ## Documentations Tab
66 ##################################################################
67
68 def __initDocumentsTab(self):
69 """
70 Private method to initialize the documents tab.
71 """
72 self.documentsList.clear()
73 self.removeDocumentsButton.setEnabled(False)
74
40 docs = self.__engine.registeredDocumentations() 75 docs = self.__engine.registeredDocumentations()
41 self.documentsList.addItems(docs) 76 self.documentsList.addItems(docs)
42 77
43 self.__registeredDocs = [] 78 self.__registeredDocs = []
44 self.__unregisteredDocs = [] 79 self.__unregisteredDocs = []
45 self.__tabsToClose = [] 80 self.__tabsToClose = []
46 81
47 try: 82 try:
48 self.__pluginHelpDocuments = \ 83 self.__pluginHelpDocuments = \
49 e5App().getObject("PluginManager").getPluginQtHelpFiles() 84 e5App().getObject("PluginManager").getPluginQtHelpFiles()
50 except KeyError: 85 except KeyError:
51 from PluginManager.PluginManager import PluginManager 86 from PluginManager.PluginManager import PluginManager
58 @pyqtSlot() 93 @pyqtSlot()
59 def on_documentsList_itemSelectionChanged(self): 94 def on_documentsList_itemSelectionChanged(self):
60 """ 95 """
61 Private slot handling a change of the documents selection. 96 Private slot handling a change of the documents selection.
62 """ 97 """
63 self.removeButton.setEnabled( 98 self.removeDocumentsButton.setEnabled(
64 len(self.documentsList.selectedItems()) != 0) 99 len(self.documentsList.selectedItems()) != 0)
65 100
66 @pyqtSlot() 101 @pyqtSlot()
67 def on_addButton_clicked(self): 102 def on_addDocumentsButton_clicked(self):
68 """ 103 """
69 Private slot to add QtHelp documents to the help database. 104 Private slot to add QtHelp documents to the help database.
70 """ 105 """
71 fileNames = E5FileDialog.getOpenFileNames( 106 fileNames = E5FileDialog.getOpenFileNames(
72 self, 107 self,
142 self.__engine.registerDocumentation(fileName) 177 self.__engine.registerDocumentation(fileName)
143 self.documentsList.addItem(ns) 178 self.documentsList.addItem(ns)
144 self.__registeredDocs.append(ns) 179 self.__registeredDocs.append(ns)
145 if ns in self.__unregisteredDocs: 180 if ns in self.__unregisteredDocs:
146 self.__unregisteredDocs.remove(ns) 181 self.__unregisteredDocs.remove(ns)
147 182
148 @pyqtSlot() 183 self.__initFiltersTab()
149 def on_removeButton_clicked(self): 184
185 @pyqtSlot()
186 def on_removeDocumentsButton_clicked(self):
150 """ 187 """
151 Private slot to remove a document from the help database. 188 Private slot to remove a document from the help database.
152 """ 189 """
153 res = E5MessageBox.yesNo( 190 res = E5MessageBox.yesNo(
154 self, 191 self,
187 224
188 if self.documentsList.count(): 225 if self.documentsList.count():
189 self.documentsList.setCurrentRow( 226 self.documentsList.setCurrentRow(
190 0, QItemSelectionModel.ClearAndSelect) 227 0, QItemSelectionModel.ClearAndSelect)
191 228
192 def hasChanges(self): 229 def hasDocumentationChanges(self):
193 """ 230 """
194 Public slot to test the dialog for changes. 231 Public slot to test the dialog for changes of configured QtHelp
232 documents.
195 233
196 @return flag indicating presence of changes 234 @return flag indicating presence of changes
235 @rtype bool
197 """ 236 """
198 return len(self.__registeredDocs) > 0 or \ 237 return len(self.__registeredDocs) > 0 or \
199 len(self.__unregisteredDocs) > 0 238 len(self.__unregisteredDocs) > 0
200 239
201 def getTabsToClose(self): 240 def getTabsToClose(self):
202 """ 241 """
203 Public method to get the list of tabs to close. 242 Public method to get the list of tabs to close.
204 243
205 @return list of tab ids to be closed (list of integers) 244 @return list of tab ids to be closed
245 @rtype list of int
206 """ 246 """
207 return self.__tabsToClose 247 return self.__tabsToClose
248
249 ##################################################################
250 ## Filters Tab
251 ##################################################################
252
253 def __initFiltersTab(self):
254 """
255 Private method to initialize the filters tab.
256 """
257 self.removeFiltersButton.setEnabled(False)
258 self.removeAttributesButton.setEnabled(False)
259
260 # save the current and selected filters
261 currentFilter = self.filtersList.currentItem()
262 if currentFilter:
263 currentFilterText = currentFilter.text()
264 else:
265 currentFilterText = ""
266 selectedFiltersText = [
267 itm.text() for itm in self.filtersList.selectedItems()]
268
269 # save the selected attributes
270 selectedAttributesText = [
271 itm.text(0) for itm in self.attributesList.selectedItems()]
272
273 self.filtersList.clear()
274 self.attributesList.clear()
275
276 helpEngineCore = QHelpEngineCore(self.__engine.collectionFile())
277
278 self.__removedFilters = []
279 self.__filterMap = {}
280 self.__filterMapBackup = {}
281 self.__removedAttributes = []
282
283 for customFilter in helpEngineCore.customFilters():
284 atts = helpEngineCore.filterAttributes(customFilter)
285 self.__filterMapBackup[customFilter] = atts
286 if customFilter not in self.__filterMap:
287 self.__filterMap[customFilter] = atts
288
289 self.filtersList.addItems(sorted(self.__filterMap.keys()))
290 for attr in helpEngineCore.filterAttributes():
291 QTreeWidgetItem(self.attributesList, [attr])
292 self.attributesList.sortItems(0, Qt.AscendingOrder)
293
294 if selectedFiltersText or currentFilterText or selectedAttributesText:
295 # restore the selected filters
296 for txt in selectedFiltersText:
297 items = self.filtersList.findItems(txt, Qt.MatchExactly)
298 for itm in items:
299 itm.setSelected(True)
300 # restore the current filter
301 if currentFilterText:
302 items = self.filtersList.findItems(currentFilterText,
303 Qt.MatchExactly)
304 if items:
305 self.filtersList.setCurrentItem(
306 items[0], QItemSelectionModel.NoUpdate)
307 # restore the selected attributes
308 for txt in selectedAttributesText:
309 items = self.attributesList.findItems(txt, Qt.MatchExactly, 0)
310 for itm in items:
311 itm.setSelected(True)
312 elif self.__filterMap:
313 self.filtersList.setCurrentRow(0)
314
315 @pyqtSlot(QListWidgetItem, QListWidgetItem)
316 def on_filtersList_currentItemChanged(self, current, previous):
317 """
318 Private slot to update the attributes depending on the current filter.
319
320 @param current reference to the current item (QListWidgetitem)
321 @param previous reference to the previous current item
322 (QListWidgetItem)
323 """
324 checkedList = []
325 if current is not None:
326 checkedList = self.__filterMap[current.text()]
327 for index in range(0, self.attributesList.topLevelItemCount()):
328 itm = self.attributesList.topLevelItem(index)
329 if itm.text(0) in checkedList:
330 itm.setCheckState(0, Qt.Checked)
331 else:
332 itm.setCheckState(0, Qt.Unchecked)
333
334 @pyqtSlot()
335 def on_filtersList_itemSelectionChanged(self):
336 """
337 Private slot handling a change of selected filters.
338 """
339 self.removeFiltersButton.setEnabled(
340 len(self.filtersList.selectedItems()) > 0)
341
342 @pyqtSlot(QTreeWidgetItem, int)
343 def on_attributesList_itemChanged(self, item, column):
344 """
345 Private slot to handle a change of an attribute.
346
347 @param item reference to the changed item (QTreeWidgetItem)
348 @param column column containing the change (integer)
349 """
350 if self.filtersList.currentItem() is None:
351 return
352
353 customFilter = self.filtersList.currentItem().text()
354 if customFilter not in self.__filterMap:
355 return
356
357 newAtts = []
358 for index in range(0, self.attributesList.topLevelItemCount()):
359 itm = self.attributesList.topLevelItem(index)
360 if itm.checkState(0) == Qt.Checked:
361 newAtts.append(itm.text(0))
362 self.__filterMap[customFilter] = newAtts
363
364 @pyqtSlot()
365 def on_attributesList_itemSelectionChanged(self):
366 """
367 Private slot handling the selection of attributes.
368 """
369 self.removeAttributesButton.setEnabled(
370 len(self.attributesList.selectedItems()) != 0)
371
372 @pyqtSlot()
373 def on_addFilterButton_clicked(self):
374 """
375 Private slot to add a new filter.
376 """
377 customFilter, ok = QInputDialog.getText(
378 None,
379 self.tr("Add Filter"),
380 self.tr("Filter name:"),
381 QLineEdit.Normal)
382 if not customFilter:
383 return
384
385 if customFilter not in self.__filterMap:
386 self.__filterMap[customFilter] = []
387 self.filtersList.addItem(customFilter)
388
389 itm = self.filtersList.findItems(
390 customFilter, Qt.MatchCaseSensitive)[0]
391 self.filtersList.setCurrentItem(itm)
392
393 @pyqtSlot()
394 def on_removeFiltersButton_clicked(self):
395 """
396 Private slot to remove the selected filters.
397 """
398 ok = E5MessageBox.yesNo(
399 self,
400 self.tr("Remove Filters"),
401 self.tr(
402 """Do you really want to remove the selected filters """
403 """from the database?"""))
404 if not ok:
405 return
406
407 items = self.filtersList.selectedItems()
408 for item in items:
409 itm = self.filtersList.takeItem(self.filtersList.row(item))
410 if itm is None:
411 continue
412
413 del self.__filterMap[itm.text()]
414 self.__removedFilters.append(itm.text())
415 del itm
416
417 if self.filtersList.count():
418 self.filtersList.setCurrentRow(
419 0, QItemSelectionModel.ClearAndSelect)
420
421 @pyqtSlot()
422 def on_removeAttributesButton_clicked(self):
423 """
424 Private slot to remove the selected filter attributes.
425 """
426 ok = E5MessageBox.yesNo(
427 self,
428 self.tr("Remove Attributes"),
429 self.tr(
430 """Do you really want to remove the selected attributes """
431 """from the database?"""))
432 if not ok:
433 return
434
435 items = self.attributesList.selectedItems()
436 for item in items:
437 itm = self.attributesList.takeTopLevelItem(
438 self.attributesList.indexOfTopLevelItem(item))
439 if itm is None:
440 continue
441
442 attr = itm.text(0)
443 self.__removedAttributes.append(attr)
444 for customFilter in self.__filterMap:
445 if attr in self.__filterMap[customFilter]:
446 self.__filterMap[customFilter].remove(attr)
447
448 del itm
449
450 @pyqtSlot()
451 def on_unusedAttributesButton_clicked(self):
452 """
453 Private slot to select all unused attributes.
454 """
455 # step 1: determine all used attributes
456 attributes = set()
457 for customFilter in self.__filterMap:
458 attributes |= set(self.__filterMap[customFilter])
459
460 # step 2: select all unused attribute items
461 self.attributesList.clearSelection()
462 for row in range(self.attributesList.topLevelItemCount()):
463 itm = self.attributesList.topLevelItem(row)
464 if itm.text(0) not in attributes:
465 itm.setSelected(True)
466
467 def __removeAttributes(self):
468 """
469 Private method to remove attributes from the Qt Help database.
470 """
471 try:
472 self.__db = sqlite3.connect(self.__engine.collectionFile())
473 except sqlite3.DatabaseError:
474 pass # ignore database errors
475
476 for attr in self.__removedAttributes:
477 self.__db.execute(
478 "DELETE FROM FilterAttributeTable WHERE Name = '{0}'"
479 .format(attr))
480 self.__db.commit()
481 self.__db.close()
482
483 @pyqtSlot()
484 def on_applyFilterChangesButton_clicked(self):
485 """
486 Private slot to apply the filter changes.
487 """
488 if self.__hasChangedFilters():
489 for customFilter in self.__removedFilters:
490 self.__engine.removeCustomFilter(customFilter)
491 for customFilter in self.__filterMap:
492 self.__engine.addCustomFilter(
493 customFilter, self.__filterMap[customFilter])
494
495 if self.__removedAttributes:
496 self.__removeAttributes()
497
498 def __hasChangedFilters(self):
499 """
500 Private method to determine, if there are filter changes.
501
502 @return flag indicating the presence of filter changes
503 @rtype bool
504 """
505 filtersChanged = False
506 if len(self.__filterMapBackup) != len(self.__filterMap):
507 filtersChanged = True
508 else:
509 for customFilter in self.__filterMapBackup:
510 if customFilter not in self.__filterMap:
511 filtersChanged = True
512 else:
513 oldFilterAtts = self.__filterMapBackup[customFilter]
514 newFilterAtts = self.__filterMap[customFilter]
515 if len(oldFilterAtts) != len(newFilterAtts):
516 filtersChanged = True
517 else:
518 for attr in oldFilterAtts:
519 if attr not in newFilterAtts:
520 filtersChanged = True
521 break
522
523 if filtersChanged:
524 break
525
526 return filtersChanged
527
528 @pyqtSlot()
529 def on_resetFilterChangesButton_clicked(self):
530 """
531 Private slot to forget the filter changes and reset the tab.
532 """
533 self.__initFiltersTab()

eric ide

mercurial