|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2008 - 2009 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing the mdi area viewmanager class. |
|
8 """ |
|
9 |
|
10 from PyQt4.QtCore import * |
|
11 from PyQt4.QtGui import * |
|
12 |
|
13 from ViewManager.ViewManager import ViewManager |
|
14 |
|
15 import QScintilla.Editor |
|
16 |
|
17 import UI.PixmapCache |
|
18 |
|
19 from E4Gui.E4Action import E4Action, addActions |
|
20 |
|
21 import Utilities |
|
22 |
|
23 class MdiArea(QMdiArea, ViewManager): |
|
24 """ |
|
25 Class implementing the mdi area viewmanager class. |
|
26 |
|
27 @signal editorChanged(string) emitted when the current editor has changed |
|
28 """ |
|
29 def __init__(self, parent): |
|
30 """ |
|
31 Constructor |
|
32 |
|
33 @param parent parent widget (QWidget) |
|
34 @param ui reference to the main user interface |
|
35 @param dbs reference to the debug server object |
|
36 """ |
|
37 QMdiArea.__init__(self, parent) |
|
38 ViewManager.__init__(self) |
|
39 self.lastFN = '' |
|
40 self.__removingView = False |
|
41 |
|
42 self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) |
|
43 self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) |
|
44 |
|
45 self.__windowMapper = QSignalMapper(self) |
|
46 |
|
47 self.connect(self.__windowMapper, SIGNAL('mapped(QWidget*)'), |
|
48 self.setActiveSubWindow) |
|
49 self.connect(self, SIGNAL('subWindowActivated(QMdiSubWindow*)'), |
|
50 self.__subWindowActivated) |
|
51 |
|
52 def canCascade(self): |
|
53 """ |
|
54 Public method to signal if cascading of managed windows is available. |
|
55 |
|
56 @return flag indicating cascading of windows is available |
|
57 """ |
|
58 return True |
|
59 |
|
60 def canTile(self): |
|
61 """ |
|
62 Public method to signal if tiling of managed windows is available. |
|
63 |
|
64 @return flag indicating tiling of windows is available |
|
65 """ |
|
66 return True |
|
67 |
|
68 def canSplit(self): |
|
69 """ |
|
70 public method to signal if splitting of the view is available. |
|
71 |
|
72 @return flag indicating splitting of the view is available. |
|
73 """ |
|
74 return False |
|
75 |
|
76 def tile(self): |
|
77 """ |
|
78 Public method to tile the managed windows. |
|
79 """ |
|
80 self.tileSubWindows() |
|
81 |
|
82 def cascade(self): |
|
83 """ |
|
84 Public method to cascade the managed windows. |
|
85 """ |
|
86 self.cascadeSubWindows() |
|
87 |
|
88 def _removeAllViews(self): |
|
89 """ |
|
90 Protected method to remove all views (i.e. windows) |
|
91 """ |
|
92 for win in self.editors: |
|
93 self._removeView(win) |
|
94 |
|
95 def _removeView(self, win): |
|
96 """ |
|
97 Protected method to remove a view (i.e. window) |
|
98 |
|
99 @param win editor window to be removed |
|
100 """ |
|
101 self.__removingView = True |
|
102 self.lastFN = '' |
|
103 win.removeEventFilter(self) |
|
104 self.closeActiveSubWindow() |
|
105 win.closeIt() |
|
106 self.__removingView = False |
|
107 |
|
108 def _addView(self, win, fn = None, noName = ""): |
|
109 """ |
|
110 Protected method to add a view (i.e. window) |
|
111 |
|
112 @param win editor window to be added |
|
113 @param fn filename of this editor |
|
114 @param noName name to be used for an unnamed editor (string or QString) |
|
115 """ |
|
116 self.addSubWindow(win) |
|
117 if fn is None: |
|
118 if not noName: |
|
119 self.untitledCount += 1 |
|
120 noName = self.trUtf8("Untitled {0}").format(self.untitledCount) |
|
121 win.setWindowTitle(noName) |
|
122 win.setNoName(noName) |
|
123 else: |
|
124 if self.lastFN != fn: |
|
125 self.lastFN = fn |
|
126 win.show() |
|
127 if win.hasSyntaxErrors(): |
|
128 self.__setSubWindowIcon(win, UI.PixmapCache.getIcon("syntaxError.png")) |
|
129 else: |
|
130 self.__setSubWindowIcon(win, UI.PixmapCache.getIcon("empty.png")) |
|
131 |
|
132 # Make the editor window a little bit smaller to make the whole |
|
133 # window with all decorations visible. This is not the most elegant |
|
134 # solution but more of a workaround for another QWorkspace strangeness. |
|
135 # 25 points are subtracted to give space for the scrollbars |
|
136 pw = win.parentWidget() |
|
137 sz = QSize(self.width() - 25, self.height() - 25) |
|
138 pw.resize(sz) |
|
139 |
|
140 win.setFocus() |
|
141 win.installEventFilter(self) |
|
142 |
|
143 def _showView(self, win, fn = None): |
|
144 """ |
|
145 Private method to show a view (i.e. window) |
|
146 |
|
147 @param win editor window to be shown |
|
148 @param fn filename of this editor (string) |
|
149 """ |
|
150 if fn is not None and self.lastFN != fn: |
|
151 self.lastFN = fn |
|
152 win.show() |
|
153 win.setFocus() |
|
154 |
|
155 def activeWindow(self): |
|
156 """ |
|
157 Private method to return the active (i.e. current) window. |
|
158 |
|
159 @return reference to the active editor |
|
160 """ |
|
161 subWindow = self.activeSubWindow() |
|
162 if subWindow is None: |
|
163 return None |
|
164 else: |
|
165 return subWindow.widget() |
|
166 |
|
167 def showWindowMenu(self, windowMenu): |
|
168 """ |
|
169 Public method to set up the viewmanager part of the Window menu. |
|
170 |
|
171 @param windowMenu reference to the window menu |
|
172 """ |
|
173 self.windowsMenu = QMenu(self.trUtf8('&Windows')) |
|
174 |
|
175 menu = self.windowsMenu |
|
176 idx = 1 |
|
177 for subWindow in self.subWindowList(): |
|
178 sv = subWindow.widget() |
|
179 if idx == 10: |
|
180 menu.addSeparator() |
|
181 menu = menu.addMenu(self.trUtf8("&More")) |
|
182 fn = sv.fileName |
|
183 if fn: |
|
184 txt = Utilities.compactPath(fn, self.ui.maxMenuFilePathLen) |
|
185 else: |
|
186 txt = sv.windowTitle() |
|
187 accel = "" |
|
188 if idx < 10: |
|
189 accel = "&%d. " % idx |
|
190 elif idx < 36: |
|
191 accel = "&%c. " % chr(idx - 9 + ord("@")) |
|
192 act = menu.addAction("%s%s" % (accel, txt)) |
|
193 self.connect(act, SIGNAL("triggered()"), |
|
194 self.__windowMapper, SLOT("map()")) |
|
195 self.__windowMapper.setMapping(act, subWindow) |
|
196 idx += 1 |
|
197 |
|
198 addActions(windowMenu, |
|
199 [None, self.nextChildAct, self.prevChildAct, |
|
200 self.tileAct, self.cascadeAct, |
|
201 self.restoreAllAct, self.iconizeAllAct, |
|
202 None]) |
|
203 act = windowMenu.addMenu(self.windowsMenu) |
|
204 if len(self.editors) == 0: |
|
205 act.setEnabled(False) |
|
206 |
|
207 def _initWindowActions(self): |
|
208 """ |
|
209 Protected method to define the user interface actions for window handling. |
|
210 """ |
|
211 self.tileAct = E4Action(self.trUtf8('Tile'), |
|
212 self.trUtf8('&Tile'), 0, 0, self, 'vm_window_tile') |
|
213 self.tileAct.setStatusTip(self.trUtf8('Tile the windows')) |
|
214 self.tileAct.setWhatsThis(self.trUtf8( |
|
215 """<b>Tile the windows</b>""" |
|
216 """<p>Rearrange and resize the windows so that they are tiled.</p>""" |
|
217 )) |
|
218 self.connect(self.tileAct, SIGNAL('triggered()'), self.tile) |
|
219 self.windowActions.append(self.tileAct) |
|
220 |
|
221 self.cascadeAct = E4Action(self.trUtf8('Cascade'), |
|
222 self.trUtf8('&Cascade'), 0, 0, self, 'vm_window_cascade') |
|
223 self.cascadeAct.setStatusTip(self.trUtf8('Cascade the windows')) |
|
224 self.cascadeAct.setWhatsThis(self.trUtf8( |
|
225 """<b>Cascade the windows</b>""" |
|
226 """<p>Rearrange and resize the windows so that they are cascaded.</p>""" |
|
227 )) |
|
228 self.connect(self.cascadeAct, SIGNAL('triggered()'), self.cascade) |
|
229 self.windowActions.append(self.cascadeAct) |
|
230 |
|
231 self.nextChildAct = E4Action(self.trUtf8('Next'), |
|
232 self.trUtf8('&Next'), 0, 0, self, 'vm_window_next') |
|
233 self.nextChildAct.setStatusTip(self.trUtf8('Activate next window')) |
|
234 self.nextChildAct.setWhatsThis(self.trUtf8( |
|
235 """<b>Next</b>""" |
|
236 """<p>Activate the next window of the list of open windows.</p>""" |
|
237 )) |
|
238 self.connect(self.nextChildAct, SIGNAL('triggered()'), self.activateNextSubWindow) |
|
239 self.windowActions.append(self.nextChildAct) |
|
240 |
|
241 self.prevChildAct = E4Action(self.trUtf8('Previous'), |
|
242 self.trUtf8('&Previous'), 0, 0, self, 'vm_window_previous') |
|
243 self.prevChildAct.setStatusTip(self.trUtf8('Activate previous window')) |
|
244 self.prevChildAct.setWhatsThis(self.trUtf8( |
|
245 """<b>Previous</b>""" |
|
246 """<p>Activate the previous window of the list of open windows.</p>""" |
|
247 )) |
|
248 self.connect(self.prevChildAct, SIGNAL('triggered()'), |
|
249 self.activatePreviousSubWindow) |
|
250 self.windowActions.append(self.prevChildAct) |
|
251 |
|
252 self.restoreAllAct = E4Action(self.trUtf8('Restore All'), |
|
253 self.trUtf8('&Restore All'), 0, 0, self, 'vm_window_restore_all') |
|
254 self.restoreAllAct.setStatusTip(self.trUtf8('Restore all windows')) |
|
255 self.restoreAllAct.setWhatsThis(self.trUtf8( |
|
256 """<b>Restore All</b>""" |
|
257 """<p>Restores all windows to their original size.</p>""" |
|
258 )) |
|
259 self.connect(self.restoreAllAct, SIGNAL('triggered()'), self.__restoreAllWindows) |
|
260 self.windowActions.append(self.restoreAllAct) |
|
261 |
|
262 self.iconizeAllAct = E4Action(self.trUtf8('Iconize All'), |
|
263 self.trUtf8('&Iconize All'), 0, 0, self, 'vm_window_iconize_all') |
|
264 self.iconizeAllAct.setStatusTip(self.trUtf8('Iconize all windows')) |
|
265 self.iconizeAllAct.setWhatsThis(self.trUtf8( |
|
266 """<b>Iconize All</b>""" |
|
267 """<p>Iconizes all windows.</p>""" |
|
268 )) |
|
269 self.connect(self.iconizeAllAct, SIGNAL('triggered()'), self.__iconizeAllWindows) |
|
270 self.windowActions.append(self.iconizeAllAct) |
|
271 |
|
272 def setEditorName(self, editor, newName): |
|
273 """ |
|
274 Public method to change the displayed name of the editor. |
|
275 |
|
276 @param editor editor window to be changed |
|
277 @param newName new name to be shown (string or QString) |
|
278 """ |
|
279 pass |
|
280 |
|
281 def __setSubWindowIcon(self, widget, icon): |
|
282 """ |
|
283 Private method to set the icon of a subwindow given it's internal widget. |
|
284 |
|
285 @param widget reference to the internal widget (QWidget) |
|
286 @param icon reference to the icon (QIcon) |
|
287 """ |
|
288 for subWindow in self.subWindowList(): |
|
289 if subWindow.widget() == widget: |
|
290 subWindow.setWindowIcon(icon) |
|
291 return |
|
292 |
|
293 def _modificationStatusChanged(self, m, editor): |
|
294 """ |
|
295 Protected slot to handle the modificationStatusChanged signal. |
|
296 |
|
297 @param m flag indicating the modification status (boolean) |
|
298 @param editor editor window changed |
|
299 """ |
|
300 if m: |
|
301 self.__setSubWindowIcon(editor, UI.PixmapCache.getIcon("fileModified.png")) |
|
302 elif editor.hasSyntaxErrors(): |
|
303 self.__setSubWindowIcon(editor, UI.PixmapCache.getIcon("syntaxError.png")) |
|
304 else: |
|
305 self.__setSubWindowIcon(editor, UI.PixmapCache.getIcon("empty.png")) |
|
306 self._checkActions(editor) |
|
307 |
|
308 def _syntaxErrorToggled(self, editor): |
|
309 """ |
|
310 Protected slot to handle the syntaxerrorToggled signal. |
|
311 |
|
312 @param editor editor that sent the signal |
|
313 """ |
|
314 if editor.hasSyntaxErrors(): |
|
315 self.__setSubWindowIcon(editor, UI.PixmapCache.getIcon("syntaxError.png")) |
|
316 else: |
|
317 self.__setSubWindowIcon(editor, UI.PixmapCache.getIcon("empty.png")) |
|
318 |
|
319 ViewManager._syntaxErrorToggled(self, editor) |
|
320 |
|
321 def __subWindowActivated(self, subWindow): |
|
322 """ |
|
323 Private slot to handle the windowActivated signal. |
|
324 |
|
325 @param subWindow the activated subwindow (QMdiSubWindow) |
|
326 """ |
|
327 if subWindow is not None: |
|
328 editor = subWindow.widget() |
|
329 self._checkActions(editor) |
|
330 if editor is not None: |
|
331 fn = editor.getFileName() |
|
332 self.emit(SIGNAL('editorChanged'), fn) |
|
333 |
|
334 def eventFilter(self, watched, event): |
|
335 """ |
|
336 Public method called to filter the event queue. |
|
337 |
|
338 @param watched the QObject being watched |
|
339 @param event the event that occurred |
|
340 @return flag indicating, whether the event was handled (boolean) |
|
341 """ |
|
342 if event.type() == QEvent.Close and \ |
|
343 not self.__removingView and \ |
|
344 isinstance(watched, QScintilla.Editor.Editor): |
|
345 watched.close() |
|
346 return True |
|
347 |
|
348 return False |
|
349 |
|
350 def __restoreAllWindows(self): |
|
351 """ |
|
352 Private slot to restore all windows. |
|
353 """ |
|
354 for win in self.subWindowList(): |
|
355 win.showNormal() |
|
356 |
|
357 def __iconizeAllWindows(self): |
|
358 """ |
|
359 Private slot to iconize all windows. |
|
360 """ |
|
361 for win in self.subWindowList(): |
|
362 win.showMinimized() |