Пример #1
0
    def __init__(self, model):
        """
        Standard constructor.

        @type  model: model.workspace.Workspace
        @param model: Corresponding model for this view.
        """
        # Initialize Observer
        Observer.__init__(self)

        parent = None

        # View related config vars
        self.config = model.config.view

        # Filename, etcetera
        self.fileName = ''
        self.filePath = os.path.join(os.getcwd(), 'examples')
        self._cwFileNewCount = 1

        size = wx.Size(self.config.getVal(tools.config.View.FRAMEWIDTH), \
                       self.config.getVal(tools.config.View.FRAMEHEIGHT))
        wx.Frame.__init__(self, parent, -1, self.GetTitle(), size=size)

        # Remember Maximized Frame; Only works on MSW
        if sys.platform in ("win32") and self.config.getVal(
                tools.config.View.FRAME_MAXIMIZED):
            self.Maximize(True)

        # Zoom
        self.zoom = self.config.getVal(tools.config.View.ZOOM_LASTVALUE)

        # initialize controller
        self._controller = CabelController(model, self)

        # List of modules and connections
        self._modules = []
        self._connections = []
        self._draggedCable = None
        self._modulesDict = {}

        # Create menus
        menubar = wx.MenuBar()
        # File
        self._filemenu = wx.Menu()
        self._filemenu.Append(wx.ID_NEW, "&New\tCTRL-N", "New..")
        self._filemenu.Append(wx.ID_OPEN, "&Open\tCTRL-O", "Open a Workspace")
        # RecentMenu
        self._recentMenuId = wx.NewId()
        recentMenu = self._getRecentMenu()
        self._filemenu.AppendMenu(self._recentMenuId, "Open Recent...",
                                  recentMenu)
        if recentMenu.GetMenuItemCount() == 0:
            self._filemenu.Enable(self._recentMenuId, False)
        self._filemenu.AppendSeparator()
        # Save
        self._filemenu.Append(wx.ID_SAVE, "&Save\tCTRL-S", "Save Workspace")
        self._filemenu.Append(wx.ID_SAVEAS, "S&ave As\tALT-S",
                              "Save Workpsace As...")
        self._filemenu.AppendSeparator()
        # Csound start/stop
        self._playStopId = wx.NewId()
        self._filemenu.Append(
            self._playStopId,
            self._controller._model.isPlaying() and 'Stop Csound\tCTRL-Y'
            or 'Start Csound\tCTRL-Y')
        idExportToCsd = wx.NewId()
        self._filemenu.Append(
            idExportToCsd, "&Export to CSD\tCTRL-E",
            "Export workspace to CSD (Csound Unified File Format)")
        self._filemenu.AppendSeparator()
        # Exit
        self._filemenu.Append(wx.ID_EXIT, "E&xit\tCTRL-Q", "Exit Cabel")
        menubar.Append(self._filemenu, "&File")

        # Modules
        self._modulesMenu = self.getModulesMenu(
            self._controller._getXmlModuleList())
        menubar.Append(self._modulesMenu, "&Modules")

        # Options
        self._optionsmenu = wx.Menu()

        # bottom Pane
        # -> properties
        if self.config.getVal(
                tools.config.View.BOTTOMWINDOW_REMEMBERPROPERTIES):
            showBottomPane = self.config.getVal(
                tools.config.View.BOTTOMWINDOW_SHOW)
        else:
            showBottomPane = self.config.getDefault(
                tools.config.View.BOTTOMWINDOW_SHOW)
        # -> menu entry
        self.id_bottomPane = wx.NewId()
        self._optionsmenu.AppendCheckItem(self.id_bottomPane,
                                          "Show &Bottom Pane\tALT-X",
                                          "Show Bottom Pane")
        self._optionsmenu.Check(self.id_bottomPane, showBottomPane)

        id_refreshMods = wx.NewId()
        self._optionsmenu.Append(id_refreshMods, "&Refresh Module List\tALT-R",
                                 "Refresh the Xml-Module List")

        self._optionsmenu.AppendSeparator()

        # Preferences
        id_options = wx.NewId()
        self._optionsmenu.Append(id_options, "Preferences\tALT-P",
                                 "Preferences")

        menubar.Append(self._optionsmenu, "&Options")

        self.SetMenuBar(menubar)

        # Associate menu events to handler functions
        self.Bind(wx.EVT_MENU, self._controller.onNew, id=wx.ID_NEW)
        self.Bind(wx.EVT_MENU, self._controller.onOpen, id=wx.ID_OPEN)
        self.Bind(wx.EVT_MENU, self._controller.onSave, id=wx.ID_SAVE)
        self.Bind(wx.EVT_MENU, self._controller.onSaveAs, id=wx.ID_SAVEAS)
        self.Bind(wx.EVT_MENU,
                  self._controller.onPlayStop,
                  id=self._playStopId)
        self.Bind(wx.EVT_MENU,
                  self._controller.onMenuExportToCsd,
                  id=idExportToCsd)
        self.Bind(wx.EVT_MENU, self._controller.onMenuExit, id=wx.ID_EXIT)
        self.Bind(wx.EVT_MENU, self.onToggleBottomPane, id=self.id_bottomPane)
        self.Bind(wx.EVT_MENU,
                  self._controller._refreshModulesMenu,
                  id=id_refreshMods)
        self.Bind(wx.EVT_MENU, self._controller.onOptionsOpen, id=id_options)
        self.Bind(wx.EVT_CLOSE, self._controller.onClose)

        # Create Statusbar
        self.statusbar = CabelStatusBar(self)
        self.SetStatusBar(self.statusbar)
        self.SetStatusBarPane(0)

        # Create splitted window
        self._splitter = CabelSplitterWindow(self, wx.ID_ANY)

        # Add workspace for synth building
        self.workspace = CabelScrolledWindow(self._splitter, -1, self)

        # wxTextCtrl which gets the stdout and stderr output of the app
        self.ioTextCtrl = None

        # Initialize Splitter
        self._splitter.initialize(self.workspace)

        # Associate mouse events to handler functions
        self.workspace.Bind(wx.EVT_LEFT_DOWN, self._controller.onMouseLeftDown)
        self.workspace.Bind(wx.EVT_LEFT_UP, self._controller.onMouseLeftUp)
        self.workspace.Bind(wx.EVT_LEFT_DCLICK,
                            self._controller.onMouseLeftDclick)
        self.workspace.Bind(wx.EVT_RIGHT_DOWN,
                            self._controller.onMouseRightDown)
        self.workspace.Bind(wx.EVT_MIDDLE_DOWN,
                            self._controller.onMouseMiddleDown)
        self.workspace.Bind(wx.EVT_MOTION, self._controller.onMouseMotion)
        self.Bind(wx.EVT_SIZE, self._controller.onSize)

        # Add additional key events
        self.Bind(wx.EVT_KEY_DOWN, self._controller.onKey)

        self.update(None, None)
