27 |
32 |
28 |
33 |
29 class FindLocationWidget(QWidget, Ui_FindLocationWidget): |
34 class FindLocationWidget(QWidget, Ui_FindLocationWidget): |
30 """ |
35 """ |
31 Class implementing a widget to search for files. |
36 Class implementing a widget to search for files. |
32 |
37 |
33 The occurrences found are displayed in a QTreeWidget showing the |
38 The occurrences found are displayed in a QTreeWidget showing the |
34 filename and the pathname. The file will be opened upon a double click |
39 filename and the pathname. The file will be opened upon a double click |
35 onto the respective entry of the list or by pressing the open button. |
40 onto the respective entry of the list or by pressing the open button. |
36 |
41 |
37 @signal sourceFile(str) emitted to open a file in the editor |
42 @signal sourceFile(str) emitted to open a file in the editor |
38 @signal designerFile(str) emitted to open a Qt-Designer file |
43 @signal designerFile(str) emitted to open a Qt-Designer file |
39 @signal linguistFile(str) emitted to open a Qt-Linguist (*.ts) file |
44 @signal linguistFile(str) emitted to open a Qt-Linguist (*.ts) file |
40 @signal trpreview([str]) emitted to preview Qt-Linguist (*.qm) files |
45 @signal trpreview([str]) emitted to preview Qt-Linguist (*.qm) files |
41 @signal pixmapFile(str) emitted to open a pixmap file |
46 @signal pixmapFile(str) emitted to open a pixmap file |
42 @signal svgFile(str) emitted to open a SVG file |
47 @signal svgFile(str) emitted to open a SVG file |
43 @signal umlFile(str) emitted to open an eric UML file |
48 @signal umlFile(str) emitted to open an eric UML file |
44 """ |
49 """ |
|
50 |
45 sourceFile = pyqtSignal(str) |
51 sourceFile = pyqtSignal(str) |
46 designerFile = pyqtSignal(str) |
52 designerFile = pyqtSignal(str) |
47 linguistFile = pyqtSignal(str) |
53 linguistFile = pyqtSignal(str) |
48 trpreview = pyqtSignal(list) |
54 trpreview = pyqtSignal(list) |
49 pixmapFile = pyqtSignal(str) |
55 pixmapFile = pyqtSignal(str) |
50 svgFile = pyqtSignal(str) |
56 svgFile = pyqtSignal(str) |
51 umlFile = pyqtSignal(str) |
57 umlFile = pyqtSignal(str) |
52 |
58 |
53 def __init__(self, project, parent=None): |
59 def __init__(self, project, parent=None): |
54 """ |
60 """ |
55 Constructor |
61 Constructor |
56 |
62 |
57 @param project reference to the project object |
63 @param project reference to the project object |
58 @type Project |
64 @type Project |
59 @param parent parent widget of this dialog |
65 @param parent parent widget of this dialog |
60 @type QWidget |
66 @type QWidget |
61 """ |
67 """ |
62 super().__init__(parent) |
68 super().__init__(parent) |
63 self.setupUi(self) |
69 self.setupUi(self) |
64 |
70 |
65 self.layout().setContentsMargins(0, 3, 0, 0) |
71 self.layout().setContentsMargins(0, 3, 0, 0) |
66 |
72 |
67 self.searchDirPicker.setMode(EricPathPickerModes.DIRECTORY_MODE) |
73 self.searchDirPicker.setMode(EricPathPickerModes.DIRECTORY_MODE) |
68 |
74 |
69 self.fileList.headerItem().setText(self.fileList.columnCount(), "") |
75 self.fileList.headerItem().setText(self.fileList.columnCount(), "") |
70 |
76 |
71 self.stopButton.setEnabled(False) |
77 self.stopButton.setEnabled(False) |
72 self.stopButton.setIcon(UI.PixmapCache.getIcon("stopLoading")) |
78 self.stopButton.setIcon(UI.PixmapCache.getIcon("stopLoading")) |
73 self.stopButton.setAutoDefault(False) |
79 self.stopButton.setAutoDefault(False) |
74 self.stopButton.clicked.connect(self.__stopSearch) |
80 self.stopButton.clicked.connect(self.__stopSearch) |
75 |
81 |
76 self.findButton.setIcon(UI.PixmapCache.getIcon("find")) |
82 self.findButton.setIcon(UI.PixmapCache.getIcon("find")) |
77 self.findButton.setAutoDefault(False) |
83 self.findButton.setAutoDefault(False) |
78 self.findButton.clicked.connect(self.__searchFile) |
84 self.findButton.clicked.connect(self.__searchFile) |
79 |
85 |
80 self.clearButton.setEnabled(False) |
86 self.clearButton.setEnabled(False) |
81 self.clearButton.setIcon(UI.PixmapCache.getIcon("clear")) |
87 self.clearButton.setIcon(UI.PixmapCache.getIcon("clear")) |
82 self.clearButton.setAutoDefault(False) |
88 self.clearButton.setAutoDefault(False) |
83 self.clearButton.clicked.connect(self.__clearResults) |
89 self.clearButton.clicked.connect(self.__clearResults) |
84 |
90 |
85 self.openButton.setEnabled(False) |
91 self.openButton.setEnabled(False) |
86 self.openButton.setIcon(UI.PixmapCache.getIcon("open")) |
92 self.openButton.setIcon(UI.PixmapCache.getIcon("open")) |
87 self.openButton.setAutoDefault(False) |
93 self.openButton.setAutoDefault(False) |
88 self.openButton.clicked.connect(self.__openFile) |
94 self.openButton.clicked.connect(self.__openFile) |
89 |
95 |
90 self.__project = project |
96 self.__project = project |
91 self.__project.projectOpened.connect(self.__projectOpened) |
97 self.__project.projectOpened.connect(self.__projectOpened) |
92 self.__project.projectClosed.connect(self.__projectClosed) |
98 self.__project.projectClosed.connect(self.__projectClosed) |
93 |
99 |
94 self.extsepLabel.setText(os.extsep) |
100 self.extsepLabel.setText(os.extsep) |
95 |
101 |
96 self.__shouldStop = False |
102 self.__shouldStop = False |
97 |
103 |
98 self.fileNameEdit.returnPressed.connect(self.__searchFile) |
104 self.fileNameEdit.returnPressed.connect(self.__searchFile) |
99 self.fileExtEdit.returnPressed.connect(self.__searchFile) |
105 self.fileExtEdit.returnPressed.connect(self.__searchFile) |
100 |
106 |
101 self.__projectClosed() |
107 self.__projectClosed() |
102 |
108 |
103 @pyqtSlot() |
109 @pyqtSlot() |
104 def __stopSearch(self): |
110 def __stopSearch(self): |
105 """ |
111 """ |
106 Private slot to handle the stop button being pressed. |
112 Private slot to handle the stop button being pressed. |
107 """ |
113 """ |
108 self.__shouldStop = True |
114 self.__shouldStop = True |
109 |
115 |
110 @pyqtSlot() |
116 @pyqtSlot() |
111 def __openFile(self, itm=None): |
117 def __openFile(self, itm=None): |
112 """ |
118 """ |
113 Private slot to open a file. |
119 Private slot to open a file. |
114 |
120 |
115 It emits a signal depending on the file extension. |
121 It emits a signal depending on the file extension. |
116 |
122 |
117 @param itm item to be opened |
123 @param itm item to be opened |
118 @type QTreeWidgetItem |
124 @type QTreeWidgetItem |
119 """ |
125 """ |
120 if itm is None: |
126 if itm is None: |
121 itm = self.fileList.currentItem() |
127 itm = self.fileList.currentItem() |
122 if itm is not None: |
128 if itm is not None: |
123 fileName = itm.text(0) |
129 fileName = itm.text(0) |
124 filePath = itm.text(1) |
130 filePath = itm.text(1) |
125 fileExt = os.path.splitext(fileName)[1] |
131 fileExt = os.path.splitext(fileName)[1] |
126 fullName = os.path.join(filePath, fileName) |
132 fullName = os.path.join(filePath, fileName) |
127 |
133 |
128 if fileExt == ".ui": |
134 if fileExt == ".ui": |
129 self.designerFile.emit(fullName) |
135 self.designerFile.emit(fullName) |
130 elif fileExt == ".ts": |
136 elif fileExt == ".ts": |
131 self.linguistFile.emit(fullName) |
137 self.linguistFile.emit(fullName) |
132 elif fileExt == ".qm": |
138 elif fileExt == ".qm": |
140 else: |
146 else: |
141 if Utilities.MimeTypes.isTextFile(fullName): |
147 if Utilities.MimeTypes.isTextFile(fullName): |
142 self.sourceFile.emit(fullName) |
148 self.sourceFile.emit(fullName) |
143 else: |
149 else: |
144 QDesktopServices.openUrl(QUrl(fullName)) |
150 QDesktopServices.openUrl(QUrl(fullName)) |
145 |
151 |
146 @pyqtSlot() |
152 @pyqtSlot() |
147 def __searchFile(self): |
153 def __searchFile(self): |
148 """ |
154 """ |
149 Private slot to handle the search. |
155 Private slot to handle the search. |
150 """ |
156 """ |
151 fileName = self.fileNameEdit.text() |
157 fileName = self.fileNameEdit.text() |
152 fileExt = self.fileExtEdit.text() |
158 fileExt = self.fileExtEdit.text() |
153 |
159 |
154 self.findStatusLabel.clear() |
160 self.findStatusLabel.clear() |
155 |
161 |
156 patternFormat = ( |
162 patternFormat = ( |
157 "{0}{1}{2}" |
163 "{0}{1}{2}" if "*" in fileName or "?" in fileName else "{0}*{1}{2}" |
158 if "*" in fileName or "?" in fileName else |
|
159 "{0}*{1}{2}" |
|
160 ) |
164 ) |
161 |
165 |
162 fileNamePatterns = [patternFormat.format( |
166 fileNamePatterns = [ |
163 fileName or "*", os.extsep, fileExt or "*")] |
167 patternFormat.format(fileName or "*", os.extsep, fileExt or "*") |
164 |
168 ] |
|
169 |
165 if not fileExt: |
170 if not fileExt: |
166 # search for files without extension as well |
171 # search for files without extension as well |
167 if "*" in fileName or "?" in fileName: |
172 if "*" in fileName or "?" in fileName: |
168 patternFormat = "{0}" |
173 patternFormat = "{0}" |
169 else: |
174 else: |
170 patternFormat = "{0}*" |
175 patternFormat = "{0}*" |
171 |
176 |
172 fileNamePatterns.append(patternFormat.format(fileName or "*")) |
177 fileNamePatterns.append(patternFormat.format(fileName or "*")) |
173 |
178 |
174 searchPaths = [] |
179 searchPaths = [] |
175 if ( |
180 if self.searchDirCheckBox.isChecked() and self.searchDirPicker.text() != "": |
176 self.searchDirCheckBox.isChecked() and |
|
177 self.searchDirPicker.text() != "" |
|
178 ): |
|
179 searchPaths.append(self.searchDirPicker.text()) |
181 searchPaths.append(self.searchDirPicker.text()) |
180 if self.projectCheckBox.isChecked(): |
182 if self.projectCheckBox.isChecked(): |
181 searchPaths.append(self.__project.getProjectPath()) |
183 searchPaths.append(self.__project.getProjectPath()) |
182 if self.syspathCheckBox.isChecked(): |
184 if self.syspathCheckBox.isChecked(): |
183 searchPaths.extend(sys.path) |
185 searchPaths.extend(sys.path) |
184 |
186 |
185 self.fileList.clear() |
187 self.fileList.clear() |
186 locations = {} |
188 locations = {} |
187 self.__shouldStop = False |
189 self.__shouldStop = False |
188 self.stopButton.setEnabled(True) |
190 self.stopButton.setEnabled(True) |
189 self.clearButton.setEnabled(False) |
191 self.clearButton.setEnabled(False) |
190 QApplication.processEvents() |
192 QApplication.processEvents() |
191 |
193 |
192 for path in searchPaths: |
194 for path in searchPaths: |
193 if os.path.isdir(path): |
195 if os.path.isdir(path): |
194 files = direntries(path, True, fileNamePatterns, |
196 files = direntries(path, True, fileNamePatterns, False, self.checkStop) |
195 False, self.checkStop) |
|
196 if files: |
197 if files: |
197 for file in files: |
198 for file in files: |
198 fp, fn = os.path.split(file) |
199 fp, fn = os.path.split(file) |
199 if fn in locations: |
200 if fn in locations: |
200 if fp in locations[fn]: |
201 if fp in locations[fn]: |
203 locations[fn].append(fp) |
204 locations[fn].append(fp) |
204 else: |
205 else: |
205 locations[fn] = [fp] |
206 locations[fn] = [fp] |
206 QTreeWidgetItem(self.fileList, [fn, fp]) |
207 QTreeWidgetItem(self.fileList, [fn, fp]) |
207 QApplication.processEvents() |
208 QApplication.processEvents() |
208 |
209 |
209 del locations |
210 del locations |
210 self.stopButton.setEnabled(False) |
211 self.stopButton.setEnabled(False) |
211 self.fileList.sortItems(self.fileList.sortColumn(), |
212 self.fileList.sortItems(self.fileList.sortColumn(), Qt.SortOrder.AscendingOrder) |
212 Qt.SortOrder.AscendingOrder) |
213 self.fileList.header().resizeSections(QHeaderView.ResizeMode.ResizeToContents) |
213 self.fileList.header().resizeSections( |
|
214 QHeaderView.ResizeMode.ResizeToContents) |
|
215 self.fileList.header().resizeSection(0, self.width() // 2) |
214 self.fileList.header().resizeSection(0, self.width() // 2) |
216 self.fileList.header().setStretchLastSection(True) |
215 self.fileList.header().setStretchLastSection(True) |
217 |
216 |
218 self.findStatusLabel.setText(self.tr( |
217 self.findStatusLabel.setText( |
219 "%n file(s) found", "", self.fileList.topLevelItemCount())) |
218 self.tr("%n file(s) found", "", self.fileList.topLevelItemCount()) |
220 |
219 ) |
|
220 |
221 self.clearButton.setEnabled(self.fileList.topLevelItemCount() != 0) |
221 self.clearButton.setEnabled(self.fileList.topLevelItemCount() != 0) |
222 |
222 |
223 @pyqtSlot() |
223 @pyqtSlot() |
224 def __clearResults(self): |
224 def __clearResults(self): |
225 """ |
225 """ |
226 Private slot to clear the current search results. |
226 Private slot to clear the current search results. |
227 """ |
227 """ |
228 self.fileList.clear() |
228 self.fileList.clear() |
229 self.clearButton.setEnabled(False) |
229 self.clearButton.setEnabled(False) |
230 self.openButton.setEnabled(False) |
230 self.openButton.setEnabled(False) |
231 |
231 |
232 def checkStop(self): |
232 def checkStop(self): |
233 """ |
233 """ |
234 Public method to check, if the search should be stopped. |
234 Public method to check, if the search should be stopped. |
235 |
235 |
236 @return flag indicating the search should be stopped |
236 @return flag indicating the search should be stopped |
237 @rtype bool |
237 @rtype bool |
238 """ |
238 """ |
239 QApplication.processEvents() |
239 QApplication.processEvents() |
240 return self.__shouldStop |
240 return self.__shouldStop |
241 |
241 |
242 @pyqtSlot(str) |
242 @pyqtSlot(str) |
243 def on_searchDirPicker_textChanged(self, text): |
243 def on_searchDirPicker_textChanged(self, text): |
244 """ |
244 """ |
245 Private slot to handle the textChanged signal of the search directory |
245 Private slot to handle the textChanged signal of the search directory |
246 edit. |
246 edit. |
247 |
247 |
248 @param text text of the search dir edit |
248 @param text text of the search dir edit |
249 @type str |
249 @type str |
250 """ |
250 """ |
251 self.searchDirCheckBox.setEnabled(text != "") |
251 self.searchDirCheckBox.setEnabled(text != "") |
252 |
252 |
253 @pyqtSlot(QTreeWidgetItem, int) |
253 @pyqtSlot(QTreeWidgetItem, int) |
254 def on_fileList_itemActivated(self, itm, column): |
254 def on_fileList_itemActivated(self, itm, column): |
255 """ |
255 """ |
256 Private slot to handle the double click on a file item. |
256 Private slot to handle the double click on a file item. |
257 |
257 |
258 It emits the signal sourceFile or designerFile depending on the |
258 It emits the signal sourceFile or designerFile depending on the |
259 file extension. |
259 file extension. |
260 |
260 |
261 @param itm the double clicked listview item |
261 @param itm the double clicked listview item |
262 @type QTreeWidgetItem |
262 @type QTreeWidgetItem |
263 @param column column that was double clicked (ignored) |
263 @param column column that was double clicked (ignored) |
264 @type int |
264 @type int |
265 """ |
265 """ |
266 self.__openFile(itm) |
266 self.__openFile(itm) |
267 |
267 |
268 @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem) |
268 @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem) |
269 def on_fileList_currentItemChanged(self, current, previous): |
269 def on_fileList_currentItemChanged(self, current, previous): |
270 """ |
270 """ |
271 Private slot handling a change of the current item. |
271 Private slot handling a change of the current item. |
272 |
272 |
273 @param current current item |
273 @param current current item |
274 @type QTreeWidgetItem |
274 @type QTreeWidgetItem |
275 @param previous prevoius current item |
275 @param previous prevoius current item |
276 @type QTreeWidgetItem |
276 @type QTreeWidgetItem |
277 """ |
277 """ |
278 self.openButton.setEnabled(current is not None) |
278 self.openButton.setEnabled(current is not None) |
279 |
279 |
280 @pyqtSlot() |
280 @pyqtSlot() |
281 def __projectOpened(self): |
281 def __projectOpened(self): |
282 """ |
282 """ |
283 Private slot to handle a project being opened. |
283 Private slot to handle a project being opened. |
284 """ |
284 """ |
285 self.projectCheckBox.setEnabled(True) |
285 self.projectCheckBox.setEnabled(True) |
286 self.projectCheckBox.setChecked(True) |
286 self.projectCheckBox.setChecked(True) |
287 |
287 |
288 @pyqtSlot() |
288 @pyqtSlot() |
289 def __projectClosed(self): |
289 def __projectClosed(self): |
290 """ |
290 """ |
291 Private slot to handle a project being closed. |
291 Private slot to handle a project being closed. |
292 """ |
292 """ |
293 self.projectCheckBox.setEnabled(False) |
293 self.projectCheckBox.setEnabled(False) |
294 self.projectCheckBox.setChecked(False) |
294 self.projectCheckBox.setChecked(False) |
295 |
295 |
296 @pyqtSlot() |
296 @pyqtSlot() |
297 def activate(self): |
297 def activate(self): |
298 """ |
298 """ |
299 Public slot to activate this widget. |
299 Public slot to activate this widget. |
300 """ |
300 """ |
303 |
303 |
304 |
304 |
305 class FindLocationDialog(QDialog): |
305 class FindLocationDialog(QDialog): |
306 """ |
306 """ |
307 Class implementing a dialog to search for files. |
307 Class implementing a dialog to search for files. |
308 |
308 |
309 The occurrences found are displayed in a QTreeWidget showing the |
309 The occurrences found are displayed in a QTreeWidget showing the |
310 filename and the pathname. The file will be opened upon a double click |
310 filename and the pathname. The file will be opened upon a double click |
311 onto the respective entry of the list or by pressing the open button. |
311 onto the respective entry of the list or by pressing the open button. |
312 |
312 |
313 @signal sourceFile(str) emitted to open a file in the editor |
313 @signal sourceFile(str) emitted to open a file in the editor |
314 @signal designerFile(str) emitted to open a Qt-Designer file |
314 @signal designerFile(str) emitted to open a Qt-Designer file |
315 @signal linguistFile(str) emitted to open a Qt-Linguist (*.ts) file |
315 @signal linguistFile(str) emitted to open a Qt-Linguist (*.ts) file |
316 @signal trpreview([str]) emitted to preview Qt-Linguist (*.qm) files |
316 @signal trpreview([str]) emitted to preview Qt-Linguist (*.qm) files |
317 @signal pixmapFile(str) emitted to open a pixmap file |
317 @signal pixmapFile(str) emitted to open a pixmap file |
318 @signal svgFile(str) emitted to open a SVG file |
318 @signal svgFile(str) emitted to open a SVG file |
319 @signal umlFile(str) emitted to open an eric UML file |
319 @signal umlFile(str) emitted to open an eric UML file |
320 """ |
320 """ |
|
321 |
321 sourceFile = pyqtSignal(str) |
322 sourceFile = pyqtSignal(str) |
322 designerFile = pyqtSignal(str) |
323 designerFile = pyqtSignal(str) |
323 linguistFile = pyqtSignal(str) |
324 linguistFile = pyqtSignal(str) |
324 trpreview = pyqtSignal(list) |
325 trpreview = pyqtSignal(list) |
325 pixmapFile = pyqtSignal(str) |
326 pixmapFile = pyqtSignal(str) |
326 svgFile = pyqtSignal(str) |
327 svgFile = pyqtSignal(str) |
327 umlFile = pyqtSignal(str) |
328 umlFile = pyqtSignal(str) |
328 |
329 |
329 def __init__(self, project, parent=None): |
330 def __init__(self, project, parent=None): |
330 """ |
331 """ |
331 Constructor |
332 Constructor |
332 |
333 |
333 @param project reference to the project object |
334 @param project reference to the project object |
334 @type Project |
335 @type Project |
335 @param parent parent widget of this dialog (defaults to None) |
336 @param parent parent widget of this dialog (defaults to None) |
336 @type QWidget (optional) |
337 @type QWidget (optional) |
337 """ |
338 """ |
338 super().__init__(parent) |
339 super().__init__(parent) |
339 self.setWindowFlags(Qt.WindowType.Window) |
340 self.setWindowFlags(Qt.WindowType.Window) |
340 |
341 |
341 self.__layout = QVBoxLayout() |
342 self.__layout = QVBoxLayout() |
342 |
343 |
343 self.__findWidget = FindLocationWidget(project, self) |
344 self.__findWidget = FindLocationWidget(project, self) |
344 self.__layout.addWidget(self.__findWidget) |
345 self.__layout.addWidget(self.__findWidget) |
345 |
346 |
346 self.__buttonBox = QDialogButtonBox( |
347 self.__buttonBox = QDialogButtonBox( |
347 QDialogButtonBox.StandardButton.Close, |
348 QDialogButtonBox.StandardButton.Close, Qt.Orientation.Horizontal, self |
348 Qt.Orientation.Horizontal, |
|
349 self |
|
350 ) |
349 ) |
351 self.__buttonBox.button( |
350 self.__buttonBox.button(QDialogButtonBox.StandardButton.Close).setAutoDefault( |
352 QDialogButtonBox.StandardButton.Close).setAutoDefault(False) |
351 False |
|
352 ) |
353 self.__layout.addWidget(self.__buttonBox) |
353 self.__layout.addWidget(self.__buttonBox) |
354 |
354 |
355 self.setLayout(self.__layout) |
355 self.setLayout(self.__layout) |
356 self.resize(600, 800) |
356 self.resize(600, 800) |
357 |
357 |
358 # connect the widgets |
358 # connect the widgets |
359 self.__findWidget.sourceFile.connect(self.sourceFile) |
359 self.__findWidget.sourceFile.connect(self.sourceFile) |
360 self.__findWidget.designerFile.connect(self.designerFile) |
360 self.__findWidget.designerFile.connect(self.designerFile) |
361 self.__findWidget.linguistFile.connect(self.linguistFile) |
361 self.__findWidget.linguistFile.connect(self.linguistFile) |
362 self.__findWidget.trpreview.connect(self.trpreview) |
362 self.__findWidget.trpreview.connect(self.trpreview) |
363 self.__findWidget.pixmapFile.connect(self.pixmapFile) |
363 self.__findWidget.pixmapFile.connect(self.pixmapFile) |
364 self.__findWidget.svgFile.connect(self.svgFile) |
364 self.__findWidget.svgFile.connect(self.svgFile) |
365 self.__findWidget.umlFile.connect(self.umlFile) |
365 self.__findWidget.umlFile.connect(self.umlFile) |
366 |
366 |
367 self.__buttonBox.accepted.connect(self.accept) |
367 self.__buttonBox.accepted.connect(self.accept) |
368 self.__buttonBox.rejected.connect(self.reject) |
368 self.__buttonBox.rejected.connect(self.reject) |
369 |
369 |
370 def activate(self): |
370 def activate(self): |
371 """ |
371 """ |
372 Public method to activate the dialog. |
372 Public method to activate the dialog. |
373 """ |
373 """ |
374 self.__findWidget.activate() |
374 self.__findWidget.activate() |
375 |
375 |
376 self.raise_() |
376 self.raise_() |
377 self.activateWindow() |
377 self.activateWindow() |
378 self.show() |
378 self.show() |