]>
Commit | Line | Data |
---|---|---|
d1dc2b32 RD |
1 | #---------------------------------------------------------------------------- |
2 | # Name: pydocview.py | |
3 | # Purpose: Python extensions to the wxWindows docview framework | |
4 | # | |
aca310e5 | 5 | # Author: Peter Yared, Morgan Hua, Matt Fryer |
d1dc2b32 RD |
6 | # |
7 | # Created: 5/15/03 | |
8 | # CVS-ID: $Id$ | |
aca310e5 | 9 | # Copyright: (c) 2003-2006 ActiveGrid, Inc. |
d1dc2b32 RD |
10 | # License: wxWindows license |
11 | #---------------------------------------------------------------------------- | |
12 | ||
13 | ||
14 | import wx | |
15 | import wx.lib.docview | |
16 | import sys | |
17 | import getopt | |
2fd34892 | 18 | from wx.lib.rcsizer import RowColSizer |
d1dc2b32 RD |
19 | import os |
20 | import os.path | |
21 | import time | |
22 | import string | |
74b89458 | 23 | import pickle |
74b89458 RD |
24 | import tempfile |
25 | import mmap | |
d1dc2b32 | 26 | _ = wx.GetTranslation |
3fa8f722 RD |
27 | if wx.Platform == '__WXMSW__': |
28 | _WINDOWS = True | |
29 | else: | |
30 | _WINDOWS = False | |
74b89458 | 31 | |
d1dc2b32 RD |
32 | #---------------------------------------------------------------------------- |
33 | # Constants | |
34 | #---------------------------------------------------------------------------- | |
35 | ||
36 | VIEW_TOOLBAR_ID = wx.NewId() | |
37 | VIEW_STATUSBAR_ID = wx.NewId() | |
38 | ||
39 | EMBEDDED_WINDOW_TOP = 1 | |
40 | EMBEDDED_WINDOW_BOTTOM = 2 | |
41 | EMBEDDED_WINDOW_LEFT = 4 | |
42 | EMBEDDED_WINDOW_RIGHT = 8 | |
43 | EMBEDDED_WINDOW_TOPLEFT = 16 | |
44 | EMBEDDED_WINDOW_BOTTOMLEFT = 32 | |
45 | EMBEDDED_WINDOW_TOPRIGHT = 64 | |
46 | EMBEDDED_WINDOW_BOTTOMRIGHT = 128 | |
47 | EMBEDDED_WINDOW_ALL = EMBEDDED_WINDOW_TOP | EMBEDDED_WINDOW_BOTTOM | EMBEDDED_WINDOW_LEFT | EMBEDDED_WINDOW_RIGHT | \ | |
48 | EMBEDDED_WINDOW_TOPLEFT | EMBEDDED_WINDOW_BOTTOMLEFT | EMBEDDED_WINDOW_TOPRIGHT | EMBEDDED_WINDOW_BOTTOMRIGHT | |
49 | ||
50 | SAVEALL_ID = wx.NewId() | |
51 | ||
52 | WINDOW_MENU_NUM_ITEMS = 9 | |
53 | ||
54 | ||
3fa8f722 | 55 | class DocFrameMixIn: |
d1dc2b32 | 56 | """ |
3fa8f722 RD |
57 | Class with common code used by DocMDIParentFrame, DocTabbedParentFrame, and |
58 | DocSDIFrame. | |
d1dc2b32 | 59 | """ |
aca310e5 | 60 | |
d1dc2b32 RD |
61 | |
62 | def GetDocumentManager(self): | |
d1dc2b32 | 63 | """ |
3fa8f722 | 64 | Returns the document manager associated with the DocMDIParentFrame. |
d1dc2b32 | 65 | """ |
3fa8f722 | 66 | return self._docManager |
d1dc2b32 RD |
67 | |
68 | ||
3fa8f722 | 69 | def InitializePrintData(self): |
d1dc2b32 | 70 | """ |
3fa8f722 | 71 | Initializes the PrintData that is used when printing. |
d1dc2b32 | 72 | """ |
3fa8f722 RD |
73 | self._printData = wx.PrintData() |
74 | self._printData.SetPaperId(wx.PAPER_LETTER) | |
d1dc2b32 RD |
75 | |
76 | ||
3fa8f722 | 77 | def CreateDefaultMenuBar(self, sdi=False): |
d1dc2b32 | 78 | """ |
3fa8f722 | 79 | Creates the default MenuBar. Contains File, Edit, View, Tools, and Help menus. |
d1dc2b32 | 80 | """ |
3fa8f722 RD |
81 | menuBar = wx.MenuBar() |
82 | ||
83 | fileMenu = wx.Menu() | |
84 | fileMenu.Append(wx.ID_NEW, _("&New...\tCtrl+N"), _("Creates a new document")) | |
85 | fileMenu.Append(wx.ID_OPEN, _("&Open...\tCtrl+O"), _("Opens an existing document")) | |
86 | fileMenu.Append(wx.ID_CLOSE, _("&Close"), _("Closes the active document")) | |
87 | if not sdi: | |
88 | fileMenu.Append(wx.ID_CLOSE_ALL, _("Close A&ll"), _("Closes all open documents")) | |
89 | fileMenu.AppendSeparator() | |
90 | fileMenu.Append(wx.ID_SAVE, _("&Save\tCtrl+S"), _("Saves the active document")) | |
91 | fileMenu.Append(wx.ID_SAVEAS, _("Save &As..."), _("Saves the active document with a new name")) | |
92 | fileMenu.Append(SAVEALL_ID, _("Save All\tCtrl+Shift+A"), _("Saves the all active documents")) | |
93 | wx.EVT_MENU(self, SAVEALL_ID, self.ProcessEvent) | |
94 | wx.EVT_UPDATE_UI(self, SAVEALL_ID, self.ProcessUpdateUIEvent) | |
95 | fileMenu.AppendSeparator() | |
96 | fileMenu.Append(wx.ID_PRINT, _("&Print\tCtrl+P"), _("Prints the active document")) | |
97 | fileMenu.Append(wx.ID_PREVIEW, _("Print Pre&view"), _("Displays full pages")) | |
98 | fileMenu.Append(wx.ID_PRINT_SETUP, _("Page Set&up"), _("Changes page layout settings")) | |
99 | fileMenu.AppendSeparator() | |
100 | if wx.Platform == '__WXMAC__': | |
101 | fileMenu.Append(wx.ID_EXIT, _("&Quit"), _("Closes this program")) | |
102 | else: | |
103 | fileMenu.Append(wx.ID_EXIT, _("E&xit"), _("Closes this program")) | |
104 | self._docManager.FileHistoryUseMenu(fileMenu) | |
105 | self._docManager.FileHistoryAddFilesToMenu() | |
106 | menuBar.Append(fileMenu, _("&File")); | |
d1dc2b32 | 107 | |
3fa8f722 RD |
108 | editMenu = wx.Menu() |
109 | editMenu.Append(wx.ID_UNDO, _("&Undo\tCtrl+Z"), _("Reverses the last action")) | |
110 | editMenu.Append(wx.ID_REDO, _("&Redo\tCtrl+Y"), _("Reverses the last undo")) | |
111 | editMenu.AppendSeparator() | |
112 | #item = wxMenuItem(self.editMenu, wxID_CUT, _("Cu&t\tCtrl+X"), _("Cuts the selection and puts it on the Clipboard")) | |
113 | #item.SetBitmap(getCutBitmap()) | |
114 | #editMenu.AppendItem(item) | |
115 | editMenu.Append(wx.ID_CUT, _("Cu&t\tCtrl+X"), _("Cuts the selection and puts it on the Clipboard")) | |
116 | wx.EVT_MENU(self, wx.ID_CUT, self.ProcessEvent) | |
117 | wx.EVT_UPDATE_UI(self, wx.ID_CUT, self.ProcessUpdateUIEvent) | |
118 | editMenu.Append(wx.ID_COPY, _("&Copy\tCtrl+C"), _("Copies the selection and puts it on the Clipboard")) | |
119 | wx.EVT_MENU(self, wx.ID_COPY, self.ProcessEvent) | |
120 | wx.EVT_UPDATE_UI(self, wx.ID_COPY, self.ProcessUpdateUIEvent) | |
121 | editMenu.Append(wx.ID_PASTE, _("&Paste\tCtrl+V"), _("Inserts Clipboard contents")) | |
122 | wx.EVT_MENU(self, wx.ID_PASTE, self.ProcessEvent) | |
123 | wx.EVT_UPDATE_UI(self, wx.ID_PASTE, self.ProcessUpdateUIEvent) | |
bbf7159c | 124 | editMenu.Append(wx.ID_CLEAR, _("&Delete"), _("Erases the selection")) |
3fa8f722 RD |
125 | wx.EVT_MENU(self, wx.ID_CLEAR, self.ProcessEvent) |
126 | wx.EVT_UPDATE_UI(self, wx.ID_CLEAR, self.ProcessUpdateUIEvent) | |
127 | editMenu.AppendSeparator() | |
128 | editMenu.Append(wx.ID_SELECTALL, _("Select A&ll\tCtrl+A"), _("Selects all available data")) | |
129 | wx.EVT_MENU(self, wx.ID_SELECTALL, self.ProcessEvent) | |
130 | wx.EVT_UPDATE_UI(self, wx.ID_SELECTALL, self.ProcessUpdateUIEvent) | |
131 | menuBar.Append(editMenu, _("&Edit")) | |
132 | if sdi: | |
133 | if self.GetDocument() and self.GetDocument().GetCommandProcessor(): | |
134 | self.GetDocument().GetCommandProcessor().SetEditMenu(editMenu) | |
aca310e5 | 135 | |
3fa8f722 RD |
136 | viewMenu = wx.Menu() |
137 | viewMenu.AppendCheckItem(VIEW_TOOLBAR_ID, _("&Toolbar"), _("Shows or hides the toolbar")) | |
138 | wx.EVT_MENU(self, VIEW_TOOLBAR_ID, self.OnViewToolBar) | |
139 | wx.EVT_UPDATE_UI(self, VIEW_TOOLBAR_ID, self.OnUpdateViewToolBar) | |
140 | viewMenu.AppendCheckItem(VIEW_STATUSBAR_ID, _("&Status Bar"), _("Shows or hides the status bar")) | |
141 | wx.EVT_MENU(self, VIEW_STATUSBAR_ID, self.OnViewStatusBar) | |
142 | wx.EVT_UPDATE_UI(self, VIEW_STATUSBAR_ID, self.OnUpdateViewStatusBar) | |
143 | menuBar.Append(viewMenu, _("&View")) | |
d1dc2b32 | 144 | |
3fa8f722 RD |
145 | helpMenu = wx.Menu() |
146 | helpMenu.Append(wx.ID_ABOUT, _("&About" + " " + wx.GetApp().GetAppName()), _("Displays program information, version number, and copyright")) | |
3fa8f722 | 147 | menuBar.Append(helpMenu, _("&Help")) |
d1dc2b32 | 148 | |
bbf7159c | 149 | wx.EVT_MENU(self, wx.ID_ABOUT, self.OnAbout) |
3fa8f722 | 150 | wx.EVT_UPDATE_UI(self, wx.ID_ABOUT, self.ProcessUpdateUIEvent) # Using ID_ABOUT to update the window menu, the window menu items are not triggering |
d1dc2b32 | 151 | |
3fa8f722 RD |
152 | if sdi: # TODO: Is this really needed? |
153 | wx.EVT_COMMAND_FIND_CLOSE(self, -1, self.ProcessEvent) | |
aca310e5 | 154 | |
3fa8f722 | 155 | return menuBar |
d1dc2b32 RD |
156 | |
157 | ||
3fa8f722 | 158 | def CreateDefaultStatusBar(self): |
d1dc2b32 | 159 | """ |
3fa8f722 | 160 | Creates the default StatusBar. |
d1dc2b32 | 161 | """ |
3fa8f722 RD |
162 | wx.Frame.CreateStatusBar(self) |
163 | self.GetStatusBar().Show(wx.ConfigBase_Get().ReadInt("ViewStatusBar", True)) | |
164 | self.UpdateStatus() | |
165 | return self.GetStatusBar() | |
d1dc2b32 RD |
166 | |
167 | ||
3fa8f722 | 168 | def CreateDefaultToolBar(self): |
d1dc2b32 | 169 | """ |
3fa8f722 | 170 | Creates the default ToolBar. |
d1dc2b32 | 171 | """ |
3fa8f722 RD |
172 | self._toolBar = self.CreateToolBar(wx.TB_HORIZONTAL | wx.NO_BORDER | wx.TB_FLAT) |
173 | self._toolBar.AddSimpleTool(wx.ID_NEW, getNewBitmap(), _("New"), _("Creates a new document")) | |
174 | self._toolBar.AddSimpleTool(wx.ID_OPEN, getOpenBitmap(), _("Open"), _("Opens an existing document")) | |
175 | self._toolBar.AddSimpleTool(wx.ID_SAVE, getSaveBitmap(), _("Save"), _("Saves the active document")) | |
176 | self._toolBar.AddSimpleTool(SAVEALL_ID, getSaveAllBitmap(), _("Save All"), _("Saves all the active documents")) | |
177 | self._toolBar.AddSeparator() | |
178 | self._toolBar.AddSimpleTool(wx.ID_PRINT, getPrintBitmap(), _("Print"), _("Displays full pages")) | |
179 | self._toolBar.AddSimpleTool(wx.ID_PREVIEW, getPrintPreviewBitmap(), _("Print Preview"), _("Prints the active document")) | |
180 | self._toolBar.AddSeparator() | |
181 | self._toolBar.AddSimpleTool(wx.ID_CUT, getCutBitmap(), _("Cut"), _("Cuts the selection and puts it on the Clipboard")) | |
182 | self._toolBar.AddSimpleTool(wx.ID_COPY, getCopyBitmap(), _("Copy"), _("Copies the selection and puts it on the Clipboard")) | |
183 | self._toolBar.AddSimpleTool(wx.ID_PASTE, getPasteBitmap(), _("Paste"), _("Inserts Clipboard contents")) | |
184 | self._toolBar.AddSimpleTool(wx.ID_UNDO, getUndoBitmap(), _("Undo"), _("Reverses the last action")) | |
185 | self._toolBar.AddSimpleTool(wx.ID_REDO, getRedoBitmap(), _("Redo"), _("Reverses the last undo")) | |
186 | self._toolBar.Realize() | |
187 | self._toolBar.Show(wx.ConfigBase_Get().ReadInt("ViewToolBar", True)) | |
188 | ||
189 | return self._toolBar | |
d1dc2b32 RD |
190 | |
191 | ||
3fa8f722 | 192 | def OnFileSaveAll(self, event): |
d1dc2b32 | 193 | """ |
3fa8f722 | 194 | Saves all of the currently open documents. |
d1dc2b32 | 195 | """ |
3fa8f722 | 196 | docs = wx.GetApp().GetDocumentManager().GetDocuments() |
aca310e5 | 197 | |
02b800ce RD |
198 | # save child documents first |
199 | for doc in docs: | |
200 | if isinstance(doc, wx.lib.pydocview.ChildDocument): | |
201 | doc.Save() | |
aca310e5 | 202 | |
02b800ce | 203 | # save parent and other documents later |
3fa8f722 | 204 | for doc in docs: |
02b800ce RD |
205 | if not isinstance(doc, wx.lib.pydocview.ChildDocument): |
206 | doc.Save() | |
d1dc2b32 RD |
207 | |
208 | ||
3fa8f722 | 209 | def OnAbout(self, event): |
d1dc2b32 | 210 | """ |
3fa8f722 | 211 | Invokes the about dialog. |
d1dc2b32 | 212 | """ |
3fa8f722 RD |
213 | aboutService = wx.GetApp().GetService(AboutService) |
214 | if aboutService: | |
215 | aboutService.ShowAbout() | |
d1dc2b32 RD |
216 | |
217 | ||
3fa8f722 | 218 | def OnViewToolBar(self, event): |
d1dc2b32 | 219 | """ |
3fa8f722 | 220 | Toggles whether the ToolBar is visible. |
d1dc2b32 | 221 | """ |
3fa8f722 RD |
222 | self._toolBar.Show(not self._toolBar.IsShown()) |
223 | self._LayoutFrame() | |
d1dc2b32 | 224 | |
3fa8f722 RD |
225 | |
226 | def OnUpdateViewToolBar(self, event): | |
d1dc2b32 | 227 | """ |
3fa8f722 | 228 | Updates the View ToolBar menu item. |
d1dc2b32 | 229 | """ |
3fa8f722 | 230 | event.Check(self.GetToolBar().IsShown()) |
d1dc2b32 RD |
231 | |
232 | ||
3fa8f722 | 233 | def OnViewStatusBar(self, event): |
d1dc2b32 | 234 | """ |
3fa8f722 | 235 | Toggles whether the StatusBar is visible. |
d1dc2b32 | 236 | """ |
3fa8f722 RD |
237 | self.GetStatusBar().Show(not self.GetStatusBar().IsShown()) |
238 | self._LayoutFrame() | |
d1dc2b32 RD |
239 | |
240 | ||
3fa8f722 | 241 | def OnUpdateViewStatusBar(self, event): |
d1dc2b32 | 242 | """ |
3fa8f722 | 243 | Updates the View StatusBar menu item. |
d1dc2b32 | 244 | """ |
3fa8f722 | 245 | event.Check(self.GetStatusBar().IsShown()) |
d1dc2b32 RD |
246 | |
247 | ||
3fa8f722 | 248 | def UpdateStatus(self, message = _("Ready")): |
d1dc2b32 | 249 | """ |
3fa8f722 | 250 | Updates the StatusBar. |
d1dc2b32 | 251 | """ |
3fa8f722 RD |
252 | # wxBug: Menubar and toolbar help strings don't pop the status text back |
253 | if self.GetStatusBar().GetStatusText() != message: | |
254 | self.GetStatusBar().PushStatusText(message) | |
d1dc2b32 RD |
255 | |
256 | ||
3fa8f722 | 257 | class DocMDIParentFrameMixIn: |
d1dc2b32 | 258 | """ |
3fa8f722 | 259 | Class with common code used by DocMDIParentFrame and DocTabbedParentFrame. |
d1dc2b32 | 260 | """ |
aca310e5 | 261 | |
d1dc2b32 | 262 | |
3fa8f722 | 263 | def _GetPosSizeFromConfig(self, pos, size): |
d1dc2b32 | 264 | """ |
3fa8f722 | 265 | Adjusts the position and size of the frame using the saved config position and size. |
d1dc2b32 | 266 | """ |
3fa8f722 RD |
267 | config = wx.ConfigBase_Get() |
268 | if pos == wx.DefaultPosition and size == wx.DefaultSize and config.ReadInt("MDIFrameMaximized", False): | |
269 | pos = [0, 0] | |
270 | size = wx.DisplaySize() | |
271 | # wxBug: Need to set to fill screen to get around bug where maximize is leaving shadow of statusbar, check out maximize call at end of this function | |
272 | else: | |
273 | if pos == wx.DefaultPosition: | |
274 | pos = config.ReadInt("MDIFrameXLoc", -1), config.ReadInt("MDIFrameYLoc", -1) | |
275 | ||
276 | if wx.Display_GetFromPoint(pos) == -1: # Check if the frame position is offscreen | |
277 | pos = wx.DefaultPosition | |
aca310e5 | 278 | |
3fa8f722 RD |
279 | if size == wx.DefaultSize: |
280 | size = wx.Size(config.ReadInt("MDIFrameXSize", 450), config.ReadInt("MDIFrameYSize", 300)) | |
281 | return pos, size | |
282 | ||
283 | ||
aca310e5 | 284 | def _InitFrame(self, embeddedWindows, minSize): |
3fa8f722 RD |
285 | """ |
286 | Initializes the frame and creates the default menubar, toolbar, and status bar. | |
287 | """ | |
288 | self._embeddedWindows = [] | |
289 | self.SetDropTarget(_DocFrameFileDropTarget(self._docManager, self)) | |
290 | ||
291 | if wx.GetApp().GetDefaultIcon(): | |
292 | self.SetIcon(wx.GetApp().GetDefaultIcon()) | |
293 | ||
294 | wx.EVT_MENU(self, wx.ID_ABOUT, self.OnAbout) | |
295 | wx.EVT_SIZE(self, self.OnSize) | |
296 | ||
297 | self.InitializePrintData() | |
298 | ||
299 | toolBar = self.CreateDefaultToolBar() | |
300 | self.SetToolBar(toolBar) | |
301 | menuBar = self.CreateDefaultMenuBar() | |
302 | statusBar = self.CreateDefaultStatusBar() | |
303 | ||
304 | config = wx.ConfigBase_Get() | |
305 | if config.ReadInt("MDIFrameMaximized", False): | |
26ee3a06 | 306 | # wxBug: On maximize, statusbar leaves a residual that needs to be refereshed, happens even when user does it |
3fa8f722 RD |
307 | self.Maximize() |
308 | ||
aca310e5 | 309 | self.CreateEmbeddedWindows(embeddedWindows, minSize) |
3fa8f722 RD |
310 | self._LayoutFrame() |
311 | ||
bbf7159c RD |
312 | if wx.Platform == '__WXMAC__': |
313 | self.SetMenuBar(menuBar) # wxBug: Have to set the menubar at the very end or the automatic MDI "window" menu doesn't get put in the right place when the services add new menus to the menubar | |
314 | ||
3fa8f722 RD |
315 | wx.GetApp().SetTopWindow(self) # Need to do this here in case the services are looking for wx.GetApp().GetTopWindow() |
316 | for service in wx.GetApp().GetServices(): | |
317 | service.InstallControls(self, menuBar = menuBar, toolBar = toolBar, statusBar = statusBar) | |
318 | if hasattr(service, "ShowWindow"): | |
319 | service.ShowWindow() # instantiate service windows for correct positioning, we'll hide/show them later based on user preference | |
320 | ||
bbf7159c RD |
321 | if wx.Platform != '__WXMAC__': |
322 | self.SetMenuBar(menuBar) # wxBug: Have to set the menubar at the very end or the automatic MDI "window" menu doesn't get put in the right place when the services add new menus to the menubar | |
3fa8f722 RD |
323 | |
324 | ||
325 | def ProcessEvent(self, event): | |
326 | """ | |
327 | Processes an event, searching event tables and calling zero or more | |
328 | suitable event handler function(s). Note that the ProcessEvent | |
329 | method is called from the wxPython docview framework directly since | |
330 | wxPython does not have a virtual ProcessEvent function. | |
331 | """ | |
332 | id = event.GetId() | |
333 | if id == SAVEALL_ID: | |
334 | self.OnFileSaveAll(event) | |
335 | return True | |
aca310e5 | 336 | |
3fa8f722 RD |
337 | return wx.GetApp().ProcessEvent(event) |
338 | ||
339 | ||
340 | def ProcessUpdateUIEvent(self, event): | |
341 | """ | |
342 | Processes a UI event, searching event tables and calling zero or more | |
343 | suitable event handler function(s). Note that the ProcessEvent | |
344 | method is called from the wxPython docview framework directly since | |
345 | wxPython does not have a virtual ProcessEvent function. | |
346 | """ | |
347 | id = event.GetId() | |
348 | if id == wx.ID_CUT: | |
349 | event.Enable(False) | |
350 | return True | |
351 | elif id == wx.ID_COPY: | |
352 | event.Enable(False) | |
353 | return True | |
354 | elif id == wx.ID_PASTE: | |
355 | event.Enable(False) | |
356 | return True | |
357 | elif id == wx.ID_CLEAR: | |
358 | event.Enable(False) | |
359 | return True | |
360 | elif id == wx.ID_SELECTALL: | |
361 | event.Enable(False) | |
362 | return True | |
363 | elif id == SAVEALL_ID: | |
364 | filesModified = False | |
365 | docs = wx.GetApp().GetDocumentManager().GetDocuments() | |
366 | for doc in docs: | |
367 | if doc.IsModified(): | |
368 | filesModified = True | |
369 | break | |
aca310e5 | 370 | |
3fa8f722 RD |
371 | event.Enable(filesModified) |
372 | return True | |
373 | else: | |
374 | return wx.GetApp().ProcessUpdateUIEvent(event) | |
375 | ||
376 | ||
aca310e5 | 377 | def CreateEmbeddedWindows(self, windows=0, minSize=20): |
3fa8f722 RD |
378 | """ |
379 | Create the specified embedded windows around the edges of the frame. | |
380 | """ | |
381 | frameSize = self.GetSize() # TODO: GetClientWindow.GetSize is still returning 0,0 since the frame isn't fully constructed yet, so using full frame size | |
aca310e5 RD |
382 | defaultHSize = max(minSize, int(frameSize[0] / 6)) |
383 | defaultVSize = max(minSize, int(frameSize[1] / 7)) | |
3fa8f722 RD |
384 | defaultSubVSize = int(frameSize[1] / 2) |
385 | config = wx.ConfigBase_Get() | |
386 | if windows & (EMBEDDED_WINDOW_LEFT | EMBEDDED_WINDOW_TOPLEFT | EMBEDDED_WINDOW_BOTTOMLEFT): | |
aca310e5 | 387 | self._leftEmbWindow = self._CreateEmbeddedWindow(self, (max(minSize,config.ReadInt("MDIEmbedLeftSize", defaultHSize)), -1), wx.LAYOUT_VERTICAL, wx.LAYOUT_LEFT, visible = config.ReadInt("MDIEmbedLeftVisible", 1), sash = wx.SASH_RIGHT) |
3fa8f722 RD |
388 | else: |
389 | self._leftEmbWindow = None | |
390 | if windows & EMBEDDED_WINDOW_TOPLEFT: | |
391 | self._topLeftEmbWindow = self._CreateEmbeddedWindow(self._leftEmbWindow, (-1, config.ReadInt("MDIEmbedTopLeftSize", defaultSubVSize)), wx.LAYOUT_HORIZONTAL, wx.LAYOUT_TOP, visible = config.ReadInt("MDIEmbedTopLeftVisible", 1), sash = wx.SASH_BOTTOM) | |
392 | else: | |
393 | self._topLeftEmbWindow = None | |
394 | if windows & EMBEDDED_WINDOW_BOTTOMLEFT: | |
395 | self._bottomLeftEmbWindow = self._CreateEmbeddedWindow(self._leftEmbWindow, (-1, config.ReadInt("MDIEmbedBottomLeftSize", defaultSubVSize)), wx.LAYOUT_HORIZONTAL, wx.LAYOUT_BOTTOM, visible = config.ReadInt("MDIEmbedBottomLeftVisible", 1)) | |
396 | else: | |
397 | self._bottomLeftEmbWindow = None | |
398 | if windows & (EMBEDDED_WINDOW_RIGHT | EMBEDDED_WINDOW_TOPRIGHT | EMBEDDED_WINDOW_BOTTOMRIGHT): | |
aca310e5 | 399 | self._rightEmbWindow = self._CreateEmbeddedWindow(self, (max(minSize,config.ReadInt("MDIEmbedRightSize", defaultHSize)), -1), wx.LAYOUT_VERTICAL, wx.LAYOUT_RIGHT, visible = config.ReadInt("MDIEmbedRightVisible", 1), sash = wx.SASH_LEFT) |
3fa8f722 RD |
400 | else: |
401 | self._rightEmbWindow = None | |
402 | if windows & EMBEDDED_WINDOW_TOPRIGHT: | |
403 | self._topRightEmbWindow = self._CreateEmbeddedWindow(self._rightEmbWindow, (-1, config.ReadInt("MDIEmbedTopRightSize", defaultSubVSize)), wx.LAYOUT_HORIZONTAL, wx.LAYOUT_TOP, visible = config.ReadInt("MDIEmbedTopRightVisible", 1), sash = wx.SASH_BOTTOM) | |
404 | else: | |
405 | self._topRightEmbWindow = None | |
406 | if windows & EMBEDDED_WINDOW_BOTTOMRIGHT: | |
407 | self._bottomRightEmbWindow = self._CreateEmbeddedWindow(self._rightEmbWindow, (-1, config.ReadInt("MDIEmbedBottomRightSize", defaultSubVSize)), wx.LAYOUT_HORIZONTAL, wx.LAYOUT_BOTTOM, visible = config.ReadInt("MDIEmbedBottomRightVisible", 1)) | |
408 | else: | |
409 | self._bottomRightEmbWindow = None | |
410 | if windows & EMBEDDED_WINDOW_TOP: | |
aca310e5 | 411 | self._topEmbWindow = self._CreateEmbeddedWindow(self, (-1, max(minSize,config.ReadInt("MDIEmbedTopSize", defaultVSize))), wx.LAYOUT_HORIZONTAL, wx.LAYOUT_TOP, visible = config.ReadInt("MDIEmbedTopVisible", 1), sash = wx.SASH_BOTTOM) |
3fa8f722 RD |
412 | else: |
413 | self._topEmbWindow = None | |
414 | if windows & EMBEDDED_WINDOW_BOTTOM: | |
aca310e5 | 415 | self._bottomEmbWindow = self._CreateEmbeddedWindow(self, (-1, max(minSize,config.ReadInt("MDIEmbedBottomSize", defaultVSize))), wx.LAYOUT_HORIZONTAL, wx.LAYOUT_BOTTOM, visible = config.ReadInt("MDIEmbedBottomVisible", 1), sash = wx.SASH_TOP) |
3fa8f722 RD |
416 | else: |
417 | self._bottomEmbWindow = None | |
418 | ||
419 | ||
420 | def SaveEmbeddedWindowSizes(self): | |
421 | """ | |
422 | Saves the sizes of the embedded windows. | |
423 | """ | |
424 | config = wx.ConfigBase_Get() | |
425 | if not self.IsMaximized(): | |
426 | config.WriteInt("MDIFrameXLoc", self.GetPositionTuple()[0]) | |
427 | config.WriteInt("MDIFrameYLoc", self.GetPositionTuple()[1]) | |
428 | config.WriteInt("MDIFrameXSize", self.GetSizeTuple()[0]) | |
429 | config.WriteInt("MDIFrameYSize", self.GetSizeTuple()[1]) | |
430 | config.WriteInt("MDIFrameMaximized", self.IsMaximized()) | |
431 | config.WriteInt("ViewToolBar", self._toolBar.IsShown()) | |
432 | config.WriteInt("ViewStatusBar", self.GetStatusBar().IsShown()) | |
433 | ||
434 | if self._leftEmbWindow: | |
435 | config.WriteInt("MDIEmbedLeftSize", self._leftEmbWindow.GetSize()[0]) | |
436 | config.WriteInt("MDIEmbedLeftVisible", self._leftEmbWindow.IsShown()) | |
437 | if self._topLeftEmbWindow: | |
438 | if self._topLeftEmbWindow._sizeBeforeHidden: | |
439 | size = self._topLeftEmbWindow._sizeBeforeHidden[1] | |
440 | else: | |
441 | size = self._topLeftEmbWindow.GetSize()[1] | |
442 | config.WriteInt("MDIEmbedTopLeftSize", size) | |
443 | config.WriteInt("MDIEmbedTopLeftVisible", self._topLeftEmbWindow.IsShown()) | |
444 | if self._bottomLeftEmbWindow: | |
445 | if self._bottomLeftEmbWindow._sizeBeforeHidden: | |
446 | size = self._bottomLeftEmbWindow._sizeBeforeHidden[1] | |
447 | else: | |
448 | size = self._bottomLeftEmbWindow.GetSize()[1] | |
449 | config.WriteInt("MDIEmbedBottomLeftSize", size) | |
450 | config.WriteInt("MDIEmbedBottomLeftVisible", self._bottomLeftEmbWindow.IsShown()) | |
451 | if self._rightEmbWindow: | |
452 | config.WriteInt("MDIEmbedRightSize", self._rightEmbWindow.GetSize()[0]) | |
453 | config.WriteInt("MDIEmbedRightVisible", self._rightEmbWindow.IsShown()) | |
454 | if self._topRightEmbWindow: | |
455 | if self._topRightEmbWindow._sizeBeforeHidden: | |
456 | size = self._topRightEmbWindow._sizeBeforeHidden[1] | |
457 | else: | |
458 | size = self._topRightEmbWindow.GetSize()[1] | |
459 | config.WriteInt("MDIEmbedTopRightSize", size) | |
460 | config.WriteInt("MDIEmbedTopRightVisible", self._topRightEmbWindow.IsShown()) | |
461 | if self._bottomRightEmbWindow: | |
462 | if self._bottomRightEmbWindow._sizeBeforeHidden: | |
463 | size = self._bottomRightEmbWindow._sizeBeforeHidden[1] | |
464 | else: | |
465 | size = self._bottomRightEmbWindow.GetSize()[1] | |
466 | config.WriteInt("MDIEmbedBottomRightSize", size) | |
467 | config.WriteInt("MDIEmbedBottomRightVisible", self._bottomRightEmbWindow.IsShown()) | |
468 | if self._topEmbWindow: | |
469 | config.WriteInt("MDIEmbedTopSize", self._topEmbWindow.GetSize()[1]) | |
470 | config.WriteInt("MDIEmbedTopVisible", self._topEmbWindow.IsShown()) | |
471 | if self._bottomEmbWindow: | |
472 | config.WriteInt("MDIEmbedBottomSize", self._bottomEmbWindow.GetSize()[1]) | |
473 | config.WriteInt("MDIEmbedBottomVisible", self._bottomEmbWindow.IsShown()) | |
474 | ||
475 | ||
476 | def GetEmbeddedWindow(self, loc): | |
477 | """ | |
478 | Returns the instance of the embedded window specified by the embedded window location constant. | |
479 | """ | |
480 | if loc == EMBEDDED_WINDOW_TOP: | |
481 | return self._topEmbWindow | |
482 | elif loc == EMBEDDED_WINDOW_BOTTOM: | |
483 | return self._bottomEmbWindow | |
484 | elif loc == EMBEDDED_WINDOW_LEFT: | |
485 | return self._leftEmbWindow | |
486 | elif loc == EMBEDDED_WINDOW_RIGHT: | |
487 | return self._rightEmbWindow | |
488 | elif loc == EMBEDDED_WINDOW_TOPLEFT: | |
489 | return self._topLeftEmbWindow | |
490 | elif loc == EMBEDDED_WINDOW_BOTTOMLEFT: | |
491 | return self._bottomLeftEmbWindow | |
492 | elif loc == EMBEDDED_WINDOW_TOPRIGHT: | |
493 | return self._topRightEmbWindow | |
494 | elif loc == EMBEDDED_WINDOW_BOTTOMRIGHT: | |
495 | return self._bottomRightEmbWindow | |
496 | return None | |
497 | ||
498 | ||
6f1a3f9c | 499 | def _CreateEmbeddedWindow(self, parent, size, orientation, alignment, visible=True, sash=None): |
3fa8f722 | 500 | """ |
aca310e5 | 501 | Creates the embedded window with the specified size, orientation, and alignment. If the |
3fa8f722 RD |
502 | window is not visible it will retain the size with which it was last viewed. |
503 | """ | |
504 | window = wx.SashLayoutWindow(parent, wx.NewId(), style = wx.NO_BORDER | wx.SW_3D) | |
505 | window.SetDefaultSize(size) | |
506 | window.SetOrientation(orientation) | |
507 | window.SetAlignment(alignment) | |
508 | if sash != None: # wx.SASH_TOP is 0 so check for None instead of just doing "if sash:" | |
509 | window.SetSashVisible(sash, True) | |
510 | #### | |
511 | def OnEmbeddedWindowSashDrag(event): | |
512 | if event.GetDragStatus() == wx.SASH_STATUS_OUT_OF_RANGE: | |
513 | return | |
514 | sashWindow = event.GetEventObject() | |
515 | if sashWindow.GetAlignment() == wx.LAYOUT_TOP or sashWindow.GetAlignment() == wx.LAYOUT_BOTTOM: | |
516 | size = wx.Size(-1, event.GetDragRect().height) | |
517 | else: | |
518 | size = wx.Size(event.GetDragRect().width, -1) | |
519 | event.GetEventObject().SetDefaultSize(size) | |
520 | self._LayoutFrame() | |
521 | sashWindow.Refresh() | |
522 | if isinstance(sashWindow.GetParent(), wx.SashLayoutWindow): | |
523 | sashWindow.Show() | |
524 | parentSashWindow = sashWindow.GetParent() # Force a refresh | |
525 | parentSashWindow.Layout() | |
526 | parentSashWindow.Refresh() | |
527 | parentSashWindow.SetSize((parentSashWindow.GetSize().width + 1, parentSashWindow.GetSize().height + 1)) | |
528 | #### | |
529 | wx.EVT_SASH_DRAGGED(window, window.GetId(), OnEmbeddedWindowSashDrag) | |
530 | window._sizeBeforeHidden = None | |
531 | if not visible: | |
532 | window.Show(False) | |
533 | if isinstance(parent, wx.SashLayoutWindow): # It's a window embedded in another sash window so remember its actual size to show it again | |
534 | window._sizeBeforeHidden = size | |
535 | return window | |
536 | ||
537 | ||
6f1a3f9c | 538 | def ShowEmbeddedWindow(self, window, show=True): |
3fa8f722 RD |
539 | """ |
540 | Shows or hides the embedded window specified by the embedded window location constant. | |
541 | """ | |
542 | window.Show(show) | |
543 | if isinstance(window.GetParent(), wx.SashLayoutWindow): # It is a parent sashwindow with multiple embedded sashwindows | |
544 | parentSashWindow = window.GetParent() | |
545 | if show: # Make sure it is visible in case all of the subwindows were hidden | |
aca310e5 | 546 | parentSashWindow.Show() |
3fa8f722 RD |
547 | if show and window._sizeBeforeHidden: |
548 | if window._sizeBeforeHidden[1] == parentSashWindow.GetClientSize()[1]: | |
549 | if window == self.GetEmbeddedWindow(EMBEDDED_WINDOW_BOTTOMLEFT) and self.GetEmbeddedWindow(EMBEDDED_WINDOW_TOPLEFT).IsShown(): | |
550 | window.SetDefaultSize((window._sizeBeforeHidden[0], window._sizeBeforeHidden[0] - self.GetEmbeddedWindow(EMBEDDED_WINDOW_TOPLEFT).GetSize()[1])) | |
551 | elif window == self.GetEmbeddedWindow(EMBEDDED_WINDOW_TOPLEFT) and self.GetEmbeddedWindow(EMBEDDED_WINDOW_BOTTOMLEFT).IsShown(): | |
552 | window.SetDefaultSize((window._sizeBeforeHidden[0], window._sizeBeforeHidden[0] - self.GetEmbeddedWindow(EMBEDDED_WINDOW_BOTTOMLEFT).GetSize()[1])) | |
553 | elif window == self.GetEmbeddedWindow(EMBEDDED_WINDOW_BOTTOMRIGHT) and self.GetEmbeddedWindow(EMBEDDED_WINDOW_TOPRIGHT).IsShown(): | |
554 | window.SetDefaultSize((window._sizeBeforeHidden[0], window._sizeBeforeHidden[0] - self.GetEmbeddedWindow(EMBEDDED_WINDOW_TOPRIGHT).GetSize()[1])) | |
555 | elif window == self.GetEmbeddedWindow(EMBEDDED_WINDOW_TOPRIGHT) and self.GetEmbeddedWindow(EMBEDDED_WINDOW_BOTTOMRIGHT).IsShown(): | |
556 | window.SetDefaultSize((window._sizeBeforeHidden[0], window._sizeBeforeHidden[0] - self.GetEmbeddedWindow(EMBEDDED_WINDOW_BOTTOMRIGHT).GetSize()[1])) | |
557 | else: | |
558 | window.SetDefaultSize(window._sizeBeforeHidden) | |
559 | # If it is not the size of the full parent sashwindow set the other window's size so that if it gets shown it will have a cooresponding size | |
560 | if window._sizeBeforeHidden[1] < parentSashWindow.GetClientSize()[1]: | |
561 | otherWindowSize = (-1, parentSashWindow.GetClientSize()[1] - window._sizeBeforeHidden[1]) | |
562 | if window == self.GetEmbeddedWindow(EMBEDDED_WINDOW_BOTTOMLEFT): | |
563 | self.GetEmbeddedWindow(EMBEDDED_WINDOW_TOPLEFT).SetDefaultSize(otherWindowSize) | |
564 | elif window == self.GetEmbeddedWindow(EMBEDDED_WINDOW_TOPLEFT): | |
565 | self.GetEmbeddedWindow(EMBEDDED_WINDOW_BOTTOMLEFT).SetDefaultSize(otherWindowSize) | |
566 | elif window == self.GetEmbeddedWindow(EMBEDDED_WINDOW_BOTTOMRIGHT): | |
567 | self.GetEmbeddedWindow(EMBEDDED_WINDOW_TOPRIGHT).SetDefaultSize(otherWindowSize) | |
568 | elif window == self.GetEmbeddedWindow(EMBEDDED_WINDOW_TOPRIGHT): | |
569 | self.GetEmbeddedWindow(EMBEDDED_WINDOW_BOTTOMRIGHT).SetDefaultSize(otherWindowSize) | |
aca310e5 | 570 | |
3fa8f722 RD |
571 | if not show: |
572 | if window == self.GetEmbeddedWindow(EMBEDDED_WINDOW_BOTTOMRIGHT) and not self.GetEmbeddedWindow(EMBEDDED_WINDOW_TOPRIGHT).IsShown() \ | |
573 | or window == self.GetEmbeddedWindow(EMBEDDED_WINDOW_TOPRIGHT) and not self.GetEmbeddedWindow(EMBEDDED_WINDOW_BOTTOMRIGHT).IsShown() \ | |
574 | or window == self.GetEmbeddedWindow(EMBEDDED_WINDOW_BOTTOMLEFT) and not self.GetEmbeddedWindow(EMBEDDED_WINDOW_TOPLEFT).IsShown() \ | |
575 | or window == self.GetEmbeddedWindow(EMBEDDED_WINDOW_TOPLEFT) and not self.GetEmbeddedWindow(EMBEDDED_WINDOW_BOTTOMLEFT).IsShown(): | |
576 | parentSashWindow.Hide() # Hide the parent sashwindow if all of the children are hidden | |
577 | parentSashWindow.Layout() # Force a refresh | |
578 | parentSashWindow.Refresh() | |
579 | parentSashWindow.SetSize((parentSashWindow.GetSize().width + 1, parentSashWindow.GetSize().height + 1)) | |
580 | self._LayoutFrame() | |
581 | ||
582 | ||
02b800ce | 583 | def HideEmbeddedWindow(self, window): |
3fa8f722 RD |
584 | """ |
585 | Hides the embedded window specified by the embedded window location constant. | |
586 | """ | |
02b800ce | 587 | self.ShowEmbeddedWindow(window, show=False) |
3fa8f722 RD |
588 | |
589 | ||
590 | class DocTabbedChildFrame(wx.Panel): | |
591 | """ | |
592 | The wxDocMDIChildFrame class provides a default frame for displaying | |
593 | documents on separate windows. This class can only be used for MDI child | |
594 | frames. | |
595 | ||
596 | The class is part of the document/view framework supported by wxWindows, | |
597 | and cooperates with the wxView, wxDocument, wxDocManager and wxDocTemplate | |
598 | classes. | |
599 | """ | |
600 | ||
601 | ||
6f1a3f9c | 602 | def __init__(self, doc, view, frame, id, title, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE, name="frame"): |
3fa8f722 RD |
603 | """ |
604 | Constructor. Note that the event table must be rebuilt for the | |
605 | frame since the EvtHandler is not virtual. | |
606 | """ | |
607 | wx.Panel.__init__(self, frame.GetNotebook(), id) | |
608 | self._childDocument = doc | |
609 | self._childView = view | |
610 | frame.AddNotebookPage(self, doc.GetPrintableName()) | |
611 | if view: | |
612 | view.SetFrame(self) | |
613 | ||
614 | ||
615 | def GetIcon(self): | |
616 | """ | |
617 | Dummy method since the icon of tabbed frames are managed by the notebook. | |
618 | """ | |
619 | return None | |
aca310e5 | 620 | |
3fa8f722 RD |
621 | |
622 | def SetIcon(self, icon): | |
623 | """ | |
624 | Dummy method since the icon of tabbed frames are managed by the notebook. | |
625 | """ | |
626 | pass | |
627 | ||
628 | ||
629 | def Destroy(self): | |
630 | """ | |
631 | Removes the current notebook page. | |
632 | """ | |
633 | wx.GetApp().GetTopWindow().RemoveNotebookPage(self) | |
634 | ||
635 | ||
636 | def SetFocus(self): | |
637 | """ | |
638 | Activates the current notebook page. | |
639 | """ | |
640 | wx.GetApp().GetTopWindow().ActivateNotebookPage(self) | |
641 | ||
642 | ||
643 | def Activate(self): # Need this in case there are embedded sash windows and such, OnActivate is not getting called | |
644 | """ | |
645 | Activates the current view. | |
646 | """ | |
647 | # Called by Project Editor | |
648 | if self._childView: | |
649 | self._childView.Activate(True) | |
650 | ||
651 | ||
652 | def GetTitle(self): | |
653 | """ | |
654 | Returns the frame's title. | |
655 | """ | |
02b800ce | 656 | return wx.GetApp().GetTopWindow().GetNotebookPageTitle(self) |
3fa8f722 RD |
657 | |
658 | ||
659 | def SetTitle(self, title): | |
660 | """ | |
661 | Sets the frame's title. | |
662 | """ | |
663 | wx.GetApp().GetTopWindow().SetNotebookPageTitle(self, title) | |
664 | ||
665 | ||
aca310e5 RD |
666 | def OnTitleIsModified(self): |
667 | """ | |
668 | Add/remove to the frame's title an indication that the document is dirty. | |
669 | If the document is dirty, an '*' is appended to the title | |
670 | """ | |
671 | title = self.GetTitle() | |
672 | if title: | |
673 | if self.GetDocument().IsModified(): | |
674 | if not title.endswith("*"): | |
675 | title = title + "*" | |
676 | self.SetTitle(title) | |
677 | else: | |
678 | if title.endswith("*"): | |
679 | title = title[:-1] | |
680 | self.SetTitle(title) | |
681 | ||
682 | ||
3fa8f722 RD |
683 | def ProcessEvent(event): |
684 | """ | |
685 | Processes an event, searching event tables and calling zero or more | |
686 | suitable event handler function(s). Note that the ProcessEvent | |
687 | method is called from the wxPython docview framework directly since | |
688 | wxPython does not have a virtual ProcessEvent function. | |
689 | """ | |
690 | if not self._childView or not self._childView.ProcessEvent(event): | |
691 | if not isinstance(event, wx.CommandEvent) or not self.GetParent() or not self.GetParent().ProcessEvent(event): | |
692 | return False | |
693 | else: | |
694 | return True | |
695 | else: | |
696 | return True | |
697 | ||
698 | ||
699 | def GetDocument(self): | |
700 | """ | |
701 | Returns the document associated with this frame. | |
702 | """ | |
703 | return self._childDocument | |
704 | ||
705 | ||
706 | def SetDocument(self, document): | |
707 | """ | |
708 | Sets the document for this frame. | |
709 | """ | |
710 | self._childDocument = document | |
711 | ||
712 | ||
713 | def GetView(self): | |
714 | """ | |
715 | Returns the view associated with this frame. | |
716 | """ | |
717 | return self._childView | |
718 | ||
719 | ||
720 | def SetView(self, view): | |
721 | """ | |
722 | Sets the view for this frame. | |
723 | """ | |
724 | self._childView = view | |
d1dc2b32 | 725 | |
3fa8f722 RD |
726 | |
727 | class DocTabbedParentFrame(wx.Frame, DocFrameMixIn, DocMDIParentFrameMixIn): | |
728 | """ | |
729 | The DocTabbedParentFrame class provides a default top-level frame for | |
730 | applications using the document/view framework. This class can only be | |
731 | used for MDI parent frames that use a tabbed interface. | |
732 | ||
733 | It cooperates with the wxView, wxDocument, wxDocManager and wxDocTemplate | |
734 | classes. | |
735 | """ | |
736 | ||
737 | ||
aca310e5 | 738 | def __init__(self, docManager, frame, id, title, pos = wx.DefaultPosition, size = wx.DefaultSize, style = wx.DEFAULT_FRAME_STYLE, name = "DocTabbedParentFrame", embeddedWindows = 0, minSize=20): |
3fa8f722 RD |
739 | """ |
740 | Constructor. Note that the event table must be rebuilt for the | |
741 | frame since the EvtHandler is not virtual. | |
742 | """ | |
743 | pos, size = self._GetPosSizeFromConfig(pos, size) | |
744 | wx.Frame.__init__(self, frame, id, title, pos, size, style, name) | |
745 | ||
746 | # From docview.MDIParentFrame | |
d1dc2b32 RD |
747 | self._docManager = docManager |
748 | ||
3fa8f722 | 749 | wx.EVT_CLOSE(self, self.OnCloseWindow) |
d1dc2b32 | 750 | |
3fa8f722 RD |
751 | wx.EVT_MENU(self, wx.ID_EXIT, self.OnExit) |
752 | wx.EVT_MENU_RANGE(self, wx.ID_FILE1, wx.ID_FILE9, self.OnMRUFile) | |
d1dc2b32 | 753 | |
3fa8f722 RD |
754 | wx.EVT_MENU(self, wx.ID_NEW, self.ProcessEvent) |
755 | wx.EVT_MENU(self, wx.ID_OPEN, self.ProcessEvent) | |
756 | wx.EVT_MENU(self, wx.ID_CLOSE_ALL, self.ProcessEvent) | |
757 | wx.EVT_MENU(self, wx.ID_CLOSE, self.ProcessEvent) | |
758 | wx.EVT_MENU(self, wx.ID_REVERT, self.ProcessEvent) | |
759 | wx.EVT_MENU(self, wx.ID_SAVE, self.ProcessEvent) | |
760 | wx.EVT_MENU(self, wx.ID_SAVEAS, self.ProcessEvent) | |
761 | wx.EVT_MENU(self, wx.ID_UNDO, self.ProcessEvent) | |
762 | wx.EVT_MENU(self, wx.ID_REDO, self.ProcessEvent) | |
763 | wx.EVT_MENU(self, wx.ID_PRINT, self.ProcessEvent) | |
764 | wx.EVT_MENU(self, wx.ID_PRINT_SETUP, self.ProcessEvent) | |
765 | wx.EVT_MENU(self, wx.ID_PREVIEW, self.ProcessEvent) | |
766 | wx.EVT_MENU(self, wx.ID_ABOUT, self.OnAbout) | |
d1dc2b32 | 767 | |
3fa8f722 RD |
768 | wx.EVT_UPDATE_UI(self, wx.ID_NEW, self.ProcessUpdateUIEvent) |
769 | wx.EVT_UPDATE_UI(self, wx.ID_OPEN, self.ProcessUpdateUIEvent) | |
770 | wx.EVT_UPDATE_UI(self, wx.ID_CLOSE_ALL, self.ProcessUpdateUIEvent) | |
771 | wx.EVT_UPDATE_UI(self, wx.ID_CLOSE, self.ProcessUpdateUIEvent) | |
772 | wx.EVT_UPDATE_UI(self, wx.ID_REVERT, self.ProcessUpdateUIEvent) | |
773 | wx.EVT_UPDATE_UI(self, wx.ID_SAVE, self.ProcessUpdateUIEvent) | |
774 | wx.EVT_UPDATE_UI(self, wx.ID_SAVEAS, self.ProcessUpdateUIEvent) | |
775 | wx.EVT_UPDATE_UI(self, wx.ID_UNDO, self.ProcessUpdateUIEvent) | |
776 | wx.EVT_UPDATE_UI(self, wx.ID_REDO, self.ProcessUpdateUIEvent) | |
777 | wx.EVT_UPDATE_UI(self, wx.ID_PRINT, self.ProcessUpdateUIEvent) | |
778 | wx.EVT_UPDATE_UI(self, wx.ID_PRINT_SETUP, self.ProcessUpdateUIEvent) | |
779 | wx.EVT_UPDATE_UI(self, wx.ID_PREVIEW, self.ProcessUpdateUIEvent) | |
780 | # End From docview.MDIParentFrame | |
781 | ||
782 | self.CreateNotebook() | |
aca310e5 RD |
783 | self._InitFrame(embeddedWindows, minSize) |
784 | ||
d1dc2b32 | 785 | |
3fa8f722 | 786 | def _LayoutFrame(self): |
d1dc2b32 | 787 | """ |
3fa8f722 | 788 | Lays out the frame. |
d1dc2b32 | 789 | """ |
3fa8f722 | 790 | wx.LayoutAlgorithm().LayoutFrame(self, self._notebook) |
aca310e5 | 791 | |
3fa8f722 RD |
792 | |
793 | def CreateNotebook(self): | |
794 | """ | |
795 | Creates the notebook to use for the tabbed document interface. | |
aca310e5 | 796 | """ |
02b800ce RD |
797 | if wx.Platform != "__WXMAC__": |
798 | self._notebook = wx.Notebook(self, wx.NewId()) | |
799 | else: | |
800 | self._notebook = wx.Listbook(self, wx.NewId(), style=wx.LB_LEFT) | |
3fa8f722 | 801 | # self._notebook.SetSizer(wx.NotebookSizer(self._notebook)) |
02b800ce RD |
802 | if wx.Platform != "__WXMAC__": |
803 | wx.EVT_NOTEBOOK_PAGE_CHANGED(self, self._notebook.GetId(), self.OnNotebookPageChanged) | |
804 | else: | |
805 | wx.EVT_LISTBOOK_PAGE_CHANGED(self, self._notebook.GetId(), self.OnNotebookPageChanged) | |
3fa8f722 | 806 | wx.EVT_RIGHT_DOWN(self._notebook, self.OnNotebookRightClick) |
02b800ce | 807 | wx.EVT_MIDDLE_DOWN(self._notebook, self.OnNotebookMiddleClick) |
aca310e5 | 808 | |
02b800ce RD |
809 | # wxBug: wx.Listbook does not implement HitTest the same way wx.Notebook |
810 | # does, so for now don't fire MouseOver events. | |
811 | if wx.Platform != "__WXMAC__": | |
812 | wx.EVT_MOTION(self._notebook, self.OnNotebookMouseOver) | |
3fa8f722 RD |
813 | |
814 | templates = wx.GetApp().GetDocumentManager().GetTemplates() | |
815 | iconList = wx.ImageList(16, 16, initialCount = len(templates)) | |
816 | self._iconIndexLookup = [] | |
817 | for template in templates: | |
818 | icon = template.GetIcon() | |
819 | if icon: | |
b792147d RD |
820 | if icon.GetHeight() != 16 or icon.GetWidth() != 16: |
821 | icon.SetHeight(16) | |
822 | icon.SetWidth(16) | |
823 | if wx.GetApp().GetDebug(): | |
824 | print "Warning: icon for '%s' isn't 16x16, not crossplatform" % template._docTypeName | |
3fa8f722 RD |
825 | iconIndex = iconList.AddIcon(icon) |
826 | self._iconIndexLookup.append((template, iconIndex)) | |
aca310e5 | 827 | |
3fa8f722 | 828 | icon = getBlankIcon() |
b792147d RD |
829 | if icon.GetHeight() != 16 or icon.GetWidth() != 16: |
830 | icon.SetHeight(16) | |
831 | icon.SetWidth(16) | |
832 | if wx.GetApp().GetDebug(): | |
833 | print "Warning: getBlankIcon isn't 16x16, not crossplatform" | |
3fa8f722 RD |
834 | self._blankIconIndex = iconList.AddIcon(icon) |
835 | self._notebook.AssignImageList(iconList) | |
d1dc2b32 RD |
836 | |
837 | ||
3fa8f722 | 838 | def GetNotebook(self): |
d1dc2b32 | 839 | """ |
3fa8f722 | 840 | Returns the notebook used by the tabbed document interface. |
d1dc2b32 | 841 | """ |
3fa8f722 | 842 | return self._notebook |
aca310e5 | 843 | |
3fa8f722 RD |
844 | |
845 | def GetActiveChild(self): | |
846 | """ | |
847 | Returns the active notebook page, which to the framework is treated as | |
848 | a document frame. | |
849 | """ | |
850 | index = self._notebook.GetSelection() | |
851 | if index == -1: | |
852 | return None | |
853 | return self._notebook.GetPage(index) | |
d1dc2b32 RD |
854 | |
855 | ||
3fa8f722 | 856 | def OnNotebookPageChanged(self, event): |
d1dc2b32 | 857 | """ |
3fa8f722 | 858 | Activates a notebook page's view when it is selected. |
d1dc2b32 | 859 | """ |
3fa8f722 RD |
860 | index = self._notebook.GetSelection() |
861 | if index > -1: | |
862 | self._notebook.GetPage(index).GetView().Activate() | |
d1dc2b32 RD |
863 | |
864 | ||
6f1a3f9c RD |
865 | def OnNotebookMouseOver(self, event): |
866 | # wxBug: On Windows XP the tooltips don't automatically disappear when you move the mouse and it is on a notebook tab, has nothing to do with this code!!! | |
867 | index, type = self._notebook.HitTest(event.GetPosition()) | |
aca310e5 | 868 | |
6f1a3f9c RD |
869 | if index > -1: |
870 | doc = self._notebook.GetPage(index).GetView().GetDocument() | |
aca310e5 RD |
871 | # wxBug: Tooltips no longer appearing on tabs except on |
872 | # about a 2 pixel area between tab top and contents that will show tip. | |
873 | self._notebook.GetParent().SetToolTip(wx.ToolTip(doc.GetFilename())) | |
6f1a3f9c RD |
874 | else: |
875 | self._notebook.SetToolTip(wx.ToolTip("")) | |
876 | event.Skip() | |
aca310e5 | 877 | |
6f1a3f9c | 878 | |
02b800ce RD |
879 | def OnNotebookMiddleClick(self, event): |
880 | """ | |
881 | Handles middle clicks for the notebook, closing the document whose tab was | |
882 | clicked on. | |
883 | """ | |
884 | index, type = self._notebook.HitTest(event.GetPosition()) | |
885 | if index > -1: | |
886 | doc = self._notebook.GetPage(index).GetView().GetDocument() | |
887 | if doc: | |
888 | doc.DeleteAllViews() | |
aca310e5 | 889 | |
3fa8f722 RD |
890 | def OnNotebookRightClick(self, event): |
891 | """ | |
892 | Handles right clicks for the notebook, enabling users to either close | |
893 | a tab or select from the available documents if the user clicks on the | |
894 | notebook's white space. | |
895 | """ | |
896 | index, type = self._notebook.HitTest(event.GetPosition()) | |
897 | menu = wx.Menu() | |
898 | x, y = event.GetX(), event.GetY() | |
899 | if index > -1: | |
900 | doc = self._notebook.GetPage(index).GetView().GetDocument() | |
901 | id = wx.NewId() | |
902 | menu.Append(id, _("Close")) | |
903 | def OnRightMenuSelect(event): | |
904 | doc.DeleteAllViews() | |
905 | wx.EVT_MENU(self, id, OnRightMenuSelect) | |
906 | if self._notebook.GetPageCount() > 1: | |
6f1a3f9c RD |
907 | id = wx.NewId() |
908 | menu.Append(id, _("Close All but \"%s\"" % doc.GetPrintableName())) | |
909 | def OnRightMenuSelect(event): | |
910 | for i in range(self._notebook.GetPageCount()-1, -1, -1): # Go from len-1 to 0 | |
911 | if i != index: | |
912 | doc = self._notebook.GetPage(i).GetView().GetDocument() | |
913 | if not self.GetDocumentManager().CloseDocument(doc, False): | |
914 | return | |
915 | wx.EVT_MENU(self, id, OnRightMenuSelect) | |
3fa8f722 RD |
916 | menu.AppendSeparator() |
917 | tabsMenu = wx.Menu() | |
918 | menu.AppendMenu(wx.NewId(), _("Select Tab"), tabsMenu) | |
919 | else: | |
920 | y = y - 25 # wxBug: It is offsetting click events in the blank notebook area | |
921 | tabsMenu = menu | |
922 | ||
923 | if self._notebook.GetPageCount() > 1: | |
924 | selectIDs = {} | |
925 | for i in range(0, self._notebook.GetPageCount()): | |
926 | id = wx.NewId() | |
927 | selectIDs[id] = i | |
928 | tabsMenu.Append(id, self._notebook.GetPageText(i)) | |
929 | def OnRightMenuSelect(event): | |
930 | self._notebook.SetSelection(selectIDs[event.GetId()]) | |
931 | wx.EVT_MENU(self, id, OnRightMenuSelect) | |
aca310e5 | 932 | |
3fa8f722 RD |
933 | self._notebook.PopupMenu(menu, wx.Point(x, y)) |
934 | menu.Destroy() | |
aca310e5 RD |
935 | |
936 | ||
3fa8f722 RD |
937 | def AddNotebookPage(self, panel, title): |
938 | """ | |
939 | Adds a document page to the notebook. | |
940 | """ | |
941 | self._notebook.AddPage(panel, title) | |
942 | index = self._notebook.GetPageCount() - 1 | |
943 | self._notebook.SetSelection(index) | |
d1dc2b32 | 944 | |
3fa8f722 RD |
945 | found = False # Now set the icon |
946 | template = panel.GetDocument().GetDocumentTemplate() | |
947 | if template: | |
948 | for t, iconIndex in self._iconIndexLookup: | |
949 | if t is template: | |
950 | self._notebook.SetPageImage(index, iconIndex) | |
951 | found = True | |
952 | break | |
953 | if not found: | |
954 | self._notebook.SetPageImage(index, self._blankIconIndex) | |
aca310e5 | 955 | |
02b800ce RD |
956 | # wxBug: the wxListbook used on Mac needs its tabs list resized |
957 | # whenever a new tab is added, but the only way to do this is | |
958 | # to resize the entire control | |
959 | if wx.Platform == "__WXMAC__": | |
960 | content_size = self._notebook.GetSize() | |
961 | self._notebook.SetSize((content_size.x+2, -1)) | |
962 | self._notebook.SetSize((content_size.x, -1)) | |
aca310e5 | 963 | |
3fa8f722 | 964 | self._notebook.Layout() |
d1dc2b32 | 965 | |
aca310e5 RD |
966 | windowMenuService = wx.GetApp().GetService(WindowMenuService) |
967 | if windowMenuService: | |
968 | windowMenuService.BuildWindowMenu(wx.GetApp().GetTopWindow()) # build file menu list when we open a file | |
3fa8f722 | 969 | |
02b800ce | 970 | |
3fa8f722 | 971 | def RemoveNotebookPage(self, panel): |
d1dc2b32 | 972 | """ |
3fa8f722 | 973 | Removes a document page from the notebook. |
d1dc2b32 | 974 | """ |
3fa8f722 RD |
975 | index = self.GetNotebookPageIndex(panel) |
976 | if index > -1: | |
aca310e5 RD |
977 | if self._notebook.GetPageCount() == 1 or index < 2: |
978 | pass | |
979 | elif index >= 1: | |
980 | self._notebook.SetSelection(index - 1) | |
981 | elif index < self._notebook.GetPageCount(): | |
982 | self._notebook.SetSelection(index + 1) | |
3fa8f722 | 983 | self._notebook.DeletePage(index) |
aca310e5 RD |
984 | self._notebook.GetParent().SetToolTip(wx.ToolTip("")) |
985 | ||
986 | windowMenuService = wx.GetApp().GetService(WindowMenuService) | |
987 | if windowMenuService: | |
988 | windowMenuService.BuildWindowMenu(wx.GetApp().GetTopWindow()) # build file menu list when we open a file | |
3fa8f722 RD |
989 | |
990 | ||
991 | def ActivateNotebookPage(self, panel): | |
992 | """ | |
993 | Sets the notebook to the specified panel. | |
994 | """ | |
995 | index = self.GetNotebookPageIndex(panel) | |
996 | if index > -1: | |
6f1a3f9c | 997 | self._notebook.SetFocus() |
3fa8f722 | 998 | self._notebook.SetSelection(index) |
aca310e5 | 999 | |
3fa8f722 RD |
1000 | |
1001 | def GetNotebookPageTitle(self, panel): | |
aca310e5 RD |
1002 | index = self.GetNotebookPageIndex(panel) |
1003 | if index != -1: | |
1004 | return self._notebook.GetPageText(self.GetNotebookPageIndex(panel)) | |
1005 | else: | |
1006 | return None | |
1007 | ||
3fa8f722 RD |
1008 | |
1009 | def SetNotebookPageTitle(self, panel, title): | |
1010 | self._notebook.SetPageText(self.GetNotebookPageIndex(panel), title) | |
aca310e5 | 1011 | |
3fa8f722 RD |
1012 | |
1013 | def GetNotebookPageIndex(self, panel): | |
1014 | """ | |
1015 | Returns the index of particular notebook panel. | |
1016 | """ | |
1017 | index = -1 | |
1018 | for i in range(self._notebook.GetPageCount()): | |
1019 | if self._notebook.GetPage(i) == panel: | |
1020 | index = i | |
1021 | break | |
1022 | return index | |
aca310e5 | 1023 | |
3fa8f722 RD |
1024 | |
1025 | def ProcessEvent(self, event): | |
1026 | """ | |
1027 | Processes an event, searching event tables and calling zero or more | |
1028 | suitable event handler function(s). Note that the ProcessEvent | |
1029 | method is called from the wxPython docview framework directly since | |
1030 | wxPython does not have a virtual ProcessEvent function. | |
1031 | """ | |
1032 | if wx.GetApp().ProcessEventBeforeWindows(event): | |
1033 | return True | |
1034 | if self._docManager and self._docManager.ProcessEvent(event): | |
1035 | return True | |
1036 | return DocMDIParentFrameMixIn.ProcessEvent(self, event) | |
1037 | ||
1038 | ||
1039 | def ProcessUpdateUIEvent(self, event): | |
1040 | """ | |
1041 | Processes a UI event, searching event tables and calling zero or more | |
1042 | suitable event handler function(s). Note that the ProcessEvent | |
1043 | method is called from the wxPython docview framework directly since | |
1044 | wxPython does not have a virtual ProcessEvent function. | |
1045 | """ | |
1046 | if wx.GetApp().ProcessUpdateUIEventBeforeWindows(event): | |
1047 | return True | |
1048 | if self._docManager and self._docManager.ProcessUpdateUIEvent(event): | |
1049 | return True | |
1050 | return DocMDIParentFrameMixIn.ProcessUpdateUIEvent(self, event) | |
1051 | ||
1052 | ||
1053 | def OnExit(self, event): | |
1054 | """ | |
1055 | Called when File/Exit is chosen and closes the window. | |
1056 | """ | |
1057 | self.Close() | |
1058 | ||
1059 | ||
1060 | def OnMRUFile(self, event): | |
1061 | """ | |
1062 | Opens the appropriate file when it is selected from the file history | |
1063 | menu. | |
1064 | """ | |
1065 | n = event.GetId() - wx.ID_FILE1 | |
1066 | filename = self._docManager.GetHistoryFile(n) | |
1067 | if filename: | |
1068 | self._docManager.CreateDocument(filename, wx.lib.docview.DOC_SILENT) | |
d1dc2b32 | 1069 | else: |
3fa8f722 RD |
1070 | self._docManager.RemoveFileFromHistory(n) |
1071 | msgTitle = wx.GetApp().GetAppName() | |
1072 | if not msgTitle: | |
1073 | msgTitle = _("File Error") | |
1074 | wx.MessageBox("The file '%s' doesn't exist and couldn't be opened.\nIt has been removed from the most recently used files list" % FileNameFromPath(file), | |
1075 | msgTitle, | |
1076 | wx.OK | wx.ICON_EXCLAMATION, | |
1077 | self) | |
d1dc2b32 | 1078 | |
3fa8f722 RD |
1079 | |
1080 | def OnSize(self, event): | |
d1dc2b32 | 1081 | """ |
3fa8f722 | 1082 | Called when the frame is resized and lays out the client window. |
d1dc2b32 | 1083 | """ |
3fa8f722 RD |
1084 | # Needed in case there are splitpanels around the mdi frame |
1085 | self._LayoutFrame() | |
d1dc2b32 RD |
1086 | |
1087 | ||
3fa8f722 RD |
1088 | def OnCloseWindow(self, event): |
1089 | """ | |
1090 | Called when the frame is closed. Remembers the frame size. | |
1091 | """ | |
1092 | self.SaveEmbeddedWindowSizes() | |
1093 | ||
1094 | # save and close services last | |
1095 | for service in wx.GetApp().GetServices(): | |
1096 | if not service.OnCloseFrame(event): | |
1097 | return | |
1098 | ||
1099 | # From docview.MDIParentFrame | |
1100 | if self._docManager.Clear(not event.CanVeto()): | |
1101 | self.Destroy() | |
1102 | else: | |
1103 | event.Veto() | |
aca310e5 | 1104 | |
3fa8f722 RD |
1105 | |
1106 | class DocMDIChildFrame(wx.MDIChildFrame): | |
d1dc2b32 | 1107 | """ |
3fa8f722 RD |
1108 | The wxDocMDIChildFrame class provides a default frame for displaying |
1109 | documents on separate windows. This class can only be used for MDI child | |
1110 | frames. | |
1111 | ||
1112 | The class is part of the document/view framework supported by wxWindows, | |
1113 | and cooperates with the wxView, wxDocument, wxDocManager and wxDocTemplate | |
1114 | classes. | |
d1dc2b32 RD |
1115 | """ |
1116 | ||
1117 | ||
6f1a3f9c | 1118 | def __init__(self, doc, view, frame, id, title, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE, name="frame"): |
d1dc2b32 | 1119 | """ |
3fa8f722 RD |
1120 | Constructor. Note that the event table must be rebuilt for the |
1121 | frame since the EvtHandler is not virtual. | |
d1dc2b32 | 1122 | """ |
3fa8f722 RD |
1123 | wx.MDIChildFrame.__init__(self, frame, id, title, pos, size, style, name) |
1124 | self._childDocument = doc | |
1125 | self._childView = view | |
1126 | if view: | |
1127 | view.SetFrame(self) | |
1128 | # self.Create(doc, view, frame, id, title, pos, size, style, name) | |
1129 | self._activeEvent = None | |
1130 | self._activated = 0 | |
1131 | wx.EVT_ACTIVATE(self, self.OnActivate) | |
1132 | wx.EVT_CLOSE(self, self.OnCloseWindow) | |
1133 | ||
1134 | if frame: # wxBug: For some reason the EVT_ACTIVATE event is not getting triggered for the first mdi client window that is opened so we have to do it manually | |
1135 | mdiChildren = filter(lambda x: isinstance(x, wx.MDIChildFrame), frame.GetChildren()) | |
1136 | if len(mdiChildren) == 1: | |
1137 | self.Activate() | |
1138 | ||
1139 | ||
1140 | ## # Couldn't get this to work, but seems to work fine with single stage construction | |
1141 | ## def Create(self, doc, view, frame, id, title, pos, size, style, name): | |
1142 | ## self._childDocument = doc | |
1143 | ## self._childView = view | |
1144 | ## if wx.MDIChildFrame.Create(self, frame, id, title, pos, size, style, name): | |
1145 | ## if view: | |
1146 | ## view.SetFrame(self) | |
1147 | ## return True | |
1148 | ## return False | |
1149 | ||
1150 | ||
1151 | ||
1152 | def Activate(self): # Need this in case there are embedded sash windows and such, OnActivate is not getting called | |
1153 | """ | |
1154 | Activates the current view. | |
1155 | """ | |
1156 | if self._childView: | |
1157 | self._childView.Activate(True) | |
1158 | ||
1159 | ||
aca310e5 RD |
1160 | def OnTitleIsModified(self): |
1161 | """ | |
1162 | Add/remove to the frame's title an indication that the document is dirty. | |
1163 | If the document is dirty, an '*' is appended to the title | |
1164 | """ | |
1165 | title = self.GetTitle() | |
1166 | if title: | |
1167 | if self.GetDocument().IsModified(): | |
1168 | if title.endswith("*"): | |
1169 | return | |
1170 | else: | |
1171 | title = title + "*" | |
1172 | self.SetTitle(title) | |
1173 | else: | |
1174 | if title.endswith("*"): | |
1175 | title = title[:-1] | |
1176 | self.SetTitle(title) | |
1177 | else: | |
1178 | return | |
1179 | ||
1180 | ||
3fa8f722 RD |
1181 | def ProcessEvent(event): |
1182 | """ | |
1183 | Processes an event, searching event tables and calling zero or more | |
1184 | suitable event handler function(s). Note that the ProcessEvent | |
1185 | method is called from the wxPython docview framework directly since | |
1186 | wxPython does not have a virtual ProcessEvent function. | |
1187 | """ | |
1188 | if self._activeEvent == event: | |
1189 | return False | |
1190 | ||
1191 | self._activeEvent = event # Break recursion loops | |
1192 | ||
1193 | if self._childView: | |
1194 | self._childView.Activate(True) | |
1195 | ||
1196 | if not self._childView or not self._childView.ProcessEvent(event): | |
1197 | if not isinstance(event, wx.CommandEvent) or not self.GetParent() or not self.GetParent().ProcessEvent(event): | |
1198 | ret = False | |
74b89458 | 1199 | else: |
3fa8f722 RD |
1200 | ret = True |
1201 | else: | |
1202 | ret = True | |
74b89458 | 1203 | |
3fa8f722 RD |
1204 | self._activeEvent = None |
1205 | return ret | |
1206 | ||
1207 | ||
1208 | def OnActivate(self, event): | |
1209 | """ | |
1210 | Sets the currently active view to be the frame's view. You may need to | |
1211 | override (but still call) this function in order to set the keyboard | |
1212 | focus for your subwindow. | |
1213 | """ | |
1214 | if self._activated != 0: | |
1215 | return True | |
1216 | self._activated += 1 | |
1217 | wx.MDIChildFrame.Activate(self) | |
1218 | if event.GetActive() and self._childView: | |
1219 | self._childView.Activate(event.GetActive()) | |
1220 | self._activated = 0 | |
1221 | ||
1222 | ||
1223 | def OnCloseWindow(self, event): | |
1224 | """ | |
1225 | Closes and deletes the current view and document. | |
1226 | """ | |
1227 | if self._childView: | |
1228 | ans = False | |
1229 | if not event.CanVeto(): | |
1230 | ans = True | |
74b89458 | 1231 | else: |
3fa8f722 RD |
1232 | ans = self._childView.Close(deleteWindow = False) |
1233 | ||
1234 | if ans: | |
1235 | self._childView.Activate(False) | |
1236 | self._childView.Destroy() | |
1237 | self._childView = None | |
1238 | if self._childDocument: | |
1239 | self._childDocument.Destroy() # This isn't in the wxWindows codebase but the document needs to be disposed of somehow | |
1240 | self._childDocument = None | |
1241 | self.Destroy() | |
1242 | else: | |
1243 | event.Veto() | |
1244 | else: | |
1245 | event.Veto() | |
1246 | ||
1247 | ||
1248 | def GetDocument(self): | |
1249 | """ | |
1250 | Returns the document associated with this frame. | |
1251 | """ | |
1252 | return self._childDocument | |
1253 | ||
1254 | ||
1255 | def SetDocument(self, document): | |
1256 | """ | |
1257 | Sets the document for this frame. | |
1258 | """ | |
1259 | self._childDocument = document | |
1260 | ||
1261 | ||
1262 | def GetView(self): | |
1263 | """ | |
1264 | Returns the view associated with this frame. | |
1265 | """ | |
1266 | return self._childView | |
74b89458 | 1267 | |
74b89458 | 1268 | |
3fa8f722 | 1269 | def SetView(self, view): |
74b89458 | 1270 | """ |
3fa8f722 | 1271 | Sets the view for this frame. |
74b89458 | 1272 | """ |
3fa8f722 RD |
1273 | self._childView = view |
1274 | ||
74b89458 | 1275 | |
3fa8f722 RD |
1276 | class DocService(wx.EvtHandler): |
1277 | """ | |
1278 | An abstract class used to add reusable services to a docview application. | |
1279 | """ | |
1280 | ||
1281 | ||
1282 | def __init__(self): | |
1283 | """Initializes the DocService.""" | |
2eeaec19 | 1284 | pass |
d1dc2b32 RD |
1285 | |
1286 | ||
1287 | def GetDocumentManager(self): | |
3fa8f722 | 1288 | """Returns the DocManager for the docview application.""" |
d1dc2b32 RD |
1289 | return self._docManager |
1290 | ||
1291 | ||
1292 | def SetDocumentManager(self, docManager): | |
3fa8f722 | 1293 | """Sets the DocManager for the docview application.""" |
d1dc2b32 | 1294 | self._docManager = docManager |
3fa8f722 RD |
1295 | |
1296 | ||
6f1a3f9c | 1297 | def InstallControls(self, frame, menuBar=None, toolBar=None, statusBar=None, document=None): |
3fa8f722 RD |
1298 | """Called to install controls into the menubar and toolbar of a SDI or MDI window. Override this method for a particular service.""" |
1299 | pass | |
d1dc2b32 RD |
1300 | |
1301 | ||
1302 | def ProcessEventBeforeWindows(self, event): | |
1303 | """ | |
aca310e5 | 1304 | Processes an event before the main window has a chance to process the window. |
3fa8f722 | 1305 | Override this method for a particular service. |
d1dc2b32 | 1306 | """ |
d1dc2b32 RD |
1307 | return False |
1308 | ||
1309 | ||
1310 | def ProcessUpdateUIEventBeforeWindows(self, event): | |
1311 | """ | |
3fa8f722 RD |
1312 | Processes a UI event before the main window has a chance to process the window. |
1313 | Override this method for a particular service. | |
d1dc2b32 | 1314 | """ |
d1dc2b32 RD |
1315 | return False |
1316 | ||
1317 | ||
1318 | def ProcessEvent(self, event): | |
1319 | """ | |
1320 | Processes an event, searching event tables and calling zero or more | |
1321 | suitable event handler function(s). Note that the ProcessEvent | |
1322 | method is called from the wxPython docview framework directly since | |
1323 | wxPython does not have a virtual ProcessEvent function. | |
1324 | """ | |
d1dc2b32 RD |
1325 | return False |
1326 | ||
1327 | ||
1328 | def ProcessUpdateUIEvent(self, event): | |
1329 | """ | |
1330 | Processes a UI event, searching event tables and calling zero or more | |
1331 | suitable event handler function(s). Note that the ProcessEvent | |
1332 | method is called from the wxPython docview framework directly since | |
1333 | wxPython does not have a virtual ProcessEvent function. | |
1334 | """ | |
d1dc2b32 RD |
1335 | return False |
1336 | ||
1337 | ||
3fa8f722 | 1338 | def OnCloseFrame(self, event): |
d1dc2b32 | 1339 | """ |
3fa8f722 RD |
1340 | Called when the a docview frame is being closed. Override this method |
1341 | so a service can either do cleanup or veto the frame being closed by | |
1342 | returning false. | |
d1dc2b32 | 1343 | """ |
3fa8f722 | 1344 | return True |
d1dc2b32 RD |
1345 | |
1346 | ||
3fa8f722 | 1347 | def OnExit(self): |
d1dc2b32 | 1348 | """ |
3fa8f722 RD |
1349 | Called when the the docview application is being closed. Override this method |
1350 | so a service can either do cleanup or veto the frame being closed by | |
1351 | returning false. | |
d1dc2b32 | 1352 | """ |
3fa8f722 | 1353 | pass |
d1dc2b32 RD |
1354 | |
1355 | ||
3fa8f722 | 1356 | def GetMenuItemPos(self, menu, id): |
d1dc2b32 | 1357 | """ |
3fa8f722 RD |
1358 | Utility method used to find the position of a menu item so that services can |
1359 | easily find where to insert a menu item in InstallControls. | |
1360 | """ | |
1361 | menuItems = menu.GetMenuItems() | |
1362 | for i, menuItem in enumerate(menuItems): | |
1363 | if menuItem.GetId() == id: | |
1364 | return i | |
1365 | return i | |
1366 | ||
1367 | ||
1368 | def GetView(self): | |
1369 | """ | |
1370 | Called by WindowMenuService to get views for services that don't | |
1371 | have dedicated documents such as the Outline Service. | |
d1dc2b32 | 1372 | """ |
d1dc2b32 RD |
1373 | return None |
1374 | ||
1375 | ||
3fa8f722 RD |
1376 | class DocOptionsService(DocService): |
1377 | """ | |
1378 | A service that implements an options menu item and an options dialog with | |
1379 | notebook tabs. New tabs can be added by other services by calling the | |
1380 | "AddOptionsPanel" method. | |
1381 | """ | |
1382 | ||
1383 | ||
6f1a3f9c | 1384 | def __init__(self, showGeneralOptions=True, supportedModes=wx.lib.docview.DOC_SDI & wx.lib.docview.DOC_MDI): |
d1dc2b32 | 1385 | """ |
3fa8f722 RD |
1386 | Initializes the options service with the option of suppressing the default |
1387 | general options pane that is included with the options service by setting | |
1388 | showGeneralOptions to False. It allowModeChanges is set to False, the | |
1389 | default general options pane will allow users to change the document | |
1390 | interface mode between SDI and MDI modes. | |
d1dc2b32 | 1391 | """ |
3fa8f722 RD |
1392 | DocService.__init__(self) |
1393 | self.ClearOptionsPanels() | |
6f1a3f9c | 1394 | self._supportedModes = supportedModes |
02b800ce | 1395 | self._toolOptionsID = wx.ID_PREFERENCES |
3fa8f722 RD |
1396 | if showGeneralOptions: |
1397 | self.AddOptionsPanel(GeneralOptionsPanel) | |
d1dc2b32 | 1398 | |
3fa8f722 | 1399 | |
6f1a3f9c | 1400 | def InstallControls(self, frame, menuBar=None, toolBar=None, statusBar=None, document=None): |
d1dc2b32 | 1401 | """ |
3fa8f722 | 1402 | Installs a "Tools" menu with an "Options" menu item. |
d1dc2b32 | 1403 | """ |
3fa8f722 RD |
1404 | toolsMenuIndex = menuBar.FindMenu(_("&Tools")) |
1405 | if toolsMenuIndex > -1: | |
1406 | toolsMenu = menuBar.GetMenu(toolsMenuIndex) | |
d1dc2b32 | 1407 | else: |
3fa8f722 RD |
1408 | toolsMenu = wx.Menu() |
1409 | if toolsMenuIndex == -1: | |
1410 | formatMenuIndex = menuBar.FindMenu(_("&Format")) | |
1411 | menuBar.Insert(formatMenuIndex + 1, toolsMenu, _("&Tools")) | |
1412 | if toolsMenu: | |
1413 | if toolsMenu.GetMenuItemCount(): | |
1414 | toolsMenu.AppendSeparator() | |
1415 | toolsMenu.Append(self._toolOptionsID, _("&Options..."), _("Sets options")) | |
1416 | wx.EVT_MENU(frame, self._toolOptionsID, frame.ProcessEvent) | |
aca310e5 | 1417 | |
d1dc2b32 | 1418 | |
3fa8f722 | 1419 | def ProcessEvent(self, event): |
d1dc2b32 | 1420 | """ |
3fa8f722 | 1421 | Checks to see if the "Options" menu item has been selected. |
d1dc2b32 | 1422 | """ |
3fa8f722 RD |
1423 | id = event.GetId() |
1424 | if id == self._toolOptionsID: | |
1425 | self.OnOptions(event) | |
1426 | return True | |
1427 | else: | |
1428 | return False | |
d1dc2b32 RD |
1429 | |
1430 | ||
6f1a3f9c | 1431 | def GetSupportedModes(self): |
d1dc2b32 | 1432 | """ |
6f1a3f9c RD |
1433 | Return the modes supported by the application. Use docview.DOC_SDI and |
1434 | docview.DOC_MDI flags to check if SDI and/or MDI modes are supported. | |
d1dc2b32 | 1435 | """ |
aca310e5 | 1436 | return self._supportedModes |
d1dc2b32 RD |
1437 | |
1438 | ||
6f1a3f9c | 1439 | def SetSupportedModes(self, _supportedModessupportedModes): |
d1dc2b32 | 1440 | """ |
6f1a3f9c RD |
1441 | Sets the modes supported by the application. Use docview.DOC_SDI and |
1442 | docview.DOC_MDI flags to set if SDI and/or MDI modes are supported. | |
d1dc2b32 | 1443 | """ |
6f1a3f9c | 1444 | self._supportedModes = supportedModes |
d1dc2b32 | 1445 | |
d1dc2b32 | 1446 | |
3fa8f722 RD |
1447 | def ClearOptionsPanels(self): |
1448 | """ | |
1449 | Clears all of the options panels that have been added into the | |
1450 | options dialog. | |
1451 | """ | |
1452 | self._optionsPanels = [] | |
d1dc2b32 RD |
1453 | |
1454 | ||
3fa8f722 | 1455 | def AddOptionsPanel(self, optionsPanel): |
d1dc2b32 | 1456 | """ |
aca310e5 | 1457 | Adds an options panel to the options dialog. |
d1dc2b32 | 1458 | """ |
3fa8f722 | 1459 | self._optionsPanels.append(optionsPanel) |
d1dc2b32 RD |
1460 | |
1461 | ||
3fa8f722 | 1462 | def OnOptions(self, event): |
d1dc2b32 | 1463 | """ |
3fa8f722 | 1464 | Shows the options dialog, called when the "Options" menu item is selected. |
d1dc2b32 | 1465 | """ |
3fa8f722 RD |
1466 | if len(self._optionsPanels) == 0: |
1467 | return | |
1468 | optionsDialog = OptionsDialog(wx.GetApp().GetTopWindow(), self._optionsPanels, self._docManager) | |
02b800ce | 1469 | optionsDialog.CenterOnParent() |
3fa8f722 RD |
1470 | if optionsDialog.ShowModal() == wx.ID_OK: |
1471 | optionsDialog.OnOK(optionsDialog) # wxBug: wxDialog should be calling this automatically but doesn't | |
1472 | optionsDialog.Destroy() | |
1473 | ||
1474 | ||
1475 | class OptionsDialog(wx.Dialog): | |
1476 | """ | |
1477 | A default options dialog used by the OptionsService that hosts a notebook | |
1478 | tab of options panels. | |
1479 | """ | |
d1dc2b32 | 1480 | |
d1dc2b32 | 1481 | |
3fa8f722 RD |
1482 | def __init__(self, parent, optionsPanelClasses, docManager): |
1483 | """ | |
1484 | Initializes the options dialog with a notebook page that contains new | |
1485 | instances of the passed optionsPanelClasses. | |
aca310e5 | 1486 | """ |
02b800ce | 1487 | wx.Dialog.__init__(self, parent, -1, _("Options")) |
d1dc2b32 | 1488 | |
3fa8f722 RD |
1489 | self._optionsPanels = [] |
1490 | self._docManager = docManager | |
1491 | ||
1492 | HALF_SPACE = 5 | |
1493 | SPACE = 10 | |
d1dc2b32 | 1494 | |
3fa8f722 | 1495 | sizer = wx.BoxSizer(wx.VERTICAL) |
d1dc2b32 | 1496 | |
02b800ce RD |
1497 | if wx.Platform == "__WXMAC__": |
1498 | optionsNotebook = wx.Listbook(self, wx.NewId(), style=wx.LB_DEFAULT) | |
1499 | else: | |
1500 | optionsNotebook = wx.Notebook(self, wx.NewId(), style=wx.NB_MULTILINE) # NB_MULTILINE is windows platform only | |
3fa8f722 | 1501 | sizer.Add(optionsNotebook, 0, wx.ALL | wx.EXPAND, SPACE) |
aca310e5 | 1502 | |
02b800ce RD |
1503 | if wx.Platform == "__WXMAC__": |
1504 | iconList = wx.ImageList(16, 16, initialCount = len(optionsPanelClasses)) | |
1505 | self._iconIndexLookup = [] | |
aca310e5 | 1506 | |
02b800ce RD |
1507 | for optionsPanelClass in optionsPanelClasses: |
1508 | optionsPanel = optionsPanelClass(optionsNotebook, -1) | |
1509 | self._optionsPanels.append(optionsPanel) | |
aca310e5 | 1510 | |
02b800ce RD |
1511 | # We need to populate the image list before setting notebook images |
1512 | if hasattr(optionsPanel, "GetIcon"): | |
1513 | icon = optionsPanel.GetIcon() | |
1514 | else: | |
1515 | icon = None | |
1516 | if icon: | |
1517 | if icon.GetHeight() != 16 or icon.GetWidth() != 16: | |
1518 | icon.SetHeight(16) | |
1519 | icon.SetWidth(16) | |
1520 | if wx.GetApp().GetDebug(): | |
1521 | print "Warning: icon for '%s' isn't 16x16, not crossplatform" % template._docTypeName | |
1522 | iconIndex = iconList.AddIcon(icon) | |
1523 | self._iconIndexLookup.append((optionsPanel, iconIndex)) | |
aca310e5 | 1524 | |
02b800ce RD |
1525 | else: |
1526 | # use -1 to represent that this panel has no icon | |
1527 | self._iconIndexLookup.append((optionsPanel, -1)) | |
aca310e5 | 1528 | |
02b800ce | 1529 | optionsNotebook.AssignImageList(iconList) |
aca310e5 | 1530 | |
02b800ce RD |
1531 | # Add icons to notebook |
1532 | for index in range(0, len(optionsPanelClasses)-1): | |
1533 | iconIndex = self._iconIndexLookup[index][1] | |
1534 | if iconIndex >= 0: | |
aca310e5 | 1535 | optionsNotebook.SetPageImage(index, iconIndex) |
02b800ce RD |
1536 | else: |
1537 | for optionsPanelClass in optionsPanelClasses: | |
1538 | optionsPanel = optionsPanelClass(optionsNotebook, -1) | |
1539 | self._optionsPanels.append(optionsPanel) | |
1540 | ||
3fa8f722 RD |
1541 | sizer.Add(self.CreateButtonSizer(wx.OK | wx.CANCEL), 0, wx.ALIGN_RIGHT | wx.RIGHT | wx.BOTTOM, HALF_SPACE) |
1542 | self.SetSizer(sizer) | |
1543 | self.Layout() | |
02b800ce | 1544 | self.Fit() |
3fa8f722 RD |
1545 | wx.CallAfter(self.DoRefresh) |
1546 | ||
1547 | ||
1548 | def DoRefresh(self): | |
d1dc2b32 | 1549 | """ |
3fa8f722 RD |
1550 | wxBug: On Windows XP when using a multiline notebook the default page doesn't get |
1551 | drawn, but it works when using a single line notebook. | |
d1dc2b32 | 1552 | """ |
3fa8f722 | 1553 | self.Refresh() |
d1dc2b32 RD |
1554 | |
1555 | ||
3fa8f722 | 1556 | def GetDocManager(self): |
d1dc2b32 | 1557 | """ |
3fa8f722 | 1558 | Returns the document manager passed to the OptionsDialog constructor. |
d1dc2b32 | 1559 | """ |
3fa8f722 | 1560 | return self._docManager |
d1dc2b32 RD |
1561 | |
1562 | ||
3fa8f722 | 1563 | def OnOK(self, event): |
d1dc2b32 | 1564 | """ |
3fa8f722 | 1565 | Calls the OnOK method of all of the OptionDialog's embedded panels |
d1dc2b32 | 1566 | """ |
3fa8f722 RD |
1567 | for optionsPanel in self._optionsPanels: |
1568 | optionsPanel.OnOK(event) | |
d1dc2b32 | 1569 | |
d1dc2b32 | 1570 | |
3fa8f722 RD |
1571 | class GeneralOptionsPanel(wx.Panel): |
1572 | """ | |
1573 | A general options panel that is used in the OptionDialog to configure the | |
1574 | generic properties of a pydocview application, such as "show tips at startup" | |
1575 | and whether to use SDI or MDI for the application. | |
1576 | """ | |
d1dc2b32 RD |
1577 | |
1578 | ||
3fa8f722 | 1579 | def __init__(self, parent, id): |
d1dc2b32 | 1580 | """ |
3fa8f722 | 1581 | Initializes the panel by adding an "Options" folder tab to the parent notebook and |
aca310e5 | 1582 | populating the panel with the generic properties of a pydocview application. |
d1dc2b32 | 1583 | """ |
3fa8f722 RD |
1584 | wx.Panel.__init__(self, parent, id) |
1585 | SPACE = 10 | |
1586 | HALF_SPACE = 5 | |
1587 | config = wx.ConfigBase_Get() | |
1588 | self._showTipsCheckBox = wx.CheckBox(self, -1, _("Show tips at start up")) | |
1589 | self._showTipsCheckBox.SetValue(config.ReadInt("ShowTipAtStartup", True)) | |
6f1a3f9c RD |
1590 | if self._AllowModeChanges(): |
1591 | supportedModes = wx.GetApp().GetService(DocOptionsService).GetSupportedModes() | |
1592 | choices = [] | |
1593 | self._sdiChoice = _("Show each document in its own window") | |
1594 | self._mdiChoice = _("Show all documents in a single window with tabs") | |
1595 | self._winMdiChoice = _("Show all documents in a single window with child windows") | |
1596 | if supportedModes & wx.lib.docview.DOC_SDI: | |
1597 | choices.append(self._sdiChoice) | |
1598 | choices.append(self._mdiChoice) | |
3fa8f722 | 1599 | if wx.Platform == "__WXMSW__": |
6f1a3f9c | 1600 | choices.append(self._winMdiChoice) |
aca310e5 | 1601 | self._documentRadioBox = wx.RadioBox(self, -1, _("Document Display Style"), |
3fa8f722 RD |
1602 | choices = choices, |
1603 | majorDimension=1, | |
1604 | ) | |
1605 | if config.ReadInt("UseWinMDI", False): | |
6f1a3f9c | 1606 | self._documentRadioBox.SetStringSelection(self._winMdiChoice) |
3fa8f722 | 1607 | elif config.ReadInt("UseMDI", True): |
6f1a3f9c | 1608 | self._documentRadioBox.SetStringSelection(self._mdiChoice) |
3fa8f722 | 1609 | else: |
6f1a3f9c | 1610 | self._documentRadioBox.SetStringSelection(self._sdiChoice) |
3fa8f722 RD |
1611 | def OnDocumentInterfaceSelect(event): |
1612 | if not self._documentInterfaceMessageShown: | |
1613 | msgTitle = wx.GetApp().GetAppName() | |
1614 | if not msgTitle: | |
1615 | msgTitle = _("Document Options") | |
2eeaec19 | 1616 | wx.MessageBox(_("Document interface changes will not appear until the application is restarted."), |
3fa8f722 RD |
1617 | msgTitle, |
1618 | wx.OK | wx.ICON_INFORMATION, | |
1619 | self.GetParent()) | |
1620 | self._documentInterfaceMessageShown = True | |
1621 | wx.EVT_RADIOBOX(self, self._documentRadioBox.GetId(), OnDocumentInterfaceSelect) | |
1622 | optionsBorderSizer = wx.BoxSizer(wx.VERTICAL) | |
1623 | optionsSizer = wx.BoxSizer(wx.VERTICAL) | |
6f1a3f9c | 1624 | if self._AllowModeChanges(): |
3fa8f722 RD |
1625 | optionsSizer.Add(self._documentRadioBox, 0, wx.ALL, HALF_SPACE) |
1626 | optionsSizer.Add(self._showTipsCheckBox, 0, wx.ALL, HALF_SPACE) | |
1627 | optionsBorderSizer.Add(optionsSizer, 0, wx.ALL, SPACE) | |
1628 | self.SetSizer(optionsBorderSizer) | |
1629 | self.Layout() | |
1630 | self._documentInterfaceMessageShown = False | |
aca310e5 | 1631 | parent.AddPage(self, _("General")) |
d1dc2b32 RD |
1632 | |
1633 | ||
6f1a3f9c RD |
1634 | def _AllowModeChanges(self): |
1635 | supportedModes = wx.GetApp().GetService(DocOptionsService).GetSupportedModes() | |
1636 | return supportedModes & wx.lib.docview.DOC_SDI and supportedModes & wx.lib.docview.DOC_MDI or wx.Platform == "__WXMSW__" and supportedModes & wx.lib.docview.DOC_MDI # More than one mode is supported, allow selection | |
1637 | ||
1638 | ||
3fa8f722 | 1639 | def OnOK(self, optionsDialog): |
d1dc2b32 | 1640 | """ |
3fa8f722 | 1641 | Updates the config based on the selections in the options panel. |
d1dc2b32 | 1642 | """ |
3fa8f722 RD |
1643 | config = wx.ConfigBase_Get() |
1644 | config.WriteInt("ShowTipAtStartup", self._showTipsCheckBox.GetValue()) | |
6f1a3f9c RD |
1645 | if self._AllowModeChanges(): |
1646 | config.WriteInt("UseMDI", (self._documentRadioBox.GetStringSelection() == self._mdiChoice)) | |
1647 | config.WriteInt("UseWinMDI", (self._documentRadioBox.GetStringSelection() == self._winMdiChoice)) | |
d1dc2b32 RD |
1648 | |
1649 | ||
02b800ce RD |
1650 | def GetIcon(self): |
1651 | """ Return icon for options panel on the Mac. """ | |
1652 | return wx.GetApp().GetDefaultIcon() | |
1653 | ||
1654 | ||
3fa8f722 RD |
1655 | class DocApp(wx.PySimpleApp): |
1656 | """ | |
1657 | The DocApp class serves as the base class for pydocview applications and offers | |
1658 | functionality such as services, creation of SDI and MDI frames, show tips, | |
1659 | and a splash screen. | |
1660 | """ | |
1661 | ||
1662 | ||
1663 | def OnInit(self): | |
d1dc2b32 | 1664 | """ |
3fa8f722 | 1665 | Initializes the DocApp. |
d1dc2b32 | 1666 | """ |
3fa8f722 RD |
1667 | self._services = [] |
1668 | self._defaultIcon = None | |
1669 | self._registeredCloseEvent = False | |
1670 | self._useTabbedMDI = True | |
1671 | ||
1672 | if not hasattr(self, "_debug"): # only set if not already initialized | |
1673 | self._debug = False | |
1674 | if not hasattr(self, "_singleInstance"): # only set if not already initialized | |
1675 | self._singleInstance = True | |
aca310e5 | 1676 | |
3fa8f722 RD |
1677 | # if _singleInstance is TRUE only allow one single instance of app to run. |
1678 | # When user tries to run a second instance of the app, abort startup, | |
1679 | # But if user also specifies files to open in command line, send message to running app to open those files | |
1680 | if self._singleInstance: | |
1681 | # create shared memory temporary file | |
1682 | if wx.Platform == '__WXMSW__': | |
1683 | tfile = tempfile.TemporaryFile(prefix="ag", suffix="tmp") | |
1684 | fno = tfile.fileno() | |
1685 | self._sharedMemory = mmap.mmap(fno, 1024, "shared_memory") | |
1686 | else: | |
1687 | tfile = file(os.path.join(tempfile.gettempdir(), tempfile.gettempprefix() + self.GetAppName() + '-' + wx.GetUserId() + "AGSharedMemory"), 'w+b') | |
1688 | tfile.write("*") | |
1689 | tfile.seek(1024) | |
1690 | tfile.write(" ") | |
1691 | tfile.flush() | |
1692 | fno = tfile.fileno() | |
1693 | self._sharedMemory = mmap.mmap(fno, 1024) | |
1694 | ||
1695 | self._singleInstanceChecker = wx.SingleInstanceChecker(self.GetAppName() + '-' + wx.GetUserId(), tempfile.gettempdir()) | |
1696 | if self._singleInstanceChecker.IsAnotherRunning(): | |
1697 | # have running single instance open file arguments | |
1698 | data = pickle.dumps(sys.argv[1:]) | |
1699 | while 1: | |
1700 | self._sharedMemory.seek(0) | |
1701 | marker = self._sharedMemory.read_byte() | |
1702 | if marker == '\0' or marker == '*': # available buffer | |
1703 | self._sharedMemory.seek(0) | |
1704 | self._sharedMemory.write_byte('-') # set writing marker | |
1705 | self._sharedMemory.write(data) # write files we tried to open to shared memory | |
1706 | self._sharedMemory.seek(0) | |
1707 | self._sharedMemory.write_byte('+') # set finished writing marker | |
1708 | self._sharedMemory.flush() | |
1709 | break | |
1710 | else: | |
1711 | time.sleep(1) # give enough time for buffer to be available | |
aca310e5 | 1712 | |
3fa8f722 RD |
1713 | return False |
1714 | else: | |
1715 | self._timer = wx.PyTimer(self.DoBackgroundListenAndLoad) | |
1716 | self._timer.Start(250) | |
1717 | ||
1718 | return True | |
aca310e5 | 1719 | |
d1dc2b32 | 1720 | |
3fa8f722 RD |
1721 | def OpenMainFrame(self): |
1722 | docManager = self.GetDocumentManager() | |
1723 | if docManager.GetFlags() & wx.lib.docview.DOC_MDI: | |
1724 | if self.GetUseTabbedMDI(): | |
1725 | frame = wx.lib.pydocview.DocTabbedParentFrame(docManager, None, -1, self.GetAppName()) | |
1726 | else: | |
aca310e5 | 1727 | frame = wx.lib.pydocview.DocMDIParentFrame(docManager, None, -1, self.GetAppName()) |
3fa8f722 | 1728 | frame.Show(True) |
d1dc2b32 | 1729 | |
02b800ce RD |
1730 | def MacOpenFile(self, filename): |
1731 | self.GetDocumentManager().CreateDocument(os.path.normpath(filename), wx.lib.docview.DOC_SILENT) | |
aca310e5 | 1732 | |
02b800ce RD |
1733 | # force display of running app |
1734 | topWindow = wx.GetApp().GetTopWindow() | |
1735 | if topWindow.IsIconized(): | |
1736 | topWindow.Iconize(False) | |
1737 | else: | |
1738 | topWindow.Raise() | |
aca310e5 | 1739 | |
3fa8f722 | 1740 | def DoBackgroundListenAndLoad(self): |
d1dc2b32 | 1741 | """ |
3fa8f722 | 1742 | Open any files specified in the given command line argument passed in via shared memory |
d1dc2b32 | 1743 | """ |
3fa8f722 RD |
1744 | self._timer.Stop() |
1745 | ||
1746 | self._sharedMemory.seek(0) | |
1747 | if self._sharedMemory.read_byte() == '+': # available data | |
1748 | data = self._sharedMemory.read(1024-1) | |
1749 | self._sharedMemory.seek(0) | |
1750 | self._sharedMemory.write_byte("*") # finished reading, set buffer free marker | |
1751 | self._sharedMemory.flush() | |
1752 | args = pickle.loads(data) | |
1753 | for arg in args: | |
02b800ce | 1754 | if (wx.Platform != "__WXMSW__" or arg[0] != "/") and arg[0] != '-' and os.path.exists(arg): |
26ee3a06 | 1755 | self.GetDocumentManager().CreateDocument(os.path.normpath(arg), wx.lib.docview.DOC_SILENT) |
aca310e5 | 1756 | |
3fa8f722 RD |
1757 | # force display of running app |
1758 | topWindow = wx.GetApp().GetTopWindow() | |
1759 | if topWindow.IsIconized(): | |
1760 | topWindow.Iconize(False) | |
1761 | else: | |
1762 | topWindow.Raise() | |
aca310e5 RD |
1763 | |
1764 | ||
3fa8f722 | 1765 | self._timer.Start(1000) # 1 second interval |
d1dc2b32 RD |
1766 | |
1767 | ||
3fa8f722 | 1768 | def OpenCommandLineArgs(self): |
74b89458 | 1769 | """ |
3fa8f722 RD |
1770 | Called to open files that have been passed to the application from the |
1771 | command line. | |
74b89458 | 1772 | """ |
3fa8f722 RD |
1773 | args = sys.argv[1:] |
1774 | for arg in args: | |
02b800ce | 1775 | if (wx.Platform != "__WXMSW__" or arg[0] != "/") and arg[0] != '-' and os.path.exists(arg): |
26ee3a06 | 1776 | self.GetDocumentManager().CreateDocument(os.path.normpath(arg), wx.lib.docview.DOC_SILENT) |
74b89458 RD |
1777 | |
1778 | ||
3fa8f722 | 1779 | def GetDocumentManager(self): |
74b89458 | 1780 | """ |
3fa8f722 | 1781 | Returns the document manager associated to the DocApp. |
74b89458 | 1782 | """ |
3fa8f722 | 1783 | return self._docManager |
74b89458 RD |
1784 | |
1785 | ||
3fa8f722 | 1786 | def SetDocumentManager(self, docManager): |
d1dc2b32 | 1787 | """ |
3fa8f722 RD |
1788 | Sets the document manager associated with the DocApp and loads the |
1789 | DocApp's file history into the document manager. | |
d1dc2b32 | 1790 | """ |
3fa8f722 RD |
1791 | self._docManager = docManager |
1792 | config = wx.ConfigBase_Get() | |
1793 | self.GetDocumentManager().FileHistoryLoad(config) | |
d1dc2b32 RD |
1794 | |
1795 | ||
3fa8f722 | 1796 | def ProcessEventBeforeWindows(self, event): |
d1dc2b32 | 1797 | """ |
3fa8f722 | 1798 | Enables services to process an event before the main window has a chance to |
aca310e5 | 1799 | process the window. |
d1dc2b32 | 1800 | """ |
3fa8f722 RD |
1801 | for service in self._services: |
1802 | if service.ProcessEventBeforeWindows(event): | |
1803 | return True | |
1804 | return False | |
d1dc2b32 RD |
1805 | |
1806 | ||
3fa8f722 | 1807 | def ProcessUpdateUIEventBeforeWindows(self, event): |
d1dc2b32 | 1808 | """ |
3fa8f722 RD |
1809 | Enables services to process a UI event before the main window has a chance |
1810 | to process the window. | |
d1dc2b32 | 1811 | """ |
3fa8f722 RD |
1812 | for service in self._services: |
1813 | if service.ProcessUpdateUIEventBeforeWindows(event): | |
1814 | return True | |
1815 | return False | |
d1dc2b32 RD |
1816 | |
1817 | ||
3fa8f722 | 1818 | def ProcessEvent(self, event): |
d1dc2b32 | 1819 | """ |
3fa8f722 RD |
1820 | Processes an event, searching event tables and calling zero or more |
1821 | suitable event handler function(s). Note that the ProcessEvent | |
1822 | method is called from the wxPython docview framework directly since | |
1823 | wxPython does not have a virtual ProcessEvent function. | |
d1dc2b32 | 1824 | """ |
3fa8f722 RD |
1825 | for service in self._services: |
1826 | if service.ProcessEvent(event): | |
1827 | return True | |
1828 | return False | |
d1dc2b32 RD |
1829 | |
1830 | ||
3fa8f722 | 1831 | def ProcessUpdateUIEvent(self, event): |
d1dc2b32 | 1832 | """ |
3fa8f722 RD |
1833 | Processes a UI event, searching event tables and calling zero or more |
1834 | suitable event handler function(s). Note that the ProcessEvent | |
1835 | method is called from the wxPython docview framework directly since | |
1836 | wxPython does not have a virtual ProcessEvent function. | |
d1dc2b32 | 1837 | """ |
3fa8f722 RD |
1838 | for service in self._services: |
1839 | if service.ProcessUpdateUIEvent(event): | |
1840 | return True | |
1841 | return False | |
d1dc2b32 RD |
1842 | |
1843 | ||
3fa8f722 | 1844 | def InstallService(self, service): |
d1dc2b32 | 1845 | """ |
3fa8f722 | 1846 | Installs an instance of a DocService into the DocApp. |
d1dc2b32 | 1847 | """ |
3fa8f722 RD |
1848 | service.SetDocumentManager(self._docManager) |
1849 | self._services.append(service) | |
1850 | return service | |
d1dc2b32 | 1851 | |
3fa8f722 RD |
1852 | |
1853 | def GetServices(self): | |
d1dc2b32 | 1854 | """ |
3fa8f722 | 1855 | Returns the DocService instances that have been installed into the DocApp. |
d1dc2b32 | 1856 | """ |
3fa8f722 | 1857 | return self._services |
d1dc2b32 RD |
1858 | |
1859 | ||
3fa8f722 | 1860 | def GetService(self, type): |
d1dc2b32 | 1861 | """ |
3fa8f722 RD |
1862 | Returns the instance of a particular type of service that has been installed |
1863 | into the DocApp. For example, "wx.GetApp().GetService(pydocview.OptionsService)" | |
1864 | returns the isntance of the OptionsService that is running within the DocApp. | |
d1dc2b32 | 1865 | """ |
3fa8f722 RD |
1866 | for service in self._services: |
1867 | if isinstance(service, type): | |
1868 | return service | |
1869 | return None | |
d1dc2b32 | 1870 | |
d1dc2b32 | 1871 | |
3fa8f722 | 1872 | def OnExit(self): |
d1dc2b32 | 1873 | """ |
3fa8f722 RD |
1874 | Called when the DocApp is exited, enables the installed DocServices to exit |
1875 | and saves the DocManager's file history. | |
d1dc2b32 | 1876 | """ |
3fa8f722 RD |
1877 | for service in self._services: |
1878 | service.OnExit() | |
d1dc2b32 | 1879 | config = wx.ConfigBase_Get() |
3fa8f722 | 1880 | self._docManager.FileHistorySave(config) |
aca310e5 | 1881 | |
3fa8f722 RD |
1882 | if hasattr(self, "_singleInstanceChecker"): |
1883 | del self._singleInstanceChecker | |
d1dc2b32 | 1884 | |
aca310e5 | 1885 | |
3fa8f722 | 1886 | def GetDefaultDocManagerFlags(self): |
d1dc2b32 | 1887 | """ |
3fa8f722 | 1888 | Returns the default flags to use when creating the DocManager. |
d1dc2b32 | 1889 | """ |
d1dc2b32 | 1890 | config = wx.ConfigBase_Get() |
3fa8f722 RD |
1891 | if config.ReadInt("UseMDI", True) or config.ReadInt("UseWinMDI", False): |
1892 | flags = wx.lib.docview.DOC_MDI | wx.lib.docview.DOC_OPEN_ONCE | |
1893 | if config.ReadInt("UseWinMDI", False): | |
1894 | self.SetUseTabbedMDI(False) | |
d1dc2b32 | 1895 | else: |
3fa8f722 RD |
1896 | flags = wx.lib.docview.DOC_SDI | wx.lib.docview.DOC_OPEN_ONCE |
1897 | return flags | |
d1dc2b32 RD |
1898 | |
1899 | ||
3fa8f722 | 1900 | def ShowTip(self, frame, tipProvider): |
d1dc2b32 | 1901 | """ |
3fa8f722 RD |
1902 | Shows the tip window, generally this is called when an application starts. |
1903 | A wx.TipProvider must be passed. | |
d1dc2b32 RD |
1904 | """ |
1905 | config = wx.ConfigBase_Get() | |
3fa8f722 RD |
1906 | showTip = config.ReadInt("ShowTipAtStartup", 1) |
1907 | if showTip: | |
1908 | index = config.ReadInt("TipIndex", 0) | |
1909 | showTipResult = wx.ShowTip(wx.GetApp().GetTopWindow(), tipProvider, showAtStartup = showTip) | |
1910 | if showTipResult != showTip: | |
1911 | config.WriteInt("ShowTipAtStartup", showTipResult) | |
d1dc2b32 RD |
1912 | |
1913 | ||
3fa8f722 | 1914 | def GetEditMenu(self, frame): |
d1dc2b32 | 1915 | """ |
3fa8f722 RD |
1916 | Utility method that finds the Edit menu within the menubar of a frame. |
1917 | """ | |
1918 | menuBar = frame.GetMenuBar() | |
1919 | if not menuBar: | |
1920 | return None | |
1921 | editMenuIndex = menuBar.FindMenu(_("&Edit")) | |
1922 | if editMenuIndex == -1: | |
1923 | return None | |
1924 | return menuBar.GetMenu(editMenuIndex) | |
d1dc2b32 RD |
1925 | |
1926 | ||
3fa8f722 | 1927 | def GetUseTabbedMDI(self): |
d1dc2b32 | 1928 | """ |
3fa8f722 | 1929 | Returns True if Windows MDI should use folder tabs instead of child windows. |
d1dc2b32 | 1930 | """ |
3fa8f722 | 1931 | return self._useTabbedMDI |
aca310e5 | 1932 | |
d1dc2b32 | 1933 | |
3fa8f722 | 1934 | def SetUseTabbedMDI(self, useTabbedMDI): |
d1dc2b32 | 1935 | """ |
3fa8f722 | 1936 | Set to True if Windows MDI should use folder tabs instead of child windows. |
d1dc2b32 | 1937 | """ |
3fa8f722 | 1938 | self._useTabbedMDI = useTabbedMDI |
d1dc2b32 RD |
1939 | |
1940 | ||
3fa8f722 | 1941 | def CreateDocumentFrame(self, view, doc, flags, id = -1, title = "", pos = wx.DefaultPosition, size = wx.DefaultSize, style = wx.DEFAULT_FRAME_STYLE): |
d1dc2b32 | 1942 | """ |
aca310e5 | 1943 | Called by the DocManager to create and return a new Frame for a Document. |
3fa8f722 RD |
1944 | Chooses whether to create an MDIChildFrame or SDI Frame based on the |
1945 | DocManager's flags. | |
d1dc2b32 | 1946 | """ |
3fa8f722 RD |
1947 | docflags = self.GetDocumentManager().GetFlags() |
1948 | if docflags & wx.lib.docview.DOC_SDI: | |
1949 | frame = self.CreateSDIDocumentFrame(doc, view, id, title, pos, size, style) | |
1950 | frame.Show() | |
d1dc2b32 | 1951 | |
3fa8f722 RD |
1952 | # wxBug: operating system bug, first window is set to the position of last window closed, ignoring passed in position on frame creation |
1953 | # also, initial size is incorrect for the same reasons | |
1954 | if frame.GetPosition() != pos: | |
1955 | frame.Move(pos) | |
1956 | if frame.GetSize() != size: | |
1957 | frame.SetSize(size) | |
d1dc2b32 | 1958 | |
3fa8f722 RD |
1959 | if doc and doc.GetCommandProcessor(): |
1960 | doc.GetCommandProcessor().SetEditMenu(self.GetEditMenu(frame)) | |
1961 | elif docflags & wx.lib.docview.DOC_MDI: | |
1962 | if self.GetUseTabbedMDI(): | |
1963 | frame = self.CreateTabbedDocumentFrame(doc, view, id, title, pos, size, style) | |
1964 | else: | |
1965 | frame = self.CreateMDIDocumentFrame(doc, view, id, title, pos, size, style) | |
1966 | if doc: | |
1967 | if doc.GetDocumentTemplate().GetIcon(): | |
1968 | frame.SetIcon(doc.GetDocumentTemplate().GetIcon()) | |
1969 | elif wx.GetApp().GetTopWindow().GetIcon(): | |
1970 | frame.SetIcon(wx.GetApp().GetTopWindow().GetIcon()) | |
1971 | if doc and doc.GetCommandProcessor(): | |
1972 | doc.GetCommandProcessor().SetEditMenu(self.GetEditMenu(wx.GetApp().GetTopWindow())) | |
1973 | if not frame.GetIcon() and self._defaultIcon: | |
1974 | frame.SetIcon(self.GetDefaultIcon()) | |
1975 | view.SetFrame(frame) | |
1976 | return frame | |
1977 | ||
1978 | ||
6f1a3f9c | 1979 | def CreateSDIDocumentFrame(self, doc, view, id=-1, title="", pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE): |
d1dc2b32 | 1980 | """ |
3fa8f722 | 1981 | Creates and returns an SDI Document Frame. |
d1dc2b32 | 1982 | """ |
3fa8f722 RD |
1983 | frame = DocSDIFrame(doc, view, None, id, title, pos, size, style) |
1984 | return frame | |
d1dc2b32 RD |
1985 | |
1986 | ||
6f1a3f9c | 1987 | def CreateTabbedDocumentFrame(self, doc, view, id=-1, title="", pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE): |
d1dc2b32 | 1988 | """ |
3fa8f722 | 1989 | Creates and returns an MDI Document Frame for a Tabbed MDI view |
d1dc2b32 | 1990 | """ |
3fa8f722 RD |
1991 | frame = DocTabbedChildFrame(doc, view, wx.GetApp().GetTopWindow(), id, title, pos, size, style) |
1992 | return frame | |
d1dc2b32 RD |
1993 | |
1994 | ||
6f1a3f9c | 1995 | def CreateMDIDocumentFrame(self, doc, view, id=-1, title="", pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE): |
d1dc2b32 | 1996 | """ |
3fa8f722 | 1997 | Creates and returns an MDI Document Frame. |
d1dc2b32 | 1998 | """ |
3fa8f722 RD |
1999 | # if any child windows are maximized, then user must want any new children maximized |
2000 | # if no children exist, then use the default value from registry | |
2001 | # wxBug: Only current window is maximized, so need to check every child frame | |
2002 | parentFrame = wx.GetApp().GetTopWindow() | |
2003 | childrenMaximized = filter(lambda child: isinstance(child, wx.MDIChildFrame) and child.IsMaximized(), parentFrame.GetChildren()) | |
2004 | if childrenMaximized: | |
2005 | maximize = True | |
2006 | else: | |
2007 | children = filter(lambda child: isinstance(child, wx.MDIChildFrame), parentFrame.GetChildren()) | |
2008 | if children: | |
2009 | # other windows exist and none are maximized | |
2010 | maximize = False | |
2011 | else: | |
2012 | # get default setting from registry | |
2013 | maximize = wx.ConfigBase_Get().ReadInt("MDIChildFrameMaximized", False) | |
2014 | ||
2015 | frame = wx.lib.docview.DocMDIChildFrame(doc, view, wx.GetApp().GetTopWindow(), id, title, pos, size, style) | |
2016 | if maximize: # wxBug: Should already be maximizing new child frames if one is maximized but it's not so we have to force it to | |
2017 | frame.Maximize(True) | |
d1dc2b32 | 2018 | |
3fa8f722 RD |
2019 | ## wx.EVT_MAXIMIZE(frame, self.OnMaximize) # wxBug: This doesn't work, need to save MDIChildFrameMaximized state on close of windows instead |
2020 | wx.EVT_CLOSE(frame, self.OnCloseChildWindow) | |
2021 | if not self._registeredCloseEvent: | |
2022 | wx.EVT_CLOSE(parentFrame, self.OnCloseMainWindow) # need to check on this, but only once | |
2023 | self._registeredCloseEvent = True | |
d1dc2b32 | 2024 | |
3fa8f722 RD |
2025 | return frame |
2026 | ||
2027 | ||
2028 | def SaveMDIDocumentFrameMaximizedState(self, maximized): | |
d1dc2b32 | 2029 | """ |
3fa8f722 RD |
2030 | Remember in the config whether the MDI Frame is maximized so that it can be restored |
2031 | on open. | |
d1dc2b32 | 2032 | """ |
3fa8f722 RD |
2033 | config = wx.ConfigBase_Get() |
2034 | maximizeFlag = config.ReadInt("MDIChildFrameMaximized", False) | |
2035 | if maximized != maximizeFlag: | |
2036 | config.WriteInt("MDIChildFrameMaximized", maximized) | |
d1dc2b32 RD |
2037 | |
2038 | ||
3fa8f722 | 2039 | def OnCloseChildWindow(self, event): |
d1dc2b32 | 2040 | """ |
3fa8f722 RD |
2041 | Called when an MDI Child Frame is closed. Calls SaveMDIDocumentFrameMaximizedState to |
2042 | remember whether the MDI Frame is maximized so that it can be restored on open. | |
d1dc2b32 | 2043 | """ |
3fa8f722 RD |
2044 | self.SaveMDIDocumentFrameMaximizedState(event.GetEventObject().IsMaximized()) |
2045 | event.Skip() | |
d1dc2b32 | 2046 | |
3fa8f722 RD |
2047 | |
2048 | def OnCloseMainWindow(self, event): | |
2049 | """ | |
2050 | Called when the MDI Parent Frame is closed. Remembers whether the MDI Parent Frame is | |
2051 | maximized. | |
2052 | """ | |
2053 | children = event.GetEventObject().GetChildren() | |
2054 | childrenMaximized = filter(lambda child: isinstance(child, wx.MDIChildFrame)and child.IsMaximized(), children) | |
2055 | if childrenMaximized: | |
2056 | self.SaveMDIDocumentFrameMaximizedState(True) | |
d1dc2b32 | 2057 | else: |
3fa8f722 RD |
2058 | childrenNotMaximized = filter(lambda child: isinstance(child, wx.MDIChildFrame), children) |
2059 | ||
2060 | if childrenNotMaximized: | |
2061 | # other windows exist and none are maximized | |
2062 | self.SaveMDIDocumentFrameMaximizedState(False) | |
2063 | ||
2064 | event.Skip() | |
d1dc2b32 | 2065 | |
d1dc2b32 | 2066 | |
3fa8f722 RD |
2067 | def GetDefaultIcon(self): |
2068 | """ | |
2069 | Returns the application's default icon. | |
2070 | """ | |
2071 | return self._defaultIcon | |
d1dc2b32 | 2072 | |
d1dc2b32 | 2073 | |
3fa8f722 RD |
2074 | def SetDefaultIcon(self, icon): |
2075 | """ | |
2076 | Sets the application's default icon. | |
2077 | """ | |
2078 | self._defaultIcon = icon | |
d1dc2b32 | 2079 | |
d1dc2b32 | 2080 | |
3fa8f722 RD |
2081 | def GetDebug(self): |
2082 | """ | |
2083 | Returns True if the application is in debug mode. | |
2084 | """ | |
2085 | return self._debug | |
d1dc2b32 RD |
2086 | |
2087 | ||
3fa8f722 | 2088 | def SetDebug(self, debug): |
d1dc2b32 | 2089 | """ |
3fa8f722 | 2090 | Sets the application's debug mode. |
d1dc2b32 | 2091 | """ |
3fa8f722 | 2092 | self._debug = debug |
d1dc2b32 RD |
2093 | |
2094 | ||
3fa8f722 | 2095 | def GetSingleInstance(self): |
d1dc2b32 | 2096 | """ |
3fa8f722 | 2097 | Returns True if the application is in single instance mode. Used to determine if multiple instances of the application is allowed to launch. |
d1dc2b32 | 2098 | """ |
3fa8f722 RD |
2099 | return self._singleInstance |
2100 | ||
2101 | ||
2102 | def SetSingleInstance(self, singleInstance): | |
2103 | """ | |
2104 | Sets application's single instance mode. | |
2105 | """ | |
2106 | self._singleInstance = singleInstance | |
2107 | ||
2108 | ||
2109 | ||
6f1a3f9c | 2110 | def CreateChildDocument(self, parentDocument, documentType, objectToEdit, path=''): |
3fa8f722 RD |
2111 | """ |
2112 | Creates a child window of a document that edits an object. The child window | |
2113 | is managed by the parent document frame, so it will be prompted to close if its | |
aca310e5 | 2114 | parent is closed, etc. Child Documents are useful when there are complicated |
3fa8f722 RD |
2115 | Views of a Document and users will need to tunnel into the View. |
2116 | """ | |
2117 | for document in self.GetDocumentManager().GetDocuments()[:]: # Cloning list to make sure we go through all docs even as they are deleted | |
2118 | if isinstance(document, ChildDocument) and document.GetParentDocument() == parentDocument: | |
2119 | if document.GetData() == objectToEdit: | |
2120 | if hasattr(document.GetFirstView().GetFrame(), "SetFocus"): | |
2121 | document.GetFirstView().GetFrame().SetFocus() | |
2122 | return document | |
2123 | for temp in wx.GetApp().GetDocumentManager().GetTemplates(): | |
2124 | if temp.GetDocumentType() == documentType: | |
2125 | break | |
2126 | temp = None | |
2127 | newDoc = temp.CreateDocument(path, 0, data = objectToEdit, parentDocument = parentDocument) | |
2128 | newDoc.SetDocumentName(temp.GetDocumentName()) | |
2129 | newDoc.SetDocumentTemplate(temp) | |
2130 | if path == '': | |
2131 | newDoc.OnNewDocument() | |
d1dc2b32 | 2132 | else: |
3fa8f722 RD |
2133 | if not newDoc.OnOpenDocument(path): |
2134 | newDoc.DeleteAllViews() # Implicitly deleted by DeleteAllViews | |
2135 | return None | |
2136 | return newDoc | |
d1dc2b32 RD |
2137 | |
2138 | ||
3fa8f722 | 2139 | def CloseChildDocuments(self, parentDocument): |
d1dc2b32 | 2140 | """ |
3fa8f722 | 2141 | Closes the child windows of a Document. |
d1dc2b32 | 2142 | """ |
3fa8f722 RD |
2143 | for document in self.GetDocumentManager().GetDocuments()[:]: # Cloning list to make sure we go through all docs even as they are deleted |
2144 | if isinstance(document, ChildDocument) and document.GetParentDocument() == parentDocument: | |
2145 | if document.GetFirstView().GetFrame(): | |
2146 | document.GetFirstView().GetFrame().SetFocus() | |
2eeaec19 | 2147 | if not document.GetFirstView().OnClose(): |
3fa8f722 RD |
2148 | return False |
2149 | return True | |
d1dc2b32 | 2150 | |
3fa8f722 RD |
2151 | |
2152 | def IsMDI(self): | |
2153 | """ | |
2154 | Returns True if the application is in MDI mode. | |
2155 | """ | |
2156 | return self.GetDocumentManager().GetFlags() & wx.lib.docview.DOC_MDI | |
d1dc2b32 RD |
2157 | |
2158 | ||
3fa8f722 | 2159 | def IsSDI(self): |
d1dc2b32 | 2160 | """ |
3fa8f722 | 2161 | Returns True if the application is in SDI mode. |
d1dc2b32 | 2162 | """ |
3fa8f722 | 2163 | return self.GetDocumentManager().GetFlags() & wx.lib.docview.DOC_SDI |
d1dc2b32 | 2164 | |
3fa8f722 RD |
2165 | |
2166 | def ShowSplash(self, image): | |
d1dc2b32 | 2167 | """ |
3fa8f722 | 2168 | Shows a splash window with the given image. Input parameter 'image' can either be a wx.Bitmap or a filename. |
d1dc2b32 | 2169 | """ |
3fa8f722 RD |
2170 | if isinstance(image, wx.Bitmap): |
2171 | splash_bmp = image | |
2172 | else: | |
2173 | splash_bmp = wx.Image(image).ConvertToBitmap() | |
aca310e5 | 2174 | self._splash = wx.SplashScreen(splash_bmp, wx.SPLASH_CENTRE_ON_SCREEN|wx.SPLASH_NO_TIMEOUT, 0, None, -1, style=wx.SIMPLE_BORDER|wx.FRAME_NO_TASKBAR) |
3fa8f722 | 2175 | self._splash.Show() |
d1dc2b32 | 2176 | |
d1dc2b32 | 2177 | |
3fa8f722 RD |
2178 | def CloseSplash(self): |
2179 | """ | |
2180 | Closes the splash window. | |
2181 | """ | |
2182 | if self._splash: | |
2183 | self._splash.Close(True) | |
aca310e5 RD |
2184 | |
2185 | ||
3fa8f722 RD |
2186 | class _DocFrameFileDropTarget(wx.FileDropTarget): |
2187 | """ | |
2188 | Class used to handle drops into the document frame. | |
2189 | """ | |
d1dc2b32 | 2190 | |
3fa8f722 RD |
2191 | def __init__(self, docManager, docFrame): |
2192 | """ | |
2193 | Initializes the FileDropTarget class with the active docManager and the docFrame. | |
2194 | """ | |
2195 | wx.FileDropTarget.__init__(self) | |
2196 | self._docManager = docManager | |
2197 | self._docFrame = docFrame | |
d1dc2b32 RD |
2198 | |
2199 | ||
3fa8f722 | 2200 | def OnDropFiles(self, x, y, filenames): |
d1dc2b32 | 2201 | """ |
3fa8f722 RD |
2202 | Called when files are dropped in the drop target and tells the docManager to open |
2203 | the files. | |
d1dc2b32 | 2204 | """ |
3fa8f722 RD |
2205 | try: |
2206 | for file in filenames: | |
2207 | self._docManager.CreateDocument(file, wx.lib.docview.DOC_SILENT) | |
2208 | except: | |
2209 | msgTitle = wx.GetApp().GetAppName() | |
2210 | if not msgTitle: | |
2211 | msgTitle = _("File Error") | |
aca310e5 | 2212 | wx.MessageBox("Could not open '%s'. '%s'" % (wx.lib.docview.FileNameFromPath(file), sys.exc_value), |
3fa8f722 RD |
2213 | msgTitle, |
2214 | wx.OK | wx.ICON_EXCLAMATION, | |
2215 | self._docManager.FindSuitableParent()) | |
d1dc2b32 RD |
2216 | |
2217 | ||
3fa8f722 RD |
2218 | class DocMDIParentFrame(wx.lib.docview.DocMDIParentFrame, DocFrameMixIn, DocMDIParentFrameMixIn): |
2219 | """ | |
2220 | The DocMDIParentFrame is the primary frame which the DocApp uses to host MDI child windows. It offers | |
2221 | features such as a default menubar, toolbar, and status bar, and a mechanism to manage embedded windows | |
2222 | on the edges of the DocMDIParentFrame. | |
2223 | """ | |
3fa8f722 | 2224 | |
aca310e5 RD |
2225 | |
2226 | def __init__(self, docManager, parent, id, title, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE, name="DocMDIFrame", embeddedWindows=0, minSize=20): | |
d1dc2b32 | 2227 | """ |
3fa8f722 RD |
2228 | Initializes the DocMDIParentFrame with the default menubar, toolbar, and status bar. Use the |
2229 | optional embeddedWindows parameter with the embedded window constants to create embedded | |
2230 | windows around the edges of the DocMDIParentFrame. | |
2231 | """ | |
2232 | pos, size = self._GetPosSizeFromConfig(pos, size) | |
2233 | wx.lib.docview.DocMDIParentFrame.__init__(self, docManager, parent, id, title, pos, size, style, name) | |
aca310e5 | 2234 | self._InitFrame(embeddedWindows, minSize) |
3fa8f722 RD |
2235 | |
2236 | ||
2237 | def _LayoutFrame(self): | |
2238 | """ | |
2239 | Lays out the frame. | |
d1dc2b32 | 2240 | """ |
d1dc2b32 RD |
2241 | wx.LayoutAlgorithm().LayoutMDIFrame(self) |
2242 | self.GetClientWindow().Refresh() | |
aca310e5 | 2243 | |
3fa8f722 RD |
2244 | |
2245 | def ProcessEvent(self, event): | |
2246 | """ | |
2247 | Processes an event, searching event tables and calling zero or more | |
2248 | suitable event handler function(s). Note that the ProcessEvent | |
2249 | method is called from the wxPython docview framework directly since | |
2250 | wxPython does not have a virtual ProcessEvent function. | |
2251 | """ | |
2252 | if wx.GetApp().ProcessEventBeforeWindows(event): | |
2253 | return True | |
2254 | if wx.lib.docview.DocMDIParentFrame.ProcessEvent(self, event): | |
2255 | return True | |
2256 | return DocMDIParentFrameMixIn.ProcessEvent(self, event) | |
d1dc2b32 RD |
2257 | |
2258 | ||
3fa8f722 | 2259 | def ProcessUpdateUIEvent(self, event): |
d1dc2b32 | 2260 | """ |
3fa8f722 RD |
2261 | Processes a UI event, searching event tables and calling zero or more |
2262 | suitable event handler function(s). Note that the ProcessEvent | |
2263 | method is called from the wxPython docview framework directly since | |
2264 | wxPython does not have a virtual ProcessEvent function. | |
d1dc2b32 | 2265 | """ |
3fa8f722 RD |
2266 | if wx.GetApp().ProcessUpdateUIEventBeforeWindows(event): |
2267 | return True | |
2268 | if wx.lib.docview.DocMDIParentFrame.ProcessUpdateUIEvent(self, event): # Let the views handle the event before the services | |
2269 | return True | |
2270 | if event.GetId() == wx.ID_ABOUT: # Using ID_ABOUT to update the window menu, the window menu items are not triggering | |
2271 | self.UpdateWindowMenu() | |
2272 | return True | |
2273 | return DocMDIParentFrameMixIn.ProcessUpdateUIEvent(self, event) | |
d1dc2b32 RD |
2274 | |
2275 | ||
3fa8f722 | 2276 | def UpdateWindowMenu(self): |
d1dc2b32 | 2277 | """ |
3fa8f722 | 2278 | Updates the WindowMenu on Windows platforms. |
d1dc2b32 | 2279 | """ |
3fa8f722 RD |
2280 | if wx.Platform == '__WXMSW__': |
2281 | children = filter(lambda child: isinstance(child, wx.MDIChildFrame), self.GetChildren()) | |
2282 | windowCount = len(children) | |
2283 | hasWindow = windowCount >= 1 | |
2284 | has2OrMoreWindows = windowCount >= 2 | |
2285 | ||
2286 | windowMenu = self.GetWindowMenu() | |
2287 | if windowMenu: | |
2288 | windowMenu.Enable(wx.IDM_WINDOWTILE, hasWindow) | |
2289 | windowMenu.Enable(wx.IDM_WINDOWTILEHOR, hasWindow) | |
2290 | windowMenu.Enable(wx.IDM_WINDOWCASCADE, hasWindow) | |
2291 | windowMenu.Enable(wx.IDM_WINDOWICONS, hasWindow) | |
2292 | windowMenu.Enable(wx.IDM_WINDOWTILEVERT, hasWindow) | |
2293 | wx.IDM_WINDOWPREV = 4006 # wxBug: Not defined for some reason | |
2294 | windowMenu.Enable(wx.IDM_WINDOWPREV, has2OrMoreWindows) | |
2295 | windowMenu.Enable(wx.IDM_WINDOWNEXT, has2OrMoreWindows) | |
aca310e5 | 2296 | |
d1dc2b32 RD |
2297 | |
2298 | ||
3fa8f722 | 2299 | def OnSize(self, event): |
d1dc2b32 | 2300 | """ |
3fa8f722 | 2301 | Called when the DocMDIParentFrame is resized and lays out the MDI client window. |
d1dc2b32 | 2302 | """ |
3fa8f722 RD |
2303 | # Needed in case there are splitpanels around the mdi frame |
2304 | self._LayoutFrame() | |
d1dc2b32 RD |
2305 | |
2306 | ||
3fa8f722 | 2307 | def OnCloseWindow(self, event): |
d1dc2b32 | 2308 | """ |
3fa8f722 | 2309 | Called when the DocMDIParentFrame is closed. Remembers the frame size. |
d1dc2b32 | 2310 | """ |
3fa8f722 | 2311 | self.SaveEmbeddedWindowSizes() |
d1dc2b32 | 2312 | |
3fa8f722 RD |
2313 | # save and close services last. |
2314 | for service in wx.GetApp().GetServices(): | |
2315 | if not service.OnCloseFrame(event): | |
2316 | return | |
d1dc2b32 | 2317 | |
3fa8f722 RD |
2318 | # save and close documents |
2319 | # documents with a common view, e.g. project view, should save the document, but not close the window | |
2320 | # and let the service close the window. | |
2321 | wx.lib.docview.DocMDIParentFrame.OnCloseWindow(self, event) | |
d1dc2b32 RD |
2322 | |
2323 | ||
3fa8f722 | 2324 | class DocSDIFrame(wx.lib.docview.DocChildFrame, DocFrameMixIn): |
d1dc2b32 RD |
2325 | """ |
2326 | The DocSDIFrame host DocManager Document windows. It offers features such as a default menubar, | |
2327 | toolbar, and status bar. | |
2328 | """ | |
aca310e5 | 2329 | |
d1dc2b32 | 2330 | |
6f1a3f9c | 2331 | def __init__(self, doc, view, parent, id, title, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE, name="DocSDIFrame"): |
d1dc2b32 RD |
2332 | """ |
2333 | Initializes the DocSDIFrame with the default menubar, toolbar, and status bar. | |
2334 | """ | |
2335 | wx.lib.docview.DocChildFrame.__init__(self, doc, view, parent, id, title, pos, size, style, name) | |
2336 | self._fileMenu = None | |
2337 | if doc: | |
2338 | self._docManager = doc.GetDocumentManager() | |
2339 | else: | |
2340 | self._docManager = None | |
2341 | self.SetDropTarget(_DocFrameFileDropTarget(self._docManager, self)) | |
2342 | ||
2343 | wx.EVT_MENU(self, wx.ID_ABOUT, self.OnAbout) | |
2344 | wx.EVT_MENU(self, wx.ID_EXIT, self.OnExit) | |
2345 | wx.EVT_MENU_RANGE(self, wx.ID_FILE1, wx.ID_FILE9, self.OnMRUFile) | |
2346 | ||
2347 | self.InitializePrintData() | |
2348 | ||
3fa8f722 | 2349 | menuBar = self.CreateDefaultMenuBar(sdi=True) |
d1dc2b32 RD |
2350 | toolBar = self.CreateDefaultToolBar() |
2351 | self.SetToolBar(toolBar) | |
2352 | statusBar = self.CreateDefaultStatusBar() | |
2353 | ||
2354 | for service in wx.GetApp().GetServices(): | |
2355 | service.InstallControls(self, menuBar = menuBar, toolBar = toolBar, statusBar = statusBar, document = doc) | |
2356 | ||
2357 | self.SetMenuBar(menuBar) # wxBug: Need to do this in SDI to mimic MDI... because have to set the menubar at the very end or the automatic MDI "window" menu doesn't get put in the right place when the services add new menus to the menubar | |
2358 | ||
2359 | ||
3fa8f722 | 2360 | def _LayoutFrame(self): |
d1dc2b32 | 2361 | """ |
3fa8f722 | 2362 | Lays out the Frame. |
d1dc2b32 | 2363 | """ |
3fa8f722 | 2364 | self.Layout() |
aca310e5 | 2365 | |
d1dc2b32 RD |
2366 | |
2367 | def OnExit(self, event): | |
2368 | """ | |
2369 | Called when the application is exitting. | |
2370 | """ | |
2371 | if self._childView.GetDocumentManager().Clear(force = False): | |
2372 | self.Destroy() | |
2373 | else: | |
2374 | event.Veto() | |
2375 | ||
2376 | ||
2377 | def OnMRUFile(self, event): | |
2378 | """ | |
2379 | Opens the appropriate file when it is selected from the file history | |
2380 | menu. | |
2381 | """ | |
2382 | n = event.GetId() - wx.ID_FILE1 | |
2383 | filename = self._docManager.GetHistoryFile(n) | |
2384 | if filename: | |
2385 | self._docManager.CreateDocument(filename, wx.lib.docview.DOC_SILENT) | |
2386 | else: | |
2387 | self._docManager.RemoveFileFromHistory(n) | |
2388 | msgTitle = wx.GetApp().GetAppName() | |
2389 | if not msgTitle: | |
2390 | msgTitle = _("File Error") | |
2391 | wx.MessageBox("The file '%s' doesn't exist and couldn't be opened.\nIt has been removed from the most recently used files list" % docview.FileNameFromPath(file), | |
2392 | msgTitle, | |
2393 | wx.OK | wx.ICON_EXCLAMATION, | |
2394 | self) | |
2395 | ||
2396 | ||
d1dc2b32 RD |
2397 | def ProcessEvent(self, event): |
2398 | """ | |
2399 | Processes an event, searching event tables and calling zero or more | |
2400 | suitable event handler function(s). Note that the ProcessEvent | |
2401 | method is called from the wxPython docview framework directly since | |
2402 | wxPython does not have a virtual ProcessEvent function. | |
2403 | """ | |
2404 | if wx.GetApp().ProcessEventBeforeWindows(event): | |
2405 | return True | |
2406 | if self._childView: | |
2407 | self._childView.Activate(True) | |
2408 | ||
2409 | id = event.GetId() | |
2410 | if id == SAVEALL_ID: | |
2411 | self.OnFileSaveAll(event) | |
2412 | return True | |
2413 | ||
2414 | if hasattr(self._childView, "GetDocumentManager") and self._childView.GetDocumentManager().ProcessEvent(event): # Need to call docmanager here since super class relies on DocParentFrame which we are not using | |
2415 | return True | |
2416 | else: | |
2417 | return wx.GetApp().ProcessEvent(event) | |
2418 | ||
2419 | ||
2420 | def ProcessUpdateUIEvent(self, event): | |
2421 | """ | |
2422 | Processes a UI event, searching event tables and calling zero or more | |
2423 | suitable event handler function(s). Note that the ProcessEvent | |
2424 | method is called from the wxPython docview framework directly since | |
2425 | wxPython does not have a virtual ProcessEvent function. | |
2426 | """ | |
2427 | if wx.GetApp().ProcessUpdateUIEventBeforeWindows(event): | |
2428 | return True | |
2429 | if self._childView: | |
2430 | if hasattr(self._childView, "GetDocumentManager"): | |
2431 | docMgr = self._childView.GetDocumentManager() | |
2432 | if docMgr: | |
2433 | if docMgr.GetCurrentDocument() != self._childView.GetDocument(): | |
2434 | return False | |
2435 | if docMgr.ProcessUpdateUIEvent(event): # Let the views handle the event before the services | |
2436 | return True | |
2437 | id = event.GetId() | |
2438 | if id == wx.ID_CUT: | |
2439 | event.Enable(False) | |
2440 | return True | |
2441 | elif id == wx.ID_COPY: | |
2442 | event.Enable(False) | |
2443 | return True | |
2444 | elif id == wx.ID_PASTE: | |
2445 | event.Enable(False) | |
2446 | return True | |
2447 | elif id == wx.ID_CLEAR: | |
2448 | event.Enable(False) | |
2449 | return True | |
2450 | elif id == wx.ID_SELECTALL: | |
2451 | event.Enable(False) | |
2452 | return True | |
2453 | elif id == SAVEALL_ID: | |
2454 | filesModified = False | |
2455 | docs = wx.GetApp().GetDocumentManager().GetDocuments() | |
2456 | for doc in docs: | |
2457 | if doc.IsModified(): | |
2458 | filesModified = True | |
2459 | break | |
aca310e5 | 2460 | |
d1dc2b32 RD |
2461 | event.Enable(filesModified) |
2462 | return True | |
2463 | else: | |
2464 | return wx.GetApp().ProcessUpdateUIEvent(event) | |
2465 | ||
2466 | ||
d1dc2b32 RD |
2467 | def OnCloseWindow(self, event): |
2468 | """ | |
2469 | Called when the window is saved. Enables services to help close the frame. | |
2470 | """ | |
2471 | for service in wx.GetApp().GetServices(): | |
2472 | service.OnCloseFrame(event) | |
2473 | wx.lib.docview.DocChildFrame.OnCloseWindow(self, event) | |
2474 | if self._fileMenu and self._docManager: | |
2475 | self._docManager.FileHistoryRemoveMenu(self._fileMenu) | |
2476 | ||
2477 | ||
74b89458 RD |
2478 | class AboutService(DocService): |
2479 | """ | |
2480 | About Dialog Service that installs under the Help menu to show the properties of the current application. | |
2481 | """ | |
2482 | ||
3fa8f722 | 2483 | def __init__(self, aboutDialog=None, image=None): |
74b89458 RD |
2484 | """ |
2485 | Initializes the AboutService. | |
2486 | """ | |
2487 | if aboutDialog: | |
2488 | self._dlg = aboutDialog | |
3fa8f722 | 2489 | self._image = None |
74b89458 RD |
2490 | else: |
2491 | self._dlg = AboutDialog # use default AboutDialog | |
3fa8f722 | 2492 | self._image = image |
aca310e5 | 2493 | |
74b89458 RD |
2494 | |
2495 | def ShowAbout(self): | |
2496 | """ | |
2497 | Show the AboutDialog | |
2498 | """ | |
3fa8f722 RD |
2499 | if self._image: |
2500 | dlg = self._dlg(wx.GetApp().GetTopWindow(), self._image) | |
2501 | else: | |
2502 | dlg = self._dlg(wx.GetApp().GetTopWindow()) | |
02b800ce | 2503 | dlg.CenterOnParent() |
74b89458 RD |
2504 | dlg.ShowModal() |
2505 | dlg.Destroy() | |
2506 | ||
2507 | ||
2508 | def SetAboutDialog(self, dlg): | |
2509 | """ | |
2510 | Customize the AboutDialog | |
2511 | """ | |
2512 | self._dlg = dlg | |
2513 | ||
2514 | ||
2515 | class AboutDialog(wx.Dialog): | |
2516 | """ | |
2517 | Opens an AboutDialog. Shared by DocMDIParentFrame and DocSDIFrame. | |
2518 | """ | |
aca310e5 | 2519 | |
3fa8f722 | 2520 | def __init__(self, parent, image=None): |
74b89458 RD |
2521 | """ |
2522 | Initializes the about dialog. | |
2523 | """ | |
2524 | wx.Dialog.__init__(self, parent, -1, _("About ") + wx.GetApp().GetAppName(), style = wx.DEFAULT_DIALOG_STYLE) | |
2525 | ||
74b89458 | 2526 | sizer = wx.BoxSizer(wx.VERTICAL) |
3fa8f722 RD |
2527 | if image: |
2528 | imageItem = wx.StaticBitmap(self, -1, image.ConvertToBitmap(), (0,0), (image.GetWidth(), image.GetHeight())) | |
2529 | sizer.Add(imageItem, 0, wx.ALIGN_CENTER|wx.ALL, 0) | |
2530 | sizer.Add(wx.StaticText(self, -1, wx.GetApp().GetAppName()), 0, wx.ALIGN_CENTRE|wx.ALL, 5) | |
aca310e5 | 2531 | |
74b89458 RD |
2532 | btn = wx.Button(self, wx.ID_OK) |
2533 | sizer.Add(btn, 0, wx.ALIGN_CENTRE|wx.ALL, 5) | |
aca310e5 | 2534 | |
74b89458 | 2535 | self.SetSizer(sizer) |
74b89458 | 2536 | sizer.Fit(self) |
aca310e5 | 2537 | |
74b89458 RD |
2538 | |
2539 | ||
d1dc2b32 RD |
2540 | class FilePropertiesService(DocService): |
2541 | """ | |
74b89458 | 2542 | Service that installs under the File menu to show the properties of the file associated |
d1dc2b32 RD |
2543 | with the current document. |
2544 | """ | |
2545 | ||
2546 | PROPERTIES_ID = wx.NewId() | |
2547 | ||
2548 | ||
2549 | def __init__(self): | |
2550 | """ | |
2551 | Initializes the PropertyService. | |
2552 | """ | |
2553 | self._customEventHandlers = [] | |
2554 | ||
2555 | ||
6f1a3f9c | 2556 | def InstallControls(self, frame, menuBar=None, toolBar=None, statusBar=None, document=None): |
d1dc2b32 RD |
2557 | """ |
2558 | Installs a File/Properties menu item. | |
2559 | """ | |
2560 | fileMenu = menuBar.GetMenu(menuBar.FindMenu(_("&File"))) | |
2561 | exitMenuItemPos = self.GetMenuItemPos(fileMenu, wx.ID_EXIT) | |
2562 | fileMenu.InsertSeparator(exitMenuItemPos) | |
2563 | fileMenu.Insert(exitMenuItemPos, FilePropertiesService.PROPERTIES_ID, _("&Properties"), _("Show file properties")) | |
2564 | wx.EVT_MENU(frame, FilePropertiesService.PROPERTIES_ID, self.ProcessEvent) | |
2565 | wx.EVT_UPDATE_UI(frame, FilePropertiesService.PROPERTIES_ID, self.ProcessUpdateUIEvent) | |
2566 | ||
2567 | ||
2568 | def ProcessEvent(self, event): | |
2569 | """ | |
2570 | Detects when the File/Properties menu item is selected. | |
2571 | """ | |
2572 | id = event.GetId() | |
2573 | if id == FilePropertiesService.PROPERTIES_ID: | |
2574 | for eventHandler in self._customEventHandlers: | |
2575 | if eventHandler.ProcessEvent(event): | |
2576 | return True | |
2577 | ||
2578 | self.ShowPropertiesDialog() | |
2579 | return True | |
2580 | else: | |
2581 | return False | |
2582 | ||
2583 | ||
2584 | def ProcessUpdateUIEvent(self, event): | |
2585 | """ | |
2586 | Updates the File/Properties menu item. | |
2587 | """ | |
2588 | id = event.GetId() | |
2589 | if id == FilePropertiesService.PROPERTIES_ID: | |
2590 | for eventHandler in self._customEventHandlers: | |
2591 | if eventHandler.ProcessUpdateUIEvent(event): | |
2592 | return True | |
2593 | ||
2594 | event.Enable(wx.GetApp().GetDocumentManager().GetCurrentDocument() != None) | |
2595 | return True | |
2596 | else: | |
2597 | return False | |
2598 | ||
2599 | ||
6f1a3f9c | 2600 | def ShowPropertiesDialog(self, filename=None): |
d1dc2b32 RD |
2601 | """ |
2602 | Shows the PropertiesDialog for the specified file. | |
2603 | """ | |
2604 | if not filename: | |
2605 | filename = wx.GetApp().GetDocumentManager().GetCurrentDocument().GetFilename() | |
2606 | ||
2607 | filePropertiesDialog = FilePropertiesDialog(wx.GetApp().GetTopWindow(), filename) | |
02b800ce | 2608 | filePropertiesDialog.CenterOnParent() |
d1dc2b32 RD |
2609 | if filePropertiesDialog.ShowModal() == wx.ID_OK: |
2610 | pass # Handle OK | |
2611 | filePropertiesDialog.Destroy() | |
2612 | ||
2613 | ||
2614 | def GetCustomEventHandlers(self): | |
2615 | """ | |
2616 | Returns the custom event handlers for the PropertyService. | |
2617 | """ | |
2618 | return self._customEventHandlers | |
2619 | ||
2620 | ||
2621 | def AddCustomEventHandler(self, handler): | |
2622 | """ | |
2623 | Adds a custom event handlers for the PropertyService. A custom event handler enables | |
2624 | a different dialog to be provided for a particular file. | |
2625 | """ | |
2626 | self._customEventHandlers.append(handler) | |
2627 | ||
2628 | ||
2629 | def RemoveCustomEventHandler(self, handler): | |
2630 | """ | |
2631 | Removes a custom event handler from the PropertyService. | |
2632 | """ | |
2633 | self._customEventHandlers.remove(handler) | |
2634 | ||
2635 | ||
6f1a3f9c | 2636 | def chopPath(self, text, length=36): |
d1dc2b32 RD |
2637 | """ |
2638 | Simple version of textwrap. textwrap.fill() unfortunately chops lines at spaces | |
2639 | and creates odd word boundaries. Instead, we will chop the path without regard to | |
2640 | spaces, but pay attention to path delimiters. | |
2641 | """ | |
74b89458 | 2642 | chopped = "" |
d1dc2b32 RD |
2643 | textLen = len(text) |
2644 | start = 0 | |
2645 | ||
2646 | while start < textLen: | |
2647 | end = start + length | |
2648 | if end > textLen: | |
2649 | end = textLen | |
2650 | ||
2651 | # see if we can find a delimiter to chop the path | |
2652 | if end < textLen: | |
2653 | lastSep = text.rfind(os.sep, start, end + 1) | |
2654 | if lastSep != -1 and lastSep != start: | |
2655 | end = lastSep | |
2656 | ||
74b89458 | 2657 | if len(chopped): |
d1dc2b32 RD |
2658 | chopped = chopped + '\n' + text[start:end] |
2659 | else: | |
2660 | chopped = text[start:end] | |
2661 | ||
2662 | start = end | |
2663 | ||
2664 | return chopped | |
2665 | ||
2666 | ||
2667 | class FilePropertiesDialog(wx.Dialog): | |
2668 | """ | |
2669 | Dialog that shows the properties of a file. Invoked by the PropertiesService. | |
2670 | """ | |
2671 | ||
2672 | ||
2673 | def __init__(self, parent, filename): | |
2674 | """ | |
2675 | Initializes the properties dialog. | |
2676 | """ | |
6f1a3f9c | 2677 | wx.Dialog.__init__(self, parent, -1, _("File Properties"), size=(310, 330)) |
d1dc2b32 RD |
2678 | |
2679 | HALF_SPACE = 5 | |
2680 | SPACE = 10 | |
2681 | ||
2682 | filePropertiesService = wx.GetApp().GetService(FilePropertiesService) | |
2683 | ||
74b89458 RD |
2684 | fileExists = os.path.exists(filename) |
2685 | ||
d1dc2b32 RD |
2686 | notebook = wx.Notebook(self, -1) |
2687 | tab = wx.Panel(notebook, -1) | |
2688 | ||
2689 | gridSizer = RowColSizer() | |
2690 | ||
2691 | gridSizer.Add(wx.StaticText(tab, -1, _("Filename:")), flag=wx.RIGHT, border=HALF_SPACE, row=0, col=0) | |
2692 | gridSizer.Add(wx.StaticText(tab, -1, os.path.basename(filename)), row=0, col=1) | |
2693 | ||
2694 | gridSizer.Add(wx.StaticText(tab, -1, _("Location:")), flag=wx.RIGHT, border=HALF_SPACE, row=1, col=0) | |
2695 | gridSizer.Add(wx.StaticText(tab, -1, filePropertiesService.chopPath(os.path.dirname(filename))), flag=wx.BOTTOM, border=SPACE, row=1, col=1) | |
2696 | ||
2697 | gridSizer.Add(wx.StaticText(tab, -1, _("Size:")), flag=wx.RIGHT, border=HALF_SPACE, row=2, col=0) | |
74b89458 RD |
2698 | if fileExists: |
2699 | gridSizer.Add(wx.StaticText(tab, -1, str(os.path.getsize(filename)) + ' ' + _("bytes")), row=2, col=1) | |
d1dc2b32 RD |
2700 | |
2701 | lineSizer = wx.BoxSizer(wx.VERTICAL) # let the line expand horizontally without vertical expansion | |
2702 | lineSizer.Add(wx.StaticLine(tab, -1, size = (10,-1)), 0, wx.EXPAND) | |
2703 | gridSizer.Add(lineSizer, flag=wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.TOP, border=HALF_SPACE, row=3, col=0, colspan=2) | |
2704 | ||
2705 | gridSizer.Add(wx.StaticText(tab, -1, _("Created:")), flag=wx.RIGHT, border=HALF_SPACE, row=4, col=0) | |
74b89458 RD |
2706 | if fileExists: |
2707 | gridSizer.Add(wx.StaticText(tab, -1, time.ctime(os.path.getctime(filename))), row=4, col=1) | |
d1dc2b32 RD |
2708 | |
2709 | gridSizer.Add(wx.StaticText(tab, -1, _("Modified:")), flag=wx.RIGHT, border=HALF_SPACE, row=5, col=0) | |
74b89458 RD |
2710 | if fileExists: |
2711 | gridSizer.Add(wx.StaticText(tab, -1, time.ctime(os.path.getmtime(filename))), row=5, col=1) | |
d1dc2b32 RD |
2712 | |
2713 | gridSizer.Add(wx.StaticText(tab, -1, _("Accessed:")), flag=wx.RIGHT, border=HALF_SPACE, row=6, col=0) | |
74b89458 RD |
2714 | if fileExists: |
2715 | gridSizer.Add(wx.StaticText(tab, -1, time.ctime(os.path.getatime(filename))), row=6, col=1) | |
d1dc2b32 RD |
2716 | |
2717 | # add a border around the inside of the tab | |
2718 | spacerGrid = wx.BoxSizer(wx.VERTICAL) | |
2719 | spacerGrid.Add(gridSizer, 0, wx.ALL, SPACE); | |
2720 | tab.SetSizer(spacerGrid) | |
2721 | notebook.AddPage(tab, _("General")) | |
d1dc2b32 RD |
2722 | |
2723 | sizer = wx.BoxSizer(wx.VERTICAL) | |
2724 | sizer.Add(notebook, 0, wx.ALL | wx.EXPAND, SPACE) | |
2725 | sizer.Add(self.CreateButtonSizer(wx.OK), 0, wx.ALIGN_RIGHT | wx.RIGHT | wx.BOTTOM, HALF_SPACE) | |
2726 | ||
2727 | sizer.Fit(self) | |
2728 | self.SetDimensions(-1, -1, 310, -1, wx.SIZE_USE_EXISTING) | |
2729 | self.SetSizer(sizer) | |
2730 | self.Layout() | |
2731 | ||
2732 | ||
2733 | class ChildDocument(wx.lib.docview.Document): | |
2734 | """ | |
2735 | A ChildDocument is a document that represents a portion of a Document. The child | |
2736 | document is managed by the parent document, so it will be prompted to close if its | |
aca310e5 | 2737 | parent is closed, etc. Child Documents are useful when there are complicated |
d1dc2b32 RD |
2738 | Views of a Document and users will need to tunnel into the View. |
2739 | """ | |
2740 | ||
2741 | ||
2742 | def GetData(self): | |
2743 | """ | |
2744 | Returns the data that the ChildDocument contains. | |
2745 | """ | |
2746 | return self._data | |
2747 | ||
2748 | ||
2749 | def SetData(self, data): | |
2750 | """ | |
2751 | Sets the data that the ChildDocument contains. | |
2752 | """ | |
2753 | self._data = data | |
2754 | ||
2755 | ||
2756 | def GetParentDocument(self): | |
2757 | """ | |
2758 | Returns the parent Document of the ChildDocument. | |
2759 | """ | |
2760 | return self._parentDocument | |
2761 | ||
2762 | ||
2763 | def SetParentDocument(self, parentDocument): | |
2764 | """ | |
2765 | Sets the parent Document of the ChildDocument. | |
aca310e5 | 2766 | """ |
d1dc2b32 RD |
2767 | self._parentDocument = parentDocument |
2768 | ||
2769 | ||
2770 | def OnSaveDocument(self, filename): | |
2771 | """ | |
2772 | Called when the ChildDocument is saved and does the minimum such that the | |
2773 | ChildDocument looks like a real Document to the framework. | |
2774 | """ | |
2775 | self.SetFilename(filename, True) | |
2776 | self.Modify(False) | |
2777 | self.SetDocumentSaved(True) | |
2778 | return True | |
2779 | ||
2780 | ||
2781 | def OnOpenDocument(self, filename): | |
2782 | """ | |
2783 | Called when the ChildDocument is opened and does the minimum such that the | |
2784 | ChildDocument looks like a real Document to the framework. | |
2785 | """ | |
2786 | self.SetFilename(filename, True) | |
2787 | self.Modify(False) | |
2788 | self.SetDocumentSaved(True) | |
2789 | self.UpdateAllViews() | |
2790 | return True | |
2791 | ||
2792 | ||
3fa8f722 RD |
2793 | def Save(self): |
2794 | """ | |
2795 | Called when the ChildDocument is saved and does the minimum such that the | |
2796 | ChildDocument looks like a real Document to the framework. | |
2797 | """ | |
2798 | return self.OnSaveDocument(self._documentFile) | |
2799 | ||
2800 | ||
2801 | def SaveAs(self): | |
2802 | """ | |
2803 | Called when the ChildDocument is saved and does the minimum such that the | |
2804 | ChildDocument looks like a real Document to the framework. | |
2805 | """ | |
aca310e5 | 2806 | return self.OnSaveDocument(self._documentFile) |
3fa8f722 RD |
2807 | |
2808 | ||
d1dc2b32 RD |
2809 | class ChildDocTemplate(wx.lib.docview.DocTemplate): |
2810 | """ | |
2811 | A ChildDocTemplate is a DocTemplate subclass that enables the creation of ChildDocuments | |
2812 | that represents a portion of a Document. The child document is managed by the parent document, | |
2813 | so it will be prompted to close if its parent is closed, etc. Child Documents are useful | |
2814 | when there are complicated Views of a Document and users will need to tunnel into the View. | |
aca310e5 | 2815 | """ |
d1dc2b32 RD |
2816 | |
2817 | ||
6f1a3f9c | 2818 | def __init__(self, manager, description, filter, dir, ext, docTypeName, viewTypeName, docType, viewType, flags=wx.lib.docview.TEMPLATE_INVISIBLE, icon=None): |
d1dc2b32 RD |
2819 | """ |
2820 | Initializes the ChildDocTemplate. | |
2821 | """ | |
6f1a3f9c | 2822 | wx.lib.docview.DocTemplate.__init__(self, manager, description, filter, dir, ext, docTypeName, viewTypeName, docType, viewType, flags=flags, icon=icon) |
d1dc2b32 RD |
2823 | |
2824 | ||
6f1a3f9c | 2825 | def CreateDocument(self, path, flags, data=None, parentDocument=None): |
d1dc2b32 RD |
2826 | """ |
2827 | Called when a ChildDocument is to be created and does the minimum such that the | |
2828 | ChildDocument looks like a real Document to the framework. | |
2829 | """ | |
2830 | doc = self._docType() | |
2831 | doc.SetFilename(path) | |
2832 | doc.SetData(data) | |
2833 | doc.SetParentDocument(parentDocument) | |
2834 | doc.SetDocumentTemplate(self) | |
2835 | self.GetDocumentManager().AddDocument(doc) | |
2836 | doc.SetCommandProcessor(doc.OnCreateCommandProcessor()) | |
2837 | if doc.OnCreate(path, flags): | |
2838 | return doc | |
2839 | else: | |
2840 | if doc in self.GetDocumentManager().GetDocuments(): | |
2841 | doc.DeleteAllViews() | |
2842 | return None | |
2843 | ||
2844 | ||
2845 | class WindowMenuService(DocService): | |
2846 | """ | |
2847 | The WindowMenuService is a service that implements a standard Window menu that is used | |
2848 | by the DocSDIFrame. The MDIFrame automatically includes a Window menu and does not use | |
2849 | the WindowMenuService. | |
2850 | """ | |
aca310e5 RD |
2851 | |
2852 | #---------------------------------------------------------------------------- | |
2853 | # Constants | |
2854 | #---------------------------------------------------------------------------- | |
2855 | ARRANGE_WINDOWS_ID = wx.NewId() | |
2856 | SELECT_MORE_WINDOWS_ID = wx.NewId() | |
2857 | SELECT_NEXT_WINDOW_ID = wx.NewId() | |
2858 | SELECT_PREV_WINDOW_ID = wx.NewId() | |
2859 | CLOSE_CURRENT_WINDOW_ID = wx.NewId() | |
2860 | ||
d1dc2b32 RD |
2861 | |
2862 | def __init__(self): | |
2863 | """ | |
2864 | Initializes the WindowMenu and its globals. | |
2865 | """ | |
aca310e5 RD |
2866 | self._selectWinIds = [] |
2867 | for i in range(0, 9): | |
2868 | self._selectWinIds.append(wx.NewId()) | |
d1dc2b32 RD |
2869 | |
2870 | ||
6f1a3f9c | 2871 | def InstallControls(self, frame, menuBar=None, toolBar=None, statusBar=None, document=None): |
d1dc2b32 RD |
2872 | """ |
2873 | Installs the Window menu. | |
2874 | """ | |
2875 | ||
aca310e5 RD |
2876 | windowMenu = None |
2877 | if hasattr(frame, "GetWindowMenu"): | |
2878 | windowMenu = frame.GetWindowMenu() | |
2879 | if not windowMenu: | |
2880 | needWindowMenu = True | |
2881 | windowMenu = wx.Menu() | |
2882 | else: | |
2883 | needWindowMenu = False | |
3fa8f722 | 2884 | |
aca310e5 RD |
2885 | if self.GetDocumentManager().GetFlags() & wx.lib.docview.DOC_SDI: |
2886 | if not _WINDOWS: # Arrange All and window navigation doesn't work on Linux | |
2887 | return | |
2888 | ||
2889 | item = windowMenu.Append(self.ARRANGE_WINDOWS_ID, _("&Arrange All"), _("Arrange the open windows")) | |
2890 | wx.EVT_MENU(frame, self.ARRANGE_WINDOWS_ID, frame.ProcessEvent) | |
2891 | wx.EVT_UPDATE_UI(frame, self.ARRANGE_WINDOWS_ID, frame.ProcessUpdateUIEvent) | |
2892 | windowMenu.AppendSeparator() | |
2893 | ||
2894 | for i, id in enumerate(self._selectWinIds): | |
2895 | wx.EVT_MENU(frame, id, frame.ProcessEvent) | |
2896 | wx.EVT_MENU(frame, self.SELECT_MORE_WINDOWS_ID, frame.ProcessEvent) | |
2897 | elif wx.GetApp().GetUseTabbedMDI(): | |
2898 | item = windowMenu.Append(self.SELECT_PREV_WINDOW_ID, _("Previous"), _("Previous Tab")) | |
2899 | wx.EVT_MENU(frame, self.SELECT_PREV_WINDOW_ID, frame.ProcessEvent) | |
2900 | wx.EVT_UPDATE_UI(frame, self.SELECT_PREV_WINDOW_ID, frame.ProcessUpdateUIEvent) | |
2901 | item = windowMenu.Append(self.SELECT_NEXT_WINDOW_ID, _("Next"), _("Next Tab")) | |
2902 | wx.EVT_MENU(frame, self.SELECT_NEXT_WINDOW_ID, frame.ProcessEvent) | |
2903 | wx.EVT_UPDATE_UI(frame, self.SELECT_NEXT_WINDOW_ID, frame.ProcessUpdateUIEvent) | |
2904 | item = windowMenu.Append(self.CLOSE_CURRENT_WINDOW_ID, _("Close Current\tCtrl+F4"), _("Close Current Tab")) | |
2905 | wx.EVT_MENU(frame, self.CLOSE_CURRENT_WINDOW_ID, frame.ProcessEvent) | |
2906 | wx.EVT_UPDATE_UI(frame, self.CLOSE_CURRENT_WINDOW_ID, frame.ProcessUpdateUIEvent) | |
2907 | self._sep = None | |
2908 | ||
2909 | for i, id in enumerate(self._selectWinIds): | |
2910 | wx.EVT_MENU(frame, id, self.OnCtrlKeySelect) | |
2911 | ||
2912 | if needWindowMenu: | |
2913 | helpMenuIndex = menuBar.FindMenu(_("&Help")) | |
2914 | menuBar.Insert(helpMenuIndex, windowMenu, _("&Window")) | |
d1dc2b32 RD |
2915 | |
2916 | self._lastFrameUpdated = None | |
2917 | ||
2918 | ||
aca310e5 RD |
2919 | def OnCtrlKeySelect(self, event): |
2920 | i = self._selectWinIds.index(event.GetId()) | |
2921 | notebook = wx.GetApp().GetTopWindow()._notebook | |
2922 | if i < notebook.GetPageCount(): | |
2923 | notebook.SetSelection(i) | |
2924 | ||
2925 | ||
d1dc2b32 RD |
2926 | def ProcessEvent(self, event): |
2927 | """ | |
2928 | Processes a Window menu event. | |
2929 | """ | |
2930 | id = event.GetId() | |
2931 | if id == self.ARRANGE_WINDOWS_ID: | |
2932 | self.OnArrangeWindows(event) | |
2933 | return True | |
2934 | elif id == self.SELECT_MORE_WINDOWS_ID: | |
2935 | self.OnSelectMoreWindows(event) | |
2936 | return True | |
aca310e5 | 2937 | elif id in self._selectWinIds: |
d1dc2b32 RD |
2938 | self.OnSelectWindowMenu(event) |
2939 | return True | |
aca310e5 RD |
2940 | elif wx.GetApp().GetUseTabbedMDI(): |
2941 | if id == self.SELECT_NEXT_WINDOW_ID: | |
2942 | notebook = wx.GetApp().GetTopWindow()._notebook | |
2943 | i = notebook.GetSelection() | |
2944 | notebook.SetSelection(i+1) | |
2945 | return True | |
2946 | elif id == self.SELECT_PREV_WINDOW_ID: | |
2947 | notebook = wx.GetApp().GetTopWindow()._notebook | |
2948 | i = notebook.GetSelection() | |
2949 | notebook.SetSelection(i-1) | |
2950 | return True | |
2951 | elif id == self.CLOSE_CURRENT_WINDOW_ID: | |
2952 | notebook = wx.GetApp().GetTopWindow()._notebook | |
2953 | i = notebook.GetSelection() | |
2954 | if i != -1: | |
2955 | doc = notebook.GetPage(i).GetView().GetDocument() | |
2956 | wx.GetApp().GetDocumentManager().CloseDocument(doc, False) | |
2957 | return True | |
d1dc2b32 RD |
2958 | else: |
2959 | return False | |
2960 | ||
2961 | ||
2962 | def ProcessUpdateUIEvent(self, event): | |
2963 | """ | |
2964 | Updates the Window menu items. | |
2965 | """ | |
2966 | id = event.GetId() | |
2967 | if id == self.ARRANGE_WINDOWS_ID: | |
2968 | frame = event.GetEventObject() | |
2969 | if not self._lastFrameUpdated or self._lastFrameUpdated != frame: | |
2970 | self.BuildWindowMenu(frame) # It's a new frame, so update the windows menu... this is as if the View::OnActivateMethod had been invoked | |
2971 | self._lastFrameUpdated = frame | |
2972 | return True | |
aca310e5 RD |
2973 | elif wx.GetApp().GetUseTabbedMDI(): |
2974 | if id == self.SELECT_NEXT_WINDOW_ID: | |
2975 | self.BuildWindowMenu(event.GetEventObject()) # build file list only when we are updating the windows menu | |
2976 | ||
2977 | notebook = wx.GetApp().GetTopWindow()._notebook | |
2978 | i = notebook.GetSelection() | |
2979 | if i == -1: | |
2980 | event.Enable(False) | |
2981 | return True | |
2982 | i += 1 | |
2983 | if i >= notebook.GetPageCount(): | |
2984 | event.Enable(False) | |
2985 | return True | |
2986 | event.Enable(True) | |
2987 | return True | |
2988 | elif id == self.SELECT_PREV_WINDOW_ID: | |
2989 | notebook = wx.GetApp().GetTopWindow()._notebook | |
2990 | i = notebook.GetSelection() | |
2991 | if i == -1: | |
2992 | event.Enable(False) | |
2993 | return True | |
2994 | i -= 1 | |
2995 | if i < 0: | |
2996 | event.Enable(False) | |
2997 | return True | |
2998 | event.Enable(True) | |
2999 | return True | |
3000 | elif id == self.CLOSE_CURRENT_WINDOW_ID: | |
3001 | event.Enable(wx.GetApp().GetTopWindow()._notebook.GetSelection() != -1) | |
3002 | return True | |
3003 | ||
3004 | return False | |
d1dc2b32 RD |
3005 | else: |
3006 | return False | |
3007 | ||
3008 | ||
3009 | def BuildWindowMenu(self, currentFrame): | |
3010 | """ | |
3011 | Builds the Window menu and adds menu items for all of the open documents in the DocManager. | |
3012 | """ | |
aca310e5 RD |
3013 | if wx.GetApp().GetUseTabbedMDI(): |
3014 | currentFrame = wx.GetApp().GetTopWindow() | |
3015 | ||
d1dc2b32 RD |
3016 | windowMenuIndex = currentFrame.GetMenuBar().FindMenu(_("&Window")) |
3017 | windowMenu = currentFrame.GetMenuBar().GetMenu(windowMenuIndex) | |
d1dc2b32 | 3018 | |
aca310e5 RD |
3019 | if self.GetDocumentManager().GetFlags() & wx.lib.docview.DOC_SDI: |
3020 | frames = self._GetWindowMenuFrameList(currentFrame) | |
3021 | max = WINDOW_MENU_NUM_ITEMS | |
3022 | if max > len(frames): | |
3023 | max = len(frames) | |
3024 | i = 0 | |
3025 | for i in range(0, max): | |
3026 | frame = frames[i] | |
3027 | item = windowMenu.FindItemById(self._selectWinIds[i]) | |
3028 | label = '&' + str(i + 1) + ' ' + frame.GetTitle() | |
3029 | if not item: | |
3030 | item = windowMenu.AppendCheckItem(self._selectWinIds[i], label) | |
3031 | else: | |
3032 | windowMenu.SetLabel(self._selectWinIds[i], label) | |
3033 | windowMenu.Check(self._selectWinIds[i], (frame == currentFrame)) | |
3034 | if len(frames) > WINDOW_MENU_NUM_ITEMS: # Add the more items item | |
3035 | if not windowMenu.FindItemById(self.SELECT_MORE_WINDOWS_ID): | |
3036 | windowMenu.Append(self.SELECT_MORE_WINDOWS_ID, _("&More Windows...")) | |
3037 | else: # Remove any extra items | |
3038 | if windowMenu.FindItemById(self.SELECT_MORE_WINDOWS_ID): | |
3039 | windowMenu.Remove(self.SELECT_MORE_WINDOWS_ID) | |
3040 | ||
3041 | for j in range(i + 1, WINDOW_MENU_NUM_ITEMS): | |
3042 | if windowMenu.FindItemById(self._selectWinIds[j]): | |
3043 | windowMenu.Remove(self._selectWinIds[j]) | |
3044 | ||
3045 | elif wx.GetApp().GetUseTabbedMDI(): | |
3046 | notebook = wx.GetApp().GetTopWindow()._notebook | |
3047 | numPages = notebook.GetPageCount() | |
3048 | ||
3049 | for id in self._selectWinIds: | |
3050 | item = windowMenu.FindItemById(id) | |
3051 | if item: | |
3052 | windowMenu.DeleteItem(item) | |
3053 | if numPages == 0 and self._sep: | |
3054 | windowMenu.DeleteItem(self._sep) | |
3055 | self._sep = None | |
3056 | ||
3057 | if numPages > len(self._selectWinIds): | |
3058 | for i in range(len(self._selectWinIds), numPages): | |
3059 | self._selectWinIds.append(wx.NewId()) | |
3060 | wx.EVT_MENU(currentFrame, self._selectWinIds[i], self.OnCtrlKeySelect) | |
3061 | ||
3062 | for i in range(0, numPages): | |
3063 | if i == 0 and not self._sep: | |
3064 | self._sep = windowMenu.AppendSeparator() | |
3065 | if i < 9: | |
3066 | menuLabel = "%s\tCtrl+%s" % (notebook.GetPageText(i), i+1) | |
3067 | else: | |
3068 | menuLabel = notebook.GetPageText(i) | |
3069 | windowMenu.Append(self._selectWinIds[i], menuLabel) | |
d1dc2b32 RD |
3070 | |
3071 | ||
3072 | def _GetWindowMenuIDList(self): | |
3073 | """ | |
3074 | Returns a list of the Window menu item IDs. | |
3075 | """ | |
aca310e5 | 3076 | return self._selectWinIds |
d1dc2b32 RD |
3077 | |
3078 | ||
6f1a3f9c | 3079 | def _GetWindowMenuFrameList(self, currentFrame=None): |
d1dc2b32 RD |
3080 | """ |
3081 | Returns the Frame associated with each menu item in the Window menu. | |
3082 | """ | |
3083 | frameList = [] | |
3084 | # get list of windows for documents | |
3085 | for doc in self._docManager.GetDocuments(): | |
3086 | for view in doc.GetViews(): | |
3087 | frame = view.GetFrame() | |
3088 | if frame not in frameList: | |
3089 | if frame == currentFrame and len(frameList) >= WINDOW_MENU_NUM_ITEMS: | |
3090 | frameList.insert(WINDOW_MENU_NUM_ITEMS - 1, frame) | |
3091 | else: | |
3092 | frameList.append(frame) | |
3093 | # get list of windows for general services | |
3094 | for service in wx.GetApp().GetServices(): | |
3095 | view = service.GetView() | |
3096 | if view: | |
3097 | frame = view.GetFrame() | |
3098 | if frame not in frameList: | |
3099 | if frame == currentFrame and len(frameList) >= WINDOW_MENU_NUM_ITEMS: | |
3100 | frameList.insert(WINDOW_MENU_NUM_ITEMS - 1, frame) | |
3101 | else: | |
3102 | frameList.append(frame) | |
3103 | ||
3104 | return frameList | |
3105 | ||
3106 | ||
3107 | def OnArrangeWindows(self, event): | |
3108 | """ | |
3109 | Called by Window/Arrange and tiles the frames on the desktop. | |
3110 | """ | |
3111 | currentFrame = event.GetEventObject() | |
3112 | ||
3113 | tempFrame = wx.Frame(None, -1, "", pos = wx.DefaultPosition, size = wx.DefaultSize) | |
3114 | sizex = tempFrame.GetSize()[0] | |
3115 | sizey = tempFrame.GetSize()[1] | |
3116 | tempFrame.Destroy() | |
3117 | ||
3118 | posx = 0 | |
3119 | posy = 0 | |
3120 | delta = 0 | |
3121 | frames = self._GetWindowMenuFrameList() | |
3122 | frames.remove(currentFrame) | |
3123 | frames.append(currentFrame) # Make the current frame the last frame so that it is the last one to appear | |
3124 | for frame in frames: | |
3125 | if delta == 0: | |
3126 | delta = frame.GetClientAreaOrigin()[1] | |
3127 | frame.SetPosition((posx, posy)) | |
3128 | frame.SetSize((sizex, sizey)) | |
3129 | # TODO: Need to loop around if posx + delta + size > displaysize | |
3130 | frame.SetFocus() | |
3131 | posx = posx + delta | |
3132 | posy = posy + delta | |
3133 | if posx + sizex > wx.DisplaySize()[0] or posy + sizey > wx.DisplaySize()[1]: | |
3134 | posx = 0 | |
3135 | posy = 0 | |
3136 | currentFrame.SetFocus() | |
3137 | ||
3138 | ||
3139 | def OnSelectWindowMenu(self, event): | |
3140 | """ | |
3141 | Called when the Window menu item representing a Frame is selected and brings the selected | |
3142 | Frame to the front of the desktop. | |
3143 | """ | |
3144 | id = event.GetId() | |
aca310e5 | 3145 | index = self._selectWinIds.index(id) |
d1dc2b32 RD |
3146 | if index > -1: |
3147 | currentFrame = event.GetEventObject() | |
3148 | frame = self._GetWindowMenuFrameList(currentFrame)[index] | |
3149 | if frame: | |
3150 | wx.CallAfter(frame.Raise) | |
3151 | ||
3152 | ||
3153 | def OnSelectMoreWindows(self, event): | |
3154 | """ | |
3155 | Called when the "Window/Select More Windows..." menu item is selected and enables user to | |
3156 | select from the Frames that do not in the Window list. Useful when there are more than | |
3157 | 10 open frames in the application. | |
3158 | """ | |
3159 | frames = self._GetWindowMenuFrameList() # TODO - make the current window the first one | |
3160 | strings = map(lambda frame: frame.GetTitle(), frames) | |
3161 | # Should preselect the current window, but not supported by wx.GetSingleChoice | |
3162 | res = wx.GetSingleChoiceIndex(_("Select a window to show:"), | |
3163 | _("Select Window"), | |
3164 | strings, | |
3165 | self) | |
3166 | if res == -1: | |
3167 | return | |
3168 | frames[res].SetFocus() | |
3169 | ||
3170 | ||
3171 | #---------------------------------------------------------------------------- | |
3172 | # File generated by encode_bitmaps.py | |
3173 | #---------------------------------------------------------------------------- | |
3174 | from wx import ImageFromStream, BitmapFromImage | |
3175 | import cStringIO | |
3176 | ||
3177 | #---------------------------------------------------------------------- | |
3178 | def getNewData(): | |
3179 | return \ | |
02b800ce | 3180 | "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ |
d1dc2b32 | 3181 | \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ |
02b800ce RD |
3182 | \x00\x01\x04IDAT8\x8d\xa5\x93\xbdj\x02A\x10\xc7\x7f{gme\xe5c\xe4\t\x82\x85\ |
3183 | \x85\x85oa\xe5+\xd8Z\xd8'e\xfa\x80\xd8\xd8X\x19R\xc4\x07\x90\x04\xd1J\x08\ | |
3184 | \x17\x0cr\\V\xe1\xe4\xfc\x80\xb58\xf7\xd8\xbd\x0f\xa280\xec\xec2\xbf\xff\xce\ | |
3185 | \xcc\xb2B8.\xf7X\xc9\xdc|L\x97J\xc7\xbe\x0c\x01\xf0\xd6\x01\x00RFtZu\x91Q\ | |
3186 | \x10\x8e\x9b\xf8\xe4\xf3[-w*\xf1\xafm\xec\xcf\x83\x89\x1a\xad\x94\xea\xbe\ | |
3187 | \x8c\x95\x99/\x1c\x17\xe7\xdaR\xcb%xh\xd4hw_\x95yn\xb5\xe0\xcb\x90\xea%\x0eO\ | |
3188 | \xf1\xba\xd9\xc7\xe5\xbf\x0f\xdfX]\xda)\x140A\r\x03<6klO\xf0w\x84~\xef\xc9\ | |
3189 | \xca/lA\xc3@\x02\xe7\x99U\x81\xb7\x0e\xa8\xec\xed\x04\x13\xde\x1c\xfe\x11\ | |
3190 | \x902\xb2@\xc8\xc2\x8b\xd9\xbcX\xc0\x045\xac\xc1 Jg\xe6\x08\xe8)\xa7o\xd5\ | |
3191 | \xb0\xbf\xcb\nd\x86x\x0b\x9c+p\x0b\x0c\xa9\x16~\xbc_\xeb\x9d\xd3\x03\xcb3q\ | |
3192 | \xefo\xbc\xfa/\x14\xd9\x19\x1f\xfb\x8aa\x87\xf2\xf7\x16\x00\x00\x00\x00IEND\ | |
aca310e5 | 3193 | \xaeB`\x82" |
d1dc2b32 RD |
3194 | |
3195 | def getNewBitmap(): | |
3196 | return BitmapFromImage(getNewImage()) | |
3197 | ||
3198 | def getNewImage(): | |
3199 | stream = cStringIO.StringIO(getNewData()) | |
3200 | return ImageFromStream(stream) | |
3201 | ||
3202 | #---------------------------------------------------------------------- | |
3203 | def getOpenData(): | |
3204 | return \ | |
3205 | '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ | |
3206 | \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ | |
02b800ce RD |
3207 | \x00\x01gIDAT8\x8d\xa5\x93=KBQ\x18\xc7\x7fWo)5\x1594DC\x04!\xd1\x0bM-\xd1\ |
3208 | \xd0T\x81\xba\xb7\xf8\x01Z\x9a\xdb\xfa\x08AC\x10\x0e\xb5\x86\xbaDC`CMaN\xd9\ | |
3209 | \x0bQF7\xe2z\xc1kz\xcd\xc4\x97\xd3\xa0\xde\xbc\\oE\xfd\xa7s\xce\xf3\xfc\x7f\ | |
3210 | \xe7y\xce\x8b$\xb9\xdc\xfcG2@\xf1bC\x00\x18%\xcd\x12\x1c^\xdc\x97~\x04\x18\ | |
3211 | \xe7K\xa2of\x05\x80\xfe\x8e@\xc3\xc8\xf2zJ\x13\xac+\xe6\xfax(a\x81\xca\xa2w\ | |
3212 | \x8a\x86\x91\x85\xaanE\xf7\x0c\xe0\xf3\xcf\x03P}|3\x97\x93\x11U\xcc\x85\xd3&\ | |
3213 | D\xee\xf4\x88\xb2\xfa5)\xab(\x99"\x00\xb9\x87c\x0b;\x19\xf1\x0b\x80\xb9pZ\ | |
3214 | \xb2\x00\x00\xd3T\xcb\xa5\x00(\xe4Uf\xd7\xb6m\xbd\xa7\x0e\xd6\x89\xc7\xa2\ | |
3215 | \xc2\x04<_\xdf\xe3\x15\x1a\xb5V\xbfc\xab\x9b6S7\xc9FIC\xbf\xcb\xe0\x15\x1a\ | |
3216 | \xbe\xe9e|\xad@C\xbfu4\x9d\xecnQ\x99\xdci\x02\x00\xea\x1f\x1a\x15]a\xa8pcK\ | |
3217 | \xae\xbf?9\x82\x02\xc1\x90$\x1b\xba\x82<\xe8\xeb\x9a\\\xcb)\xdd|\x14r\x15<\ | |
3218 | \xad\xb1\xab\x99\x98bdb\xd4q\xa7\xefd\xbb\x05\xa7\xdd\x8f\x0e/\x9d\x01\x85\ | |
3219 | \xbc\nX+8K\\\x99\xe5\x02x\x16\xf6\xba\x02$\xc9\xe56\x1fF[\xda\x8bn\x9er\xa7\ | |
3220 | \x02\xc1\x90\xedoH\xed\xdf\x18\x8fE\xc5o\x0c\x8e\x80\xbf\xea\x13\xa8\x18\x89\ | |
aca310e5 | 3221 | 5\xe7L\xb3:\x00\x00\x00\x00IEND\xaeB`\x82' |
d1dc2b32 RD |
3222 | |
3223 | def getOpenBitmap(): | |
3224 | return BitmapFromImage(getOpenImage()) | |
3225 | ||
3226 | def getOpenImage(): | |
3227 | stream = cStringIO.StringIO(getOpenData()) | |
3228 | return ImageFromStream(stream) | |
3229 | ||
3230 | #---------------------------------------------------------------------- | |
3231 | def getCopyData(): | |
3232 | return \ | |
3233 | '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ | |
3234 | \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ | |
02b800ce RD |
3235 | \x00\x01_IDAT8\x8d\x8d\x92\xbfK\x02a\x18\xc7?w\xfa\'\xd8\xd0\xa0\xe4v\xd0$M\ |
3236 | \x8dB\x11\x11\xa5B\x7f@C\xd0RC{k8E\x834\xb45\n\x15\xfd\x80hhh\xd2\xadI\x82\ | |
3237 | \xa4!\xb8\x84\xca\xd4;\xa5\xf2R\xe1m\xd0\xfb\xf5^\x1e~\xe1\xe5^\x9e{\xbe\x9f\ | |
3238 | \xf7\xfb\xbcwJ\xa9\xa2\x0bFj\x98\xdf\x00\xd4\xea\x06\x00f\xdbbosQ!L\xa5\x8a.\ | |
3239 | \xaa_"\xb0\x8e\xce\xcb\xa2\xfc)\xc4N\xfeT(j\x84\xb1\xabT\xd1E,\x19w\x80\x8d\ | |
3240 | \x97Ww?A"\xd5n\xf2*\x96\x8c\x13K\xc6\xd1R\x1aZJcai\x1e\x80\xf4j\x9a\xed\xfd\ | |
3241 | \xa2\xf0\x01B\xe7\x1b\xa9\xd9\x1d>;\x03X\xd9X\xf7AToC\xb3\xeb\xc6\x96e\xb6-\ | |
3242 | \x1en\xef\xb999\x03\xe0\xea\xf2B\x00Dku\x83)\xcd\x85\x8c;}n9\r\x80\xd1\x87b\ | |
3243 | \xbe\x00\xb33\xc3\x04f\xdbr\x9a;\x03\xbfI\x86\x1a\xfd\xe0\x01\xaam\xec\x0c\ | |
3244 | \x86\r\xf6\x8d{\xcd\xf6;\x00\xb3\'\x01\xde?\x9a>\xba\x9cH6\xb7,x~\xaa:=Q\x9f\ | |
3245 | \xb9\xe7\x1fE\xae\xb7\\\xb6\x1f\xe0\x8d\x15H$\x99\x1b?\x12@\xd7\xdf\xd0\x0f\ | |
3246 | \nN!\x91\x98\x9e\xd8\x0c\x10\xbd>\xdeU\xeco\np\xf7\xf8\xebK\x14fvF\xc8ds\xce\ | |
3247 | \xff\xbd\xb6u(\xbc\x89\xbc\x17\xf6\x9f\x14E\x8d\x04\x8a\xdeDa\xcads\xca\x1f\ | |
aca310e5 | 3248 | \x0cI\xd4\xda\x88E\x9d\xc4\x00\x00\x00\x00IEND\xaeB`\x82' |
d1dc2b32 RD |
3249 | |
3250 | def getCopyBitmap(): | |
3251 | return BitmapFromImage(getCopyImage()) | |
3252 | ||
3253 | def getCopyImage(): | |
3254 | stream = cStringIO.StringIO(getCopyData()) | |
3255 | return ImageFromStream(stream) | |
3256 | ||
3257 | #---------------------------------------------------------------------- | |
3258 | def getPasteData(): | |
3259 | return \ | |
3260 | "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ | |
3261 | \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ | |
02b800ce RD |
3262 | \x00\x01\x90IDAT8\x8d\x8d\x93?H\x02a\x18\x87\x9fSw\xb1\xa9!q\xc8\xb0?B\xd0\ |
3263 | \x98\x10DS\x10\x98\x82C\xd1\x12\x1a\xcd\rb&\xad\x1a\x144F`[\xd4 hBPKC\x83P\ | |
3264 | \x8b4\xe4\xa9tP\x82\x98\x88`$\x82\x8b\xd8p\xddu\xa7\xa5\xfd\x96{\xbf\xef\xfd\ | |
3265 | \xbd\xcf\xf7~w\xf7\n\x82\xc1\x08@M\xect\xd1(x\x12ef\xcaN./\x11\\\xdc\xd3\xa6\ | |
3266 | pz\x8d\x82\x12\x0b\x82\xc1HM\xect-c\xf7\xaa!\x10\xc9\xe0]rR\xac\xb4\x01\xc8\ | |
3267 | \xe5%\xe2\xbbF5_|\x0c\xa9\x10\x03=\nD2\x00$\xef\x9e\xc9\xe5%ryI\xde?\xe8\xe8\ | |
3268 | |\xe9\xabT\x17\xc0\xd4\x0b\xd8\nl\xa8q\xfd\xa3%\xb7\xd9x\xe1\xad=\xc2q\xba\ | |
3269 | \xc2\x8e\xfbU\xe7\xef\x03\x00\x98m\xd6\xef\xa7\xb23\xc9\xdbm\x06\xfb\x8a\x8f\ | |
3270 | \xe0y\x8a\xc0\xc4\x10\x00\xc0\xcdEB\x8d\x97\xd7}j\xbc\xb0\xe6!~\x99d\xd11\ | |
3271 | \x04\xa0-R$]'\xa84M4\xca\x05p8\x7f\x07\xd4?Z\x98mr\x07\x95\xa6\x9c\xf6o{\xb0\ | |
3272 | \xce\xbb\x00\xb0\x03\xe9\xc3\xd8\xf0+h;x\xf9\xfc\xcb\xd5\x0bh>Pzw1>\x0bg\xa7\ | |
3273 | )]\xaaQ.\x00`\xdb\x0c\x0f\x00hN\xf4o{~=\xf9\xa9\x0eY\xb1\x8awI\xf3\x0ej\x05\ | |
3274 | \xb0\x98\x1f\x00x-\xd5\xb0\xce\xc3\xd1~LW\x98\x15\xab\xccM\x8f\xfe\xaf\x03\ | |
3275 | \x00w0\xccS\xfdgm\xfb\xc3\xd7\xf7++w\xd5\x16\x0f\x92\t\xe4\xe9zN\x86\xbe\xa7\ | |
3276 | 1\xaa\xfbLY\xb1:\x10 (\xe3\x0c?\x03\xf2_\xb9W=\xc2\x17\x1c\xf8\x87\x9a\x03\ | |
aca310e5 | 3277 | \x12\xd7\xb9\x00\x00\x00\x00IEND\xaeB`\x82" |
d1dc2b32 RD |
3278 | |
3279 | def getPasteBitmap(): | |
3280 | return BitmapFromImage(getPasteImage()) | |
3281 | ||
3282 | def getPasteImage(): | |
3283 | stream = cStringIO.StringIO(getPasteData()) | |
3284 | return ImageFromStream(stream) | |
3285 | ||
3286 | #---------------------------------------------------------------------- | |
3287 | def getSaveData(): | |
3288 | return \ | |
3289 | '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ | |
3290 | \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ | |
02b800ce RD |
3291 | \x00\x01\x1dIDAT8\x8d\x9d\x93=N\xc3@\x10\x85\xbf\xf5\xa2-\xf1\x11\xa0\x8dC\ |
3292 | \x8f\x82\xa0\xe5\xa7\xa6\xe2\x04\xb4p\x00\x1a\xfb\x02\x11T\xf4\xa4\xa0\xc1\ | |
3293 | \xc1\\\x01\x90R"\xc5\xa4\x89RD\x14\x04$\xa2@\x01\xb1\x04C\xe1\xc8\xb1`\x1dC^\ | |
3294 | 5;?\xef\xcd\x8cv\x94r4\xf1\xc5\xa7P\x82a\xff\xb7o\xfd@+\x94\xa3\xb9o"2\xa8K\ | |
3295 | \x18\x86R\x84\xc1\x87\xc8\xdd\xf3X|\xdf\x17\x11\x91\x9bc$\x8a"q\xf2\x8cZk\ | |
3296 | \xab\xfa\xd3\x18\x1e\xdf\x12\xba\xef\x06\x80\xdb\x13\x95\xc5\x1ckE\t\xd6\xb6\ | |
3297 | \xf7\xec\x04I\x92\x94\xaa\xff\xc4\\\x1d\xf0\xd2\xfd\x1bA\x99:\xc0B\xfe\xb1\ | |
3298 | \xbb\xf1@\x10\x043\xc5\x8f6\xaf\x00\xe8u\xc0]\x9e\x10\x0c\xfb@m\x92\xb0\xbf8\ | |
3299 | \xcd\x1e\xb5\xacm\xdb;\x18\xb5\xc0]%8}\xcd\x85+\x99\xd5\x8e\xbf2\xfb\xfc\xb0\ | |
3300 | g\x1f!U\xac\xe0y^\xe62\xc6p\xd6h\x14\x8e4s\x89\xc6\xa4\xcb[\xa9V\xffG\xa0\ | |
3301 | \xb5\xce\x8a\x97j[\xb4\xe3\xb8\x90@)\'\xfd\xbe\xd7\xf5\xe2\x83\xeau\xec~w\'\ | |
3302 | \x9a\x12\x00\\6\xc3\xd2\xab,\xec`^|\x03\xb6\xdf|Q.\xa7\x15\x89\x00\x00\x00\ | |
aca310e5 | 3303 | \x00IEND\xaeB`\x82' |
d1dc2b32 RD |
3304 | |
3305 | def getSaveBitmap(): | |
3306 | return BitmapFromImage(getSaveImage()) | |
3307 | ||
3308 | def getSaveImage(): | |
3309 | stream = cStringIO.StringIO(getSaveData()) | |
3310 | return ImageFromStream(stream) | |
3311 | ||
3312 | #---------------------------------------------------------------------- | |
3313 | def getSaveAllData(): | |
3314 | return \ | |
3315 | '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ | |
3316 | \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ | |
02b800ce RD |
3317 | \x00\x01UIDAT8\x8d\x9d\x93\xbfK\xc3@\x1c\xc5\xdf%\x01g\xeb \x1d\x8a\x8b\x83M\ |
3318 | \x11\xe9\x16\x8a\x8b\xff@\xa0\xdd\x14\'\x17\x17A2\xe9,\x08\xc9\x14\x82n.nn\ | |
3319 | \x9a\xde?\xe0R;\xb88\x99v\xe8`\x86\n."\x81\xb6\xb4\xb4~\x1d\xd2\xc4^\x92j\ | |
3320 | \xf5\x03\xc7\xfd~\xf7\xeeq\xc7<\x17\x84)\xa3\x1e\x04\x863\xfd\xf10\xac\xb7\ | |
3321 | \x8fe&,\xf2\\\x10\xf9\x06q\xce)I\x7fL\xf4\xda\'2M\x93\x88\x88\x1e.@\x9csb\ | |
3322 | \x92\x8c\xb8x.\xa8X6\xd0z\xb2c\xd1?9\x89\x1c\xfc\xd7\x89\x82\x04\xeb\x9f:Z\ | |
3323 | \xf5l\';9\xe0\xf1\xea\x14\xca\x12\xb0\xe2\xebh8 ))\x00\x00\xc5\xb2\x81\x8e\ | |
3324 | \xc4\xb1\xb5GB\xd9< \x14\xf6\t\xf7\xef&*Ga\xf6\x99\x02Y\x0c&\xc0\xc7\x08x\ | |
3325 | \xe9\x01A\x10\xa0y\xc9\x16\x17\x98\xdd\x1cQ\xd1\x8d\x9f\x05<\xcf\x136\xcf#\ | |
3326 | \x15b\xc4\xc9\xee\x1b,\xcb\x8a\xfbA\x10\xc4\xed\xf3\xc3\x01\x00\xc0o\x03J\ | |
3327 | \xa9&\xb3\x86c\xd3r![\xe47\x14 |\x14\xcf\xb7\x13JNZ7\xab\xc2\xe9\xddn7\x9e\ | |
3328 | \xbb>\xcb\x01\x98\xc9\xa0T\x93Y\x93\xdbH\xa2\xaa*4MC\xb5Z\xcdt \x84\x98\xfa(\ | |
3329 | S\xf2\xf9\xfc\xdc+0&\xc9\xa9\xc1\x86\xf3}\x1d\xbf\r\xacm\x84\xf5\xc2\x02\x00\ | |
aca310e5 | 3330 | Pw\xefR\x99d\xf1\x05z\x94\xd0b\xcb S\xf3\x00\x00\x00\x00IEND\xaeB`\x82' |
d1dc2b32 RD |
3331 | |
3332 | def getSaveAllBitmap(): | |
3333 | return BitmapFromImage(getSaveAllImage()) | |
3334 | ||
3335 | def getSaveAllImage(): | |
3336 | stream = cStringIO.StringIO(getSaveAllData()) | |
3337 | return ImageFromStream(stream) | |
3338 | ||
3339 | #---------------------------------------------------------------------- | |
3340 | def getPrintData(): | |
3341 | return \ | |
02b800ce | 3342 | '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ |
d1dc2b32 | 3343 | \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ |
02b800ce RD |
3344 | \x00\x01\xa7IDAT8\x8d\xa5S=K\xc3P\x14=\xef\xb5 \x0e\xf6\x17\xb8$X\x10\xa7\ |
3345 | \x82\xb4\n]\x05A\x07\xebd%\xfe\x02\x97\x82\xe0\xa0\x83\xa3\x88\xb5E\xfd\x07j\ | |
3346 | \x0bq\xea\x07\x18(8:5\x16\xa2H\xf1\x8bN\x12\tt\xe9\x8b\xddZ\x9eC|i\x93\xd4\ | |
3347 | \x0f\xf0\xc0\xe1\xe6\xbe\xdc{\xde\xb9\xc9{\x84\xd0\x10\xfe\x83\xb0x8m\xf6\ | |
3348 | \xb8i\xf7=/\xfb\xad\x07O\x9e]\x9f%\x01\x05BC 4\x84\x1d\xbd\xc7\xfdx\xb2\x1d^\ | |
3349 | \x99\x9c\x1f\xe6\x8ey\xb5Z\xe5\xa2^\x90\n\xa1\x83\xb91\xb2{;p\xf0\xfc\xe1\ | |
3350 | \xc4W\xdb\x89\xe3\xcb\x19\xa8\xaa\x8aJ\xb9\xc4\x87\r\xd0\xe1\xc4o\xf9/\x08\ | |
3351 | \x03\xc0\xc5\xf9\x19\x07\x80\xfb\xaf\x9d\xc5\xae-6(4\xed>\x9aoA\x01zq~\xc6\ | |
3352 | \x15E\x81\xa2(\xee\xe2\xd4\x84\x13\xe5H\xb0\xc1?\x06\x05\x80b\xb1\xe8\x16\ | |
3353 | \xbc\xda\x0e[\xcc\xa1i\xf71\xfcw\xf2\xf9\xbcG\x84\x14\n\x05\x1e\x8b\xc5\xa0\ | |
3354 | \xd5\xae\xb1\xbd\x95\x81eY#gm\xb7\xdb\x9e|cs\x1fw7\x97$lZm\xc4\x00,-. \x9b?\ | |
3355 | \xc1tT\x1e)\xc0\x18C$\x12\x01c\xce\x87\xe9\xbe\xeb\xa8\x94K\x9cNGeh\xb5k\x00\ | |
3356 | \x80\xd1\xa8#\x91H@\x96\xe5\x00%I\xc2\xe3K\x0b\x9a\xa6A\x92$W8\xbc\x92Z%\xeb\ | |
3357 | \xe95n4\xea\x01\xab\x9dN\xc7\xe3"9\x1fGr>\xeeYs\x8fr:\x9d\x06c\x0c\x86ax\nL\ | |
3358 | \xcb;\xbb\x1f\x84\xd0\x10*\xe5\x12WU\x15\xcd7`f\xf2\xc7z\x00\x80\xae\xeb\xc8\ | |
3359 | \xe5rXI\xad\x12"nc\xa5\\\xe2{G*\xba\xef\xfa\xaf\x02\xa2\xd9u \xe0?\xe7\xdfA4\ | |
aca310e5 | 3360 | \x03\xc0\'\xe3\x82\xc9\x18g\x90\x8e]\x00\x00\x00\x00IEND\xaeB`\x82' |
d1dc2b32 RD |
3361 | |
3362 | def getPrintBitmap(): | |
3363 | return BitmapFromImage(getPrintImage()) | |
3364 | ||
3365 | def getPrintImage(): | |
3366 | stream = cStringIO.StringIO(getPrintData()) | |
3367 | return ImageFromStream(stream) | |
3368 | ||
3369 | #---------------------------------------------------------------------- | |
3370 | def getPrintPreviewData(): | |
3371 | return \ | |
3372 | '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ | |
3373 | \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ | |
02b800ce RD |
3374 | \x00\x01mIDAT8\x8d\x8d\x92\xbdK\x02a\x1c\xc7?w\x1a\x85E\x04588XHa\xd1\x14!AB\ |
3375 | \r.\xbd\x07m-By.M\xfe\x03N\x05\x0e\xed\xf9\x124\x045\x04\x15\xdc\xda&4\xb5DC\ | |
3376 | J\x8a\x81E\t.\x82\x918\xd8\xf0pOw\xde\x19}\xe1\xe1w\xf7;>\xdf\xdf\xcbs\xca\ | |
3377 | \xddC\xb9C\x97\x1e\x8bU\xf9\x9c\xd8]V\xba\xbf\x9b\xa5\x02\xf8\xa6\xc6-ge=\ | |
3378 | \x0c@p)\xcc\xc1\xe1\xa5\xad\x80\xcd\xa0\x97\x86\xfb`5\xba\xf3\xa7\x89\xdb)Y\ | |
3379 | \xff\x16\xf1"{%s\xb77\xd7\x9d\xcd\xadm\xdb86\x03\x03\x0eE\xc2\x04\xdbPk\xc1y\ | |
3380 | 2Edf\xday\x84\xe6\xdb\x93\x84\x8c\xd8h\x8bSk\xf5j\xdcdPj\x8eX`C\x06\x9c?\x8a\ | |
3381 | \xe3\xef/\xa3\xeb:\xb1\xfd=\xdb.,#4\xdav\x18-m\x01b\xd0\xc9\xe6N\xe5.Ts\xcbN\ | |
3382 | pz\x0e\xa2~\x91\x0bx\x00-m\xe9D-W>%h\xc0\x1f_\xbf\x15\xef\xeb\x90\xaf\xc1\ | |
3383 | \xe2\x18x="\x82\xb8\x15\xd9\x81yYf\x18\xe0\xac"\xc0\xc0\x10\x84\xc6D4\xcb\ | |
3384 | \xf2#u\xc3\xb2m`t\x00&\x07E4\xcb]x.QH\xa6\xec$\x13\xf83q^\xb44^\x8f\xb8\xa5"\ | |
3385 | p\x9c\x88\xa3\x91\xe1\x9d5\x00\x14Eu\xc9y\x9c\xa4\xeb\xba\xe5}\xb6\x9a\x01`\ | |
3386 | \xc1\x07\xf39\x97\xa2(\xaa\xab\x17+\xd5]\xe0\xf5dC\x9a\xfc\xcb\xc0\xc9\xd00\ | |
aca310e5 | 3387 | \xf9\x011\xc9\x87\xf3\xb4\xd1t\xaf\x00\x00\x00\x00IEND\xaeB`\x82' |
d1dc2b32 RD |
3388 | |
3389 | def getPrintPreviewBitmap(): | |
3390 | return BitmapFromImage(getPrintPreviewImage()) | |
3391 | ||
3392 | def getPrintPreviewImage(): | |
3393 | stream = cStringIO.StringIO(getPrintPreviewData()) | |
3394 | return ImageFromStream(stream) | |
3395 | ||
3396 | #---------------------------------------------------------------------- | |
3397 | def getCutData(): | |
3398 | return \ | |
02b800ce | 3399 | '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ |
d1dc2b32 | 3400 | \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ |
02b800ce RD |
3401 | \x00\x01HIDAT8\x8d\x85\x92OK\x02Q\x14\xc5\x7f\xa3\x05}\x1b\xa1\xc0\x9d\xb4\ |
3402 | \xaaf6\x93a\x10\xe3^\x83l\xdf\xc6\xa5\x1bIA\xb4\xa0\x9cM\xe5"\x84\x18\xff\ | |
3403 | \x108\xbb\xf0\x93\xb4v\x15h\xa9\xaf\x16\xaf\x85\xbcat^\xd3\x81\xb79\xf7\xdc\ | |
3404 | \xf3\xce{\xf7b$\x92\x84O\xa7\xd3\x91\x9b\\\xf8\xd4\xeb\xb5\xb5z\x02\r\x9e\ | |
3405 | \x1e\x1f\xa4\x8eo5\x1b\x12`\xd0\xef\x05u\xadA.\x97\xc3u\xef\xd7LZ\xcd\x86\ | |
3406 | \xb4\xedlD\xab5\xd0A\x08\xc1l6e>_\xc4\x1b\x88o\x01@\xde\xc9\x07\x91k\xd7Ui\ | |
3407 | \x9a\x96\xd6xk\x93(\x14\xce\r@\x1e\x1e\x1cE\xc4\x9e\xe7\x91J\xa58\xce\x9e\ | |
3408 | \x18\x7f\x1a\x00,\x17\xab\x98\xb6\x9dE\x08!M\xd3\x8aDW0\x8cDR[P\xb1U\xa3\xef\ | |
3409 | \x8f"\xb7C\xcc\'\xee\xbdw\xf1</h\xceL\x86Z\x9d\xf6\to\x17\xbb2m90z\xc6\xf7!3\ | |
3410 | \x19\x92\xb6\x1c\xc6\xdd\xab\x886v\x8ci\xcb\t\x9a\x15\xc2K\xa45P\xb7\x17o+\ | |
3411 | \x00,\xa6\x9f\x00\x14o+\xec\x9f\x15X\xba\x97\xf1\tTC\x1c\xfe]e\x80v\xa9\xcc\ | |
3412 | \xb8\xeb2\xfb\xf8\xe2\xf5\xaeA\xbbT\xd6\xea"c\x1c\xf4{r\xfbe\xf5Y?\xa7\xd5\ | |
3413 | \x80W\xd1w\n7k\xa3\xd4\xee\x81\x8a\x18\x16\xea8\x80_\\\xa2\x8b\x88!\xd2S\x08\ | |
aca310e5 | 3414 | \x00\x00\x00\x00IEND\xaeB`\x82' |
d1dc2b32 RD |
3415 | |
3416 | def getCutBitmap(): | |
3417 | return BitmapFromImage(getCutImage()) | |
3418 | ||
3419 | def getCutImage(): | |
3420 | stream = cStringIO.StringIO(getCutData()) | |
3421 | return ImageFromStream(stream) | |
3422 | ||
3423 | #---------------------------------------------------------------------- | |
3424 | def getUndoData(): | |
3425 | return \ | |
3426 | "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ | |
3427 | \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ | |
02b800ce RD |
3428 | \x00\x01\xa7IDAT8\x8d\xa5\x90\xbfK[Q\x18\x86\x9fs#\x8d\x7fBu\xc8\xd6\xc9\xc1\ |
3429 | \xa1\x83\xd0\x16\xa1C@*\x98\xc4\xa2\x12\xda\x8e5\x9b\x83\x04\x07Aph\x17)\x16\ | |
3430 | \xdd\xd4\xc1\xa1Z\x1b\xc5&9\xa6P\xbaw\xa8\x9b\x9b\xa0S\xb0\xe2\x8f\\%1^\x8d\ | |
3431 | \xde\xfa9\x84s\xf1\xea\xa5\x06<p\x86\xc3\xf9\x9e\xe7\xbc\xefQ\xca\n\xf1\x90\ | |
3432 | \xd5t\xdf@\xba\x10\x95r\xcd\x01`\xee\xf5o\xd5\xb0 ]\x88\n@\xd7\xb3^\x00.\xaf\ | |
3433 | \xce\xd8\x9d>\x10\x80\x1fC[\x9eH\x05UH\x17\xa2r\x13\xac\x9d_Pq\x8f\x01(96\ | |
3434 | \xdf\x16\xd7X\xff\xb8\xaf\x02\x05\x066\xa0+5\xe6\xb3\x0b\x1c\xeeW\x00x\xd1\ | |
3435 | \xf3\x14\x80\xaf\x93\xbf\xd8\xcb\xb8\xeaN\x05\xd3\xd7\xbc\x9a\xd1\xdf\x19\ | |
3436 | \x8cL@\xa4~\x9f\x9a\xec\xa3\xb3\xa7\r\x80|.+>\xc1\xfb\xd5\xe72\xf0\xf2-U\xa7\ | |
3437 | \xec\x83c\xf1\x84\xd79\x9f\xcbJj\xa9/\xf8\x13\xcb\xe7U.\xaf\xcep\xa5\x06P\ | |
3438 | \x8f\x1d\xf1'\x8c\xc5\x13*\x9f\xcb\x8a'\xe8_l\x17\x80\xe57\x1b\xea\xd4\xae\ | |
3439 | \xc7w\xfe9\x94\x1c\xdb\x83\x1e\x0f4\t\xc0^\xc6UFb\xee\xacS\xdba\xf8\xd5\x08\ | |
3440 | \xdd\xd3O\xc4t7\xab\xb8m\x93Z\xf2w\xbe\xfdgJk-\xb3\xc5\x11\xc6\xde\x8dS\x95\ | |
3441 | \x8a\xd7\xbf\xe4\xd8\xec\x9c\xecr\xb2Sfm\xf9\x0f3\xc9\x15\xdf\xcb^\x82X<\xa1\ | |
3442 | \x06#\x13\x0c}\x1a\x06 \xdc\xfc\xc87\xf0?\xb8\x1e\xc1\n\xa1\xac\x10Zk\xe9\ | |
3443 | \x18k\x95\x9fGS\xf2\xa58*\x9f7S\xd2\x92\x0c\x8b\xd6Z\xccL\xd0\xf6\x1d\xb4\ | |
3444 | \xd6\xd2\x92\x0c\xcb\xea\xdf\x0f\r\xc1w\x047%\x8d\xc0\x81\x02#i\x04VV\x88k\ | |
aca310e5 | 3445 | \x82\xbe\xde\xc2\xb0\xb2\xea\xa7\x00\x00\x00\x00IEND\xaeB`\x82" |
d1dc2b32 RD |
3446 | |
3447 | def getUndoBitmap(): | |
3448 | return BitmapFromImage(getUndoImage()) | |
3449 | ||
3450 | def getUndoImage(): | |
3451 | stream = cStringIO.StringIO(getUndoData()) | |
3452 | return ImageFromStream(stream) | |
3453 | ||
3454 | #---------------------------------------------------------------------- | |
3455 | def getRedoData(): | |
3456 | return \ | |
3457 | "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ | |
3458 | \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ | |
02b800ce RD |
3459 | \x00\x01\x88IDAT8\x8d\xa5\x92\xc1K\x02A\x14\xc6\xbfQ\t\xbc\x14tJ\xfb\x0f2\ |
3460 | \x08\xbaD\xdd:\xe5!\xd2\xad$/\x82FP\x06\x99\x87\x04\xa1\x83D\x10\x0b\x85\xd4\ | |
3461 | \xa9\x8c (\x82<\xad\xce\xa9\xff\xc0[\xd2)\xbcu\t\xb2\xd0\xa5\xb5\x94\x14z\ | |
3462 | \x1dd\x87]\x1bBh\xe0\xc1\xf0\xde\xfb~3\xef\x9ba\xcc\xe1\xc4\x7f\x96K\x96\xdc\ | |
3463 | \xd6\xfcd\xeeO\x94;\xd67\xc0\x14Fg\xd7E\xae~\xa5S\xe3\xd3@!\xfe(\x051s\x84m\ | |
3464 | \xcdOV!\x004\xbf\r\x00\x80\xde\xae\xe2B\xbb\x94B\\\x00\x10\xb9\x9a\x12\xe2,W\ | |
3465 | Eqc~S\xec\xd7\x94\x18\xaa\xafY*e^l\x10\x87\xf5\xb4,W\xb1<\x98\x16q\x98W\xa1\ | |
3466 | \xb7\xab\x00\x80F\xa7\x0e\x00(\x164\xb2\x02\xc0\x1cN(\xb9qRr\xe3\xc49'\xe6p\ | |
3467 | \xc2\x1a3\xfb\xa3t\xfb\xbcK\xe7O[\xa4V\xc2\xe4K\x0e\xdb\xfa\\\x00\x10\xf3\ | |
3468 | \x1c\x00\x00\x02AEj\x94\xd11P\xffz\x93\x95\xba\x80^\xe1\xf4\xde\x08\x01@)\ | |
3469 | \xf3\xc2\xdek-!\xae5u\xe8\xcf-\x00\x80gi\x80l\x1e\xf4\xae\xc4j\x14c\x89!1o\ | |
3470 | \xad\xa9\x8b\xda\xc6\xf5\n\x16v&\xbb\x16\xc8~b\xb1\xa0\x91\xfa\x10G4\xb2h;\ | |
3471 | \xbd\xd1\xfe\x10=\xfc\xe8\x1eg\x91\xbc\xfc\x06\x81\xa0\xc2\xd2\x13\xa789\xbe\ | |
3472 | \x91\xde\xce\x14\x07\x82\nC\xaf\xeb\xd6\xe0\x9c\x93/9Lj%L\xa9\xf2\x1c\xa5\ | |
3473 | \xcas\xe4\r\xb9m\xaf\xf0'\xc0\x84xCnR+\xe1_\xe2\xbe\x00V\x88\xec\x9f\xf4\x05\ | |
aca310e5 | 3474 | 0!\xb2\xfc\x0f\xe0\xc4\xb6\xad\x97R\xe5z\x00\x00\x00\x00IEND\xaeB`\x82" |
d1dc2b32 RD |
3475 | |
3476 | def getRedoBitmap(): | |
3477 | return BitmapFromImage(getRedoImage()) | |
3478 | ||
3479 | def getRedoImage(): | |
3480 | stream = cStringIO.StringIO(getRedoData()) | |
3481 | return ImageFromStream(stream) | |
aca310e5 | 3482 | |
3fa8f722 RD |
3483 | #---------------------------------------------------------------------------- |
3484 | ||
3485 | def getBlankData(): | |
3486 | return \ | |
bbf7159c RD |
3487 | '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ |
3488 | \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ | |
3489 | \x00\x00]IDAT8\x8d\xed\x931\x0e\xc00\x08\x03m\x92\xff\xff8q\x87\xb6C\x11\x89\ | |
3490 | \xa8X:\xd4\x13\x03:\x1b\x01\xa45T\xd4\xefBsh\xd7Hk\xdc\x02\x00@\x8a\x19$\xa1\ | |
3491 | 9\x14A,\x95\xf3\x82G)\xd3\x00\xf24\xf7\x90\x1ev\x07\xee\x1e\xf4:\xc1J?\xe0\ | |
3492 | \x0b\x80\xc7\x1d\xf8\x1dg\xc4\xea7\x96G8\x00\xa8\x91\x19(\x85#P\x7f\x00\x00\ | |
aca310e5 | 3493 | \x00\x00IEND\xaeB`\x82' |
3fa8f722 RD |
3494 | |
3495 | ||
3496 | def getBlankBitmap(): | |
3497 | return BitmapFromImage(getBlankImage()) | |
3498 | ||
3499 | def getBlankImage(): | |
3500 | stream = cStringIO.StringIO(getBlankData()) | |
3501 | return ImageFromStream(stream) | |
3502 | ||
3503 | def getBlankIcon(): | |
bbf7159c | 3504 | return wx.IconFromBitmap(getBlankBitmap()) |
aca310e5 | 3505 | |
3fa8f722 | 3506 |