Пример #2
0
    def __init__(self, model):
        """
        Standard constructor.

        @type  model: model.workspace.Workspace
        @param model: Corresponding model for this view.
        """
        # Initialize Observer
        Observer.__init__(self)
        
        parent = None

        # View related config vars
        self.config = model.config.view
        
        # Filename, etcetera
        self.fileName = ''
        self.filePath = os.path.join(os.getcwd(), 'examples')
        self._cwFileNewCount = 1
        
        size = wx.Size(self.config.getVal(tools.config.View.FRAMEWIDTH), \
                       self.config.getVal(tools.config.View.FRAMEHEIGHT))
        wx.Frame.__init__(self, parent, -1, self.GetTitle(), size = size)
        
        # Remember Maximized Frame; Only works on MSW
        if sys.platform in ("win32") and self.config.getVal(tools.config.View.FRAME_MAXIMIZED):
            self.Maximize(True)
            
        # Zoom
        self.zoom = self.config.getVal(tools.config.View.ZOOM_LASTVALUE)

        # initialize controller
        self._controller = CabelController(model, self)

        # List of modules and connections
        self._modules = []
        self._connections = []
        self._draggedCable = None
        self._modulesDict = {}

        # Create menus
        menubar = wx.MenuBar()
        # File
        self._filemenu = wx.Menu()
        self._filemenu.Append(wx.ID_NEW, "&New\tCTRL-N", "New..")
        self._filemenu.Append(wx.ID_OPEN, "&Open\tCTRL-O", "Open a Workspace")
        # RecentMenu
        self._recentMenuId = wx.NewId()
        recentMenu = self._getRecentMenu()
        self._filemenu.AppendMenu(self._recentMenuId, "Open Recent...", recentMenu)
        if recentMenu.GetMenuItemCount() == 0:
            self._filemenu.Enable(self._recentMenuId, False)
        self._filemenu.AppendSeparator()
        # Save
        self._filemenu.Append(wx.ID_SAVE, "&Save\tCTRL-S", "Save Workspace")
        self._filemenu.Append(wx.ID_SAVEAS, "S&ave As\tALT-S", "Save Workpsace As...")
        self._filemenu.AppendSeparator()
        # Csound start/stop
        self._playStopId = wx.NewId()
        self._filemenu.Append(self._playStopId, self._controller._model.isPlaying() and 'Stop Csound\tCTRL-Y' or 'Start Csound\tCTRL-Y')
        idExportToCsd = wx.NewId()
        self._filemenu.Append(idExportToCsd, "&Export to CSD\tCTRL-E",
                              "Export workspace to CSD (Csound Unified File Format)")
        self._filemenu.AppendSeparator()
        # Exit
        self._filemenu.Append(wx.ID_EXIT, "E&xit\tCTRL-Q", "Exit Cabel")
        menubar.Append(self._filemenu, "&File")
        
        # Modules
        self._modulesMenu = self.getModulesMenu(self._controller._getXmlModuleList())
        menubar.Append(self._modulesMenu, "&Modules")
        
        # Options
        self._optionsmenu = wx.Menu()

        # bottom Pane
        # -> properties
        if self.config.getVal(tools.config.View.BOTTOMWINDOW_REMEMBERPROPERTIES):
            showBottomPane = self.config.getVal(tools.config.View.BOTTOMWINDOW_SHOW)
        else:
            showBottomPane = self.config.getDefault(tools.config.View.BOTTOMWINDOW_SHOW)
        # -> menu entry
        self.id_bottomPane = wx.NewId()
        self._optionsmenu.AppendCheckItem(self.id_bottomPane, "Show &Bottom Pane\tALT-X",
                                    "Show Bottom Pane")
        self._optionsmenu.Check(self.id_bottomPane, showBottomPane)
        
        id_refreshMods = wx.NewId()
        self._optionsmenu.Append(id_refreshMods, "&Refresh Module List\tALT-R", "Refresh the Xml-Module List")
        
        self._optionsmenu.AppendSeparator()
        
        # Preferences
        id_options = wx.NewId()
        self._optionsmenu.Append(id_options, "Preferences\tALT-P", "Preferences")
                
        menubar.Append(self._optionsmenu, "&Options")

        self.SetMenuBar(menubar)

        # Associate menu events to handler functions
        self.Bind(wx.EVT_MENU, self._controller.onNew, id = wx.ID_NEW)
        self.Bind(wx.EVT_MENU, self._controller.onOpen, id = wx.ID_OPEN)
        self.Bind(wx.EVT_MENU, self._controller.onSave, id = wx.ID_SAVE)
        self.Bind(wx.EVT_MENU, self._controller.onSaveAs, id = wx.ID_SAVEAS)
        self.Bind(wx.EVT_MENU, self._controller.onPlayStop, id = self._playStopId)
        self.Bind(wx.EVT_MENU, self._controller.onMenuExportToCsd, id = idExportToCsd)
        self.Bind(wx.EVT_MENU, self._controller.onMenuExit, id = wx.ID_EXIT)
        self.Bind(wx.EVT_MENU, self.onToggleBottomPane, id = self.id_bottomPane)
        self.Bind(wx.EVT_MENU, self._controller._refreshModulesMenu, id = id_refreshMods)
        self.Bind(wx.EVT_MENU, self._controller.onOptionsOpen, id = id_options)
        self.Bind(wx.EVT_CLOSE, self._controller.onClose)

        # Create Statusbar
        self.statusbar = CabelStatusBar(self)
        self.SetStatusBar(self.statusbar)
        self.SetStatusBarPane(0)
        
        # Create splitted window
        self._splitter = CabelSplitterWindow(self, wx.ID_ANY)
        
        # Add workspace for synth building
        self.workspace = CabelScrolledWindow(self._splitter, -1, self)

        # wxTextCtrl which gets the stdout and stderr output of the app
        self.ioTextCtrl = None

        # Initialize Splitter
        self._splitter.initialize(self.workspace)

        # Associate mouse events to handler functions
        self.workspace.Bind(wx.EVT_LEFT_DOWN, self._controller.onMouseLeftDown)
        self.workspace.Bind(wx.EVT_LEFT_UP, self._controller.onMouseLeftUp)
        self.workspace.Bind(wx.EVT_LEFT_DCLICK, self._controller.onMouseLeftDclick)
        self.workspace.Bind(wx.EVT_RIGHT_DOWN, self._controller.onMouseRightDown)
        self.workspace.Bind(wx.EVT_MIDDLE_DOWN, self._controller.onMouseMiddleDown)
        self.workspace.Bind(wx.EVT_MOTION, self._controller.onMouseMotion)
        self.Bind(wx.EVT_SIZE, self._controller.onSize)

        # Add additional key events
        self.Bind(wx.EVT_KEY_DOWN, self._controller.onKey)

        self.update(None, None)
