X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/2481bf3cb684141768951d987a5adce365735051..a7d8ec1e42288ca161d70e754bbe32dd387c7765:/wxPython/wx/tools/XRCed/xrced.py diff --git a/wxPython/wx/tools/XRCed/xrced.py b/wxPython/wx/tools/XRCed/xrced.py index f1ba7d58c8..63cc39c6f2 100644 --- a/wxPython/wx/tools/XRCed/xrced.py +++ b/wxPython/wx/tools/XRCed/xrced.py @@ -6,7 +6,7 @@ """ -xrced -- Simple resource editor for XRC format used by wxWindows/wxPython +xrced -- Simple resource editor for XRC format used by wxWidgets/wxPython GUI toolkit. Usage: @@ -20,14 +20,15 @@ Options: -v output version info and exit """ - from globals import * -import os, sys, getopt, re, traceback +import os, sys, getopt, re, traceback, tempfile, shutil, cPickle +from xml.parsers import expat # Local modules from tree import * # imports xxx which imports params from panel import * from tools import * +from params import genericStyles # Cleanup recursive import sideeffects, otherwise we can't create undoMan import undo undo.ParamPage = ParamPage @@ -39,6 +40,9 @@ if __name__ == '__main__': else: basePath = os.path.dirname(__file__) +# Remember system path +sys_path = sys.path + # 1 adds CMD command to Help menu debug = 0 @@ -50,38 +54,47 @@ select "Append Child", and then any command.

Or just press one of the buttons on the tools palette.

Enter XML ID, change properties, create children.

To test your interface select Test command (View menu).

