1# -*- coding: utf-8 -*-
2
3# Copyright (c) 2007 - 2021 Detlev Offenbach <detlev@die-offenbachs.de>
4#
5
6"""
7Module implementing the QFileDialog wizard plugin.
8"""
9
10import re
11
12from PyQt5.QtCore import QObject
13from PyQt5.QtWidgets import QDialog
14
15from E5Gui.E5Application import e5App
16from E5Gui.E5Action import E5Action
17from E5Gui import E5MessageBox
18
19import UI.Info
20
21# Start-Of-Header
22name = "QFileDialog Wizard Plugin"
23author = "Detlev Offenbach <detlev@die-offenbachs.de>"
24autoactivate = True
25deactivateable = True
26version = UI.Info.VersionOnly
27className = "FileDialogWizard"
28packageName = "__core__"
29shortDescription = "Show the QFileDialog wizard."
30longDescription = """This plugin shows the QFileDialog wizard."""
31pyqtApi = 2
32# End-Of-Header
33
34error = ""
35
36
37class FileDialogWizard(QObject):
38    """
39    Class implementing the QFileDialog wizard plugin.
40    """
41    def __init__(self, ui):
42        """
43        Constructor
44
45        @param ui reference to the user interface object (UI.UserInterface)
46        """
47        super().__init__(ui)
48        self.__ui = ui
49
50        # PyQt5
51        self.__pyqtRe = re.compile(r"(?:import|from)\s+PyQt([56])")
52
53    def activate(self):
54        """
55        Public method to activate this plugin.
56
57        @return tuple of None and activation status (boolean)
58        """
59        self.__initActions()
60        self.__initMenu()
61
62        return None, True
63
64    def deactivate(self):
65        """
66        Public method to deactivate this plugin.
67        """
68        menu = self.__ui.getMenu("wizards")
69        if menu:
70            menu.removeAction(self.qFileDialogAction)
71            menu.removeAction(self.e5FileDialogAction)
72        self.__ui.removeE5Actions(
73            [self.qFileDialogAction, self.e5FileDialogAction],
74            'wizards')
75
76    def __initActions(self):
77        """
78        Private method to initialize the actions.
79        """
80        self.qFileDialogAction = E5Action(
81            self.tr('QFileDialog Wizard'),
82            self.tr('Q&FileDialog Wizard...'), 0, 0, self,
83            'wizards_qfiledialog')
84        self.qFileDialogAction.setStatusTip(self.tr('QFileDialog Wizard'))
85        self.qFileDialogAction.setWhatsThis(self.tr(
86            """<b>QFileDialog Wizard</b>"""
87            """<p>This wizard opens a dialog for entering all the parameters"""
88            """ needed to create a QFileDialog. The generated code is"""
89            """ inserted at the current cursor position.</p>"""
90        ))
91        self.qFileDialogAction.triggered.connect(self.__handleQFileDialog)
92
93        self.e5FileDialogAction = E5Action(
94            self.tr('E5FileDialog Wizard'),
95            self.tr('E&5FileDialog Wizard...'), 0, 0, self,
96            'wizards_e5filedialog')
97        self.e5FileDialogAction.setStatusTip(self.tr('E5FileDialog Wizard'))
98        self.e5FileDialogAction.setWhatsThis(self.tr(
99            """<b>E5FileDialog Wizard</b>"""
100            """<p>This wizard opens a dialog for entering all the parameters"""
101            """ needed to create an E5FileDialog. The generated code is"""
102            """ inserted at the current cursor position.</p>"""
103        ))
104        self.e5FileDialogAction.triggered.connect(self.__handleE5FileDialog)
105
106        self.__ui.addE5Actions(
107            [self.qFileDialogAction, self.e5FileDialogAction],
108            'wizards')
109
110    def __initMenu(self):
111        """
112        Private method to add the actions to the right menu.
113        """
114        menu = self.__ui.getMenu("wizards")
115        if menu:
116            menu.addAction(self.e5FileDialogAction)
117            menu.addAction(self.qFileDialogAction)
118
119    def __callForm(self, editor, variant):
120        """
121        Private method to display a dialog and get the code.
122
123        @param editor reference to the current editor
124        @type Editor
125        @param variant variant of code to be generated
126            (-1 = E5FileDialog, 0 = unknown, 5 = PyQt5)
127        @type int
128        @return the generated code (string)
129        """
130        from WizardPlugins.FileDialogWizard.FileDialogWizardDialog import (
131            FileDialogWizardDialog
132        )
133        dlg = FileDialogWizardDialog(variant, None)
134        if dlg.exec() == QDialog.DialogCode.Accepted:
135            line, index = editor.getCursorPosition()
136            indLevel = editor.indentation(line) // editor.indentationWidth()
137            if editor.indentationsUseTabs():
138                indString = '\t'
139            else:
140                indString = editor.indentationWidth() * ' '
141            return (dlg.getCode(indLevel, indString), 1)
142        else:
143            return (None, 0)
144
145    def __handle(self, variant):
146        """
147        Private method to handle the wizards action.
148
149        @param variant dialog variant to be generated
150            (E5FileDialog or QFileDialog)
151        @type str
152        @exception ValueError raised to indicate an illegal file dialog variant
153        """
154        editor = e5App().getObject("ViewManager").activeWindow()
155
156        if editor is None:
157            E5MessageBox.critical(
158                self.__ui,
159                self.tr('No current editor'),
160                self.tr('Please open or create a file first.'))
161        else:
162            if variant not in ("QFileDialog", "E5FileDialog"):
163                raise ValueError("Illegal dialog variant given")
164
165            if variant == "QFileDialog":
166                match = self.__pyqtRe.search(editor.text())
167                if match is None:
168                    # unknown
169                    dialogVariant = 0
170                else:
171                    # PyQt5/PyQt6
172                    dialogVariant = int(match.group(1))
173            else:
174                # E5FileDialog
175                dialogVariant = -1
176
177            code, ok = self.__callForm(editor, dialogVariant)
178            if ok:
179                line, index = editor.getCursorPosition()
180                # It should be done on this way to allow undo
181                editor.beginUndoAction()
182                editor.insertAt(code, line, index)
183                editor.endUndoAction()
184
185    def __handleQFileDialog(self):
186        """
187        Private slot to handle the wizard QFileDialog action.
188        """
189        self.__handle("QFileDialog")
190
191    def __handleE5FileDialog(self):
192        """
193        Private slot to handle the wizard E5FileDialog action.
194        """
195        self.__handle("E5FileDialog")
196