]>
Commit | Line | Data |
---|---|---|
7153b2cb RD |
1 | #!/usr/bin/env python |
2 | ||
3 | """ | |
4 | This sample comes from an IBM developerWorks article at | |
5 | http://www-106.ibm.com/developerworks/library/l-wxpy/index.html | |
6 | ||
7 | This small program was adapted to demonstrate the current guide lines | |
8 | on http://wiki.wxpython.org/index.cgi/wxPython_20Style_20Guide. | |
9 | Changes are noted in readme.txt. | |
10 | """ | |
11 | ||
c12bc4de | 12 | import sys, os |
7153b2cb RD |
13 | import wx |
14 | ||
c12bc4de RD |
15 | |
16 | # Process the command line. Not much to do; | |
17 | # just get the name of the project file if it's given. Simple. | |
18 | projfile = 'Unnamed' | |
19 | if len(sys.argv) > 1: | |
7153b2cb | 20 | projfile = sys.argv[1] |
c12bc4de RD |
21 | |
22 | ||
7153b2cb RD |
23 | def MsgDlg(window, string, caption='wxProject', style=wx.YES_NO|wx.CANCEL): |
24 | """Common MessageDialog.""" | |
25 | dlg = wx.MessageDialog(window, string, caption, style) | |
26 | result = dlg.ShowModal() | |
c12bc4de | 27 | dlg.Destroy() |
7153b2cb RD |
28 | return result |
29 | ||
c12bc4de | 30 | |
7153b2cb RD |
31 | class main_window(wx.Frame): |
32 | """wxProject MainFrame.""" | |
33 | def __init__(self, parent, title): | |
34 | """Create the wxProject MainFrame.""" | |
35 | wx.Frame.__init__(self, parent, title=title, size=(500, 500), | |
36 | style=wx.DEFAULT_FRAME_STYLE|wx.NO_FULL_REPAINT_ON_RESIZE) | |
c12bc4de RD |
37 | |
38 | ||
c12bc4de | 39 | # Set up menu bar for the program. |
7153b2cb | 40 | self.mainmenu = wx.MenuBar() # Create menu bar. |
c12bc4de | 41 | |
7153b2cb RD |
42 | # Make the 'Project' menu. |
43 | menu = wx.Menu() | |
c12bc4de | 44 | |
7153b2cb RD |
45 | item = menu.Append(wx.ID_OPEN, '&Open', 'Open project') # Append a new menu |
46 | self.Bind(wx.EVT_MENU, self.OnProjectOpen, item) # Create and assign a menu event. | |
c12bc4de | 47 | |
7153b2cb RD |
48 | item = menu.Append(wx.ID_NEW, '&New', 'New project') |
49 | self.Bind(wx.EVT_MENU, self.OnProjectNew, item) | |
c12bc4de | 50 | |
7153b2cb RD |
51 | item = menu.Append(wx.ID_EXIT, 'E&xit', 'Exit program') |
52 | self.Bind(wx.EVT_MENU, self.OnProjectExit, item) | |
c12bc4de | 53 | |
7153b2cb | 54 | self.mainmenu.Append(menu, '&Project') # Add the project menu to the menu bar. |
c12bc4de | 55 | |
7153b2cb RD |
56 | # Make the 'File' menu. |
57 | menu = wx.Menu() | |
c12bc4de | 58 | |
7153b2cb RD |
59 | item = menu.Append(wx.ID_ANY, '&Add', 'Add file to project') |
60 | self.Bind(wx.EVT_MENU, self.OnFileAdd, item) | |
c12bc4de | 61 | |
7153b2cb RD |
62 | item = menu.Append(wx.ID_ANY, '&Remove', 'Remove file from project') |
63 | self.Bind(wx.EVT_MENU, self.OnFileRemove, item) | |
c12bc4de | 64 | |
7153b2cb RD |
65 | item = menu.Append(wx.ID_ANY, '&Open', 'Open file for editing') |
66 | self.Bind(wx.EVT_MENU, self.OnFileOpen, item) | |
67 | ||
68 | item = menu.Append(wx.ID_ANY, '&Save', 'Save file') | |
69 | self.Bind(wx.EVT_MENU, self.OnFileSave, item) | |
70 | ||
71 | self.mainmenu.Append(menu, '&File') # Add the file menu to the menu bar. | |
72 | ||
73 | # Attach the menu bar to the window. | |
74 | self.SetMenuBar(self.mainmenu) | |
c12bc4de | 75 | |
c12bc4de | 76 | # Create the splitter window. |
7153b2cb RD |
77 | splitter = wx.SplitterWindow(self, style=wx.NO_3D|wx.SP_3D) |
78 | splitter.SetMinimumPaneSize(1) | |
c12bc4de | 79 | |
c12bc4de | 80 | # Create the tree on the left. |
7153b2cb RD |
81 | self.tree = wx.TreeCtrl(splitter, style=wx.TR_DEFAULT_STYLE) |
82 | self.tree.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT, self.OnTreeLabelEdit) | |
83 | self.tree.Bind(wx.EVT_TREE_END_LABEL_EDIT, self.OnTreeLabelEditEnd) | |
84 | self.tree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnTreeItemActivated) | |
85 | ||
c12bc4de | 86 | # Create the editor on the right. |
7153b2cb RD |
87 | self.editor = wx.TextCtrl(splitter, style=wx.TE_MULTILINE) |
88 | self.editor.Enable(0) | |
c12bc4de | 89 | |
c12bc4de | 90 | # Install the tree and the editor. |
7153b2cb RD |
91 | splitter.SplitVertically(self.tree, self.editor) |
92 | splitter.SetSashPosition(180, True) | |
c12bc4de RD |
93 | |
94 | # Some global state variables. | |
1e4a197e | 95 | self.projectdirty = False |
7153b2cb RD |
96 | self.root = None |
97 | self.close = False | |
98 | ||
99 | self.Bind(wx.EVT_CLOSE, self.OnProjectExit) | |
100 | ||
101 | self.Show(True) | |
c12bc4de RD |
102 | |
103 | # ---------------------------------------------------------------------------------------- | |
104 | # Some nice little handlers. | |
105 | # ---------------------------------------------------------------------------------------- | |
106 | ||
c12bc4de | 107 | def project_open(self, project_file): |
7153b2cb | 108 | """Open and process a wxProject file.""" |
c12bc4de | 109 | try: |
7153b2cb | 110 | input = open(project_file, 'r') |
c12bc4de RD |
111 | self.tree.DeleteAllItems() |
112 | ||
113 | self.project_file = project_file | |
7153b2cb RD |
114 | name = input.readline().replace ('\n', '') |
115 | self.SetTitle(name) | |
116 | ||
117 | # create the file elements in the tree control. | |
c12bc4de RD |
118 | self.root = self.tree.AddRoot(name) |
119 | self.activeitem = self.root | |
120 | for line in input.readlines(): | |
7153b2cb RD |
121 | self.tree.AppendItem(self.root, line.replace ('\n', '')) |
122 | input.close() | |
123 | self.tree.Expand(self.root) | |
c12bc4de RD |
124 | |
125 | self.editor.Clear() | |
7153b2cb | 126 | self.editor.Enable(False) |
c12bc4de | 127 | |
1e4a197e | 128 | self.projectdirty = False |
c12bc4de RD |
129 | except IOError: |
130 | pass | |
131 | ||
132 | def project_save(self): | |
7153b2cb | 133 | """Save a wxProject file.""" |
c12bc4de | 134 | try: |
7153b2cb RD |
135 | output = open(self.project_file, 'w+') |
136 | output.write(self.tree.GetItemText(self.root) + '\n') | |
137 | count = self.tree.GetChildrenCount(self.root) # collect all file (tree) items. | |
c12bc4de RD |
138 | iter = 0 |
139 | child = '' | |
140 | for i in range(count): | |
141 | if i == 0: | |
7153b2cb | 142 | child, cookie = self.tree.GetFirstChild(self.root) |
c12bc4de | 143 | else: |
7153b2cb RD |
144 | child, cookie = self.tree.GetNextChild(self.root, cookie) |
145 | output.write(self.tree.GetItemText(child) + '\n') | |
c12bc4de | 146 | output.close() |
1e4a197e | 147 | self.projectdirty = False |
c12bc4de | 148 | except IOError: |
7153b2cb RD |
149 | MsgDlg(self, 'There was an error saving the new project file.', 'Error!', wx.OK) |
150 | ||
151 | def CheckProjectDirty(self): | |
152 | """Were the current project changed? If so, save it before.""" | |
153 | open_it = True | |
154 | if self.projectdirty: | |
155 | # save the current project file first. | |
156 | result = MsgDlg(self, 'The project has been changed. Save?') | |
157 | if result == wx.ID_YES: | |
158 | self.project_save() | |
159 | if result == wx.ID_CANCEL: | |
160 | open_it = False | |
161 | return open_it | |
162 | ||
163 | def CheckTreeRootItem(self): | |
164 | """Is there any root item?""" | |
165 | if not self.root: | |
166 | MsgDlg(self, 'Please create or open a project before.', 'Error!', wx.OK) | |
167 | return False | |
168 | return True | |
c12bc4de RD |
169 | |
170 | # ---------------------------------------------------------------------------------------- | |
171 | # Event handlers from here on out. | |
172 | # ---------------------------------------------------------------------------------------- | |
173 | ||
174 | def OnProjectOpen(self, event): | |
7153b2cb RD |
175 | """Open a wxProject file.""" |
176 | open_it = self.CheckProjectDirty() | |
c12bc4de | 177 | if open_it: |
7153b2cb RD |
178 | dlg = wx.FileDialog(self, 'Choose a project to open', '.', '', '*.wxp', wx.OPEN) |
179 | if dlg.ShowModal() == wx.ID_OK: | |
180 | self.project_open(dlg.GetPath()) | |
181 | dlg.Destroy() | |
c12bc4de RD |
182 | |
183 | def OnProjectNew(self, event): | |
7153b2cb RD |
184 | """Create a new wxProject.""" |
185 | open_it = self.CheckProjectDirty() | |
c12bc4de | 186 | if open_it: |
7153b2cb RD |
187 | dlg = wx.TextEntryDialog(self, 'Name for new project:', 'New Project', |
188 | 'New project', wx.OK|wx.CANCEL) | |
189 | if dlg.ShowModal() == wx.ID_OK: | |
190 | newproj = dlg.GetValue() | |
191 | dlg.Destroy() | |
192 | dlg = wx.FileDialog(self, 'Place to store new project.', '.', '', '*.wxp', wx.SAVE) | |
193 | if dlg.ShowModal() == wx.ID_OK: | |
194 | try: | |
195 | # save the project file. | |
196 | proj = open(dlg.GetPath(), 'w') | |
197 | proj.write(newproj + '\n') | |
198 | proj.close() | |
199 | self.project_open(dlg.GetPath()) | |
200 | except IOError: | |
201 | MsgDlg(self, 'There was an error saving the new project file.', 'Error!', wx.OK) | |
202 | dlg.Destroy() | |
203 | ||
204 | def SaveCurrentFile(self): | |
205 | """Check and save current file.""" | |
206 | go_ahead = True | |
207 | if self.root: | |
208 | if self.activeitem != self.root: | |
209 | if self.editor.IsModified(): # Save modified file before | |
210 | result = MsgDlg(self, 'The edited file has changed. Save it?') | |
211 | if result == wx.ID_YES: | |
212 | self.editor.SaveFile(self.tree.GetItemText(self.activeitem)) | |
213 | if result == wx.ID_CANCEL: | |
214 | go_ahead = False | |
215 | if go_ahead: | |
216 | self.tree.SetItemBold(self.activeitem, 0) | |
217 | return go_ahead | |
c12bc4de RD |
218 | |
219 | def OnProjectExit(self, event): | |
7153b2cb RD |
220 | """Quit the program.""" |
221 | if not self.close: | |
222 | self.close = True | |
223 | if not self.SaveCurrentFile(): | |
224 | self.close = False | |
225 | if self.projectdirty and self.close: | |
226 | result = MsgDlg(self, 'The project has been changed. Save?') | |
227 | if result == wx.ID_YES: | |
228 | self.project_save() | |
229 | if result == wx.ID_CANCEL: | |
230 | self.close = False | |
231 | if self.close: | |
232 | self.Close() | |
233 | else: | |
234 | event.Skip() | |
c12bc4de RD |
235 | |
236 | def OnFileAdd(self, event): | |
7153b2cb RD |
237 | """Adds a file to the current project.""" |
238 | if not self.CheckTreeRootItem(): | |
239 | return | |
240 | ||
241 | dlg = wx.FileDialog(self, 'Choose a file to add.', '.', '', '*.*', wx.OPEN) | |
242 | if dlg.ShowModal() == wx.ID_OK: | |
243 | path = os.path.split(dlg.GetPath()) | |
244 | self.tree.AppendItem(self.root, path[1]) | |
245 | self.tree.Expand(self.root) | |
246 | self.project_save() | |
c12bc4de RD |
247 | |
248 | def OnFileRemove(self, event): | |
7153b2cb RD |
249 | """Removes a file to the current project.""" |
250 | if not self.CheckTreeRootItem(): | |
251 | return | |
c12bc4de RD |
252 | item = self.tree.GetSelection() |
253 | if item != self.root: | |
7153b2cb RD |
254 | self.tree.Delete(item) |
255 | self.project_save() | |
c12bc4de RD |
256 | |
257 | def OnFileOpen(self, event): | |
7153b2cb RD |
258 | """Opens current selected file.""" |
259 | if self.root: | |
260 | item = self.tree.GetSelection() | |
261 | if item != self.root: | |
262 | self.OnTreeItemActivated(None, item) | |
263 | return | |
264 | MsgDlg(self, 'There is no file to load.', 'Error!', wx.OK) | |
c12bc4de RD |
265 | |
266 | def OnFileSave(self, event): | |
7153b2cb RD |
267 | """Saves current selected file.""" |
268 | if self.root: | |
269 | if self.activeitem != self.root: | |
270 | self.editor.SaveFile(self.tree.GetItemText(self.activeitem)) | |
271 | return | |
272 | MsgDlg(self, 'There is no file to save.', 'Error!', wx.OK) | |
c12bc4de RD |
273 | |
274 | ||
275 | def OnTreeLabelEdit(self, event): | |
7153b2cb RD |
276 | """Edit tree label (only root label can be edited).""" |
277 | item = event.GetItem() | |
c12bc4de | 278 | if item != self.root: |
7153b2cb | 279 | event.Veto() |
c12bc4de RD |
280 | |
281 | def OnTreeLabelEditEnd(self, event): | |
7153b2cb | 282 | """End editing the tree label.""" |
1e4a197e | 283 | self.projectdirty = True |
c12bc4de | 284 | |
7153b2cb RD |
285 | |
286 | def OnTreeItemActivated(self, event, item=None): | |
287 | """Tree item was activated: try to open this file.""" | |
288 | go_ahead = self.SaveCurrentFile() | |
c12bc4de RD |
289 | |
290 | if go_ahead: | |
7153b2cb RD |
291 | if event: |
292 | item = event.GetItem() | |
293 | self.activeitem = item | |
294 | if item != self.root: | |
295 | # load the current selected file | |
296 | self.tree.SetItemBold(item, 1) | |
297 | self.editor.Enable(1) | |
298 | self.editor.LoadFile(self.tree.GetItemText(item)) | |
299 | self.editor.SetInsertionPoint(0) | |
300 | self.editor.SetFocus() | |
301 | else: | |
302 | self.editor.Clear() | |
303 | self.editor.Enable(0) | |
304 | ||
305 | ||
306 | class App(wx.App): | |
307 | """wxProject Application.""" | |
c12bc4de | 308 | def OnInit(self): |
7153b2cb RD |
309 | """Create the wxProject Application.""" |
310 | frame = main_window(None, 'wxProject - ' + projfile) | |
311 | if projfile != 'Unnamed': | |
312 | frame.project_open(projfile) | |
1e4a197e | 313 | return True |
c12bc4de | 314 | |
c12bc4de | 315 | |
7153b2cb RD |
316 | if __name__ == '__main__': |
317 | app = App(0) | |
318 | app.MainLoop() |