eric7/Tools/TRPreviewer.py

branch
eric7
changeset 8312
800c432b34c8
parent 8243
cc717c2ae956
child 8318
962bce857696
equal deleted inserted replaced
8311:4e8b98454baa 8312:800c432b34c8
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2004 - 2021 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing the TR Previewer main window.
8 """
9
10 import os
11 import contextlib
12
13 from PyQt5.QtCore import (
14 QDir, QTimer, QFileInfo, pyqtSignal, QEvent, QSize, QTranslator, QObject,
15 Qt, QCoreApplication
16 )
17 from PyQt5.QtGui import QKeySequence
18 from PyQt5.QtWidgets import (
19 QSizePolicy, QSpacerItem, QWidget, QHBoxLayout, QWhatsThis, QMdiArea,
20 QApplication, QComboBox, QVBoxLayout, QAction, QLabel
21 )
22 from PyQt5 import uic
23
24
25 from E5Gui import E5MessageBox, E5FileDialog
26 from E5Gui.E5MainWindow import E5MainWindow
27 from E5Gui.E5Application import e5App
28
29 import UI.PixmapCache
30 import UI.Config
31
32 import Preferences
33
34
35 noTranslationName = QCoreApplication.translate(
36 "TRPreviewer", "<No translation>")
37
38
39 class TRPreviewer(E5MainWindow):
40 """
41 Class implementing the UI Previewer main window.
42 """
43 def __init__(self, filenames=None, parent=None, name=None):
44 """
45 Constructor
46
47 @param filenames filenames of form and/or translation files to load
48 @param parent parent widget of this window (QWidget)
49 @param name name of this window (string)
50 """
51 self.mainWidget = None
52 self.currentFile = QDir.currentPath()
53
54 super().__init__(parent)
55 if not name:
56 self.setObjectName("TRPreviewer")
57 else:
58 self.setObjectName(name)
59
60 self.setStyle(Preferences.getUI("Style"),
61 Preferences.getUI("StyleSheet"))
62
63 self.resize(QSize(800, 600).expandedTo(self.minimumSizeHint()))
64 self.statusBar()
65
66 self.setWindowIcon(UI.PixmapCache.getIcon("eric"))
67 self.setWindowTitle(self.tr("Translations Previewer"))
68
69 self.cw = QWidget(self)
70 self.cw.setObjectName("qt_central_widget")
71
72 self.TRPreviewerLayout = QVBoxLayout(self.cw)
73 self.TRPreviewerLayout.setContentsMargins(6, 6, 6, 6)
74 self.TRPreviewerLayout.setSpacing(6)
75 self.TRPreviewerLayout.setObjectName("TRPreviewerLayout")
76
77 self.languageLayout = QHBoxLayout()
78 self.languageLayout.setContentsMargins(0, 0, 0, 0)
79 self.languageLayout.setSpacing(6)
80 self.languageLayout.setObjectName("languageLayout")
81
82 self.languageLabel = QLabel(
83 self.tr("Select language file"), self.cw)
84 self.languageLabel.setObjectName("languageLabel")
85 self.languageLayout.addWidget(self.languageLabel)
86
87 self.languageCombo = QComboBox(self.cw)
88 self.languageCombo.setObjectName("languageCombo")
89 self.languageCombo.setEditable(False)
90 self.languageCombo.setToolTip(self.tr("Select language file"))
91 self.languageCombo.setSizePolicy(
92 QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred)
93 self.languageLayout.addWidget(self.languageCombo)
94
95 languageSpacer = QSpacerItem(
96 40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
97 self.languageLayout.addItem(languageSpacer)
98 self.TRPreviewerLayout.addLayout(self.languageLayout)
99
100 self.preview = WidgetArea(self.cw)
101 self.preview.setObjectName("preview")
102 self.TRPreviewerLayout.addWidget(self.preview)
103 self.preview.lastWidgetClosed.connect(self.__updateActions)
104
105 self.setCentralWidget(self.cw)
106
107 self.languageCombo.activated[int].connect(self.__setTranslation)
108
109 self.translations = TranslationsDict(self.languageCombo, self)
110 self.translations.translationChanged.connect(
111 self.preview.rebuildWidgets)
112
113 self.__initActions()
114 self.__initMenus()
115 self.__initToolbars()
116
117 self.__updateActions()
118
119 # fire up the single application server
120 from .TRSingleApplication import TRSingleApplicationServer
121 self.SAServer = TRSingleApplicationServer(self)
122 self.SAServer.loadForm.connect(self.preview.loadWidget)
123 self.SAServer.loadTranslation.connect(self.translations.add)
124
125 # defere loading of a UI file until we are shown
126 self.filesToLoad = [] if filenames is None else filenames[:]
127
128 def show(self):
129 """
130 Public slot to show this dialog.
131
132 This overloaded slot loads a UI file to be previewed after
133 the main window has been shown. This way, previewing a dialog
134 doesn't interfere with showing the main window.
135 """
136 super().show()
137 if self.filesToLoad:
138 filenames, self.filesToLoad = (self.filesToLoad[:], [])
139 first = True
140 for fn in filenames:
141 fi = QFileInfo(fn)
142 if fi.suffix().lower() == 'ui':
143 self.preview.loadWidget(fn)
144 elif fi.suffix().lower() == 'qm':
145 self.translations.add(fn, first)
146 first = False
147
148 self.__updateActions()
149
150 def closeEvent(self, event):
151 """
152 Protected event handler for the close event.
153
154 @param event close event (QCloseEvent)
155 """
156 if self.SAServer is not None:
157 self.SAServer.shutdown()
158 self.SAServer = None
159 event.accept()
160
161 def __initActions(self):
162 """
163 Private method to define the user interface actions.
164 """
165 self.openUIAct = QAction(
166 UI.PixmapCache.getIcon("openUI"),
167 self.tr('&Open UI Files...'), self)
168 self.openUIAct.setStatusTip(self.tr('Open UI files for display'))
169 self.openUIAct.setWhatsThis(self.tr(
170 """<b>Open UI Files</b>"""
171 """<p>This opens some UI files for display.</p>"""
172 ))
173 self.openUIAct.triggered.connect(self.__openWidget)
174
175 self.openQMAct = QAction(
176 UI.PixmapCache.getIcon("openQM"),
177 self.tr('Open &Translation Files...'), self)
178 self.openQMAct.setStatusTip(self.tr(
179 'Open Translation files for display'))
180 self.openQMAct.setWhatsThis(self.tr(
181 """<b>Open Translation Files</b>"""
182 """<p>This opens some translation files for display.</p>"""
183 ))
184 self.openQMAct.triggered.connect(self.__openTranslation)
185
186 self.reloadAct = QAction(
187 UI.PixmapCache.getIcon("reload"),
188 self.tr('&Reload Translations'), self)
189 self.reloadAct.setStatusTip(self.tr(
190 'Reload the loaded translations'))
191 self.reloadAct.setWhatsThis(self.tr(
192 """<b>Reload Translations</b>"""
193 """<p>This reloads the translations for the loaded"""
194 """ languages.</p>"""
195 ))
196 self.reloadAct.triggered.connect(self.translations.reload)
197
198 self.exitAct = QAction(
199 UI.PixmapCache.getIcon("exit"), self.tr('&Quit'), self)
200 self.exitAct.setShortcut(QKeySequence(
201 self.tr("Ctrl+Q", "File|Quit")))
202 self.exitAct.setStatusTip(self.tr('Quit the application'))
203 self.exitAct.setWhatsThis(self.tr(
204 """<b>Quit</b>"""
205 """<p>Quit the application.</p>"""
206 ))
207 self.exitAct.triggered.connect(e5App().closeAllWindows)
208
209 self.whatsThisAct = QAction(
210 UI.PixmapCache.getIcon("whatsThis"),
211 self.tr('&What\'s This?'), self)
212 self.whatsThisAct.setShortcut(QKeySequence(self.tr("Shift+F1")))
213 self.whatsThisAct.setStatusTip(self.tr('Context sensitive help'))
214 self.whatsThisAct.setWhatsThis(self.tr(
215 """<b>Display context sensitive help</b>"""
216 """<p>In What's This? mode, the mouse cursor shows an arrow"""
217 """ with a question mark, and you can click on the interface"""
218 """ elements to get a short description of what they do and"""
219 """ how to use them. In dialogs, this feature can be accessed"""
220 """ using the context help button in the titlebar.</p>"""
221 ))
222 self.whatsThisAct.triggered.connect(self.__whatsThis)
223
224 self.aboutAct = QAction(self.tr('&About'), self)
225 self.aboutAct.setStatusTip(self.tr(
226 'Display information about this software'))
227 self.aboutAct.setWhatsThis(self.tr(
228 """<b>About</b>"""
229 """<p>Display some information about this software.</p>"""
230 ))
231 self.aboutAct.triggered.connect(self.__about)
232
233 self.aboutQtAct = QAction(self.tr('About &Qt'), self)
234 self.aboutQtAct.setStatusTip(
235 self.tr('Display information about the Qt toolkit'))
236 self.aboutQtAct.setWhatsThis(self.tr(
237 """<b>About Qt</b>"""
238 """<p>Display some information about the Qt toolkit.</p>"""
239 ))
240 self.aboutQtAct.triggered.connect(self.__aboutQt)
241
242 self.tileAct = QAction(self.tr('&Tile'), self)
243 self.tileAct.setStatusTip(self.tr('Tile the windows'))
244 self.tileAct.setWhatsThis(self.tr(
245 """<b>Tile the windows</b>"""
246 """<p>Rearrange and resize the windows so that they are"""
247 """ tiled.</p>"""
248 ))
249 self.tileAct.triggered.connect(self.preview.tileSubWindows)
250
251 self.cascadeAct = QAction(self.tr('&Cascade'), self)
252 self.cascadeAct.setStatusTip(self.tr('Cascade the windows'))
253 self.cascadeAct.setWhatsThis(self.tr(
254 """<b>Cascade the windows</b>"""
255 """<p>Rearrange and resize the windows so that they are"""
256 """ cascaded.</p>"""
257 ))
258 self.cascadeAct.triggered.connect(self.preview.cascadeSubWindows)
259
260 self.closeAct = QAction(
261 UI.PixmapCache.getIcon("close"), self.tr('&Close'), self)
262 self.closeAct.setShortcut(QKeySequence(self.tr(
263 "Ctrl+W", "File|Close")))
264 self.closeAct.setStatusTip(self.tr('Close the current window'))
265 self.closeAct.setWhatsThis(self.tr(
266 """<b>Close Window</b>"""
267 """<p>Close the current window.</p>"""
268 ))
269 self.closeAct.triggered.connect(self.preview.closeWidget)
270
271 self.closeAllAct = QAction(self.tr('Clos&e All'), self)
272 self.closeAllAct.setStatusTip(self.tr('Close all windows'))
273 self.closeAllAct.setWhatsThis(self.tr(
274 """<b>Close All Windows</b>"""
275 """<p>Close all windows.</p>"""
276 ))
277 self.closeAllAct.triggered.connect(self.preview.closeAllWidgets)
278
279 def __initMenus(self):
280 """
281 Private method to create the menus.
282 """
283 mb = self.menuBar()
284
285 menu = mb.addMenu(self.tr('&File'))
286 menu.setTearOffEnabled(True)
287 menu.addAction(self.openUIAct)
288 menu.addAction(self.openQMAct)
289 menu.addAction(self.reloadAct)
290 menu.addSeparator()
291 menu.addAction(self.closeAct)
292 menu.addAction(self.closeAllAct)
293 menu.addSeparator()
294 menu.addAction(self.exitAct)
295
296 self.windowMenu = mb.addMenu(self.tr('&Window'))
297 self.windowMenu.setTearOffEnabled(True)
298 self.windowMenu.aboutToShow.connect(self.__showWindowMenu)
299 self.windowMenu.triggered.connect(self.preview.toggleSelectedWidget)
300
301 mb.addSeparator()
302
303 menu = mb.addMenu(self.tr('&Help'))
304 menu.setTearOffEnabled(True)
305 menu.addAction(self.aboutAct)
306 menu.addAction(self.aboutQtAct)
307 menu.addSeparator()
308 menu.addAction(self.whatsThisAct)
309
310 def __initToolbars(self):
311 """
312 Private method to create the toolbars.
313 """
314 filetb = self.addToolBar(self.tr("File"))
315 filetb.setIconSize(UI.Config.ToolBarIconSize)
316 filetb.addAction(self.openUIAct)
317 filetb.addAction(self.openQMAct)
318 filetb.addAction(self.reloadAct)
319 filetb.addSeparator()
320 filetb.addAction(self.closeAct)
321 filetb.addSeparator()
322 filetb.addAction(self.exitAct)
323
324 helptb = self.addToolBar(self.tr("Help"))
325 helptb.setIconSize(UI.Config.ToolBarIconSize)
326 helptb.addAction(self.whatsThisAct)
327
328 def __whatsThis(self):
329 """
330 Private slot called in to enter Whats This mode.
331 """
332 QWhatsThis.enterWhatsThisMode()
333
334 def __updateActions(self):
335 """
336 Private slot to update the actions state.
337 """
338 if self.preview.hasWidgets():
339 self.closeAct.setEnabled(True)
340 self.closeAllAct.setEnabled(True)
341 self.tileAct.setEnabled(True)
342 self.cascadeAct.setEnabled(True)
343 else:
344 self.closeAct.setEnabled(False)
345 self.closeAllAct.setEnabled(False)
346 self.tileAct.setEnabled(False)
347 self.cascadeAct.setEnabled(False)
348
349 if self.translations.hasTranslations():
350 self.reloadAct.setEnabled(True)
351 else:
352 self.reloadAct.setEnabled(False)
353
354 def __about(self):
355 """
356 Private slot to show the about information.
357 """
358 E5MessageBox.about(
359 self,
360 self.tr("TR Previewer"),
361 self.tr(
362 """<h3> About TR Previewer </h3>"""
363 """<p>The TR Previewer loads and displays Qt User-Interface"""
364 """ files and translation files and shows dialogs for a"""
365 """ selected language.</p>"""
366 )
367 )
368
369 def __aboutQt(self):
370 """
371 Private slot to show info about Qt.
372 """
373 E5MessageBox.aboutQt(self, self.tr("TR Previewer"))
374
375 def __openWidget(self):
376 """
377 Private slot to handle the Open Dialog action.
378 """
379 fileNameList = E5FileDialog.getOpenFileNames(
380 None,
381 self.tr("Select UI files"),
382 "",
383 self.tr("Qt User-Interface Files (*.ui)"))
384
385 for fileName in fileNameList:
386 self.preview.loadWidget(fileName)
387
388 self.__updateActions()
389
390 def __openTranslation(self):
391 """
392 Private slot to handle the Open Translation action.
393 """
394 fileNameList = E5FileDialog.getOpenFileNames(
395 None,
396 self.tr("Select translation files"),
397 "",
398 self.tr("Qt Translation Files (*.qm)"))
399
400 first = True
401 for fileName in fileNameList:
402 self.translations.add(fileName, first)
403 first = False
404
405 self.__updateActions()
406
407 def __setTranslation(self, index):
408 """
409 Private slot to activate a translation.
410
411 @param index index of the selected entry
412 @type int
413 """
414 name = self.languageCombo.itemText(index)
415 self.translations.set(name)
416
417 def __showWindowMenu(self):
418 """
419 Private slot to handle the aboutToShow signal of the window menu.
420 """
421 self.windowMenu.clear()
422 self.windowMenu.addAction(self.tileAct)
423 self.windowMenu.addAction(self.cascadeAct)
424 self.windowMenu.addSeparator()
425
426 self.preview.showWindowMenu(self.windowMenu)
427
428 def reloadTranslations(self):
429 """
430 Public slot to reload all translations.
431 """
432 self.translations.reload()
433
434
435 class Translation:
436 """
437 Class to store the properties of a translation.
438 """
439 def __init__(self):
440 """
441 Constructor
442 """
443 self.fileName = None
444 self.name = None
445 self.translator = None
446
447
448 class TranslationsDict(QObject):
449 """
450 Class to store all loaded translations.
451
452 @signal translationChanged() emit after a translator was set
453 """
454 translationChanged = pyqtSignal()
455
456 def __init__(self, selector, parent):
457 """
458 Constructor
459
460 @param selector reference to the QComboBox used to show the
461 available languages (QComboBox)
462 @param parent parent widget (QWidget)
463 """
464 super().__init__(parent)
465
466 self.selector = selector
467 self.currentTranslator = None
468 self.selector.addItem(noTranslationName)
469 self.translations = [] # list of Translation objects
470
471 def add(self, fileName, setTranslation=True):
472 """
473 Public method to add a translation to the list.
474
475 If the translation file (*.qm) has not been loaded yet, it will
476 be loaded automatically.
477
478 @param fileName name of the translation file to be added (string)
479 @param setTranslation flag indicating, if this should be set as
480 the active translation (boolean)
481 """
482 if not self.__haveFileName(fileName):
483 ntr = Translation()
484 ntr.fileName = fileName
485 ntr.name = self.__uniqueName(fileName)
486 if ntr.name is None:
487 E5MessageBox.warning(
488 self.parent(),
489 self.tr("Set Translator"),
490 self.tr(
491 """<p>The translation filename <b>{0}</b>"""
492 """ is invalid.</p>""").format(fileName))
493 return
494
495 ntr.translator = self.loadTransFile(fileName)
496 if ntr.translator is None:
497 return
498
499 self.selector.addItem(ntr.name)
500 self.translations.append(ntr)
501
502 if setTranslation:
503 tr = self.__findFileName(fileName)
504 self.set(tr.name)
505
506 def set(self, name):
507 """
508 Public slot to set a translator by name.
509
510 @param name name (language) of the translator to set (string)
511 """
512 nTranslator = None
513
514 if name != noTranslationName:
515 trans = self.__findName(name)
516 if trans is None:
517 E5MessageBox.warning(
518 self.parent(),
519 self.tr("Set Translator"),
520 self.tr(
521 """<p>The translator <b>{0}</b> is not known.</p>""")
522 .format(name))
523 return
524
525 nTranslator = trans.translator
526
527 if nTranslator == self.currentTranslator:
528 return
529
530 if self.currentTranslator is not None:
531 QApplication.removeTranslator(self.currentTranslator)
532 if nTranslator is not None:
533 QApplication.installTranslator(nTranslator)
534 self.currentTranslator = nTranslator
535
536 self.selector.blockSignals(True)
537 self.selector.setCurrentIndex(self.selector.findText(name))
538 self.selector.blockSignals(False)
539
540 self.translationChanged.emit()
541
542 def reload(self):
543 """
544 Public method to reload all translators.
545 """
546 cname = self.selector.currentText()
547 if self.currentTranslator is not None:
548 QApplication.removeTranslator(self.currentTranslator)
549 self.currentTranslator = None
550
551 fileNames = []
552 for trans in self.translations:
553 trans.translator = None
554 fileNames.append(trans.fileName)
555 self.translations = []
556 self.selector.clear()
557
558 self.selector.addItem(noTranslationName)
559
560 for fileName in fileNames:
561 self.add(fileName, False)
562
563 if self.__haveName(cname):
564 self.set(cname)
565 else:
566 self.set(noTranslationName)
567
568 def __findFileName(self, transFileName):
569 """
570 Private method to find a translation by file name.
571
572 @param transFileName file name of the translation file (string)
573 @return reference to a translation object or None
574 """
575 for trans in self.translations:
576 if trans.fileName == transFileName:
577 return trans
578 return None
579
580 def __findName(self, name):
581 """
582 Private method to find a translation by name.
583
584 @param name name (language) of the translation (string)
585 @return reference to a translation object or None
586 """
587 for trans in self.translations:
588 if trans.name == name:
589 return trans
590 return None
591
592 def __haveFileName(self, transFileName):
593 """
594 Private method to check for the presence of a translation.
595
596 @param transFileName file name of the translation file (string)
597 @return flag indicating the presence of the translation (boolean)
598 """
599 return self.__findFileName(transFileName) is not None
600
601 def __haveName(self, name):
602 """
603 Private method to check for the presence of a named translation.
604
605 @param name name (language) of the translation (string)
606 @return flag indicating the presence of the translation (boolean)
607 """
608 return self.__findName(name) is not None
609
610 def __uniqueName(self, transFileName):
611 """
612 Private method to generate a unique name.
613
614 @param transFileName file name of the translation file (string)
615 @return unique name (string or None)
616 """
617 name = os.path.basename(transFileName)
618 if not name:
619 return None
620
621 uname = name
622 cnt = 1
623 while self.__haveName(uname):
624 cnt += 1
625 uname = "{0} <{1}>".format(name, cnt)
626
627 return uname
628
629 def __del(self, name):
630 """
631 Private method to delete a translator from the list of available
632 translators.
633
634 @param name name of the translator to delete (string)
635 """
636 if name == noTranslationName:
637 return
638
639 trans = self.__findName(name)
640 if trans is None:
641 return
642
643 if self.selector().currentText() == name:
644 self.set(noTranslationName)
645
646 self.translations.remove(trans)
647 del trans
648
649 def loadTransFile(self, transFileName):
650 """
651 Public slot to load a translation file.
652
653 @param transFileName file name of the translation file (string)
654 @return reference to the new translator object (QTranslator)
655 """
656 tr = QTranslator()
657 if tr.load(transFileName):
658 return tr
659
660 E5MessageBox.warning(
661 self.parent(),
662 self.tr("Load Translator"),
663 self.tr("""<p>The translation file <b>{0}</b> could"""
664 """ not be loaded.</p>""").format(transFileName))
665 return None
666
667 def hasTranslations(self):
668 """
669 Public method to check for loaded translations.
670
671 @return flag signaling if any translation was loaded (boolean)
672 """
673 return len(self.translations) > 0
674
675
676 class WidgetView(QWidget):
677 """
678 Class to show a dynamically loaded widget (or dialog).
679 """
680 def __init__(self, uiFileName, parent=None, name=None):
681 """
682 Constructor
683
684 @param uiFileName name of the UI file to load (string)
685 @param parent parent widget (QWidget)
686 @param name name of this widget (string)
687 """
688 super().__init__(parent)
689 if name:
690 self.setObjectName(name)
691 self.setWindowTitle(name)
692
693 self.__widget = None
694 self.__uiFileName = uiFileName
695 self.__layout = QHBoxLayout(self)
696 self.__valid = False
697 self.__timer = QTimer(self)
698 self.__timer.setSingleShot(True)
699 self.__timer.timeout.connect(self.buildWidget)
700
701 def isValid(self):
702 """
703 Public method to return the validity of this widget view.
704
705 @return flag indicating the validity (boolean)
706 """
707 return self.__valid
708
709 def uiFileName(self):
710 """
711 Public method to retrieve the name of the UI file.
712
713 @return filename of the loaded UI file (string)
714 """
715 return self.__uiFileName
716
717 def buildWidget(self):
718 """
719 Public slot to load a UI file.
720 """
721 if self.__widget:
722 self.__widget.close()
723 self.__layout.removeWidget(self.__widget)
724 del self.__widget
725 self.__widget = None
726
727 with contextlib.suppress(Exception):
728 self.__widget = uic.loadUi(self.__uiFileName)
729
730 if not self.__widget:
731 E5MessageBox.warning(
732 self,
733 self.tr("Load UI File"),
734 self.tr(
735 """<p>The file <b>{0}</b> could not be loaded.</p>""")
736 .format(self.__uiFileName))
737 self.__valid = False
738 return
739
740 self.__widget.setParent(self)
741 self.__layout.addWidget(self.__widget)
742 self.__widget.show()
743 self.__valid = True
744 self.adjustSize()
745
746 self.__timer.stop()
747
748 def __rebuildWidget(self):
749 """
750 Private method to schedule a rebuild of the widget.
751 """
752 self.__timer.start(0)
753
754
755 class WidgetArea(QMdiArea):
756 """
757 Specialized MDI area to show the loaded widgets.
758
759 @signal lastWidgetClosed() emitted after the last widget was closed
760 @signal rebuildWidgets() emitted to indicate a change of loaded widgets
761 """
762 lastWidgetClosed = pyqtSignal()
763 rebuildWidgets = pyqtSignal()
764
765 def __init__(self, parent=None):
766 """
767 Constructor
768
769 @param parent parent widget (QWidget)
770 """
771 super().__init__(parent)
772
773 self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
774 self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
775
776 self.widgets = []
777
778 def loadWidget(self, uiFileName):
779 """
780 Public slot to load a UI file.
781
782 @param uiFileName name of the UI file to load (string)
783 """
784 wview = self.__findWidget(uiFileName)
785 if wview is None:
786 name = os.path.basename(uiFileName)
787 if not name:
788 E5MessageBox.warning(
789 self,
790 self.tr("Load UI File"),
791 self.tr(
792 """<p>The file <b>{0}</b> could not be loaded.</p>""")
793 .format(uiFileName))
794 return
795
796 uname = name
797 cnt = 1
798 while self.findChild(WidgetView, uname) is not None:
799 cnt += 1
800 uname = "{0} <{1}>".format(name, cnt)
801 name = uname
802
803 wview = WidgetView(uiFileName, self, name)
804 wview.buildWidget()
805 if not wview.isValid():
806 del wview
807 return
808
809 self.rebuildWidgets.connect(wview.buildWidget)
810 wview.installEventFilter(self)
811
812 win = self.addSubWindow(wview)
813 self.widgets.append(win)
814
815 wview.showNormal()
816
817 def eventFilter(self, obj, ev):
818 """
819 Public method called to filter an event.
820
821 @param obj object, that generated the event (QObject)
822 @param ev the event, that was generated by object (QEvent)
823 @return flag indicating if event was filtered out
824 """
825 if obj in self.widgets and ev.type() == QEvent.Type.Close:
826 with contextlib.suppress(ValueError):
827 self.widgets.remove(obj)
828 if len(self.widgets) == 0:
829 self.lastWidgetClosed.emit()
830
831 return QMdiArea.eventFilter(self, obj, ev)
832
833 def __findWidget(self, uiFileName):
834 """
835 Private method to find a specific widget view.
836
837 @param uiFileName filename of the loaded UI file (string)
838 @return reference to the widget (WidgetView) or None
839 """
840 wviewList = self.findChildren(WidgetView)
841 if wviewList is None:
842 return None
843
844 for wview in wviewList:
845 if wview.uiFileName() == uiFileName:
846 return wview
847
848 return None
849
850 def closeWidget(self):
851 """
852 Public slot to close the active window.
853 """
854 aw = self.activeSubWindow()
855 if aw is not None:
856 aw.close()
857
858 def closeAllWidgets(self):
859 """
860 Public slot to close all windows.
861 """
862 for w in self.widgets[:]:
863 w.close()
864
865 def showWindowMenu(self, windowMenu):
866 """
867 Public method to set up the widgets part of the Window menu.
868
869 @param windowMenu reference to the window menu
870 """
871 for idx, wid in enumerate(self.widgets):
872 act = windowMenu.addAction(wid.windowTitle())
873 act.setData(idx)
874 act.setCheckable(True)
875 act.setChecked(not wid.isHidden())
876
877 def toggleSelectedWidget(self, act):
878 """
879 Public method to handle the toggle of a window.
880
881 @param act reference to the action that triggered (QAction)
882 """
883 idx = act.data()
884 if idx is not None:
885 self.__toggleWidget(self.widgets[idx])
886
887 def __toggleWidget(self, w):
888 """
889 Private method to toggle a workspace window.
890
891 @param w window to be toggled
892 """
893 if w.isHidden():
894 w.show()
895 else:
896 w.hide()
897
898 def hasWidgets(self):
899 """
900 Public method to check for loaded widgets.
901
902 @return flag signaling if any widget was loaded (boolean)
903 """
904 return len(self.widgets) > 0

eric ide

mercurial