Пример #3
0
class CabelFrame(wx.Frame, Observer):
    """
    CabelFrame.

    A frame showing the contents of a single Cabel session.

    @type _controller: view.workspace.CabelController
    @ivar _controller: Corresponding controller for this view.
    @type _modules: list
    @ivar _modules: List of modules to paint on workspace.
    @type _connections: list
    @ivar _connections: List of connections to paint on workspace.
    @type _draggedCable: model.view.connection.Connection
    @ivar _draggedCable: Visual feedback when connection two modules.
    @type _modulesDict: dict
    @ivar _modulesDict: Dictionary to map ids to their
                        corresponding view modules.
    @type __fileMenu: wx.Menu
    @ivar __fileMenu: File Menu.
    @type _modulesMenu: wx.Menu
    @ivar _modulesMenu: Menu with all in th modules- searchpath
                        defined xml modules
    @type __recentMenuId: id
    @ivar __recentMenuId: Id of RecentMenu Entry.
    @type _splitter: CabelSplitterWindow
    @ivar _splitter: Splitter Window.
    @type _shell: wx.py.shell.Shell
    @ivar _shell: Python shell for command input.
    @type config: tools.config.Config.View
    @ivar config: relevant config Vars
    @type statusbar: wx.StatusBar
    @ivar statusbar: Statusbar of CabelFrame
    @type workspace: view.workspace.CabelScrolledWindow
    @ivar workspace: Workspace for synth building.
    @type ioTextCtrl: wx.TextCtrl
    @ivar ioTextCtrl: Gets the stdout and stderr output of the app
    @type fileName: string
    @ivar fileName: Name of the workspace
    @type filePath: string
    @ivar filePath: Save-Path of the workspace.
    @type zoom: int
    @ivar zoom: Zoom.
    """
    def __init__(self, model):
        """
        Standard constructor.

        @type  model: model.workspace.Workspace
        @param model: Corresponding model for this view.
        """
        # Initialize Observer
        Observer.__init__(self)

        parent = None

        # View related config vars
        self.config = model.config.view

        # Filename, etcetera
        self.fileName = ''
        self.filePath = os.path.join(os.getcwd(), 'examples')
        self._cwFileNewCount = 1

        size = wx.Size(self.config.getVal(tools.config.View.FRAMEWIDTH), \
                       self.config.getVal(tools.config.View.FRAMEHEIGHT))
        wx.Frame.__init__(self, parent, -1, self.GetTitle(), size=size)

        # Remember Maximized Frame; Only works on MSW
        if sys.platform in ("win32") and self.config.getVal(
                tools.config.View.FRAME_MAXIMIZED):
            self.Maximize(True)

        # Zoom
        self.zoom = self.config.getVal(tools.config.View.ZOOM_LASTVALUE)

        # initialize controller
        self._controller = CabelController(model, self)

        # List of modules and connections
        self._modules = []
        self._connections = []
        self._draggedCable = None
        self._modulesDict = {}

        # Create menus
        menubar = wx.MenuBar()
        # File
        self._filemenu = wx.Menu()
        self._filemenu.Append(wx.ID_NEW, "&New\tCTRL-N", "New..")
        self._filemenu.Append(wx.ID_OPEN, "&Open\tCTRL-O", "Open a Workspace")
        # RecentMenu
        self._recentMenuId = wx.NewId()
        recentMenu = self._getRecentMenu()
        self._filemenu.AppendMenu(self._recentMenuId, "Open Recent...",
                                  recentMenu)
        if recentMenu.GetMenuItemCount() == 0:
            self._filemenu.Enable(self._recentMenuId, False)
        self._filemenu.AppendSeparator()
        # Save
        self._filemenu.Append(wx.ID_SAVE, "&Save\tCTRL-S", "Save Workspace")
        self._filemenu.Append(wx.ID_SAVEAS, "S&ave As\tALT-S",
                              "Save Workpsace As...")
        self._filemenu.AppendSeparator()
        # Csound start/stop
        self._playStopId = wx.NewId()
        self._filemenu.Append(
            self._playStopId,
            self._controller._model.isPlaying() and 'Stop Csound\tCTRL-Y'
            or 'Start Csound\tCTRL-Y')
        idExportToCsd = wx.NewId()
        self._filemenu.Append(
            idExportToCsd, "&Export to CSD\tCTRL-E",
            "Export workspace to CSD (Csound Unified File Format)")
        self._filemenu.AppendSeparator()
        # Exit
        self._filemenu.Append(wx.ID_EXIT, "E&xit\tCTRL-Q", "Exit Cabel")
        menubar.Append(self._filemenu, "&File")

        # Modules
        self._modulesMenu = self.getModulesMenu(
            self._controller._getXmlModuleList())
        menubar.Append(self._modulesMenu, "&Modules")

        # Options
        self._optionsmenu = wx.Menu()

        # bottom Pane
        # -> properties
        if self.config.getVal(
                tools.config.View.BOTTOMWINDOW_REMEMBERPROPERTIES):
            showBottomPane = self.config.getVal(
                tools.config.View.BOTTOMWINDOW_SHOW)
        else:
            showBottomPane = self.config.getDefault(
                tools.config.View.BOTTOMWINDOW_SHOW)
        # -> menu entry
        self.id_bottomPane = wx.NewId()
        self._optionsmenu.AppendCheckItem(self.id_bottomPane,
                                          "Show &Bottom Pane\tALT-X",
                                          "Show Bottom Pane")
        self._optionsmenu.Check(self.id_bottomPane, showBottomPane)

        id_refreshMods = wx.NewId()
        self._optionsmenu.Append(id_refreshMods, "&Refresh Module List\tALT-R",
                                 "Refresh the Xml-Module List")

        self._optionsmenu.AppendSeparator()

        # Preferences
        id_options = wx.NewId()
        self._optionsmenu.Append(id_options, "Preferences\tALT-P",
                                 "Preferences")

        menubar.Append(self._optionsmenu, "&Options")

        self.SetMenuBar(menubar)

        # Associate menu events to handler functions
        self.Bind(wx.EVT_MENU, self._controller.onNew, id=wx.ID_NEW)
        self.Bind(wx.EVT_MENU, self._controller.onOpen, id=wx.ID_OPEN)
        self.Bind(wx.EVT_MENU, self._controller.onSave, id=wx.ID_SAVE)
        self.Bind(wx.EVT_MENU, self._controller.onSaveAs, id=wx.ID_SAVEAS)
        self.Bind(wx.EVT_MENU,
                  self._controller.onPlayStop,
                  id=self._playStopId)
        self.Bind(wx.EVT_MENU,
                  self._controller.onMenuExportToCsd,
                  id=idExportToCsd)
        self.Bind(wx.EVT_MENU, self._controller.onMenuExit, id=wx.ID_EXIT)
        self.Bind(wx.EVT_MENU, self.onToggleBottomPane, id=self.id_bottomPane)
        self.Bind(wx.EVT_MENU,
                  self._controller._refreshModulesMenu,
                  id=id_refreshMods)
        self.Bind(wx.EVT_MENU, self._controller.onOptionsOpen, id=id_options)
        self.Bind(wx.EVT_CLOSE, self._controller.onClose)

        # Create Statusbar
        self.statusbar = CabelStatusBar(self)
        self.SetStatusBar(self.statusbar)
        self.SetStatusBarPane(0)

        # Create splitted window
        self._splitter = CabelSplitterWindow(self, wx.ID_ANY)

        # Add workspace for synth building
        self.workspace = CabelScrolledWindow(self._splitter, -1, self)

        # wxTextCtrl which gets the stdout and stderr output of the app
        self.ioTextCtrl = None

        # Initialize Splitter
        self._splitter.initialize(self.workspace)

        # Associate mouse events to handler functions
        self.workspace.Bind(wx.EVT_LEFT_DOWN, self._controller.onMouseLeftDown)
        self.workspace.Bind(wx.EVT_LEFT_UP, self._controller.onMouseLeftUp)
        self.workspace.Bind(wx.EVT_LEFT_DCLICK,
                            self._controller.onMouseLeftDclick)
        self.workspace.Bind(wx.EVT_RIGHT_DOWN,
                            self._controller.onMouseRightDown)
        self.workspace.Bind(wx.EVT_MIDDLE_DOWN,
                            self._controller.onMouseMiddleDown)
        self.workspace.Bind(wx.EVT_MOTION, self._controller.onMouseMotion)
        self.Bind(wx.EVT_SIZE, self._controller.onSize)

        # Add additional key events
        self.Bind(wx.EVT_KEY_DOWN, self._controller.onKey)

        self.update(None, None)

    def createWorkspace(self, workspaceReader):
        """
        """
        # Open workspace from worksp
        if workspaceReader:
            # Set view modules
            self._modules = workspaceReader.viewModules.values()
            self._modulesDict = workspaceReader.viewModules

            # Set connections
            self._connections = []
            for c in workspaceReader.connections:
                outModule = self._modulesDict[c['fromModuleId']]
                inModule = self._modulesDict[c['toModuleId']]
                self._connections.append(ModuleConnection(outModule, \
                                            c['fromVarId'], \
                                            inModule, \
                                            c['toVarId']))
            # Set file location
            self.fileName = workspaceReader.fileName
            self.filePath = workspaceReader.filePath

        # Delete old workspace and create new one
        else:
            self._modules = []
            self._modulesDict = {}
            self._connections = []

            self.fileName = ''
            self._cwFileNewCount += 1

            self._controller._actModule = None

        self.workspace.Refresh()
        return self

    def update(self, observable, arg):
        """
        This method is called whenever the observed object is
        changed. An application calls an observable object's
        notifyObservers method to have all the object's observers
        notified of the change.

        @type  o: Observable
        @param o: The observable object.
        @type  arg: object
        @param arg: An argument passed to the notifyObservers method.
        """
        # Refresh the workspace?
        refresh = True
        # Read arg gand do what has to be done.
        if arg:
            # model.workspace.addModule;
            # arg[1] module to add
            if arg[0] == 'add':
                newModule = arg[1]
                self.addModule(newModule, self._controller._lastMousePt)
            # model.workspace.removeModule;
            # arg[1] module to remove, arg[2] in- & outgoing connections to remove
            elif arg[0] == 'remove':
                rmModule = arg[1]
                rmConnections = arg[2]
                self.removeModule(rmModule, rmConnections)
            # model.workspace.connect;
            # arg[1] new connection
            elif arg[0] == 'connect':
                newConnection = arg[1]
                self.addConnection(newConnection)
            # model.workspace.disconnect;
            # arg[1] connection to be removed
            elif arg[0] == 'disconnect':
                rmConnections = arg[1]
                self.removeConnection(rmConnections)
            # model.workspace.setValue:
            # arg[1] input variable which changed, arg[2] new value of input var
            elif arg[0] == 'set':
                inVar = arg[1]
                newValue = arg[2]
            # gets triggered by the config.setting.updateView method:
            # arg[1] in view workspace defined method without parameters.
            elif arg[0] == 'funCall':
                self._controller._callFunc(self, arg[1])

        # Repaints the workspace
        if refresh:
            self.workspace.Refresh()

    def onToggleBottomPane(self, event):
        """
        Toggle bottom pane in the splitter window.

        @type  event: wx.Event
        @param event: Event associated with this function.
        """
        if not self.config.getVal(tools.config.View.BOTTOMWINDOW_SHOW):
            self._splitter.split()
        else:
            self._splitter.unSplit()

    def addModule(self, module, pt):
        """
        Adds module to view workspace.

        @type  module: model.module.Module
        @param module: module to add to view workspace
        @type  pt: wx.Point
        @param pt: Position on the workspace of module to add
        """
        # Module is not yet on the view.workspace
        if not self._modulesDict.has_key(module.id):
            viewModule = Module(pt.x, pt.y, module, self._controller)
            # if lastToAddPosition not changes, this helps
            pt.x += 25
            pt.y += 20
            self._modulesDict[module.id] = viewModule
        # Yet it is
        else:
            viewModule = self._modulesDict[module.id]
        # If it is not yet in the internal list of view.Modules
        if viewModule not in self._modules:
            # then add it
            self._modules.append(viewModule)
        # Set added module to actModule
        self._controller.setModuleFocus(viewModule)
        return viewModule

    def removeModule(self, module, connections):
        """
        Removes module from workspace.

        @type  module: model.module.Module
        @param module: module to be removed from view workspace.
        @type  connections: list
        @param connections: list of model.connection.Connection to delete.
        """
        # remove modules connections
        for c in connections:
            self.removeConnection(c)

        # remove module
        if self._modulesDict.has_key(module.id):

            viewModule = self._modulesDict[module.id]
            self._modules.remove(viewModule)

            if self._controller._actModule == viewModule:
                self._controller.setModuleFocus(None)

            del self._modulesDict[module.id]

    def addConnection(self, connection):
        """
        Add connection to view workspace.

        @type  connection: model.connection.Connection
        @param connection: Model connection to add to view workspace.
        """
        outputNum = connection.fromVar.module.outVars.index(connection.fromVar)
        inputNum = connection.toVar.module.inVars.index(connection.toVar)
        newConnection = ModuleConnection(
            self._modulesDict[connection.fromVar.module.id], outputNum,
            self._modulesDict[connection.toVar.module.id], inputNum)
        if newConnection not in self._connections:
            self._connections.append(newConnection)

    def removeConnection(self, connection):
        """
        Remove connection from view workspace.

        @type  connection: model.connection.Connection
        @param connection: Connection to remove from view workspace.
        """
        # Create corresponding view connection
        outputNum = connection.fromVar.module.outVars.index(connection.fromVar)
        inputNum = connection.toVar.module.inVars.index(connection.toVar)
        fromModule = connection.fromVar.module
        toModule = connection.toVar.module
        rmConnection = ModuleConnection(self._modulesDict[fromModule.id],
                                        outputNum,
                                        self._modulesDict[toModule.id],
                                        inputNum)
        # If in _connections list remove it
        if rmConnection in self._connections:
            self._connections.remove(rmConnection)

    def getModuleAt(self, pt):
        """
        Return the first module found at given point.

        @type  pt: wx.Point
        @param pt: Point to test if on a module.
        @rtype : view.module.Module
        @return: Module at point or None.
        """
        # Search from last added module to first
        for i in range(len(self._modules) - 1, -1, -1):
            if self._modules[i].isOnModule(pt):
                return self._modules[i]
        return None

    def scrollWorkspaceOnBorder(self, pt):
        """
        If pt is on workspace border scrolls workspace.

        @type  pt: wx.Point
        @param pt: Point to test if on worspace border.
        """
        unitX, unitY = self.workspace.GetScrollPixelsPerUnit()
        sizeX, sizeY = self.workspace.GetClientSize()
        originX, originY = self.workspace.GetViewStart()
        distanceLeft = pt.x - originX * unitX
        distanceRight = originX * unitX + sizeX - pt.x
        distanceTop = pt.y - originY * unitY
        distanceBottom = originY * unitY + sizeY - pt.y
        if distanceLeft < 10:
            self.workspace.Scroll(originX - 1, -1)
        if distanceRight < 10:
            self.workspace.Scroll(originX + 1, -1)
        if distanceTop < 10:
            self.workspace.Scroll(-1, originY - 1)
        if distanceBottom < 10:
            self.workspace.Scroll(-1, originY + 1)

    def getModulesMenu(self, xmlModuleList):
        """
        Gets the Menu for all the defined Xml Modules.

        @type  xmlModuleList: list
        @param xmlModuleList: List of tuples which represents the
                              structure of the modules folder.
        @rtype:  wx.Menu
        @return: Menu
        """
        modulesmenu = wx.Menu()
        for xmlModuleListItem in xmlModuleList:
            newId = wx.NewId()
            if isinstance(xmlModuleListItem[1], list):
                modulesmenu.AppendMenu(
                    newId, xmlModuleListItem[0],
                    self.getModulesMenu(xmlModuleListItem[1]))
            else:
                self._controller._idToModules[newId] = xmlModuleListItem[
                    1].fullName
                modulesmenu.Append(newId, xmlModuleListItem[0],
                                   xmlModuleListItem[1].description)
                self.Bind(wx.EVT_MENU,
                          self._controller.onModulesMenu,
                          id=newId)

        return modulesmenu

    def getModuleMenu(self):
        """
        Return menu when right clicking on a module.
        """
        modulemenu = wx.Menu()

        # "Remove Module" Entry
        delId = wx.NewId()
        modulemenu.Append(delId, 'Remove Module')
        self.Bind(wx.EVT_MENU, self._controller.onRemoveActModule, id=delId)

        # "Zoom Module" Entries
        if self.config.getVal(tools.config.View.ZOOM_INDIVIDUAL_ACTIVE):
            # Zoom Entry
            modulemenu.AppendSeparator()
            # Zoom Entry Ids
            zoomInId = wx.NewId()
            zoomOutId = wx.NewId()
            # Zooms
            zoomDefault = self.config.getVal(
                tools.config.View.ZOOM_FACTOR_DEFAULT)
            # Scales
            scaleInFactor = scaleOutFactor = zoomDefault / 100
            # Zoom Menu Entries
            modulemenu.Append(zoomInId, 'zoom +' + str(zoomDefault) + '%')
            modulemenu.Append(zoomOutId, 'zoom -' + str(zoomDefault) + '%')
            # Bindings
            self.Bind(wx.EVT_MENU,
                      self._controller.onScaleInActModule,
                      id=zoomInId)
            self.Bind(wx.EVT_MENU,
                      self._controller.onScaleOutActModule,
                      id=zoomOutId)

        if self.config.getVal(tools.config.Directories.EDITOR):
            modulemenu.AppendSeparator()
            viewXmlId = wx.NewId()
            modulemenu.Append(viewXmlId, 'Show Module Xml')
            self.Bind(wx.EVT_MENU,
                      self._controller.onShowModuleXML,
                      id=viewXmlId)

        return modulemenu

    def _getRecentMenu(self):
        """
        """
        configDir = self._controller._configDirs
        recentList = []
        recentList = configDir.getVal(tools.config.Directories.RECENTFILES)

        recentMenu = wx.Menu()

        for i in xrange(0, len(recentList)):
            recentId = wx.NewId()
            recentMenu.Append(
                recentId,
                '&' + str(i) + ' ' + str(os.path.normpath(recentList[i])))
            self._controller._idToRecent[recentId] = str(recentList[i])
            self.Bind(wx.EVT_MENU, self._controller.onRecent, id=recentId)

        return recentMenu

    def reloadRecentMenu(self):
        """
        """
        self._filemenu.Remove(self._recentMenuId)
        recentMenu = self._getRecentMenu()
        self._filemenu.InsertMenu(2, self._recentMenuId, 'Open Recent...',
                                  recentMenu)

        # Depending if there are Items in the RecentMenu Disable / Enable it
        if self._filemenu.IsEnabled(self._recentMenuId):
            if recentMenu.GetMenuItemCount() == 0:
                self._filemenu.Enable(self._recentMenuId, False)
        else:
            if recentMenu.GetMenuItemCount() > 0:
                self._filemenu.Enable(self._recentMenuId, True)

    def createDraggedCable(self, startPt, endPt):
        """
        Create connection between startPt and endPt as visual feedback
        for connection mode.

        @type  startPt: wx.Point
        @param startPt: Start point of dragged cable.
        @type  endPt: wx.Point
        @param endPt: End point of dragged cable.
        """
        self._draggedCable = Connection(startPt, endPt)

    def removeDraggedCable(self):
        """
        Remove dragged cable from workspace.
        """
        self._draggedCable = None
        self.workspace.Refresh()

    def getModules(self):
        """
        Return list of view modules.

        @rtype: List
        @return: List of view modules.
        """
        return self._modules

    def getConnections(self):
        """
        Return list of view connections.

        @rtype: List
        @return: List of view connections.
        """
        return self._connections

    def getDraggedCable(self):
        """
        Return dragged cable object.

        @rtype: model.view.connection.Connection
        @return: Visual feedback when connection two modules.
        """
        return self._draggedCable

    def GetTitle(self):
        """
        Return Title string for the CabelFrame.
        
        @rtype: string
        @return: Title string for the CabelFrame.
        """
        try:
            star = (self._controller._saved and [''] or ['*'])[0]
        except AttributeError:
            # self._controller isn't defined yet
            star = ''

        if self.fileName == '':
            documentName = 'new' + str(self._cwFileNewCount) + '.cw'
        else:
            documentName = self.fileName + '.cw'

        return 'Cabel - [' + documentName + ']' + star