-Consult README file for the details. +Consult README.txt file for the details. """ defaultIDs = {xxxPanel:'PANEL', xxxDialog:'DIALOG', xxxFrame:'FRAME', - xxxMenuBar:'MENUBAR', xxxMenu:'MENU', xxxToolBar:'TOOLBAR'} + xxxMenuBar:'MENUBAR', xxxMenu:'MENU', xxxToolBar:'TOOLBAR', + xxxWizard:'WIZARD', xxxBitmap:'BITMAP', xxxIcon:'ICON'} + +defaultName = 'UNTITLED.xrc' ################################################################################ # ScrolledMessageDialog - modified from wxPython lib to set fixed-width font -class ScrolledMessageDialog(wxDialog): - def __init__(self, parent, msg, caption, pos = wxDefaultPosition, size = (500,300)): - from wxPython.lib.layoutf import Layoutf - wxDialog.__init__(self, parent, -1, caption, pos, size) - text = wxTextCtrl(self, -1, msg, wxDefaultPosition, - wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY) - text.SetFont(modernFont) - dc = wxWindowDC(text) - # !!! possible bug - GetTextExtent without font returns sysfont dims - w, h = dc.GetFullTextExtent(' ', modernFont)[:2] - ok = wxButton(self, wxID_OK, "OK") +class ScrolledMessageDialog(wx.Dialog): + def __init__(self, parent, msg, caption, pos = wx.DefaultPosition, size = (500,300)): + from wx.lib.layoutf import Layoutf + wx.Dialog.__init__(self, parent, -1, caption, pos, size) + text = wx.TextCtrl(self, -1, msg, wx.DefaultPosition, + wx.DefaultSize, wx.TE_MULTILINE | wx.TE_READONLY) + text.SetFont(g.modernFont()) + dc = wx.WindowDC(text) + w, h = dc.GetFullTextExtent(' ', g.modernFont())[:2] + ok = wx.Button(self, wx.ID_OK, "OK") + ok.SetDefault() text.SetConstraints(Layoutf('t=t5#1;b=t5#2;l=l5#1;r=r5#1', (self,ok))) text.SetSize((w * 80 + 30, h * 40)) - ok.SetConstraints(Layoutf('b=b5#1;x%w50#1;w!80;h!25', (self,))) + text.ShowPosition(1) # scroll to the first line + ok.SetConstraints(Layoutf('b=b5#1;x%w50#1;w!80;h!35', (self,))) self.SetAutoLayout(True) self.Fit() - self.CenterOnScreen(wxBOTH) + self.CenterOnScreen(wx.BOTH) ################################################################################ -class Frame(wxFrame): +# Event handler for using during location +class Locator(wx.EvtHandler): + def ProcessEvent(self, evt): + print evt + +class Frame(wx.Frame): def __init__(self, pos, size): - wxFrame.__init__(self, None, -1, '', pos, size) + wx.Frame.__init__(self, None, -1, '', pos, size) global frame frame = g.frame = self bar = self.CreateStatusBar(2) @@ -91,130 +104,207 @@ class Frame(wxFrame): # Idle flag self.inIdle = False + # Load our own resources + self.res = xrc.EmptyXmlResource() + # !!! Blocking of assert failure occurring in older unicode builds + try: + quietlog = wx.LogNull() + self.res.Load(os.path.join(basePath, 'xrced.xrc')) + except wx._core.PyAssertionError: + print 'PyAssertionError was ignored' + # Make menus - menuBar = wxMenuBar() + menuBar = wx.MenuBar() - menu = wxMenu() - menu.Append(wxID_NEW, '&New\tCtrl-N', 'New file') - menu.Append(wxID_OPEN, '&Open...\tCtrl-O', 'Open XRC file') - menu.Append(wxID_SAVE, '&Save\tCtrl-S', 'Save XRC file') - menu.Append(wxID_SAVEAS, 'Save &As...', 'Save XRC file under different name') + menu = wx.Menu() + menu.Append(wx.ID_NEW, '&New\tCtrl-N', 'New file') + menu.AppendSeparator() + menu.Append(wx.ID_OPEN, '&Open...\tCtrl-O', 'Open XRC file') + + self.recentMenu = wx.Menu() + g.fileHistory.UseMenu(self.recentMenu) + g.fileHistory.AddFilesToMenu() + self.Bind(wx.EVT_MENU, self.OnRecentFile, id=wx.ID_FILE1, id2=wx.ID_FILE9) + menu.AppendMenu(-1, 'Open &Recent', self.recentMenu, 'Open a recent file') + + menu.AppendSeparator() + menu.Append(wx.ID_SAVE, '&Save\tCtrl-S', 'Save XRC file') + menu.Append(wx.ID_SAVEAS, 'Save &As...', 'Save XRC file under different name') + self.ID_GENERATE_PYTHON = wx.NewId() + menu.Append(self.ID_GENERATE_PYTHON, '&Generate Python...', + 'Generate a Python module that uses this XRC') menu.AppendSeparator() - menu.Append(wxID_EXIT, '&Quit\tCtrl-Q', 'Exit application') + self.ID_PREFS = wx.NewId() + menu.Append(self.ID_PREFS, 'Preferences...', 'Change XRCed settings') + menu.AppendSeparator() + menu.Append(wx.ID_EXIT, '&Quit\tCtrl-Q', 'Exit application') + menuBar.Append(menu, '&File') - menu = wxMenu() - menu.Append(wxID_UNDO, '&Undo\tCtrl-Z', 'Undo') - menu.Append(wxID_REDO, '&Redo\tCtrl-Y', 'Redo') + menu = wx.Menu() + menu.Append(wx.ID_UNDO, '&Undo\tCtrl-Z', 'Undo') + menu.Append(wx.ID_REDO, '&Redo\tCtrl-Y', 'Redo') menu.AppendSeparator() - menu.Append(wxID_CUT, 'Cut\tCtrl-X', 'Cut to the clipboard') - menu.Append(wxID_COPY, '&Copy\tCtrl-C', 'Copy to the clipboard') - menu.Append(wxID_PASTE, '&Paste\tCtrl-V', 'Paste from the clipboard') - self.ID_DELETE = wxNewId() + menu.Append(wx.ID_CUT, 'Cut\tCtrl-X', 'Cut to the clipboard') + menu.Append(wx.ID_COPY, '&Copy\tCtrl-C', 'Copy to the clipboard') + menu.Append(wx.ID_PASTE, '&Paste\tCtrl-V', 'Paste from the clipboard') + self.ID_DELETE = wx.NewId() menu.Append(self.ID_DELETE, '&Delete\tCtrl-D', 'Delete object') -# menu.AppendSeparator() - ID_SELECT = wxNewId() -# menu.Append(ID_SELECT, '&Select', 'Select object') + menu.AppendSeparator() + self.ID_LOCATE = wx.NewId() + self.ID_TOOL_LOCATE = wx.NewId() + self.ID_TOOL_PASTE = wx.NewId() + menu.Append(self.ID_LOCATE, '&Locate\tCtrl-L', 'Locate control in test window and select it') menuBar.Append(menu, '&Edit') - menu = wxMenu() - self.ID_EMBED_PANEL = wxNewId() + menu = wx.Menu() + self.ID_EMBED_PANEL = wx.NewId() menu.Append(self.ID_EMBED_PANEL, '&Embed Panel', 'Toggle embedding properties panel in the main window', True) menu.Check(self.ID_EMBED_PANEL, conf.embedPanel) - self.ID_SHOW_TOOLS = wxNewId() + self.ID_SHOW_TOOLS = wx.NewId() menu.Append(self.ID_SHOW_TOOLS, 'Show &Tools', 'Toggle tools', True) menu.Check(self.ID_SHOW_TOOLS, conf.showTools) menu.AppendSeparator() - self.ID_TEST = wxNewId() - menu.Append(self.ID_TEST, '&Test\tF5', 'Test window') - self.ID_REFRESH = wxNewId() + self.ID_TEST = wx.NewId() + menu.Append(self.ID_TEST, '&Test\tF5', 'Show test window') + self.ID_REFRESH = wx.NewId() menu.Append(self.ID_REFRESH, '&Refresh\tCtrl-R', 'Refresh test window') - self.ID_AUTO_REFRESH = wxNewId() - menu.Append(self.ID_AUTO_REFRESH, '&Auto-refresh\tCtrl-A', + self.ID_AUTO_REFRESH = wx.NewId() + menu.Append(self.ID_AUTO_REFRESH, '&Auto-refresh\tAlt-A', 'Toggle auto-refresh mode', True) menu.Check(self.ID_AUTO_REFRESH, conf.autoRefresh) + self.ID_TEST_HIDE = wx.NewId() + menu.Append(self.ID_TEST_HIDE, '&Hide\tF6', 'Close test window') menuBar.Append(menu, '&View') - menu = wxMenu() - menu.Append(wxID_ABOUT, '&About...', 'About XCRed') - self.ID_README = wxNewId() - menu.Append(self.ID_README, '&Readme...', 'View the README file') + menu = wx.Menu() + self.ID_MOVEUP = wx.NewId() + menu.Append(self.ID_MOVEUP, '&Up', 'Move before previous sibling') + self.ID_MOVEDOWN = wx.NewId() + menu.Append(self.ID_MOVEDOWN, '&Down', 'Move after next sibling') + self.ID_MOVELEFT = wx.NewId() + menu.Append(self.ID_MOVELEFT, '&Make sibling', 'Make sibling of parent') + self.ID_MOVERIGHT = wx.NewId() + menu.Append(self.ID_MOVERIGHT, '&Make child', 'Make child of previous sibling') + menuBar.Append(menu, '&Move') + + menu = wx.Menu() + menu.Append(wx.ID_ABOUT, '&About...', 'About XCRed') + self.ID_README = wx.NewId() + menu.Append(self.ID_README, '&Readme...\tF1', 'View the README file') if debug: - self.ID_DEBUG_CMD = wxNewId() + self.ID_DEBUG_CMD = wx.NewId() menu.Append(self.ID_DEBUG_CMD, 'CMD', 'Python command line') - EVT_MENU(self, self.ID_DEBUG_CMD, self.OnDebugCMD) + wx.EVT_MENU(self, self.ID_DEBUG_CMD, self.OnDebugCMD) menuBar.Append(menu, '&Help') self.menuBar = menuBar self.SetMenuBar(menuBar) # Create toolbar - tb = self.CreateToolBar(wxTB_HORIZONTAL | wxNO_BORDER | wxTB_FLAT) - tb.SetToolBitmapSize((24, 23)) - tb.AddSimpleTool(wxID_NEW, images.getNewBitmap(), 'New', 'New file') - tb.AddSimpleTool(wxID_OPEN, images.getOpenBitmap(), 'Open', 'Open file') - tb.AddSimpleTool(wxID_SAVE, images.getSaveBitmap(), 'Save', 'Save file') - tb.AddControl(wxStaticLine(tb, -1, size=(-1,23), style=wxLI_VERTICAL)) - tb.AddSimpleTool(wxID_UNDO, images.getUndoBitmap(), 'Undo', 'Undo') - tb.AddSimpleTool(wxID_REDO, images.getRedoBitmap(), 'Redo', 'Redo') - tb.AddControl(wxStaticLine(tb, -1, size=(-1,23), style=wxLI_VERTICAL)) - tb.AddSimpleTool(wxID_CUT, images.getCutBitmap(), 'Cut', 'Cut') - tb.AddSimpleTool(wxID_COPY, images.getCopyBitmap(), 'Copy', 'Copy') - tb.AddSimpleTool(wxID_PASTE, images.getPasteBitmap(), 'Paste', 'Paste') - tb.AddControl(wxStaticLine(tb, -1, size=(-1,23), style=wxLI_VERTICAL)) + tb = self.CreateToolBar(wx.TB_HORIZONTAL | wx.NO_BORDER | wx.TB_FLAT) + tb.SetToolBitmapSize((24,24)) + new_bmp = wx.ArtProvider.GetBitmap(wx.ART_NORMAL_FILE, wx.ART_TOOLBAR) + open_bmp = wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, wx.ART_TOOLBAR) + save_bmp = wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE, wx.ART_TOOLBAR) + undo_bmp = wx.ArtProvider.GetBitmap(wx.ART_UNDO, wx.ART_TOOLBAR) + redo_bmp = wx.ArtProvider.GetBitmap(wx.ART_REDO, wx.ART_TOOLBAR) + cut_bmp = wx.ArtProvider.GetBitmap(wx.ART_CUT, wx.ART_TOOLBAR) + copy_bmp = wx.ArtProvider.GetBitmap(wx.ART_COPY, wx.ART_TOOLBAR) + paste_bmp= wx.ArtProvider.GetBitmap(wx.ART_PASTE, wx.ART_TOOLBAR) + + tb.AddSimpleTool(wx.ID_NEW, new_bmp, 'New', 'New file') + tb.AddSimpleTool(wx.ID_OPEN, open_bmp, 'Open', 'Open file') + tb.AddSimpleTool(wx.ID_SAVE, save_bmp, 'Save', 'Save file') + tb.AddControl(wx.StaticLine(tb, -1, size=(-1,23), style=wx.LI_VERTICAL)) + tb.AddSimpleTool(wx.ID_UNDO, undo_bmp, 'Undo', 'Undo') + tb.AddSimpleTool(wx.ID_REDO, redo_bmp, 'Redo', 'Redo') + tb.AddControl(wx.StaticLine(tb, -1, size=(-1,23), style=wx.LI_VERTICAL)) + tb.AddSimpleTool(wx.ID_CUT, cut_bmp, 'Cut', 'Cut') + tb.AddSimpleTool(wx.ID_COPY, copy_bmp, 'Copy', 'Copy') + tb.AddSimpleTool(self.ID_TOOL_PASTE, paste_bmp, 'Paste', 'Paste') + tb.AddControl(wx.StaticLine(tb, -1, size=(-1,23), style=wx.LI_VERTICAL)) + tb.AddSimpleTool(self.ID_TOOL_LOCATE, + images.getLocateBitmap(), #images.getLocateArmedBitmap(), + 'Locate', 'Locate control in test window and select it', True) + tb.AddControl(wx.StaticLine(tb, -1, size=(-1,23), style=wx.LI_VERTICAL)) tb.AddSimpleTool(self.ID_TEST, images.getTestBitmap(), 'Test', 'Test window') tb.AddSimpleTool(self.ID_REFRESH, images.getRefreshBitmap(), 'Refresh', 'Refresh view') tb.AddSimpleTool(self.ID_AUTO_REFRESH, images.getAutoRefreshBitmap(), 'Auto-refresh', 'Toggle auto-refresh mode', True) - if wxPlatform == '__WXGTK__': - tb.AddSeparator() # otherwise auto-refresh sticks in status line + tb.AddControl(wx.StaticLine(tb, -1, size=(-1,23), style=wx.LI_VERTICAL)) + tb.AddSimpleTool(self.ID_MOVEUP, images.getToolMoveUpBitmap(), + 'Up', 'Move before previous sibling') + tb.AddSimpleTool(self.ID_MOVEDOWN, images.getToolMoveDownBitmap(), + 'Down', 'Move after next sibling') + tb.AddSimpleTool(self.ID_MOVELEFT, images.getToolMoveLeftBitmap(), + 'Make Sibling', 'Make sibling of parent') + tb.AddSimpleTool(self.ID_MOVERIGHT, images.getToolMoveRightBitmap(), + 'Make Child', 'Make child of previous sibling') +# if wx.Platform == '__WXGTK__': +# tb.AddSeparator() # otherwise auto-refresh sticks in status line tb.ToggleTool(self.ID_AUTO_REFRESH, conf.autoRefresh) tb.Realize() + self.tb = tb self.minWidth = tb.GetSize()[0] # minimal width is the size of toolbar # File - EVT_MENU(self, wxID_NEW, self.OnNew) - EVT_MENU(self, wxID_OPEN, self.OnOpen) - EVT_MENU(self, wxID_SAVE, self.OnSaveOrSaveAs) - EVT_MENU(self, wxID_SAVEAS, self.OnSaveOrSaveAs) - EVT_MENU(self, wxID_EXIT, self.OnExit) + wx.EVT_MENU(self, wx.ID_NEW, self.OnNew) + wx.EVT_MENU(self, wx.ID_OPEN, self.OnOpen) + wx.EVT_MENU(self, wx.ID_SAVE, self.OnSaveOrSaveAs) + wx.EVT_MENU(self, wx.ID_SAVEAS, self.OnSaveOrSaveAs) + wx.EVT_MENU(self, self.ID_GENERATE_PYTHON, self.OnGeneratePython) + wx.EVT_MENU(self, self.ID_PREFS, self.OnPrefs) + wx.EVT_MENU(self, wx.ID_EXIT, self.OnExit) # Edit - EVT_MENU(self, wxID_UNDO, self.OnUndo) - EVT_MENU(self, wxID_REDO, self.OnRedo) - EVT_MENU(self, wxID_CUT, self.OnCutDelete) - EVT_MENU(self, wxID_COPY, self.OnCopy) - EVT_MENU(self, wxID_PASTE, self.OnPaste) - EVT_MENU(self, self.ID_DELETE, self.OnCutDelete) - EVT_MENU(self, ID_SELECT, self.OnSelect) + wx.EVT_MENU(self, wx.ID_UNDO, self.OnUndo) + wx.EVT_MENU(self, wx.ID_REDO, self.OnRedo) + wx.EVT_MENU(self, wx.ID_CUT, self.OnCutDelete) + wx.EVT_MENU(self, wx.ID_COPY, self.OnCopy) + wx.EVT_MENU(self, wx.ID_PASTE, self.OnPaste) + wx.EVT_MENU(self, self.ID_TOOL_PASTE, self.OnPaste) + wx.EVT_MENU(self, self.ID_DELETE, self.OnCutDelete) + wx.EVT_MENU(self, self.ID_LOCATE, self.OnLocate) + wx.EVT_MENU(self, self.ID_TOOL_LOCATE, self.OnLocate) # View - EVT_MENU(self, self.ID_EMBED_PANEL, self.OnEmbedPanel) - EVT_MENU(self, self.ID_SHOW_TOOLS, self.OnShowTools) - EVT_MENU(self, self.ID_TEST, self.OnTest) - EVT_MENU(self, self.ID_REFRESH, self.OnRefresh) - EVT_MENU(self, self.ID_AUTO_REFRESH, self.OnAutoRefresh) + wx.EVT_MENU(self, self.ID_EMBED_PANEL, self.OnEmbedPanel) + wx.EVT_MENU(self, self.ID_SHOW_TOOLS, self.OnShowTools) + wx.EVT_MENU(self, self.ID_TEST, self.OnTest) + wx.EVT_MENU(self, self.ID_REFRESH, self.OnRefresh) + wx.EVT_MENU(self, self.ID_AUTO_REFRESH, self.OnAutoRefresh) + wx.EVT_MENU(self, self.ID_TEST_HIDE, self.OnTestHide) + # Move + wx.EVT_MENU(self, self.ID_MOVEUP, self.OnMoveUp) + wx.EVT_MENU(self, self.ID_MOVEDOWN, self.OnMoveDown) + wx.EVT_MENU(self, self.ID_MOVELEFT, self.OnMoveLeft) + wx.EVT_MENU(self, self.ID_MOVERIGHT, self.OnMoveRight) # Help - EVT_MENU(self, wxID_ABOUT, self.OnAbout) - EVT_MENU(self, self.ID_README, self.OnReadme) + wx.EVT_MENU(self, wx.ID_ABOUT, self.OnAbout) + wx.EVT_MENU(self, self.ID_README, self.OnReadme) # Update events - EVT_UPDATE_UI(self, wxID_CUT, self.OnUpdateUI) - EVT_UPDATE_UI(self, wxID_COPY, self.OnUpdateUI) - EVT_UPDATE_UI(self, wxID_PASTE, self.OnUpdateUI) - EVT_UPDATE_UI(self, wxID_UNDO, self.OnUpdateUI) - EVT_UPDATE_UI(self, wxID_REDO, self.OnUpdateUI) - EVT_UPDATE_UI(self, self.ID_DELETE, self.OnUpdateUI) - EVT_UPDATE_UI(self, self.ID_TEST, self.OnUpdateUI) - EVT_UPDATE_UI(self, self.ID_REFRESH, self.OnUpdateUI) + wx.EVT_UPDATE_UI(self, wx.ID_SAVE, self.OnUpdateUI) + wx.EVT_UPDATE_UI(self, wx.ID_CUT, self.OnUpdateUI) + wx.EVT_UPDATE_UI(self, wx.ID_COPY, self.OnUpdateUI) + wx.EVT_UPDATE_UI(self, wx.ID_PASTE, self.OnUpdateUI) + wx.EVT_UPDATE_UI(self, self.ID_LOCATE, self.OnUpdateUI) + wx.EVT_UPDATE_UI(self, self.ID_TOOL_LOCATE, self.OnUpdateUI) + wx.EVT_UPDATE_UI(self, self.ID_TOOL_PASTE, self.OnUpdateUI) + wx.EVT_UPDATE_UI(self, wx.ID_UNDO, self.OnUpdateUI) + wx.EVT_UPDATE_UI(self, wx.ID_REDO, self.OnUpdateUI) + wx.EVT_UPDATE_UI(self, self.ID_DELETE, self.OnUpdateUI) + wx.EVT_UPDATE_UI(self, self.ID_TEST, self.OnUpdateUI) + wx.EVT_UPDATE_UI(self, self.ID_REFRESH, self.OnUpdateUI) # Build interface - sizer = wxBoxSizer(wxVERTICAL) - sizer.Add(wxStaticLine(self, -1), 0, wxEXPAND) + sizer = wx.BoxSizer(wx.VERTICAL) + #sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND) # Horizontal sizer for toolbar and splitter - self.toolsSizer = sizer1 = wxBoxSizer() - splitter = wxSplitterWindow(self, -1, style=wxSP_3DSASH) + self.toolsSizer = sizer1 = wx.BoxSizer() + splitter = wx.SplitterWindow(self, -1, style=wx.SP_3DSASH) self.splitter = splitter splitter.SetMinimumPaneSize(100) # Create tree @@ -228,20 +318,19 @@ class Frame(wxFrame): # Vertical toolbar for GUI buttons g.tools = tools = Tools(self) tools.Show(conf.showTools) - if conf.showTools: sizer1.Add(tools, 0, wxEXPAND) + if conf.showTools: sizer1.Add(tools, 0, wx.EXPAND) tree.RegisterKeyEvents() - # !!! frame styles are broken - # Miniframe for not embedded mode - miniFrame = wxFrame(self, -1, 'Properties Panel', - (conf.panelX, conf.panelY), - (conf.panelWidth, conf.panelHeight)) + # Miniframe for split mode + miniFrame = wx.MiniFrame(self, -1, 'Properties & Style', + (conf.panelX, conf.panelY), + (conf.panelWidth, conf.panelHeight)) self.miniFrame = miniFrame - sizer2 = wxBoxSizer() + sizer2 = wx.BoxSizer() miniFrame.SetAutoLayout(True) miniFrame.SetSizer(sizer2) - EVT_CLOSE(self.miniFrame, self.OnCloseMiniFrame) + wx.EVT_CLOSE(self.miniFrame, self.OnCloseMiniFrame) # Create panel for parameters global panel if conf.embedPanel: @@ -250,24 +339,38 @@ class Frame(wxFrame): splitter.SplitVertically(tree, panel, conf.sashPos) else: panel = Panel(miniFrame) - sizer2.Add(panel, 1, wxEXPAND) + sizer2.Add(panel, 1, wx.EXPAND) miniFrame.Show(True) splitter.Initialize(tree) - sizer1.Add(splitter, 1, wxEXPAND) - sizer.Add(sizer1, 1, wxEXPAND) + sizer1.Add(splitter, 1, wx.EXPAND) + sizer.Add(sizer1, 1, wx.EXPAND) self.SetAutoLayout(True) self.SetSizer(sizer) - # Initialize - self.clipboard = None - self.Clear() - # Other events - EVT_IDLE(self, self.OnIdle) - EVT_CLOSE(self, self.OnCloseWindow) - EVT_LEFT_DOWN(self, self.OnLeftDown) - EVT_KEY_DOWN(self, tools.OnKeyDown) - EVT_KEY_UP(self, tools.OnKeyUp) + wx.EVT_IDLE(self, self.OnIdle) + wx.EVT_CLOSE(self, self.OnCloseWindow) + wx.EVT_KEY_DOWN(self, tools.OnKeyDown) + wx.EVT_KEY_UP(self, tools.OnKeyUp) + wx.EVT_ICONIZE(self, self.OnIconize) + + def OnRecentFile(self,evt): + # open recently used file + if not self.AskSave(): return + wx.BeginBusyCursor() + + # get the pathname based on the menu ID + fileNum = evt.GetId() - wx.ID_FILE1 + path = g.fileHistory.GetHistoryFile(fileNum) + + if self.Open(path): + self.SetStatusText('Data loaded') + # add it back to the history so it will be moved up the list + self.SaveRecent(path) + else: + self.SetStatusText('Failed') + + wx.EndBusyCursor() def OnNew(self, evt): if not self.AskSave(): return @@ -275,46 +378,113 @@ class Frame(wxFrame): def OnOpen(self, evt): if not self.AskSave(): return - dlg = wxFileDialog(self, 'Open', os.path.dirname(self.dataFile), - '', '*.xrc', wxOPEN | wxCHANGE_DIR) - if dlg.ShowModal() == wxID_OK: + dlg = wx.FileDialog(self, 'Open', os.path.dirname(self.dataFile), + '', '*.xrc', wx.OPEN | wx.CHANGE_DIR) + if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() self.SetStatusText('Loading...') - wxYield() - wxBeginBusyCursor() - if self.Open(path): - self.SetStatusText('Data loaded') - else: - self.SetStatusText('Failed') - wxEndBusyCursor() + wx.BeginBusyCursor() + try: + if self.Open(path): + self.SetStatusText('Data loaded') + self.SaveRecent(path) + else: + self.SetStatusText('Failed') + finally: + wx.EndBusyCursor() dlg.Destroy() def OnSaveOrSaveAs(self, evt): - if evt.GetId() == wxID_SAVEAS or not self.dataFile: - if self.dataFile: defaultName = '' - else: defaultName = 'UNTITLED.xrc' - dlg = wxFileDialog(self, 'Save As', os.path.dirname(self.dataFile), - defaultName, '*.xrc', - wxSAVE | wxOVERWRITE_PROMPT | wxCHANGE_DIR) - if dlg.ShowModal() == wxID_OK: + if evt.GetId() == wx.ID_SAVEAS or not self.dataFile: + if self.dataFile: name = '' + else: name = defaultName + dirname = os.path.abspath(os.path.dirname(self.dataFile)) + dlg = wx.FileDialog(self, 'Save As', dirname, name, '*.xrc', + wx.SAVE | wx.OVERWRITE_PROMPT | wx.CHANGE_DIR) + if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() + if isinstance(path, unicode): + path = path.encode(sys.getfilesystemencoding()) dlg.Destroy() else: dlg.Destroy() return + + if conf.localconf: + # if we already have a localconf then it needs to be + # copied to a new config with the new name + lc = conf.localconf + nc = self.CreateLocalConf(path) + flag, key, idx = lc.GetFirstEntry() + while flag: + nc.Write(key, lc.Read(key)) + flag, key, idx = lc.GetNextEntry(idx) + conf.localconf = nc + else: + # otherwise create a new one + conf.localconf = self.CreateLocalConf(path) else: path = self.dataFile self.SetStatusText('Saving...') - wxYield() - wxBeginBusyCursor() + wx.BeginBusyCursor() try: - self.Save(path) - self.dataFile = path - self.SetStatusText('Data saved') - except IOError: - self.SetStatusText('Failed') - wxEndBusyCursor() + try: + tmpFile,tmpName = tempfile.mkstemp(prefix='xrced-') + os.close(tmpFile) + self.Save(tmpName) # save temporary file first + shutil.move(tmpName, path) + self.dataFile = path + self.SetModified(False) + if conf.localconf.ReadBool("autogenerate", False): + pypath = conf.localconf.Read("filename") + embed = conf.localconf.ReadBool("embedResource", False) + genGettext = conf.localconf.ReadBool("genGettext", False) + self.GeneratePython(self.dataFile, pypath, embed, genGettext) + + self.SetStatusText('Data saved') + self.SaveRecent(path) + except IOError: + self.SetStatusText('Failed') + finally: + wx.EndBusyCursor() + + def SaveRecent(self,path): + # append to recently used files + g.fileHistory.AddFileToHistory(path) + + def GeneratePython(self, dataFile, pypath, embed, genGettext): + try: + import wx.tools.pywxrc + rescomp = wx.tools.pywxrc.XmlResourceCompiler() + rescomp.MakePythonModule([dataFile], pypath, embed, genGettext) + except: + inf = sys.exc_info() + wx.LogError(traceback.format_exception(inf[0], inf[1], None)[-1]) + wx.LogError('Error generating python code : %s' % pypath) + raise + + def OnGeneratePython(self, evt): + if self.modified or not conf.localconf: + wx.MessageBox("Save the XRC file first!", "Error") + return + + dlg = PythonOptions(self, conf.localconf, self.dataFile) + dlg.ShowModal() + dlg.Destroy() + + def OnPrefs(self, evt): + dlg = PrefsDialog(self) + if dlg.ShowModal() == wx.ID_OK: + # Fetch new preferences + for id,cdp in dlg.checkControls.items(): + c,d,p = cdp + if dlg.FindWindowById(id).IsChecked(): + d[p] = str(c.GetValue()) + elif p in d: del d[p] + g.conf.allowExec = ('ask', 'yes', 'no')[dlg.radio_allow_exec.GetSelection()] + dlg.Destroy() + def OnExit(self, evt): self.Close() @@ -322,23 +492,44 @@ class Frame(wxFrame): # Extra check to not mess with idle updating if undoMan.CanUndo(): undoMan.Undo() + g.panel.SetModified(False) + if not undoMan.CanUndo(): + self.SetModified(False) def OnRedo(self, evt): if undoMan.CanRedo(): undoMan.Redo() + self.SetModified(True) def OnCopy(self, evt): selected = tree.selection if not selected: return # key pressed event xxx = tree.GetPyData(selected) - self.clipboard = xxx.element.cloneNode(True) - self.SetStatusText('Copied') + if wx.TheClipboard.Open(): + if xxx.isElement: + data = wx.CustomDataObject('XRCED') + # Set encoding in header + # (False,True) + s = xxx.node.toxml(encoding=expat.native_encoding) + else: + data = wx.CustomDataObject('XRCED_node') + s = xxx.node.data + data.SetData(cPickle.dumps(s)) + wx.TheClipboard.SetData(data) + wx.TheClipboard.Close() + self.SetStatusText('Copied') + else: + wx.MessageBox("Unable to open the clipboard", "Error") def OnPaste(self, evt): selected = tree.selection if not selected: return # key pressed event # For pasting with Ctrl pressed + appendChild = True if evt.GetId() == pullDownMenu.ID_PASTE_SIBLING: appendChild = False + elif evt.GetId() == self.ID_TOOL_PASTE: + if g.tree.ctrl: appendChild = False + else: appendChild = not tree.NeedInsert(selected) else: appendChild = not tree.NeedInsert(selected) xxx = tree.GetPyData(selected) if not appendChild: @@ -348,63 +539,240 @@ class Frame(wxFrame): # Expanded container (must have children) elif tree.IsExpanded(selected) and tree.GetChildrenCount(selected, False): # Insert as first child - nextItem = tree.GetFirstChild(selected, 0)[0] + nextItem = tree.GetFirstChild(selected)[0] parentLeaf = selected else: # No children or unexpanded item - appendChild stays True - nextItem = wxTreeItemId() # no next item + nextItem = wx.TreeItemId() # no next item parentLeaf = selected parent = tree.GetPyData(parentLeaf).treeObject() - # Create a copy of clipboard element - elem = self.clipboard.cloneNode(True) + # Create a copy of clipboard pickled element + success = success_node = False + if wx.TheClipboard.Open(): + try: + data = wx.CustomDataObject('XRCED') + if wx.TheClipboard.IsSupported(data.GetFormat()): + try: + success = wx.TheClipboard.GetData(data) + except: + # there is a problem if XRCED_node is in clipboard + # but previous SetData was for XRCED + pass + if not success: # try other format + data = wx.CustomDataObject('XRCED_node') + if wx.TheClipboard.IsSupported(data.GetFormat()): + success_node = wx.TheClipboard.GetData(data) + finally: + wx.TheClipboard.Close() + + if not success and not success_node: + wx.MessageBox( + "There is no data in the clipboard in the required format", + "Error") + return + + xml = cPickle.loads(data.GetData()) # xml representation of element + if success: + elem = minidom.parseString(xml).childNodes[0] + else: + elem = g.tree.dom.createComment(xml) + # Tempopary xxx object to test things xxx = MakeXXXFromDOM(parent, elem) + + # Check compatibility + if not self.ItemsAreCompatible(parent, xxx.treeObject()): return + + # Check parent and child relationships. + # If parent is sizer or notebook, child is of wrong class or + # parent is normal window, child is child container then detach child. + isChildContainer = isinstance(xxx, xxxChildContainer) + parentIsBook = parent.__class__ in [xxxNotebook, xxxChoicebook, xxxListbook] + if isChildContainer and \ + ((parent.isSizer and not isinstance(xxx, xxxSizerItem)) or \ + (parentIsBook and not isinstance(xxx, xxxPage)) or \ + not (parent.isSizer or parentIsBook)): + elem.removeChild(xxx.child.node) # detach child + elem.unlink() # delete child container + elem = xxx.child.node # replace + # This may help garbage collection + xxx.child.parent = None + isChildContainer = False + # Parent is sizer or notebook, child is not child container + if parent.isSizer and not isChildContainer and not isinstance(xxx, xxxSpacer): + # Create sizer item element + sizerItemElem = MakeEmptyDOM(parent.itemTag) + sizerItemElem.appendChild(elem) + elem = sizerItemElem + elif isinstance(parent, xxxNotebook) and not isChildContainer: + pageElem = MakeEmptyDOM('notebookpage') + pageElem.appendChild(elem) + elem = pageElem + elif isinstance(parent, xxxChoicebook) and not isChildContainer: + pageElem = MakeEmptyDOM('choicebookpage') + pageElem.appendChild(elem) + elem = pageElem + elif isinstance(parent, xxxListbook) and not isChildContainer: + pageElem = MakeEmptyDOM('listbookpage') + pageElem.appendChild(elem) + elem = pageElem + # Insert new node, register undo + newItem = tree.InsertNode(parentLeaf, parent, elem, nextItem) + undoMan.RegisterUndo(UndoPasteCreate(parentLeaf, parent, newItem, selected)) + # Scroll to show new item (!!! redundant?) + tree.EnsureVisible(newItem) + tree.SelectItem(newItem) + if not tree.IsVisible(newItem): + tree.ScrollTo(newItem) + tree.Refresh() + # Update view? + if g.testWin and tree.IsHighlatable(newItem): + if conf.autoRefresh: + tree.needUpdate = True + tree.pendingHighLight = newItem + else: + tree.pendingHighLight = None + self.SetModified() + self.SetStatusText('Pasted') + + def ItemsAreCompatible(self, parent, child): # Check compatibility error = False + # Comments are always compatible + if child.__class__ == xxxComment: + return True # Top-level - x = xxx.treeObject() - if x.__class__ in [xxxDialog, xxxFrame, xxxMenuBar]: + if child.__class__ in [xxxDialog, xxxFrame, xxxWizard]: # Top-level classes if parent.__class__ != xxxMainNode: error = True - elif x.__class__ == xxxToolBar: + elif child.__class__ == xxxMenuBar: + # Menubar can be put in frame or dialog + if parent.__class__ not in [xxxMainNode, xxxFrame, xxxDialog]: error = True + elif child.__class__ == xxxToolBar: # Toolbar can be top-level of child of panel or frame - if parent.__class__ not in [xxxMainNode, xxxPanel, xxxFrame]: error = True - elif x.__class__ == xxxPanel and parent.__class__ == xxxMainNode: + if parent.__class__ not in [xxxMainNode, xxxPanel, xxxFrame] and \ + not parent.isSizer: error = True + elif child.__class__ == xxxPanel and parent.__class__ == xxxMainNode: pass - elif x.__class__ == xxxSpacer: + elif child.__class__ == xxxSpacer: if not parent.isSizer: error = True - elif x.__class__ == xxxSeparator: + elif child.__class__ == xxxSeparator: if not parent.__class__ in [xxxMenu, xxxToolBar]: error = True - elif x.__class__ == xxxTool: + elif child.__class__ == xxxTool: if parent.__class__ != xxxToolBar: error = True - elif x.__class__ == xxxMenu: + elif child.__class__ == xxxMenu: if not parent.__class__ in [xxxMainNode, xxxMenuBar, xxxMenu]: error = True - elif x.__class__ == xxxMenuItem: + elif child.__class__ == xxxMenuItem: if not parent.__class__ in [xxxMenuBar, xxxMenu]: error = True - elif x.isSizer and parent.__class__ == xxxNotebook: error = True + elif child.isSizer and parent.__class__ in [xxxNotebook, xxxChoicebook, xxxListbook]: + error = True else: # normal controls can be almost anywhere if parent.__class__ == xxxMainNode or \ parent.__class__ in [xxxMenuBar, xxxMenu]: error = True if error: if parent.__class__ == xxxMainNode: parentClass = 'root' else: parentClass = parent.className - wxLogError('Incompatible parent/child: parent is %s, child is %s!' % - (parentClass, x.className)) - return + wx.LogError('Incompatible parent/child: parent is %s, child is %s!' % + (parentClass, child.className)) + return False + return True + + def OnMoveUp(self, evt): + selected = tree.selection + if not selected: return + + index = tree.ItemIndex(selected) + if index == 0: return # No previous sibling found + + # Undo info + self.lastOp = 'MOVEUP' + status = 'Moved before previous sibling' + + # Prepare undo data + panel.Apply() + + parent = tree.GetItemParent(selected) + elem = tree.RemoveLeaf(selected) + nextItem = tree.GetFirstChild(parent)[0] + for i in range(index - 1): nextItem = tree.GetNextSibling(nextItem) + selected = tree.InsertNode(parent, tree.GetPyData(parent).treeObject(), elem, nextItem) + newIndex = tree.ItemIndex(selected) + tree.SelectItem(selected) + + undoMan.RegisterUndo(UndoMove(parent, index, parent, newIndex)) + + self.modified = True + self.SetStatusText(status) + + return + + def OnMoveDown(self, evt): + selected = tree.selection + if not selected: return + + index = tree.ItemIndex(selected) + next = tree.GetNextSibling(selected) + if not next: return + + # Undo info + self.lastOp = 'MOVEDOWN' + status = 'Moved after next sibling' + + # Prepare undo data + panel.Apply() + + parent = tree.GetItemParent(selected) + elem = tree.RemoveLeaf(selected) + nextItem = tree.GetFirstChild(parent)[0] + for i in range(index + 1): nextItem = tree.GetNextSibling(nextItem) + selected = tree.InsertNode(parent, tree.GetPyData(parent).treeObject(), elem, nextItem) + newIndex = tree.ItemIndex(selected) + tree.SelectItem(selected) + + undoMan.RegisterUndo(UndoMove(parent, index, parent, newIndex)) + + self.modified = True + self.SetStatusText(status) + + return + + def OnMoveLeft(self, evt): + selected = tree.selection + if not selected: return + + oldParent = tree.GetItemParent(selected) + if not oldParent: return + pparent = tree.GetItemParent(oldParent) + if not pparent: return + + # Check compatibility + if not self.ItemsAreCompatible(tree.GetPyData(pparent).treeObject(), tree.GetPyData(selected).treeObject()): return + + # Undo info + self.lastOp = 'MOVELEFT' + status = 'Made next sibling of parent' + + oldIndex = tree.ItemIndex(selected) + elem = tree.RemoveLeaf(selected) + nextItem = tree.GetFirstChild(pparent)[0] + parentIndex = tree.ItemIndex(oldParent) + for i in range(parentIndex + 1): nextItem = tree.GetNextSibling(nextItem) # Check parent and child relationships. # If parent is sizer or notebook, child is of wrong class or # parent is normal window, child is child container then detach child. + parent = tree.GetPyData(pparent).treeObject() + xxx = MakeXXXFromDOM(parent, elem) isChildContainer = isinstance(xxx, xxxChildContainer) if isChildContainer and \ ((parent.isSizer and not isinstance(xxx, xxxSizerItem)) or \ (isinstance(parent, xxxNotebook) and not isinstance(xxx, xxxNotebookPage)) or \ not (parent.isSizer or isinstance(parent, xxxNotebook))): - elem.removeChild(xxx.child.element) # detach child + elem.removeChild(xxx.child.node) # detach child elem.unlink() # delete child container - elem = xxx.child.element # replace + elem = xxx.child.node # replace # This may help garbage collection xxx.child.parent = None isChildContainer = False @@ -418,30 +786,80 @@ class Frame(wxFrame): pageElem = MakeEmptyDOM('notebookpage') pageElem.appendChild(elem) elem = pageElem - # Insert new node, register undo - newItem = tree.InsertNode(parentLeaf, parent, elem, nextItem) - undoMan.RegisterUndo(UndoPasteCreate(parentLeaf, parent, newItem, selected)) - # Scroll to show new item (!!! redundant?) - tree.EnsureVisible(newItem) - tree.SelectItem(newItem) - if not tree.IsVisible(newItem): - tree.ScrollTo(newItem) - tree.Refresh() - # Update view? - if g.testWin and tree.IsHighlatable(newItem): - if conf.autoRefresh: - tree.needUpdate = True - tree.pendingHighLight = newItem - else: - tree.pendingHighLight = None + + selected = tree.InsertNode(pparent, tree.GetPyData(pparent).treeObject(), elem, nextItem) + newIndex = tree.ItemIndex(selected) + tree.SelectItem(selected) + + undoMan.RegisterUndo(UndoMove(oldParent, oldIndex, pparent, newIndex)) + self.modified = True - self.SetStatusText('Pasted') + self.SetStatusText(status) + + def OnMoveRight(self, evt): + selected = tree.selection + if not selected: return + oldParent = tree.GetItemParent(selected) + if not oldParent: return + + newParent = tree.GetPrevSibling(selected) + if not newParent: return + + parent = tree.GetPyData(newParent).treeObject() + + # Check compatibility + if not self.ItemsAreCompatible(parent, tree.GetPyData(selected).treeObject()): return + + # Undo info + self.lastOp = 'MOVERIGHT' + status = 'Made last child of previous sibling' + + oldIndex = tree.ItemIndex(selected) + elem = tree.RemoveLeaf(selected) + + # Check parent and child relationships. + # If parent is sizer or notebook, child is of wrong class or + # parent is normal window, child is child container then detach child. + xxx = MakeXXXFromDOM(parent, elem) + isChildContainer = isinstance(xxx, xxxChildContainer) + if isChildContainer and \ + ((parent.isSizer and not isinstance(xxx, xxxSizerItem)) or \ + (isinstance(parent, xxxNotebook) and not isinstance(xxx, xxxNotebookPage)) or \ + not (parent.isSizer or isinstance(parent, xxxNotebook))): + elem.removeChild(xxx.child.node) # detach child + elem.unlink() # delete child container + elem = xxx.child.node # replace + # This may help garbage collection + xxx.child.parent = None + isChildContainer = False + # Parent is sizer or notebook, child is not child container + if parent.isSizer and not isChildContainer and not isinstance(xxx, xxxSpacer): + # Create sizer item element + sizerItemElem = MakeEmptyDOM('sizeritem') + sizerItemElem.appendChild(elem) + elem = sizerItemElem + elif isinstance(parent, xxxNotebook) and not isChildContainer: + pageElem = MakeEmptyDOM('notebookpage') + pageElem.appendChild(elem) + elem = pageElem + + selected = tree.InsertNode(newParent, tree.GetPyData(newParent).treeObject(), elem, wx.TreeItemId()) + + newIndex = tree.ItemIndex(selected) + tree.SelectItem(selected) + + undoMan.RegisterUndo(UndoMove(oldParent, oldIndex, newParent, newIndex)) + + self.modified = True + self.SetStatusText(status) + + def OnCutDelete(self, evt): selected = tree.selection if not selected: return # key pressed event # Undo info - if evt.GetId() == wxID_CUT: + if evt.GetId() == wx.ID_CUT: self.lastOp = 'CUT' status = 'Removed to clipboard' else: @@ -461,48 +879,51 @@ class Frame(wxFrame): # Prepare undo data panel.Apply() index = tree.ItemFullIndex(selected) + xxx = tree.GetPyData(selected) parent = tree.GetPyData(tree.GetItemParent(selected)).treeObject() elem = tree.RemoveLeaf(selected) undoMan.RegisterUndo(UndoCutDelete(index, parent, elem)) - if evt.GetId() == wxID_CUT: - if self.clipboard: self.clipboard.unlink() - self.clipboard = elem.cloneNode(True) + if evt.GetId() == wx.ID_CUT: + if wx.TheClipboard.Open(): + if xxx.isElement: + data = wx.CustomDataObject('XRCED') + # (False, True) + s = elem.toxml(encoding=expat.native_encoding) + else: + data = wx.CustomDataObject('XRCED_node') + s = xxx.node.data + data.SetData(cPickle.dumps(s)) + wx.TheClipboard.SetData(data) + wx.TheClipboard.Close() + else: + wx.MessageBox("Unable to open the clipboard", "Error") tree.pendingHighLight = None - tree.Unselect() + tree.UnselectAll() + tree.selection = None + # Update tools + g.tools.UpdateUI() panel.Clear() - self.modified = True + self.SetModified() self.SetStatusText(status) def OnSubclass(self, evt): selected = tree.selection xxx = tree.GetPyData(selected).treeObject() - elem = xxx.element + elem = xxx.node subclass = xxx.subclass - dlg = wxTextEntryDialog(self, 'Subclass:', defaultValue=subclass) - if dlg.ShowModal() == wxID_OK: + dlg = wx.TextEntryDialog(self, 'Subclass:', defaultValue=subclass) + if dlg.ShowModal() == wx.ID_OK: subclass = dlg.GetValue() if subclass: elem.setAttribute('subclass', subclass) - self.modified = True elif elem.hasAttribute('subclass'): elem.removeAttribute('subclass') - self.modified = True + self.SetModified() xxx.subclass = elem.getAttribute('subclass') tree.SetItemText(selected, xxx.treeName()) panel.pages[0].box.SetLabel(xxx.panelName()) dlg.Destroy() - def OnSelect(self, evt): - print >> sys.stderr, 'Xperimental function!' - wxYield() - self.SetCursor(wxCROSS_CURSOR) - self.CaptureMouse() - - def OnLeftDown(self, evt): - pos = evt.GetPosition() - self.SetCursor(wxNullCursor) - self.ReleaseMouse() - def OnEmbedPanel(self, evt): conf.embedPanel = evt.IsChecked() if conf.embedPanel: @@ -513,8 +934,7 @@ class Frame(wxFrame): pos = self.GetPosition() sizePanel = panel.GetSize() panel.Reparent(self.splitter) - self.miniFrame.GetSizer().RemoveWindow(panel) - wxYield() + self.miniFrame.GetSizer().Remove(panel) # Widen self.SetDimensions(pos.x, pos.y, size.width + sizePanel.width, size.height) self.splitter.SplitVertically(tree, panel, conf.sashPos) @@ -528,11 +948,11 @@ class Frame(wxFrame): sizer = self.miniFrame.GetSizer() panel.Reparent(self.miniFrame) panel.Show(True) - sizer.Add(panel, 1, wxEXPAND) + sizer.Add(panel, 1, wx.EXPAND) self.miniFrame.Show(True) self.miniFrame.SetDimensions(conf.panelX, conf.panelY, conf.panelWidth, conf.panelHeight) - wxYield() + self.miniFrame.Layout() # Reduce width self.SetDimensions(pos.x, pos.y, max(size.width - sizePanel.width, self.minWidth), size.height) @@ -541,7 +961,7 @@ class Frame(wxFrame): conf.showTools = evt.IsChecked() g.tools.Show(conf.showTools) if conf.showTools: - self.toolsSizer.Prepend(g.tools, 0, wxEXPAND) + self.toolsSizer.Prepend(g.tools, 0, wx.EXPAND) else: self.toolsSizer.Remove(g.tools) self.toolsSizer.Layout() @@ -550,6 +970,62 @@ class Frame(wxFrame): if not tree.selection: return # key pressed event tree.ShowTestWindow(tree.selection) + def OnTestHide(self, evt): + tree.CloseTestWindow() + + # Find object by relative position + def FindObject(self, item, obj): + # We simply perform depth-first traversal, sinse it's too much + # hassle to deal with all sizer/window combinations + w = tree.FindNodeObject(item) + if w == obj or isinstance(w, wx.GBSizerItem) and w.GetWindow() == obj: + return item + if tree.ItemHasChildren(item): + child = tree.GetFirstChild(item)[0] + while child: + found = self.FindObject(child, obj) + if found: return found + child = tree.GetNextSibling(child) + return None + + # Click event after locate activated + def OnTestWinLeftDown(self, evt): + # Restore normal event processing + self.SetHandler(g.testWin) + g.testWin.Disconnect(wx.ID_ANY, wx.ID_ANY, wx.wxEVT_LEFT_DOWN) + item = self.FindObject(g.testWin.item, evt.GetEventObject()) + if item: + tree.EnsureVisible(item) + tree.SelectItem(item) + self.tb.ToggleTool(self.ID_TOOL_LOCATE, False) + if item: + self.SetStatusText('Selected %s' % tree.GetItemText(item)) + else: + self.SetStatusText('Locate failed!') + + def SetHandler(self, w, h=None): + if h: + w.SetEventHandler(h) + w.SetCursor(wx.CROSS_CURSOR) + else: + w.SetEventHandler(w) + w.SetCursor(wx.NullCursor) + for ch in w.GetChildren(): + self.SetHandler(ch, h) + + def OnLocate(self, evt): + if g.testWin: + if evt.GetId() == self.ID_LOCATE or \ + evt.GetId() == self.ID_TOOL_LOCATE and evt.IsChecked(): + self.SetHandler(g.testWin, g.testWin) + g.testWin.Connect(wx.ID_ANY, wx.ID_ANY, wx.wxEVT_LEFT_DOWN, self.OnTestWinLeftDown) + if evt.GetId() == self.ID_LOCATE: + self.tb.ToggleTool(self.ID_TOOL_LOCATE, True) + elif evt.GetId() == self.ID_TOOL_LOCATE and not evt.IsChecked(): + self.SetHandler(g.testWin, None) + g.testWin.Disconnect(wx.ID_ANY, wx.ID_ANY, wx.wxEVT_LEFT_DOWN) + self.SetStatusText('Click somewhere in your test window now') + def OnRefresh(self, evt): # If modified, apply first selection = tree.selection @@ -575,7 +1051,7 @@ XRCed version %s (c) Roman Rolinsky Homepage: http://xrced.sourceforge.net\ ''' % version - dlg = wxMessageDialog(self, str, 'About XRCed', wxOK | wxCENTRE) + dlg = wx.MessageDialog(self, str, 'About XRCed', wx.OK | wx.CENTRE) dlg.ShowModal() dlg.Destroy() @@ -587,7 +1063,6 @@ Homepage: http://xrced.sourceforge.net\ # Simple emulation of python command line def OnDebugCMD(self, evt): - import traceback while 1: try: exec raw_input('C:\> ') @@ -619,28 +1094,58 @@ Homepage: http://xrced.sourceforge.net\ # Expanded container (must have children) elif tree.shift and tree.IsExpanded(selected) \ and tree.GetChildrenCount(selected, False): - nextItem = tree.GetFirstChild(selected, 0)[0] + nextItem = tree.GetFirstChild(selected)[0] parentLeaf = selected else: - nextItem = wxTreeItemId() + nextItem = wx.TreeItemId() parentLeaf = selected parent = tree.GetPyData(parentLeaf) if parent.hasChild: parent = parent.child - # Create element - className = pullDownMenu.createMap[evt.GetId()] - xxx = MakeEmptyXXX(parent, className) + self.CreateXXX(parent, parentLeaf, nextItem, evt.GetId()) - # Set default name for top-level windows - if parent.__class__ == xxxMainNode: - cl = xxx.treeObject().__class__ - frame.maxIDs[cl] += 1 - xxx.treeObject().name = '%s%d' % (defaultIDs[cl], frame.maxIDs[cl]) - xxx.treeObject().element.setAttribute('name', xxx.treeObject().name) + # Actual method to create object and add to XML and wx trees + def CreateXXX(self, parent, parentLeaf, nextItem, id): + selected = tree.selection + # Create object_ref? + if id == ID_NEW.REF: + ref = wx.GetTextFromUser('Create reference to:', 'Create reference') + if not ref: return + xxx = MakeEmptyRefXXX(parent, ref) + elif id == ID_NEW.COMMENT: + xxx = MakeEmptyCommentXXX(parent) + else: + # Create empty element + if id >= ID_NEW.CUSTOM: + className = pullDownMenu.customMap[id] + else: + className = pullDownMenu.createMap[id] + xxx = MakeEmptyXXX(parent, className) # Insert new node, register undo - elem = xxx.element - newItem = tree.InsertNode(parentLeaf, parent, elem, nextItem) + if xxx.isElement: # true object + # Set default name for top-level windows + if parent.__class__ == xxxMainNode: + cl = xxx.treeObject().__class__ + frame.maxIDs[cl] += 1 + xxx.setTreeName('%s%d' % (defaultIDs[cl], frame.maxIDs[cl])) + # And for some other standard controls + elif parent.__class__ == xxxStdDialogButtonSizer: + # ... we can even set automatically tree name + xxx.setTreeName(pullDownMenu.stdButtonIDs[id][0]) + obj = xxx.treeObject() + # ... and label + elem = g.tree.dom.createElement('label') + elem.appendChild(g.tree.dom.createTextNode(pullDownMenu.stdButtonIDs[id][1])) + obj.params['label'] = xxxParam(elem) + xxx.treeObject().node.appendChild(elem) + # Else, set label if exists to class name + elif 'label' in xxx.treeObject().allParams: + label = className + if label[:2] == 'wx': label = label[2:] + xxx.treeObject().set('label', label.upper()) + # For comment nodes, simply add node + newItem = tree.InsertNode(parentLeaf, parent, xxx.node, nextItem) undoMan.RegisterUndo(UndoPasteCreate(parentLeaf, parent, newItem, selected)) tree.EnsureVisible(newItem) tree.SelectItem(newItem) @@ -648,40 +1153,49 @@ Homepage: http://xrced.sourceforge.net\ tree.ScrollTo(newItem) tree.Refresh() # Update view? - if g.testWin and tree.IsHighlatable(newItem): + if xxx.isElement and g.testWin and tree.IsHighlatable(newItem): if conf.autoRefresh: tree.needUpdate = True tree.pendingHighLight = newItem else: tree.pendingHighLight = None tree.SetFocus() - self.modified = True + if not xxx.isElement: + tree.EditLabel(newItem) + self.SetModified() + return xxx # Replace one object with another def OnReplace(self, evt): selected = tree.selection xxx = tree.GetPyData(selected).treeObject() - elem = xxx.element + elem = xxx.node parent = elem.parentNode - parentXXX = xxx.parent + undoMan.RegisterUndo(UndoReplace(selected)) # New class className = pullDownMenu.createMap[evt.GetId() - 1000] + # Create temporary empty node (with default values) dummy = MakeEmptyDOM(className) - xxxClass = xxxDict[className] + if className == 'spacer' and xxx.className != 'spacer': + klass = xxxSpacer + elif xxx.className == 'spacer' and className != 'spacer': + klass = xxxSizerItem + else: + klass = xxxDict[className] # Remove non-compatible children - if tree.ItemHasChildren(selected) and not xxxClass.hasChildren: + if tree.ItemHasChildren(selected) and not klass.hasChildren: tree.DeleteChildren(selected) nodes = elem.childNodes[:] tags = [] for node in nodes: + if node.nodeType != minidom.Node.ELEMENT_NODE: continue remove = False tag = node.tagName if tag == 'object': - if not xxxClass.hasChildren: - remove = True - elif tag not in xxxClass.allParams and \ - (not xxxClass.hasStyle or tag not in xxxClass.styles): + if not klass.hasChildren: remove = True + elif tag not in klass.allParams and \ + (not klass.hasStyle or tag not in klass.styles): remove = True else: tags.append(tag) @@ -689,31 +1203,62 @@ Homepage: http://xrced.sourceforge.net\ elem.removeChild(node) node.unlink() - # Copy parameters present in dummy but not in elem - for node in dummy.childNodes: - tag = node.tagName - if tag not in tags: - elem.appendChild(node.cloneNode(True)) + # Remove sizeritem child if spacer + if className == 'spacer' and xxx.className != 'spacer': + sizeritem = elem.parentNode + assert sizeritem.getAttribute('class') == 'sizeritem' + sizeritem.removeChild(elem) + elem.unlink() + elem = sizeritem + tree.GetPyData(selected).hasChild = False + elif xxx.className == 'spacer' and className != 'spacer': + # Create sizeritem element + assert xxx.parent.isSizer + elem.setAttribute('class', 'sizeritem') + node = MakeEmptyDOM(className) + elem.appendChild(node) + # Replace to point to new object + xxx = xxxSizerItem(xxx.parent, elem) + elem = node + tree.SetPyData(selected, xxx) + xxx = xxx.child + else: + # Copy parameters present in dummy but not in elem + for node in dummy.childNodes: + if node.tagName not in tags: elem.appendChild(node.cloneNode(True)) dummy.unlink() + # Change class name - elem.setAttribute('class', className) + elem.setAttribute('class', className) + if elem.hasAttribute('subclass'): + elem.removeAttribute('subclass') # clear subclassing # Re-create xxx element - xxx = MakeXXXFromDOM(parentXXX, elem) + xxx = MakeXXXFromDOM(xxx.parent, elem) + # Remove incompatible style flags + if 'style' in xxx.params: + styles = map(string.strip, xxx.params['style'].value().split('|')) + newStyles = [s for s in styles if s in klass.winStyles or s in genericStyles] + if newStyles != styles: + if newStyles: + value = reduce(lambda a,b: a+'|'+b, newStyles) + else: + value = '' + xxx.params['style'].update(value) + # Update parent in child objects if tree.ItemHasChildren(selected): - i, cookie = tree.GetFirstChild(selected, 0) + i, cookie = tree.GetFirstChild(selected) while i.IsOk(): x = tree.GetPyData(i) x.parent = xxx if x.hasChild: x.child.parent = xxx i, cookie = tree.GetNextChild(selected, cookie) - + # Update tree if tree.GetPyData(selected).hasChild: # child container container = tree.GetPyData(selected) - container.child = xxx - container.hasChildren = xxx.hasChildren - container.isSizer = xxx.isSizer + container.resetChild(xxx) + xxx = container else: tree.SetPyData(selected, xxx) tree.SetItemText(selected, xxx.treeName()) @@ -723,8 +1268,7 @@ Homepage: http://xrced.sourceforge.net\ if parent.__class__ == xxxMainNode: cl = xxx.treeObject().__class__ frame.maxIDs[cl] += 1 - xxx.treeObject().name = '%s%d' % (defaultIDs[cl], frame.maxIDs[cl]) - xxx.treeObject().element.setAttribute('name', xxx.treeObject().name) + xxx.setTreeName('%s%d' % (defaultIDs[cl], frame.maxIDs[cl])) # Update panel g.panel.SetData(xxx) @@ -740,7 +1284,7 @@ Homepage: http://xrced.sourceforge.net\ else: tree.pendingHighLight = None tree.SetFocus() - self.modified = True + self.SetModified() # Expand/collapse subtree def OnExpand(self, evt): @@ -760,109 +1304,159 @@ Homepage: http://xrced.sourceforge.net\ self.SetStatusText('') def OnUpdateUI(self, evt): - if evt.GetId() in [wxID_CUT, wxID_COPY, self.ID_DELETE]: + if evt.GetId() in [wx.ID_CUT, wx.ID_COPY, self.ID_DELETE]: evt.Enable(tree.selection is not None and tree.selection != tree.root) - elif evt.GetId() == wxID_PASTE: - evt.Enable((self.clipboard and tree.selection) != None) + elif evt.GetId() == wx.ID_SAVE: + evt.Enable(self.modified) + elif evt.GetId() in [wx.ID_PASTE, self.ID_TOOL_PASTE]: + evt.Enable(tree.selection is not None) elif evt.GetId() == self.ID_TEST: evt.Enable(tree.selection is not None and tree.selection != tree.root) - elif evt.GetId() == wxID_UNDO: evt.Enable(undoMan.CanUndo()) - elif evt.GetId() == wxID_REDO: evt.Enable(undoMan.CanRedo()) + elif evt.GetId() in [self.ID_LOCATE, self.ID_TOOL_LOCATE]: + evt.Enable(g.testWin is not None) + elif evt.GetId() == wx.ID_UNDO: evt.Enable(undoMan.CanUndo()) + elif evt.GetId() == wx.ID_REDO: evt.Enable(undoMan.CanRedo()) def OnIdle(self, evt): if self.inIdle: return # Recursive call protection self.inIdle = True - if tree.needUpdate: - if conf.autoRefresh: - if g.testWin: - self.SetStatusText('Refreshing test window...') - # (re)create - tree.CreateTestWin(g.testWin.item) - wxYield() - self.SetStatusText('') - tree.needUpdate = False - elif tree.pendingHighLight: - tree.HighLight(tree.pendingHighLight) - else: - evt.Skip() - self.inIdle = False + try: + if tree.needUpdate: + if conf.autoRefresh: + if g.testWin: + #self.SetStatusText('Refreshing test window...') + # (re)create + tree.CreateTestWin(g.testWin.item) + #self.SetStatusText('') + tree.needUpdate = False + elif tree.pendingHighLight: + try: + tree.HighLight(tree.pendingHighLight) + except: + # Remove highlight if any problem + if g.testWin.highLight: + g.testWin.highLight.Remove() + tree.pendingHighLight = None + raise + else: + evt.Skip() + finally: + self.inIdle = False # We don't let close panel window def OnCloseMiniFrame(self, evt): return + def OnIconize(self, evt): + if evt.Iconized(): + conf.x, conf.y = self.GetPosition() + conf.width, conf.height = self.GetSize() + if conf.embedPanel: + conf.sashPos = self.splitter.GetSashPosition() + else: + conf.panelX, conf.panelY = self.miniFrame.GetPosition() + conf.panelWidth, conf.panelHeight = self.miniFrame.GetSize() + self.miniFrame.Iconize() + else: + if not conf.embedPanel: + self.miniFrame.Iconize(False) + evt.Skip() + def OnCloseWindow(self, evt): if not self.AskSave(): return if g.testWin: g.testWin.Destroy() - # Destroy cached windows - panel.cacheParent.Destroy() if not panel.GetPageCount() == 2: panel.page2.Destroy() - conf.x, conf.y = self.GetPosition() - conf.width, conf.height = self.GetSize() - if conf.embedPanel: - conf.sashPos = self.splitter.GetSashPosition() else: - conf.panelX, conf.panelY = self.miniFrame.GetPosition() - conf.panelWidth, conf.panelHeight = self.miniFrame.GetSize() + # If we don't do this, page does not get destroyed (a bug?) + panel.RemovePage(1) + if not self.IsIconized(): + conf.x, conf.y = self.GetPosition() + conf.width, conf.height = self.GetSize() + if conf.embedPanel: + conf.sashPos = self.splitter.GetSashPosition() + else: + conf.panelX, conf.panelY = self.miniFrame.GetPosition() + conf.panelWidth, conf.panelHeight = self.miniFrame.GetSize() evt.Skip() + def CreateLocalConf(self, path): + name = os.path.splitext(path)[0] + name += '.xcfg' + return wx.FileConfig(localFilename=name) + def Clear(self): self.dataFile = '' - if self.clipboard: - self.clipboard.unlink() - self.clipboard = None + conf.localconf = None undoMan.Clear() - self.modified = False + self.SetModified(False) tree.Clear() panel.Clear() if g.testWin: g.testWin.Destroy() g.testWin = None - self.SetTitle(progname) # Numbers for new controls self.maxIDs = {} - self.maxIDs[xxxPanel] = self.maxIDs[xxxDialog] = self.maxIDs[xxxFrame] = \ - self.maxIDs[xxxMenuBar] = self.maxIDs[xxxMenu] = self.maxIDs[xxxToolBar] = 0 + for cl in [xxxPanel, xxxDialog, xxxFrame, + xxxMenuBar, xxxMenu, xxxToolBar, + xxxWizard, xxxBitmap, xxxIcon]: + self.maxIDs[cl] = 0 + # Restore handlers, menu, etc. to initial + setHandlers(self.handlers[:]) + g.pullDownMenu.custom = self.custom[:] + # Remove modules imported from comment directives + map(sys.modules.pop, [m for m in sys.modules if m not in self.modules]) + xxxParamComment.locals = {} # clear local namespace + xxxParamComment.allow = None # clear execution state + + def SetModified(self, state=True): + self.modified = state + name = os.path.basename(self.dataFile) + if not name: name = defaultName + if state: + self.SetTitle(progname + ': ' + name + ' *') + else: + self.SetTitle(progname + ': ' + name) def Open(self, path): if not os.path.exists(path): - wxLogError('File does not exists: %s' % path) + wx.LogError('File does not exists: %s' % path) return False # Try to read the file try: f = open(path) self.Clear() - # Parse first line to get encoding (!! hack, I don't know a better way) - line = f.readline() - mo = re.match(r'^<\?xml ([^<>]* )?encoding="(?P[^<>].*)"\?>', line) - # Build wx tree - f.seek(0) dom = minidom.parse(f) - # Set encoding global variable and document encoding property - if mo: - dom.encoding = g.currentEncoding = mo.group('encd') - if dom.encoding not in ['ascii', sys.getdefaultencoding()]: - wxLogWarning('Encoding is different from system default') - else: - g.currentEncoding = 'ascii' - dom.encoding = '' f.close() + # Set encoding global variable and default encoding + if dom.encoding: + g.currentEncoding = dom.encoding + wx.SetDefaultPyEncoding(g.currentEncoding.encode()) + else: + g.currentEncoding = '' # Change dir + self.dataFile = path = os.path.abspath(path) dir = os.path.dirname(path) if dir: os.chdir(dir) + # Allow importing modules from the same directory + sys.path = sys_path + [dir] tree.SetData(dom) - self.dataFile = path self.SetTitle(progname + ': ' + os.path.basename(path)) + conf.localconf = self.CreateLocalConf(self.dataFile) except: # Nice exception printing inf = sys.exc_info() - wxLogError(traceback.format_exception(inf[0], inf[1], None)[-1]) - wxLogError('Error reading file: %s' % path) + wx.LogError(traceback.format_exception(inf[0], inf[1], None)[-1]) + wx.LogError('Error reading file: %s' % path) + if debug: raise return False return True def Indent(self, node, indent = 0): + if node.nodeType == minidom.Node.COMMENT_NODE: + text = self.domCopy.createTextNode('\n' + ' ' * indent) + node.parentNode.insertBefore(text, node) + return # no children # Copy child list because it will change soon children = node.childNodes[:] # Main node doesn't need to be indented @@ -876,87 +1470,250 @@ Homepage: http://xrced.sourceforge.net\ node.appendChild(text) # Indent children which are elements for n in children: - if n.nodeType == minidom.Node.ELEMENT_NODE: + if n.nodeType == minidom.Node.ELEMENT_NODE or \ + n.nodeType == minidom.Node.COMMENT_NODE: self.Indent(n, indent + 2) def Save(self, path): try: + import codecs # Apply changes if tree.selection and panel.IsModified(): - self.OnRefresh(wxCommandEvent()) - f = open(path, 'w') + self.OnRefresh(wx.CommandEvent()) + if g.currentEncoding: + f = codecs.open(path, 'wt', g.currentEncoding) + else: + f = codecs.open(path, 'wt') # Make temporary copy for formatting it # !!! We can't clone dom node, it works only once #self.domCopy = tree.dom.cloneNode(True) self.domCopy = MyDocument() mainNode = self.domCopy.appendChild(tree.mainNode.cloneNode(True)) + # Remove first child (test element) + testElem = mainNode.firstChild + mainNode.removeChild(testElem) + testElem.unlink() self.Indent(mainNode) - self.domCopy.writexml(f, encoding=tree.rootObj.params['encoding'].value()) + self.domCopy.writexml(f, encoding = g.currentEncoding) f.close() self.domCopy.unlink() self.domCopy = None - self.modified = False + self.SetModified(False) panel.SetModified(False) + conf.localconf.Flush() except: - wxLogError('Error writing file: %s' % path) + inf = sys.exc_info() + wx.LogError(traceback.format_exception(inf[0], inf[1], None)[-1]) + wx.LogError('Error writing file: %s' % path) raise - + def AskSave(self): if not (self.modified or panel.IsModified()): return True - flags = wxICON_EXCLAMATION | wxYES_NO | wxCANCEL | wxCENTRE - dlg = wxMessageDialog( self, 'File is modified. Save before exit?', + flags = wx.ICON_EXCLAMATION | wx.YES_NO | wx.CANCEL | wx.CENTRE + dlg = wx.MessageDialog( self, 'File is modified. Save before exit?', 'Save before too late?', flags ) say = dlg.ShowModal() dlg.Destroy() - if say == wxID_YES: - self.OnSaveOrSaveAs(wxCommandEvent(wxID_SAVE)) + wx.Yield() + if say == wx.ID_YES: + self.OnSaveOrSaveAs(wx.CommandEvent(wx.ID_SAVE)) # If save was successful, modified flag is unset if not self.modified: return True - elif say == wxID_NO: - self.modified = False + elif say == wx.ID_NO: + self.SetModified(False) panel.SetModified(False) return True return False - def SaveUndo(self): - pass # !!! +################################################################################ + +class PythonOptions(wx.Dialog): + + def __init__(self, parent, cfg, dataFile): + pre = wx.PreDialog() + g.frame.res.LoadOnDialog(pre, parent, "PYTHON_OPTIONS") + self.PostCreate(pre) + + self.cfg = cfg + self.dataFile = dataFile + + self.AutoGenerateCB = xrc.XRCCTRL(self, "AutoGenerateCB") + self.EmbedCB = xrc.XRCCTRL(self, "EmbedCB") + self.GettextCB = xrc.XRCCTRL(self, "GettextCB") + self.MakeXRSFileCB = xrc.XRCCTRL(self, "MakeXRSFileCB") + self.FileNameTC = xrc.XRCCTRL(self, "FileNameTC") + self.BrowseBtn = xrc.XRCCTRL(self, "BrowseBtn") + self.GenerateBtn = xrc.XRCCTRL(self, "GenerateBtn") + self.SaveOptsBtn = xrc.XRCCTRL(self, "SaveOptsBtn") + + self.Bind(wx.EVT_BUTTON, self.OnBrowse, self.BrowseBtn) + self.Bind(wx.EVT_BUTTON, self.OnGenerate, self.GenerateBtn) + self.Bind(wx.EVT_BUTTON, self.OnSaveOpts, self.SaveOptsBtn) + + if self.cfg.Read("filename", "") != "": + self.FileNameTC.SetValue(self.cfg.Read("filename")) + else: + name = os.path.splitext(os.path.split(dataFile)[1])[0] + name += '_xrc.py' + self.FileNameTC.SetValue(name) + self.AutoGenerateCB.SetValue(self.cfg.ReadBool("autogenerate", False)) + self.EmbedCB.SetValue(self.cfg.ReadBool("embedResource", False)) + self.MakeXRSFileCB.SetValue(self.cfg.ReadBool("makeXRS", False)) + self.GettextCB.SetValue(self.cfg.ReadBool("genGettext", False)) + + + def OnBrowse(self, evt): + path = self.FileNameTC.GetValue() + dirname = os.path.abspath(os.path.dirname(path)) + name = os.path.split(path)[1] + dlg = wx.FileDialog(self, 'Save As', dirname, name, '*.py', + wx.SAVE | wx.OVERWRITE_PROMPT) + if dlg.ShowModal() == wx.ID_OK: + path = dlg.GetPath() + self.FileNameTC.SetValue(path) + dlg.Destroy() + + + def OnGenerate(self, evt): + pypath = self.FileNameTC.GetValue() + embed = self.EmbedCB.GetValue() + genGettext = self.GettextCB.GetValue() + frame.GeneratePython(self.dataFile, pypath, embed, genGettext) + self.OnSaveOpts() + + + def OnSaveOpts(self, evt=None): + self.cfg.Write("filename", self.FileNameTC.GetValue()) + self.cfg.WriteBool("autogenerate", self.AutoGenerateCB.GetValue()) + self.cfg.WriteBool("embedResource", self.EmbedCB.GetValue()) + self.cfg.WriteBool("makeXRS", self.MakeXRSFileCB.GetValue()) + self.cfg.WriteBool("genGettext", self.GettextCB.GetValue()) + + self.EndModal(wx.ID_OK) + +################################################################################ + +class PrefsDialog(wx.Dialog): + + def __init__(self, parent): + pre = wx.PreDialog() + g.frame.res.LoadOnDialog(pre, parent, "DIALOG_PREFS") + self.PostCreate(pre) + self.checkControls = {} # map of check IDs to (control,dict,param) + + ##xxx = sys.modules['xxx'] + import xxx + d = xxx.xxxSizerItem.defaults_panel + + self.check_proportion_panel = xrc.XRCCTRL(self, 'check_proportion_panel') + id = self.check_proportion_panel.GetId() + wx.EVT_CHECKBOX(self, id, self.OnCheck) + self.checkControls[id] = (xrc.XRCCTRL(self, 'spin_proportion_panel'), + d, 'option') + + self.check_flag_panel = xrc.XRCCTRL(self, 'check_flag_panel') + id = self.check_flag_panel.GetId() + wx.EVT_CHECKBOX(self, id, self.OnCheck) + self.checkControls[id] = (xrc.XRCCTRL(self, 'text_flag_panel'), + d, 'flag') + + d = xxx.xxxSizerItem.defaults_control + + self.check_proportion_panel = xrc.XRCCTRL(self, 'check_proportion_control') + id = self.check_proportion_panel.GetId() + wx.EVT_CHECKBOX(self, id, self.OnCheck) + self.checkControls[id] = (xrc.XRCCTRL(self, 'spin_proportion_control'), + d, 'option') + + self.check_flag_panel = xrc.XRCCTRL(self, 'check_flag_control') + id = self.check_flag_panel.GetId() + wx.EVT_CHECKBOX(self, id, self.OnCheck) + self.checkControls[id] = (xrc.XRCCTRL(self, 'text_flag_control'), + d, 'flag') + + for id,cdp in self.checkControls.items(): + c,d,p = cdp + try: + if isinstance(c, wx.SpinCtrl): + c.SetValue(int(d[p])) + else: + c.SetValue(d[p]) + self.FindWindowById(id).SetValue(True) + except KeyError: + c.Enable(False) + + self.radio_allow_exec = xrc.XRCCTRL(self, 'radio_allow_exec') + try: + radio = {'ask': 0, 'yes':1, 'no':2}[g.conf.allowExec] + except KeyError: + radio = 0 + self.radio_allow_exec.SetSelection(radio) + + def OnCheck(self, evt): + self.checkControls[evt.GetId()][0].Enable(evt.IsChecked()) + evt.Skip() ################################################################################ +# Parse string in form var1=val1[,var2=val2]* as dictionary +def ReadDictFromString(s): + d = {} + for vv in s.split(','): + var,val = vv.split(':') + d[var.strip()] = val + return d + +# Transform dictionary with strings into one string +def DictToString(d): + return ','.join(map(':'.join, d.items())) + def usage(): print >> sys.stderr, 'usage: xrced [-dhiv] [file]' -class App(wxApp): +class App(wx.App): def OnInit(self): + # Check version + if wx.VERSION[:3] < MinWxVersion: + wx.LogWarning('''\ +This version of XRCed may not work correctly on your version of wxWidgets. \ +Please upgrade wxWidgets to %d.%d.%d or higher.''' % MinWxVersion) global debug # Process comand-line + opts = args = None try: opts, args = getopt.getopt(sys.argv[1:], 'dhiv') + for o,a in opts: + if o == '-h': + usage() + sys.exit(0) + elif o == '-d': + debug = True + elif o == '-v': + print 'XRCed version', version + sys.exit(0) + except getopt.GetoptError: - if wxPlatform != '__WXMAC__': # macs have some extra parameters + if wx.Platform != '__WXMAC__': # macs have some extra parameters print >> sys.stderr, 'Unknown option' usage() sys.exit(1) - for o,a in opts: - if o == '-h': - usage() - sys.exit(0) - elif o == '-d': - debug = True - elif o == '-v': - print 'XRCed version', version - sys.exit(0) self.SetAppName('xrced') # Settings global conf - conf = g.conf = wxConfig(style = wxCONFIG_USE_LOCAL_FILE) + conf = g.conf = wx.Config(style = wx.CONFIG_USE_LOCAL_FILE) + conf.localconf = None conf.autoRefresh = conf.ReadInt('autorefresh', True) pos = conf.ReadInt('x', -1), conf.ReadInt('y', -1) size = conf.ReadInt('width', 800), conf.ReadInt('height', 600) conf.embedPanel = conf.ReadInt('embedPanel', True) conf.showTools = conf.ReadInt('showTools', True) conf.sashPos = conf.ReadInt('sashPos', 200) + + # read recently used files + g.fileHistory = wx.FileHistory() + g.fileHistory.Load(conf) + if not conf.embedPanel: conf.panelX = conf.ReadInt('panelX', -1) conf.panelY = conf.ReadInt('panelY', -1) @@ -965,15 +1722,49 @@ class App(wxApp): conf.panelWidth = conf.ReadInt('panelWidth', 200) conf.panelHeight = conf.ReadInt('panelHeight', 200) conf.panic = not conf.HasEntry('nopanic') + # Preferences + conf.allowExec = conf.Read('Prefs/allowExec', 'ask') + p = 'Prefs/sizeritem_defaults_panel' + import xxx + if conf.HasEntry(p): + ##sys.modules['xxx'].xxxSizerItem.defaults_panel = ReadDictFromString(conf.Read(p)) + xxx.xxxSizerItem.defaults_panel = ReadDictFromString(conf.Read(p)) + p = 'Prefs/sizeritem_defaults_control' + if conf.HasEntry(p): + ##sys.modules['xxx'].xxxSizerItem.defaults_control = ReadDictFromString(conf.Read(p)) + xxx.xxxSizerItem.defaults_control = ReadDictFromString(conf.Read(p)) + # Add handlers - wxFileSystem_AddHandler(wxMemoryFSHandler()) - wxInitAllImageHandlers() + wx.FileSystem.AddHandler(wx.MemoryFSHandler()) # Create main frame frame = Frame(pos, size) frame.Show(True) - # Load resources from XRC file (!!! should be transformed to .py later?) - frame.res = wxXmlResource('') - frame.res.Load(os.path.join(basePath, 'xrced.xrc')) + + # Load plugins + plugins = os.getenv('XRCEDPATH') + if plugins: + cwd = os.getcwd() + try: + for dir in plugins.split(':'): + if os.path.isdir(dir) and \ + os.path.isfile(os.path.join(dir, '__init__.py')): + # Normalize + dir = os.path.abspath(os.path.normpath(dir)) + sys.path = sys_path + [os.path.dirname(dir)] + try: + os.chdir(dir) + __import__(os.path.basename(dir), globals(), locals(), ['*']) + except: + print traceback.print_exc() + finally: + os.chdir(cwd) + # Store important data + frame.handlers = getHandlers()[:] + frame.custom = g.pullDownMenu.custom[:] + frame.modules = sys.modules.copy() + + # Initialize + frame.Clear() # Load file after showing if args: @@ -985,7 +1776,7 @@ class App(wxApp): def OnExit(self): # Write config global conf - wc = wxConfigBase_Get() + wc = conf wc.WriteInt('autorefresh', conf.autoRefresh) wc.WriteInt('x', conf.x) wc.WriteInt('y', conf.y) @@ -999,11 +1790,24 @@ class App(wxApp): wc.WriteInt('sashPos', conf.sashPos) wc.WriteInt('panelWidth', conf.panelWidth) wc.WriteInt('panelHeight', conf.panelHeight) - wc.WriteInt('nopanic', True) + wc.WriteInt('nopanic', 1) + g.fileHistory.Save(wc) + # Preferences + wc.DeleteGroup('Prefs') + wc.Write('Prefs/allowExec', conf.allowExec) + import xxx + ##v = sys.modules['xxx'].xxxSizerItem.defaults_panel + v = xxx.xxxSizerItem.defaults_panel + if v: wc.Write('Prefs/sizeritem_defaults_panel', DictToString(v)) + ###v = sys.modules['xxx'].xxxSizerItem.defaults_control + v = xxx.xxxSizerItem.defaults_control + if v: wc.Write('Prefs/sizeritem_defaults_control', DictToString(v)) + wc.Flush() def main(): app = App(0, useBestVisual=False) + #app.SetAssertMode(wx.PYAPP_ASSERT_LOG) app.MainLoop() app.OnExit() global conf