repos/MysteryMachine
view MysteryMachine/Ui/wx/__init__.py @ 313:d7591777a9f6
New installer,README and version bump for 0.14
| author | Roger Gammans <rgammans@computer-surgery.co.uk> |
|---|---|
| date | Thu Apr 07 20:53:16 2011 +0100 (13 months ago) |
| parents | a938f45533a8 |
| children |
line source
1 #!/usr/bin/env python
2 # Ui/wx/__init__.py - Copyright R G Gammans
3 #
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License along
16 # with this program; if not, write to the Free Software Foundation, Inc.,
17 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 #
19 #
20 #
22 from __future__ import with_statement
24 import MysteryMachine
25 from MysteryMachine.Exceptions import *
27 from MysteryMachine.schema.MMAttribute import MMAttribute
28 from MysteryMachine.schema.MMObject import MMObject
29 from MysteryMachine.schema.MMSystem import MMSystem
32 import mercurial.ui as hgui
33 import tempfile
35 import wx
36 import wx.aui
37 import wx.lib.scrolledpanel as scrolled
39 #Change to read this out of the generated file , created from mercurial data.
40 DEVELOPERS = [ "Roger Gammans" ]
41 COPYRIGHT = "(C) Roger Gammans"
42 LICENSE = """
43 Copyright (C) 2008-2010 Roger Gammans <roger@gammascience.co.uk>.
44 This is free software; see the source for copying conditions. There is NO
45 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
47 You can redistribute it and/or modify it under the terms of the GNU General
48 Public License as published by the Free Software Foundation; either version
49 2 of the License, or (at your option) any later version.
50 """
52 NAME = "MysteryMachine"
53 VERSION = "0.14"
54 WEBSITE = "http://trac.backslashat.org/mysterymachine"
56 ID_NEW=wx.ID_NEW
57 ID_OPENPKFILE=wx.ID_OPEN
58 ID_CLOSE=wx.ID_CLOSE
59 ID_REVERT=wx.ID_REVERT
60 ID_QUIT=wx.ID_EXIT
61 ID_ABOUT=wx.ID_ABOUT
62 ID_ABOUTWX=107
63 ID_OPENURI=108
64 ID_COMMIT=109
65 ID_SAVE=wx.ID_SAVE
66 ID_SAVEAS=wx.ID_SAVEAS
68 ID_VIEW_BASE=1000
69 #
71 ID_URI_DIR_BROWSE=200
73 def _noop(uri):
74 return None
76 class OpenUriDialog(wx.Dialog):
77 def __init__(self,parent,id, title = "Open from a URI", caption =u"Chose URI to open", action = _noop ):
78 super(OpenUriDialog,self).__init__(parent,id,title)
79 self.action = action
80 outersizer=wx.StaticBoxSizer(wx.StaticBox(self,1,caption), wx.VERTICAL)
81 sizer=wx.BoxSizer( wx.HORIZONTAL)
82 self.SetSizer(outersizer)
83 outersizer.Add(sizer ,1 , wx.EXPAND, 20)
84 schemes = MysteryMachine.store.GetStoreNames()
85 self.combobox = wx.ComboBox(self,-1,choices = list(schemes) )
86 self.textctrl = wx.TextCtrl(self,-1)
87 self.button = wx.Button(self,ID_URI_DIR_BROWSE,label="Browse")
88 wx.EVT_BUTTON(self,ID_URI_DIR_BROWSE,self.onDirBrowse)
89 sizer.Add(self.combobox,1)
90 sizer.Add(wx.StaticText(self,-1,label = ":" ) ,0)
91 sizer.Add(self.textctrl,2)
92 sizer.Add(self.button,1)
94 sizer2=wx.StdDialogButtonSizer()
95 sizer2.Add(wx.Button(self,wx.ID_OK,"OK"))
96 sizer2.Add(wx.Button(self,wx.ID_CANCEL,"Cancel"))
97 outersizer.Add(sizer2)
98 outersizer.Fit(self)
100 wx.EVT_BUTTON(self,wx.ID_OK,self.onDoLoad)
101 wx.EVT_BUTTON(self,wx.ID_CANCEL,self.onCancel)
102 self.Show()
104 def onDoLoad(self,evt):
105 print "inDoload"
106 uri = self.combobox.GetValue() + ":" + self.textctrl.GetValue()
107 sys = self.action(uri)
108 wx.GetApp().OpenFrame(sys)
109 self.Close()
110 self.Destroy()
113 def onCancel(self,evt):
114 print "o-uri cancelled"
115 self.Close()
116 self.Destroy()
118 def GetUri(self):
119 return self.combobox.GetValue() + ":" + self.textctrl.GetValue()
121 def onDirBrowse(self,event):
122 chosendir = wx.DirSelector("Select system directory")
123 self.textctrl.SetValue(chosendir)
126 class ScrolledTab(scrolled.ScrolledPanel):
127 pass
128 def __init__(self,parent,*args,**kwargs):
130 super(scrolled.ScrolledPanel,self).__init__(parent,*args,**kwargs)
131 self.sizer = wx.GridSizer()
132 self.SetSizer(self.sizer)
133 self.innerpanel = None
135 def Add(self,panel):
136 self.innerpanel =panel
137 self.GetSizer().Add(panel,1,wx.EXPAND)
138 self.innerpanel.FitInside()
139 self.innerpanel.Show(True)
140 self.Layout()
141 self.SetAutoLayout(True)
142 self.SetupScrolling()
144 def getPanelName(self):
145 return self.innerpanel.getPanelName()
149 def _create_new(uri):
150 return wx.GetApp().ctx.CreateNew(uri = uri)
152 class MainWindow(wx.Frame):
155 AboutInfo = wx.AboutDialogInfo()
156 for dev in DEVELOPERS:
157 AboutInfo.AddDeveloper(dev)
158 AboutInfo.SetCopyright(COPYRIGHT)
159 AboutInfo.SetLicense(LICENSE)
160 AboutInfo.SetVersion(VERSION)
161 AboutInfo.SetWebSite(WEBSITE)
163 def __init__(self,parent,id,title,size):
164 wx.Frame.__init__(self,parent,id,title)
165 self.app = None
166 #Create menu.
167 self.menu=wx.MenuBar()
168 self.fileMenu=wx.Menu()
169 self.fileMenu.Append( ID_NEW , "&New","Create a new freeform")
170 wx.EVT_MENU(self, ID_NEW, self.OnNew)
172 self.fileMenu.Append(ID_OPENPKFILE,"&Open PackFile")
173 wx.EVT_MENU(self, ID_OPENPKFILE , self.OnOpenFile)
175 self.fileMenu.Append(ID_OPENURI ,"Open From a &URI")
176 wx.EVT_MENU(self, ID_OPENURI , self.OnOpenUri)
178 self.revertMenuItem = self.fileMenu.Append(ID_REVERT,"&Revert")
179 self.revertMenuItem.Enable(False)
180 wx.EVT_MENU(self, ID_REVERT, self.OnRevert)
182 self.commitMenuItem = self.fileMenu.Append(ID_COMMIT,"&Commit")
183 self.commitMenuItem.Enable(False)
184 wx.EVT_MENU(self, ID_COMMIT, self.OnCommit)
186 self.saveMenuItem = self.fileMenu.Append(ID_SAVE,"&Save")
187 self.saveMenuItem.Enable(False)
188 wx.EVT_MENU(self, ID_SAVE, self.OnSave)
190 self.saveasMenuItem = self.fileMenu.Append(ID_SAVEAS,"Save As..")
191 self.saveasMenuItem.Enable(False)
192 wx.EVT_MENU(self, ID_SAVEAS, self.OnSaveAs)
194 self.closeMenuItem = self.fileMenu.Append(ID_CLOSE,"&Close")
195 self.closeMenuItem.Enable(False)
196 wx.EVT_MENU(self, ID_CLOSE, self.OnClose)
199 self.fileMenu.AppendSeparator()
201 self.fileMenu.Append(ID_QUIT,"&Quit")
202 wx.EVT_MENU(self, ID_QUIT, self.OnExit)
204 self.ViewMenu=wx.Menu()
205 self.helpMenu=wx.Menu()
207 self.menu.Append(self.fileMenu,"&File")
208 self.menu.Append(self.ViewMenu,"&View")
209 self.menu.Append(self.helpMenu,"&Help")
211 self.helpMenu.Append(ID_ABOUT,"&About Mystery Machine")
212 wx.EVT_MENU(self, ID_ABOUT, self.OnAboutMM)
214 self.SetMenuBar(self.menu)
215 self.status=wx.StatusBar(self)
216 self.status.Enable()
217 self.status.Show()
218 self.SetStatusBar(self.status)
220 #Variable to store references to view objects
221 self.nextViewId=ID_VIEW_BASE
223 self.panel = None
224 self.Layout()
228 def OnNew(self,event):
229 print "onnew"
230 dialog = OpenUriDialog(None , -1 , title = "Chose Uri to store new sytem" , caption = "Enter scheme and Uri" , action = _create_new)
231 #Set some default values here so users don't need to worry.
232 dialog.combobox.SetValue("hgafile")
233 workdir = tempfile.mkdtemp("mm-newsystem")
234 dialog.textctrl.SetValue(workdir)
235 pass
237 def OnAboutMM(self,event):
238 print self.__class__.AboutInfo
239 wx.AboutBox(self.__class__.AboutInfo)
241 def OnOpenFile(self,event):
242 packfile = wx.FileSelector("Open a MysteryMachine Packfile",wildcard="*.mmpack")
243 print packfile
244 sys = self.app.ctx.OpenPackFile(packfile)
245 self.app.OpenFrame(sys)
247 def OnSave(self,event):
248 try:
249 self.sys.SaveAsPackFile()
250 except NoPackFileName , e:
251 self.OnSaveAs(event)
253 def OnSaveAs(self,event):
254 name = str(self.sys) + ".mmpack"
255 packfile = wx.FileSelector("Save a MysteryMachine Packfile",wildcard="*.mmpack",
256 default_filename = name,
257 default_extension = ".mmpack",flags = wx.FD_SAVE + wx.FD_OVERWRITE_PROMPT)
258 self.sys.SaveAsPackFile(packfile)
260 def AssignSystem(self,sys):
261 import systree
262 if sys:
263 self.nb = wx.aui.AuiNotebook(self)
264 panel = systree.TreePanel(self,sys)
265 self.SetTitle("MysteryMachine - %s" % (sys or ""))
267 self.AddPanel(panel)
269 self.sizer = wx.BoxSizer(wx.VERTICAL)
270 self.sizer.Add(self.nb,1,wx.EXPAND)
271 self.SetSizer(self.sizer)
272 self.Layout()
273 else:
274 self.sizer.Remove(self.nb)
275 for page_nr in range(self.nb.GetPageCount()):
276 self.nb.DeletePage(page_nr)
277 self.nb.Close()
278 self.nb = None
279 self.SetTitle("MysteryMachine")
280 self.SetSizer(None)
281 self.sizer = None
283 self.sys = sys
284 self.app.frames[sys] = self
285 self.app.systems[self] = sys
286 self.closeMenuItem.Enable(sys is not None)
287 self.saveMenuItem.Enable(sys is not None)
288 self.saveasMenuItem.Enable(sys is not None)
289 self.revertMenuItem.Enable(sys is not None)
290 self.commitMenuItem.Enable(sys is not None)
292 def AddPanel(self,panel):
293 self.nb.AddPage(panel,panel.getPanelName())
296 def GetNewNodePanel(self,parent,schema_node):
297 """Returns a panel for the passed in schema node
299 schema_node must be a node in a MysteryMachine.schema.
300 """
301 ##FIXME: consult userprefs to find what panel to open
302 # for each object type.
303 panel = None
305 if isinstance(schema_node,MMAttribute):
306 import attributepanel
307 panel = attributepanel.AttributePanel(parent, schema_node )
309 if isinstance(schema_node,MMObject):
310 import objectpanel
311 panel = objectpanel.ObjectPanel(parent, schema_node )
313 if isinstance(schema_node,MMSystem):
314 import systree
315 panel = systree.TreePanel(parent,schema_node)
316 return panel
318 def NewSchemaView(self,schema_node):
319 """Creates a new tab showing schema_node.
321 schema_node must be a node in a MysteryMachine.schema.
322 """
324 panel = ScrolledTab(self,-1)
325 innerpanel = self.GetNewNodePanel(panel,schema_node)
326 if innerpanel is None:
327 panel.Destroy()
328 return
329 panel.Add(innerpanel)
331 if panel: self.AddPanel(panel)
334 def OnOpenUri(self,event):
335 dialog = OpenUriDialog(None , -1 , action = self.app.ctx.OpenUri)
337 def OnRevert(self,event):
338 print "onrevertr"
339 pass
341 def OnCommit(self,event):
342 caption = "Enter log message for this changeset"
343 title = ""
344 newstr = wx.GetTextFromUser(title,caption = caption)
345 self.sys.Commit(newstr)
348 def OnClose(self,event):
349 print "onclose"
350 #TODO: Check if system is saved.
351 self.app.CloseFrame(self)
353 def OnExit(self,event):
354 wx.GetApp().ExitMainLoop()
356 def AddView(self,viewname,desc,evtHndlr):
357 id=++self.nextViewId
358 self.ViewMenu.Append(id,viewname,desc);
359 wx.EVT_MENU(self,id,evtHndlr)
360 return id
362 def SetApp(self,app):
363 self.app = app
366 class WxMercurialUi(hgui.ui):
367 def plain(self):
368 """Activates plain mode so parsing of repsonses is easier"""
369 return True
371 class MMWxApp(wx.PySimpleApp):
372 def __init__(self,options = []):
373 wx.PySimpleApp.__init__(self)
375 self.args = options
376 self.ctx = None
378 self.SetVendorName("Roger Gammans")
379 self.SetAppName("MysteryMachine")
381 win=MainWindow(None ,-1,"MysteryMachine", size=(400,200))
382 self.SetTopWindow(win)
383 win.SetApp(self)
384 win.Show()
386 self.ui = WxMercurialUi()
387 self.frames = { None: win }
388 self.systems = { win: None }
390 def OpenFrame(self,system):
391 """Assigns a system to a Frame.
393 Opens a new top level frame for a system, or assigns
394 to an existing unassigned frame if any.
395 """
396 if system in self.frames:
397 #System already open so raise it's window to the top.
398 self.frames[system].Raise()
399 return
401 if None in self.frames:
402 win = self.frames[None]
403 del self.frames[None]
404 win.AssignSystem(system)
405 else:
406 newwin = MainWindow(None ,-1, "", size=(400,400))
407 newwin.SetApp(self)
408 newwin.AssignSystem(system)
409 newwin.Show()
411 def CloseFrame(self,frame):
412 """Close an existing frame and system
413 """
415 system = self.systems[frame]
416 if len(self.frames) == 1:
417 frame.AssignSystem(None)
418 else:
419 frame.Close()
420 del self.frames[system]
421 del self.systems[frame]
423 def mercurial_ui(self):
424 return self.ui
426 def Run(self):
427 with MysteryMachine.StartApp(self.args) as ctx:
428 self.ctx = ctx
429 self.MainLoop()
430 self.ctx = None
434 def main():
435 from MysteryMachine.Main import process_args
437 options = process_args()
438 ui = MMWxApp(options)
440 ui.Run()
443 if __name__ == "__main__":
444 main()
