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 |
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() |