src/eric7/Tools/TRPreviewer.py

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

eric ide

mercurial