class PluginManagerDialog(wx.Dialog): """Manage the available plugins.""" def __init__(self): pre = wx.PreDialog() # the Create step is done by XRC. self.PostCreate(pre) def Init(self, plugins, pluginsDisabled): """Method called after the panel has been initialized.""" # Set window icon if not guiutil.IsMac(): self.SetIcon(guiutil.get_icon()) # Initialize controls self.tcPlugins = XRCCTRL(self, 'tcPlugins') self.panelTreeView = XRCCTRL(self, 'panelTreeView') self.panelProperties = XRCCTRL(self, 'panelProperties') self.lblName = XRCCTRL(self, 'lblName') self.lblAuthor = XRCCTRL(self, 'lblAuthor') self.lblPluginType = XRCCTRL(self, 'lblPluginType') self.lblVersion = XRCCTRL(self, 'lblVersion') self.lblVersionNumber = XRCCTRL(self, 'lblVersionNumber') self.lblDescription = XRCCTRL(self, 'lblDescription') self.checkEnabled = XRCCTRL(self, 'checkEnabled') self.lblMessage = XRCCTRL(self, 'lblMessage') self.btnGetMorePlugins = XRCCTRL(self, 'btnGetMorePlugins') self.btnDeletePlugin = XRCCTRL(self, 'btnDeletePlugin') self.plugins = plugins self.pluginsDisabled = set(pluginsDisabled) # Bind interface events to the proper methods # wx.EVT_BUTTON(self, XRCID('btnDeletePlugin'), self.DeletePlugin) wx.EVT_CHECKBOX(self, XRCID('checkEnabled'), self.OnEnablePlugin) wx.EVT_TREE_ITEM_ACTIVATED(self, XRCID('tcPlugins'), self.OnEnablePlugin) wx.EVT_TREE_SEL_CHANGED(self, XRCID('tcPlugins'), self.OnSelectTreeItem) wx.EVT_TREE_SEL_CHANGING(self, XRCID('tcPlugins'), self.OnSelectRootItem) # Modify the control and font size as needed font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) if guiutil.IsMac(): children = list(self.Children) + \ list(self.panelTreeView.Children) + \ list(self.panelProperties.Children) for control in children: control.SetFont(font) control.SetWindowVariant(wx.WINDOW_VARIANT_SMALL) XRCCTRL(self, 'wxID_OK').SetWindowVariant(wx.WINDOW_VARIANT_NORMAL) font.SetWeight(wx.FONTWEIGHT_BOLD) if guiutil.IsMSWindows(): self.tcPlugins.SetPosition((0, 3)) self.panelTreeView.SetWindowStyle(wx.STATIC_BORDER) if (guiutil.IsMac() or guiutil.IsGtk()): self.tcPlugins.SetPosition((-30, 0)) self.panelTreeView.SetWindowStyle(wx.SUNKEN_BORDER) self.lblName.SetFont(font) self.lblMessage.SetFont(font) self.Layout() self.InitPluginList() self.LoadPlugins() def InitPluginList(self): """Initialize the plugin list control.""" iSize = (16, 16) iList = wx.ImageList(iSize[0], iSize[1]) iList.Add( wx.Bitmap(util.GetResourcePath('bricks.png'), wx.BITMAP_TYPE_PNG)) iList.Add( wx.Bitmap(util.GetResourcePath('plugin.png'), wx.BITMAP_TYPE_PNG)) iList.Add( wx.Bitmap(util.GetResourcePath('plugin_disabled.png'), wx.BITMAP_TYPE_PNG)) self.tcPlugins.AssignImageList(iList) self.root = self.tcPlugins.AddRoot('Plugins') self.baseroot = self.tcPlugins.AppendItem(self.root, "Built-In Plugins", 0) self.userroot = self.tcPlugins.AppendItem(self.root, "User Plugins", 0) font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) font.SetWeight(wx.FONTWEIGHT_BOLD) self.tcPlugins.SetItemFont(self.baseroot, font) self.tcPlugins.SetItemFont(self.userroot, font) def LoadPlugins(self): """Update and load the data for the plugin list control.""" # Set up the plugins for each plugin entry point of dicompyler for n, plugin in enumerate(self.plugins): # Skip plugin if it doesn't contain the required dictionary # or actually is a proper Python module p = plugin['plugin'] if not hasattr(p, 'pluginProperties'): continue props = p.pluginProperties() root = self.userroot if (plugin['location'] == 'base'): root = self.baseroot else: root = self.userroot i = self.tcPlugins.AppendItem(root, props['name'], 1) if (p.__name__ in self.pluginsDisabled): self.tcPlugins.SetItemImage(i, 2) self.tcPlugins.SetItemTextColour(i, wx.Colour(169, 169, 169)) self.tcPlugins.SetPyData(i, n) self.tcPlugins.SelectItem(i) self.tcPlugins.ExpandAll() wx.EVT_TREE_ITEM_COLLAPSING(self, XRCID('tcPlugins'), self.OnExpandCollapseTree) wx.EVT_TREE_ITEM_EXPANDING(self, XRCID('tcPlugins'), self.OnExpandCollapseTree) def OnSelectTreeItem(self, evt): """Update the interface when the selected item has changed.""" item = evt.GetItem() n = self.tcPlugins.GetPyData(item) if (n == None): self.panelProperties.Hide() return self.panelProperties.Show() plugin = self.plugins[n] p = plugin['plugin'] props = p.pluginProperties() self.lblName.SetLabel(props['name']) self.lblAuthor.SetLabel(props['author'].replace('&', '&&')) self.lblVersionNumber.SetLabel(str(props['version'])) ptype = props['plugin_type'] self.lblPluginType.SetLabel(ptype[0].capitalize() + ptype[1:]) self.lblDescription.SetLabel(props['description'].replace('&', '&&')) self.checkEnabled.SetValue(not (p.__name__ in self.pluginsDisabled)) self.Layout() self.panelProperties.Layout() def OnSelectRootItem(self, evt): """Block the root items from being selected.""" item = evt.GetItem() n = self.tcPlugins.GetPyData(item) if (n == None): evt.Veto() def OnExpandCollapseTree(self, evt): """Block the tree from expanding or collapsing.""" evt.Veto() def OnEnablePlugin(self, evt=None): """Publish the enabled/disabled state of the plugin.""" item = self.tcPlugins.GetSelection() n = self.tcPlugins.GetPyData(item) plugin = self.plugins[n] p = plugin['plugin'] # Set the checkbox to the appropriate state if the event # comes from the treeview if (evt.EventType == wx.EVT_TREE_ITEM_ACTIVATED.typeId): self.checkEnabled.SetValue(not self.checkEnabled.IsChecked()) if self.checkEnabled.IsChecked(): self.tcPlugins.SetItemImage(item, 1) self.tcPlugins.SetItemTextColour(item, wx.BLACK) self.pluginsDisabled.remove(p.__name__) logger.debug("%s enabled", p.__name__) else: self.tcPlugins.SetItemImage(item, 2) self.tcPlugins.SetItemTextColour(item, wx.Colour(169, 169, 169)) self.pluginsDisabled.add(p.__name__) logger.debug("%s disabled", p.__name__) pub.sendMessage( 'preferences.updated.value', {'general.plugins.disabled_list': list(self.pluginsDisabled)})
class EditorFrame(wx.Frame): """ A wx.Panel for displaying and editing Categories """ def __init__(self, parent, block_store, id=wx.ID_ANY, style=wx.EXPAND): #load from XRC, need to use two-stage create res = gui.XrcUtilities.XmlResource('./gui/xrc/TpclEditorFrame.xrc') pre = wx.PreFrame() res.LoadOnFrame(pre, parent, "editor") self.PostCreate(pre) self.block_store = block_store self.OnCreate() def OnCreate(self): self.SetSize((600, 400)) #widgets self.code_stc = XRCCTRL(self, "code_stc") self.code_stc.Bind(wx.EVT_LEFT_UP, self.ContextMenuHandler) self.block_tree = XRCCTRL(self, "block_tree") self.block_tree.SetBlockstore(self.block_store) self.preview_ctrl = XRCCTRL(self, "preview_ctrl") self.block_tree.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelectionChanged) #buttons self.clear_button = XRCCTRL(self, "clear_button") self.Bind(wx.EVT_BUTTON, self.OnClear, self.clear_button) self.remove_button = XRCCTRL(self, "remove_button") self.Bind(wx.EVT_BUTTON, self.OnRemove, self.remove_button) self.save_button = XRCCTRL(self, "save_button") self.Bind(wx.EVT_BUTTON, self.OnSave, self.save_button) self.info_button = XRCCTRL(self, "info_button") self.Bind(wx.EVT_BUTTON, self.OnInfo, self.info_button) #fill the block_tree #tpcl.IO.LoadBlockIntoTree(self.block_tree) self.root_expression = None self.CreateQuickInsertMenu() def CreateQuickInsertMenu(self): self.quick_insert_menu = wx.Menu() submenus = [ "Procedure Definitions", "Literal Expression", "Numerical Functions", "Flow Control" ] for sm in submenus: cat_id = self.block_store.FindCategory(sm) smenu = wx.Menu() for child_id in self.block_store.GetChildBlocks(cat_id): node = self.block_store.GetNode(child_id) mitem = smenu.Append(wx.ID_ANY, node.name) self.Bind(wx.EVT_MENU, MakeInserter(self, node.block), mitem) self.quick_insert_menu.AppendMenu(wx.ID_ANY, sm, smenu) def OnInfo(self, event): """\ Opens a dialog without a parent for the moment """ sel_id = self.block_tree.GetSelection() if sel_id.IsOk(): block = self.block_tree.GetPyData(sel_id) if block: info_dialog = BlockInfoDialog(self, block.name, block.display, block.description) info_dialog.ShowModal() event.Skip() def OnClear(self, event): """\ Clears the code window, deleting all unsaved changes. """ self.code_stc.ClearAll() #for now we'll put the root expression back in place self.root_expression = None event.Skip() def OnRemove(self, event): """\ Removes the current tpcl code block that is selected. """ pos = self.code_stc.GetCurrentPos() try: self.root_expression.RemoveExpression(pos) self.code_stc.SetText(str(self.root_expression)) except ValueError: #text in top level expression, get rid of it self.root_expression = None self.code_stc.ClearAll() event.Skip() def OnSave(self, event): """\ Saves the current work. """ event.Skip() def OnSelectionChanged(self, event): """\ Selection change in the block tree We need to fill the preview control here """ print "Handling selection changed event." sel_id = self.block_tree.GetSelection() if sel_id.IsOk(): block = self.block_tree.GetPyData(sel_id) if block: self.preview_ctrl.SetValue(block.display) else: self.preview_ctrl.SetValue("") else: self.preview_ctrl.SetValue("") event.Skip() def OnInsert(self, event, block=None): """\ Inserts the currently selected code block into the currently selected code socket. """ pos = self.code_stc.GetCurrentPos() if not block: sel_id = self.block_tree.GetSelection() if sel_id.IsOk(): block = self.block_tree.GetPyData(sel_id) if block: print "Trying to insert block..." try: #provide the OnInsert function of the block # access to us as a parent frame for when they # need to show a dialog parent_frame = self expression = TpclExpression(block) insert_ok = True if block.on_insert: print "Trying to use OnInsert function of block" exec(block.on_insert) insert_ok = OnInsert(expression) if insert_ok: if not self.root_expression: self.root_expression = expression else: self.root_expression.InsertExpression(pos, expression) self.code_stc.SetText(str(self.root_expression)) except ValueError: print "Tried to insert in a place where there's no expansion point" event.Skip() def ContextMenuHandler(self, event): """\ Processes a left click on the STC """ event.Skip() print "Trying to show context menu at pos:", self.code_stc.GetCurrentPos( ) try: if wx.GetMouseState().ControlDown(): print "Trying to show popup menu..." menu = wx.Menu() offset = self.code_stc.GetCurrentPos() if not self.root_expression: is_insertion_point = True is_added_insertion_point = False is_expansion_point = False else: is_insertion_point = self.root_expression.IsInsertionPoint( offset)[0] is_added_insertion_point = self.root_expression.IsAddedInsertionPoint( offset)[0] is_expansion_point = self.root_expression.IsExpansionPoint( offset)[0] print "is_insertion_point", is_insertion_point print "is_expansion_point", is_expansion_point sel_id = self.block_tree.GetSelection() if sel_id.IsOk(): block = self.block_tree.GetPyData(sel_id) else: block = None #insert item insert_item = menu.Append(wx.ID_ANY, "Insert") self.Bind(wx.EVT_MENU, self.OnInsert, insert_item) #only enable if we're on an expansion point insert_item.Enable(block != None and is_insertion_point) #quick insert quick_insert = menu.AppendMenu(wx.ID_ANY, "Quick Insert...", self.quick_insert_menu) quick_insert.Enable(is_insertion_point) #remove item remove_item = menu.Append(wx.ID_ANY, "Remove") self.Bind(wx.EVT_MENU, self.OnRemove, remove_item) remove_item.Enable( (not is_insertion_point and not is_expansion_point) or is_added_insertion_point) #check for expansion menu if is_expansion_point: exp_menu = wx.Menu() i = 0 for option in self.root_expression.GetExpansionOptions( offset): opt_item = exp_menu.Append(wx.ID_ANY, option) self.Bind(wx.EVT_MENU, MakeExpander(self, offset, i), opt_item) i += 1 menu.AppendMenu(wx.ID_ANY, "Expansion Point...", exp_menu) self.code_stc.PopupMenu(menu, event.GetPosition()) except ValueError: print "Index out of range..." def ShowModal(self): print "TPCLEE Showing itself Modally" self.MakeModal(True) self.old_top_window = wx.GetApp().GetTopWindow() wx.GetApp().SetTopWindow(self) self.Bind(wx.EVT_CLOSE, self.OnClose) self.Show(True) def OnClose(self, event): self.MakeModal(False) self.Unbind(wx.EVT_CLOSE) wx.GetApp().SetTopWindow(self.old_top_window) event.Skip()