Пример #4
0
class CabelFrame(wx.Frame, Observer):
    """
    CabelFrame.

    A frame showing the contents of a single Cabel session.

    @type _controller: view.workspace.CabelController
    @ivar _controller: Corresponding controller for this view.
    @type _modules: list
    @ivar _modules: List of modules to paint on workspace.
    @type _connections: list
    @ivar _connections: List of connections to paint on workspace.
    @type _draggedCable: model.view.connection.Connection
    @ivar _draggedCable: Visual feedback when connection two modules.
    @type _modulesDict: dict
    @ivar _modulesDict: Dictionary to map ids to their
                        corresponding view modules.
    @type __fileMenu: wx.Menu
    @ivar __fileMenu: File Menu.
    @type _modulesMenu: wx.Menu
    @ivar _modulesMenu: Menu with all in th modules- searchpath
                        defined xml modules
    @type __recentMenuId: id
    @ivar __recentMenuId: Id of RecentMenu Entry.
    @type _splitter: CabelSplitterWindow
    @ivar _splitter: Splitter Window.
    @type _shell: wx.py.shell.Shell
    @ivar _shell: Python shell for command input.
    @type config: tools.config.Config.View
    @ivar config: relevant config Vars
    @type statusbar: wx.StatusBar
    @ivar statusbar: Statusbar of CabelFrame
    @type workspace: view.workspace.CabelScrolledWindow
    @ivar workspace: Workspace for synth building.
    @type ioTextCtrl: wx.TextCtrl
    @ivar ioTextCtrl: Gets the stdout and stderr output of the app
    @type fileName: string
    @ivar fileName: Name of the workspace
    @type filePath: string
    @ivar filePath: Save-Path of the workspace.
    @type zoom: int
    @ivar zoom: Zoom.
    """


    def __init__(self, model):
        """
        Standard constructor.

        @type  model: model.workspace.Workspace
        @param model: Corresponding model for this view.
        """
        # Initialize Observer
        Observer.__init__(self)
        
        parent = None

        # View related config vars
        self.config = model.config.view
        
        # Filename, etcetera
        self.fileName = ''
        self.filePath = os.path.join(os.getcwd(), 'examples')
        self._cwFileNewCount = 1
        
        size = wx.Size(self.config.getVal(tools.config.View.FRAMEWIDTH), \
                       self.config.getVal(tools.config.View.FRAMEHEIGHT))
        wx.Frame.__init__(self, parent, -1, self.GetTitle(), size = size)
        
        # Remember Maximized Frame; Only works on MSW
        if sys.platform in ("win32") and self.config.getVal(tools.config.View.FRAME_MAXIMIZED):
            self.Maximize(True)
            
        # Zoom
        self.zoom = self.config.getVal(tools.config.View.ZOOM_LASTVALUE)

        # initialize controller
        self._controller = CabelController(model, self)

        # List of modules and connections
        self._modules = []
        self._connections = []
        self._draggedCable = None
        self._modulesDict = {}

        # Create menus
        menubar = wx.MenuBar()
        # File
        self._filemenu = wx.Menu()
        self._filemenu.Append(wx.ID_NEW, "&New\tCTRL-N", "New..")
        self._filemenu.Append(wx.ID_OPEN, "&Open\tCTRL-O", "Open a Workspace")
        # RecentMenu
        self._recentMenuId = wx.NewId()
        recentMenu = self._getRecentMenu()
        self._filemenu.AppendMenu(self._recentMenuId, "Open Recent...", recentMenu)
        if recentMenu.GetMenuItemCount() == 0:
            self._filemenu.Enable(self._recentMenuId, False)
        self._filemenu.AppendSeparator()
        # Save
        self._filemenu.Append(wx.ID_SAVE, "&Save\tCTRL-S", "Save Workspace")
        self._filemenu.Append(wx.ID_SAVEAS, "S&ave As\tALT-S", "Save Workpsace As...")
        self._filemenu.AppendSeparator()
        # Csound start/stop
        self._playStopId = wx.NewId()
        self._filemenu.Append(self._playStopId, self._controller._model.isPlaying() and 'Stop Csound\tCTRL-Y' or 'Start Csound\tCTRL-Y')
        idExportToCsd = wx.NewId()
        self._filemenu.Append(idExportToCsd, "&Export to CSD\tCTRL-E",
                              "Export workspace to CSD (Csound Unified File Format)")
        self._filemenu.AppendSeparator()
        # Exit
        self._filemenu.Append(wx.ID_EXIT, "E&xit\tCTRL-Q", "Exit Cabel")
        menubar.Append(self._filemenu, "&File")
        
        # Modules
        self._modulesMenu = self.getModulesMenu(self._controller._getXmlModuleList())
        menubar.Append(self._modulesMenu, "&Modules")
        
        # Options
        self._optionsmenu = wx.Menu()

        # bottom Pane
        # -> properties
        if self.config.getVal(tools.config.View.BOTTOMWINDOW_REMEMBERPROPERTIES):
            showBottomPane = self.config.getVal(tools.config.View.BOTTOMWINDOW_SHOW)
        else:
            showBottomPane = self.config.getDefault(tools.config.View.BOTTOMWINDOW_SHOW)
        # -> menu entry
        self.id_bottomPane = wx.NewId()
        self._optionsmenu.AppendCheckItem(self.id_bottomPane, "Show &Bottom Pane\tALT-X",
                                    "Show Bottom Pane")
        self._optionsmenu.Check(self.id_bottomPane, showBottomPane)
        
        id_refreshMods = wx.NewId()
        self._optionsmenu.Append(id_refreshMods, "&Refresh Module List\tALT-R", "Refresh the Xml-Module List")
        
        self._optionsmenu.AppendSeparator()
        
        # Preferences
        id_options = wx.NewId()
        self._optionsmenu.Append(id_options, "Preferences\tALT-P", "Preferences")
                
        menubar.Append(self._optionsmenu, "&Options")

        self.SetMenuBar(menubar)

        # Associate menu events to handler functions
        self.Bind(wx.EVT_MENU, self._controller.onNew, id = wx.ID_NEW)
        self.Bind(wx.EVT_MENU, self._controller.onOpen, id = wx.ID_OPEN)
        self.Bind(wx.EVT_MENU, self._controller.onSave, id = wx.ID_SAVE)
        self.Bind(wx.EVT_MENU, self._controller.onSaveAs, id = wx.ID_SAVEAS)
        self.Bind(wx.EVT_MENU, self._controller.onPlayStop, id = self._playStopId)
        self.Bind(wx.EVT_MENU, self._controller.onMenuExportToCsd, id = idExportToCsd)
        self.Bind(wx.EVT_MENU, self._controller.onMenuExit, id = wx.ID_EXIT)
        self.Bind(wx.EVT_MENU, self.onToggleBottomPane, id = self.id_bottomPane)
        self.Bind(wx.EVT_MENU, self._controller._refreshModulesMenu, id = id_refreshMods)
        self.Bind(wx.EVT_MENU, self._controller.onOptionsOpen, id = id_options)
        self.Bind(wx.EVT_CLOSE, self._controller.onClose)

        # Create Statusbar
        self.statusbar = CabelStatusBar(self)
        self.SetStatusBar(self.statusbar)
        self.SetStatusBarPane(0)
        
        # Create splitted window
        self._splitter = CabelSplitterWindow(self, wx.ID_ANY)
        
        # Add workspace for synth building
        self.workspace = CabelScrolledWindow(self._splitter, -1, self)

        # wxTextCtrl which gets the stdout and stderr output of the app
        self.ioTextCtrl = None

        # Initialize Splitter
        self._splitter.initialize(self.workspace)

        # Associate mouse events to handler functions
        self.workspace.Bind(wx.EVT_LEFT_DOWN, self._controller.onMouseLeftDown)
        self.workspace.Bind(wx.EVT_LEFT_UP, self._controller.onMouseLeftUp)
        self.workspace.Bind(wx.EVT_LEFT_DCLICK, self._controller.onMouseLeftDclick)
        self.workspace.Bind(wx.EVT_RIGHT_DOWN, self._controller.onMouseRightDown)
        self.workspace.Bind(wx.EVT_MIDDLE_DOWN, self._controller.onMouseMiddleDown)
        self.workspace.Bind(wx.EVT_MOTION, self._controller.onMouseMotion)
        self.Bind(wx.EVT_SIZE, self._controller.onSize)

        # Add additional key events
        self.Bind(wx.EVT_KEY_DOWN, self._controller.onKey)

        self.update(None, None)


    def createWorkspace(self, workspaceReader):
        """
        """
        # Open workspace from worksp
        if workspaceReader:
            # Set view modules
            self._modules = workspaceReader.viewModules.values()
            self._modulesDict = workspaceReader.viewModules
            
            # Set connections
            self._connections = []
            for c in workspaceReader.connections:
                outModule = self._modulesDict[c['fromModuleId']]
                inModule = self._modulesDict[c['toModuleId']]
                self._connections.append(ModuleConnection(outModule, \
                                            c['fromVarId'], \
                                            inModule, \
                                            c['toVarId']))
            # Set file location                                
            self.fileName = workspaceReader.fileName
            self.filePath = workspaceReader.filePath
            
        # Delete old workspace and create new one
        else:
            self._modules = []
            self._modulesDict = {}
            self._connections = []
            
            self.fileName = ''
            self._cwFileNewCount += 1
            
            self._controller._actModule = None
        
        self.workspace.Refresh()
        return self            
        

    def update(self, observable, arg):
        """
        This method is called whenever the observed object is
        changed. An application calls an observable object's
        notifyObservers method to have all the object's observers
        notified of the change.

        @type  o: Observable
        @param o: The observable object.
        @type  arg: object
        @param arg: An argument passed to the notifyObservers method.
        """
        # Refresh the workspace?
        refresh = True
        # Read arg gand do what has to be done.
        if arg:
            # model.workspace.addModule;
            # arg[1] module to add
            if arg[0] == 'add':
                newModule = arg[1]
                self.addModule(newModule, self._controller._lastMousePt)
            # model.workspace.removeModule;
            # arg[1] module to remove, arg[2] in- & outgoing connections to remove
            elif arg[0] == 'remove':
                rmModule = arg[1]
                rmConnections = arg[2]
                self.removeModule(rmModule, rmConnections)
            # model.workspace.connect;
            # arg[1] new connection
            elif arg[0] == 'connect':
                newConnection = arg[1]
                self.addConnection(newConnection)
            # model.workspace.disconnect;
            # arg[1] connection to be removed
            elif arg[0] == 'disconnect':
                rmConnections = arg[1]
                self.removeConnection(rmConnections)
            # model.workspace.setValue:
            # arg[1] input variable which changed, arg[2] new value of input var
            elif arg[0] == 'set':
                inVar = arg[1]
                newValue = arg[2]
            # gets triggered by the config.setting.updateView method:
            # arg[1] in view workspace defined method without parameters.
            elif arg[0] == 'funCall':
                self._controller._callFunc(self, arg[1])
            
        # Repaints the workspace
        if refresh:
            self.workspace.Refresh()


    def onToggleBottomPane(self, event):
        """
        Toggle bottom pane in the splitter window.

        @type  event: wx.Event
        @param event: Event associated with this function.
        """
        if not self.config.getVal(tools.config.View.BOTTOMWINDOW_SHOW):
            self._splitter.split()
        else:
            self._splitter.unSplit()


    def addModule(self, module, pt):
        """
        Adds module to view workspace.

        @type  module: model.module.Module
        @param module: module to add to view workspace
        @type  pt: wx.Point
        @param pt: Position on the workspace of module to add
        """
        # Module is not yet on the view.workspace
        if not self._modulesDict.has_key(module.id):
            viewModule = Module(pt.x, pt.y, module, self._controller)
            # if lastToAddPosition not changes, this helps
            pt.x += 25
            pt.y += 20
            self._modulesDict[module.id] = viewModule
        # Yet it is
        else:
            viewModule = self._modulesDict[module.id]
        # If it is not yet in the internal list of view.Modules
        if viewModule not in self._modules:
            # then add it
            self._modules.append(viewModule)
        # Set added module to actModule
        self._controller.setModuleFocus(viewModule)
        return viewModule


    def removeModule(self, module, connections):
        """
        Removes module from workspace.

        @type  module: model.module.Module
        @param module: module to be removed from view workspace.
        @type  connections: list
        @param connections: list of model.connection.Connection to delete.
        """
        # remove modules connections
        for c in connections:
            self.removeConnection(c)

        # remove module
        if self._modulesDict.has_key(module.id):

            viewModule = self._modulesDict[module.id]
            self._modules.remove(viewModule)

            if self._controller._actModule == viewModule:
                self._controller.setModuleFocus(None)

            del self._modulesDict[module.id]


    def addConnection(self, connection):
        """
        Add connection to view workspace.

        @type  connection: model.connection.Connection
        @param connection: Model connection to add to view workspace.
        """
        outputNum = connection.fromVar.module.outVars.index(connection.fromVar)
        inputNum = connection.toVar.module.inVars.index(connection.toVar)
        newConnection = ModuleConnection(self._modulesDict[connection.fromVar.module.id],
                                         outputNum,
                                         self._modulesDict[connection.toVar.module.id],
                                         inputNum)
        if newConnection not in self._connections:
            self._connections.append(newConnection)


    def removeConnection(self, connection):
        """
        Remove connection from view workspace.

        @type  connection: model.connection.Connection
        @param connection: Connection to remove from view workspace.
        """
        # Create corresponding view connection
        outputNum = connection.fromVar.module.outVars.index(connection.fromVar)
        inputNum = connection.toVar.module.inVars.index(connection.toVar)
        fromModule = connection.fromVar.module
        toModule = connection.toVar.module
        rmConnection = ModuleConnection(self._modulesDict[fromModule.id],
                                        outputNum,
                                        self._modulesDict[toModule.id],
                                        inputNum)
        # If in _connections list remove it
        if rmConnection in self._connections:
            self._connections.remove(rmConnection)


    def getModuleAt(self, pt):
        """
        Return the first module found at given point.

        @type  pt: wx.Point
        @param pt: Point to test if on a module.
        @rtype : view.module.Module
        @return: Module at point or None.
        """
        # Search from last added module to first
        for i in range(len(self._modules) - 1, -1, -1):
            if self._modules[i].isOnModule(pt):
                return self._modules[i]
        return None


    def scrollWorkspaceOnBorder(self, pt):
        """
        If pt is on workspace border scrolls workspace.

        @type  pt: wx.Point
        @param pt: Point to test if on worspace border.
        """
        unitX, unitY = self.workspace.GetScrollPixelsPerUnit()
        sizeX, sizeY = self.workspace.GetClientSize()
        originX, originY = self.workspace.GetViewStart()
        distanceLeft = pt.x - originX * unitX
        distanceRight = originX * unitX + sizeX - pt.x
        distanceTop = pt.y - originY * unitY
        distanceBottom = originY * unitY + sizeY - pt.y
        if distanceLeft < 10:
            self.workspace.Scroll(originX - 1, -1)
        if distanceRight < 10:
            self.workspace.Scroll(originX + 1, -1)
        if distanceTop < 10:
            self.workspace.Scroll(-1, originY - 1)
        if distanceBottom < 10:
            self.workspace.Scroll(-1, originY + 1)


    def getModulesMenu(self, xmlModuleList):
        """
        Gets the Menu for all the defined Xml Modules.

        @type  xmlModuleList: list
        @param xmlModuleList: List of tuples which represents the
                              structure of the modules folder.
        @rtype:  wx.Menu
        @return: Menu
        """
        modulesmenu = wx.Menu()
        for xmlModuleListItem in xmlModuleList:
            newId = wx.NewId()
            if isinstance(xmlModuleListItem[1], list):
                modulesmenu.AppendMenu(newId, xmlModuleListItem[0],
                                       self.getModulesMenu(xmlModuleListItem[1]))
            else:
                self._controller._idToModules[newId] = xmlModuleListItem[1].fullName
                modulesmenu.Append(newId, xmlModuleListItem[0],
                                   xmlModuleListItem[1].description)
                self.Bind(wx.EVT_MENU, self._controller.onModulesMenu, id = newId)

        return modulesmenu


    def getModuleMenu(self):
        """
        Return menu when right clicking on a module.
        """
        modulemenu = wx.Menu()
        
        # "Remove Module" Entry
        delId = wx.NewId()
        modulemenu.Append(delId, 'Remove Module')
        self.Bind(wx.EVT_MENU, self._controller.onRemoveActModule, id = delId)
        
        # "Zoom Module" Entries
        if self.config.getVal(tools.config.View.ZOOM_INDIVIDUAL_ACTIVE):
            # Zoom Entry
            modulemenu.AppendSeparator()        
            # Zoom Entry Ids
            zoomInId = wx.NewId()
            zoomOutId = wx.NewId()
            # Zooms
            zoomDefault = self.config.getVal(tools.config.View.ZOOM_FACTOR_DEFAULT)
            # Scales
            scaleInFactor = scaleOutFactor = zoomDefault / 100
            # Zoom Menu Entries
            modulemenu.Append(zoomInId, 'zoom +' + str(zoomDefault) + '%')
            modulemenu.Append(zoomOutId, 'zoom -' + str(zoomDefault) + '%')
            # Bindings
            self.Bind(wx.EVT_MENU, self._controller.onScaleInActModule, id = zoomInId)
            self.Bind(wx.EVT_MENU, self._controller.onScaleOutActModule, id = zoomOutId)
            
        if self.config.getVal(tools.config.Directories.EDITOR):
            modulemenu.AppendSeparator()
            viewXmlId = wx.NewId()
            modulemenu.Append(viewXmlId, 'Show Module Xml')
            self.Bind(wx.EVT_MENU, self._controller.onShowModuleXML, id = viewXmlId)

        return modulemenu


    def _getRecentMenu(self):
        """
        """
        configDir = self._controller._configDirs
        recentList = []
        recentList = configDir.getVal(tools.config.Directories.RECENTFILES)
        
        recentMenu = wx.Menu()
        
        for i in xrange (0, len(recentList)):
            recentId = wx.NewId()
            recentMenu.Append(recentId, '&' + str(i) + ' ' + str(os.path.normpath(recentList[i])))
            self._controller._idToRecent[recentId] = str(recentList[i])
            self.Bind(wx.EVT_MENU, self._controller.onRecent, id = recentId)
            
        return recentMenu
        
        
    def reloadRecentMenu(self):
        """
        """
        self._filemenu.Remove(self._recentMenuId)
        recentMenu = self._getRecentMenu()
        self._filemenu.InsertMenu(2, self._recentMenuId, 'Open Recent...', recentMenu)
        
        # Depending if there are Items in the RecentMenu Disable / Enable it
        if self._filemenu.IsEnabled(self._recentMenuId):
            if recentMenu.GetMenuItemCount() == 0:
                self._filemenu.Enable(self._recentMenuId, False)
        else:
            if recentMenu.GetMenuItemCount() > 0:
                self._filemenu.Enable(self._recentMenuId, True)
        

    def createDraggedCable(self, startPt, endPt):
        """
        Create connection between startPt and endPt as visual feedback
        for connection mode.

        @type  startPt: wx.Point
        @param startPt: Start point of dragged cable.
        @type  endPt: wx.Point
        @param endPt: End point of dragged cable.
        """
        self._draggedCable = Connection(startPt, endPt)


    def removeDraggedCable(self):
        """
        Remove dragged cable from workspace.
        """
        self._draggedCable = None
        self.workspace.Refresh()


    def getModules(self):
        """
        Return list of view modules.

        @rtype: List
        @return: List of view modules.
        """
        return self._modules


    def getConnections(self):
        """
        Return list of view connections.

        @rtype: List
        @return: List of view connections.
        """
        return self._connections


    def getDraggedCable(self):
        """
        Return dragged cable object.

        @rtype: model.view.connection.Connection
        @return: Visual feedback when connection two modules.
        """
        return self._draggedCable
        
        
    def GetTitle(self):
        """
        Return Title string for the CabelFrame.
        
        @rtype: string
        @return: Title string for the CabelFrame.
        """
        try:
            star = (self._controller._saved and [''] or ['*'])[0]
        except AttributeError:
            # self._controller isn't defined yet
            star = ''
        
        if self.fileName == '':
            documentName = 'new' + str(self._cwFileNewCount) + '.cw'
        else:
            documentName = self.fileName + '.cw'
        
        return 'Cabel - [' + documentName + ']' + star