Пример #1
0
def ResizeRecentProjectsList():
    """
	Updates the length of the recent projects list
	to the size specified by the 'RecentProjectsListMaxSize' config.
	"""
    sm = SettingsManager()
    new_size = sm.get_config('RecentProjectsListMaxSize')

    try:
        old_list = sm.get_config('RecentProjectsList')
    except KeyError:
        old_list = []
    sm.set_value('RecentProjectsList', old_list[:new_size])
Пример #2
0
 def OnNewButton(self, event=None):
     # handle click on New project button
     self.DisableKeypresses()
     # get project filename extension
     SettingsMgr = SettingsManager()
     ProjFileExt = SettingsMgr.get_config('ProjFileExt')
     OpenSuccess = False  # whether valid project files are identified for opening
     # let the user select a template
     DialogueBox = SelectTemplateDialogue(
         parent=self,
         title=_('Vizop: Choose a template'),
         ColourScheme=self.ColourScheme,
         ProjTemplates=self.ProjTemplates)
     if DialogueBox.ShowModal() == wx.ID_OK:
         # get the template file and project filename to create from the user
         TargetTemplateFile, ProjFilename, SaveOnFly = DialogueBox.ReturnData
         # force the project filename to have expected extension
         ProjFilename = EnsureFilenameHasExtension(ProjFilename,
                                                   ProjFileExt)
         CreatableProjFiles, ProjOpenData = self.HandleNewFileRequest(
             [TargetTemplateFile],
             NewFilenames=[ProjFilename],
             NewProjects=True,
             SaveOnFly=SaveOnFly)
         OpenSuccess = bool(CreatableProjFiles)
     # allow user to continue working in Welcome Frame if no projects can be created. TODO give user feedback
     if not OpenSuccess:
         self.ReinstateKeypresses()
Пример #3
0
 def OnStoreButton(self, event=None):
     # handle 'Start new file from template and store my work' request
     global KeyPressHash
     self.DisableKeypresses()
     # retrieve the target template filename from the dropdown box
     SettingsMgr = SettingsManager()
     TargetTemplateStub = self.tc.GetStringSelection()
     TargetTemplateFile = self.avail_templates[TargetTemplateStub]
     if IsReadableFile(TargetTemplateFile):
         # get a default directory in which to store the project
         try:
             DefDir = SettingsMgr.get_config('NewProjDir')
         except KeyError:
             # No default dir found in settings: store one
             DefDir = SettingsMgr.get_value('UserHomeDir')
             SettingsMgr.set_value('NewProjDir', DefDir)
         # get default extension for project files
         ProjFileExt = SettingsMgr.get_config('ProjFileExt')
         # get a filename to store the project
         (StoreLocOK, ProjFilename) = GetFilenameForSave(
             DialogueParentFrame=self,
             DialogueTitle=_('Vizop needs a filename for your new project'),
             DefaultDir=DefDir,
             DefaultFile='',
             Wildcard='',
             DefaultExtension=ProjFileExt)
         if StoreLocOK:
             # set dialogue box's return data: TargetTemplateFile (str), ProjFilename (str), SaveOnFly (bool)
             self.ReturnData = (TargetTemplateFile, ProjFilename, True)
             SettingsMgr.set_value('NewProjDir',
                                   os.path.dirname(ProjFilename))
             # close the template selection dialogue box
             self.EndModal(wx.ID_OK)
         else:  # we're returning to template selection dialogue: reinstate keyboard shortcuts
             self.ReinstateKeypresses()
     else:  # there was a problem with the template file; pop up a message
         i = wx.MessageBox(
             _('Vizop says sorry'),
             (_("Template %s can't be opened") % TargetTemplateStub),
             style=wx.OK)
Пример #4
0
def select_file_from_all(message='',
                         default_path=None,
                         wildcard='*',
                         allow_multi_files=False,
                         parent_frame=None,
                         **Args):
    """
	Provide generic file selection dialogue. Allows user to select any file(s)
	from the filesystem.
	Returns list of full file paths selected (or [] if none were selected)
	"""
    # **Args is to soak up obsolete arg read_only (no longer recognised by wxPython)
    # force MacOS to apply filter in wildcard
    wx.SystemOptions.SetOption(u"osx.openfiledialog.always-show-types", 1)
    # get default directory to show in dialogue
    if default_path is None:
        sm = SettingsManager()
        try:  # get saved path from config file
            default_path = sm.get_config('UserWorkingDir')
        except KeyError:  # no path saved; select user's home folder
            default_path = os.path.expanduser('~')

    dialogue = wx.FileDialog(message=message,
                             defaultDir=default_path,
                             wildcard='Vizop project files (*.vip)|*.vip',
                             style=((wx.FD_MULTIPLE * allow_multi_files)
                                    | wx.FD_OPEN),
                             parent=parent_frame,
                             pos=(100, 100))

    if dialogue.ShowModal() == wx.ID_OK:  # dialogue box exited with OK button
        if allow_multi_files:
            return dialogue.GetPaths()
        else:
            return [dialogue.GetPath()]
    else:
        # dialogue box exited with Cancel button
        return []
Пример #5
0
def GetValueFromUserConfig(ConfigName):
    # retrieve and return config value for ConfigName (str) from the user's config data (stored in config file)
    # returns default (see settings module) if no key has been stored
    sm = SettingsManager()
    return sm.get_config(ConfigName)
Пример #6
0
class NoProjectOpenFrame(wx.Frame):
    # Define the welcome window that appears whenever no project is open, including at launch of vizop

    def __init__(self, parent, ID, title, ColourScheme):
        global KeyPressHash
        self.ColourScheme = ColourScheme
        wx.Frame.__init__(self, parent, wx.ID_ANY, title, size=(600, 400))
        self.settings_manager = SettingsManager()
        self.Centre(
        )  # places window in centre of screen, Rappin p235. TODO need to place in centre of primary display

        # set up sizers to contain the objects on the welcome frame
        self.sizer1 = wx.BoxSizer(wx.HORIZONTAL)

        # set up logo
        self.sizer1.Add(LogoPanel(self, self.ColourScheme), 1,
                        wx.ALIGN_LEFT | wx.EXPAND)
        # set up button area
        # set correct shortcut key text for 'Exit' key
        ExitShortcutKey = {
            'Linux': 'Ctrl + Q',
            'Windows': 'Ctrl + Q',
            'Darwin': info.CommandSymbol + 'Q'
        }.get(system(), 'Ctrl + Q')
        # info per button: (text in button, x and y location, handling routine, keyboard shortcut, internal name)
        ButtonInfo = [
            (_('Open recent project | R'), 40, 40, self.OnOpenRecentButton,
             ord('r'), 'Recent'),
            (_('Open existing project | O'), 40, 90, self.OnOpenExistingButton,
             ord('o'), 'Existing'),
            (_('Start new project | N'), 40, 140, self.OnNewButton, ord('n'),
             'New'),
            (_('Join a project collaboration | J'), 40, 190,
             self.OnJoinCollaborationButton, ord('j'), 'Join'),
            (_('About Vizop | T'), 40, 240, self.OnAbout, ord('t'), 'About'),
            (_('Exit | ' + ExitShortcutKey), 40, 290, self.OnExitButton,
             [wx.WXK_CONTROL, ord('q')], 'Exit')
        ]

        # get the current recent project list, or create a new one if it doesn't exist
        try:
            RecentProjList = self.settings_manager.get_config(
                'RecentProjectsList')
        except KeyError:
            RecentProjList = []
        # get filename of all available project templates
        self.ProjTemplates = GetAvailProjTemplates()

        panel3 = wx.Panel(self)  # panel to hold the buttons
        panel3.SetBackgroundColour(ColourScheme.BackBright)
        KeyPressHash = ClearKeyPressRegister(KeyPressHash)
        for (ButtonText, x, y, ButtonHandler, Key, Name) in ButtonInfo:
            # set up each button in the welcome frame
            RegisterKey = True  # whether to register the keypress
            b = wx.Button(panel3, -1, ButtonText, pos=(x, y), size=(220, 40))
            b.Bind(wx.EVT_BUTTON, ButtonHandler)
            b.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.NORMAL))
            b.SetForegroundColour('navy')
            if (Name == 'Recent') and not RecentProjList:
                b.Disable()  # disable Recent projects button if none available
                RegisterKey = False
            if (Name == 'New') and not self.ProjTemplates:
                b.Disable(
                )  # disable New project button if no templates available
                RegisterKey = False
            if RegisterKey:
                KeyPressHash = RegisterKeyPressHandler(KeyPressHash, Key,
                                                       ButtonHandler)

        panel3.SetFocus()  # enable button bar to handle Tab, Space, Enter keys
        self.sizer1.Add(panel3, 1, wx.EXPAND)
        self.sizer1.SetItemMinSize(1, (300, 400))

        self.Bind(wx.EVT_IDLE, self.OnIdle)
        # Lay out sizers
        self.SetMinSize((600, 400))
        self.SetSizer(self.sizer1)  # assigns sizer1 to fill Welcome frame
        self.SetAutoLayout(True)
        self.sizer1.FitInside(self)
        self.Show(True)

    def OnIdle(
        self, Event
    ):  # during idle time, handle keystrokes for shortcuts. This procedure is repeated in module datacore
        global KeyPressHash
        # initialise storage object used to remember keys pressed last time, for chord detection in correct order
        if not hasattr(self, 'PrevChordKeys'): self.PrevChordKeys = []
        KeysDownThisTime = [
        ]  # prepare list of key codes that are 'hit' and match any keys in KeyPressHash
        KeyPressIndexHit = None  # which item (index in KeyPressHash) is to be invoked
        for (HashIndex, (KeyStroke, Handler, Args)) in enumerate(
                KeyPressHash
        ):  # check each keystroke registered in KeyPressHash
            if type(KeyStroke) is int:
                if wx.GetKeyState(KeyStroke):
                    KeysDownThisTime.append(KeyStroke)
                    if not (KeyStroke in self.PrevChordKeys):
                        KeyPressIndexHit = HashIndex  # KeyStroke has been detected this time, but not last time
            elif type(KeyStroke) is list:  # key chord handling
                ChordFulfilled = True
                for k in KeyStroke:  # check each key in KeyStroke
                    if wx.GetKeyState(k): KeysDownThisTime.append(k)
                    else: ChordFulfilled = False
                # check that (1) all keys in KeyStroke are pressed, AND
                # (2) not all of them were pressed last time (i.e. >=1 of them is newly pressed)
                if ChordFulfilled and not set(KeyStroke).issubset(
                        set(self.PrevChordKeys)):
                    KeyPressIndexHit = HashIndex  # invoke handler if keystroke detected
        self.PrevChordKeys = KeysDownThisTime  # store currently-pressed keys for comparison next time
        # Must do the line above BEFORE invoking Handler - else KeyStrokes newly defined in Handler may falsely activate
        if (KeyPressIndexHit is not None):
            (KeyStroke, Handler, Args) = KeyPressHash[KeyPressIndexHit]
            Handler(**Args)  # invoke handler

    def WrapUpAfterOpeningProjects(self,
                                   ProjFiles,
                                   TemplateFiles,
                                   RequestToQuit=False,
                                   SaveOnFly=True):
        # after successful opening of project file(s) from welcome frame, perform tidying up
        # ProjFiles is list of paths of valid project files to be opened or created (str)
        # TemplateFiles is list of paths of valid template files to be used to create new projects, using the filepaths
        # in ProjFiles (str)
        # RequestToQuit (bool): whether vizop should quit now, on user's request
        # SaveOnFly (bool): whether new project should be saved on the fly
        # set return values
        NoProjectOpenFrameData.Data = {
            'ProjectFilesToOpen': ProjFiles,
            'TemplateFilesToSpawnFrom': TemplateFiles,
            'RequestToQuit': RequestToQuit,
            'SaveOnFly': SaveOnFly
        }
        self.Destroy()  # destroy welcome frame

    def WrapUpAfterJoinCollaborationRequest(self):
        # perform tidying up and exit welcome frame after receiving request to collaborate on remote project
        # similar to WrapUpAfterOpeningProjects() except there's no open project to handle
        NoProjectOpenFrameData.Data = {
            'ProjectFilesToOpen': [],
            'TemplateFilesToSpawnFrom': [],
            'RequestToQuit': False,
            'SaveOnFly': False,
            'OpenCollaboration': True
        }
        self.Destroy()  # destroy welcome frame

    def DisableKeypresses(
        self
    ):  # temporarily suppress all keypress handlers, to avoid inadvertent behaviour
        global KeyPressHash
        self.OldKPR = KeyPressHash[:]
        KeyPressHash = ClearKeyPressRegister(
            KeyPressHash)  # to avoid inadvertent behaviour from key presses

    def ReinstateKeypresses(self):  # reinstate keyboard shortcuts
        global KeyPressHash
        KeyPressHash = self.OldKPR

    def HandleNewFileRequest(self,
                             Filenames,
                             NewFilenames=[],
                             NewProjects=False,
                             SaveOnFly=True):
        # Check NewFilenames can be opened.
        # Check whether Filenames (list of paths) contains openable project templates.
        # NewFilename: full paths of files to create for new project
        # NewProjects (bool): whether the Filenames are templates to use for creation of new projects (always True)
        # SaveOnFly (bool): if creating new project, whether work should be saved on the fly
        # If any openable projects, call WrapUpAfterOpeningProjects() to close Welcome Frame and send data to datacore.
        # Return values: OpenableProjFiles (list of paths that contain valid and openable projects)
        #       ProjOpenData (list of dict of data for each file, returned from projects.TestProjectsOpenable)
        ProjOpenData = projects.TestProjectsOpenable(
            Filenames,
            ReadOnly=False)  # find out if the projects can be opened
        # expected return value (ProjOpenData): a list of dict, one for each project file in Filenames
        # dict keys are: Openable (bool), Comment (str) - explaining why project is not openable (for user feedback)
        # make list of openable/creatable project files
        OpenableProjFiles = [
            Filenames[i] for i in range(len(Filenames))
            if ProjOpenData[i]['Openable']
            if (IsWritableLocation(os.path.dirname(NewFilenames[i]))
                or not SaveOnFly)
        ]
        # Note, the writability check is duplicated in projects.SaveEntireProject() and might be redundant here
        if OpenableProjFiles:  # can any of the selected project files be opened?
            if NewProjects:  # tidy up and exit Welcome Frame
                self.WrapUpAfterOpeningProjects(
                    ProjFiles=NewFilenames,
                    TemplateFiles=OpenableProjFiles,
                    SaveOnFly=SaveOnFly)
            else:
                self.WrapUpAfterOpeningProjects(ProjFiles=OpenableProjFiles,
                                                TemplateFiles=[])
        return OpenableProjFiles, ProjOpenData

    def HandleOpenFileRequest(self,
                              Filenames,
                              NewFilenames=[],
                              NewProjects=False,
                              SaveOnFly=True):
        # Check whether Filenames (list of existing paths) contains openable projects.
        # NewFilename: full paths of files to create for new project (redundant, now using HandleNewFileRequest() )
        # NewProjects (bool): whether the Filenames are templates to use for creation of new projects - always False
        # SaveOnFly (bool): if creating new project, whether work should be saved on the fly
        # If any openable projects, call WrapUpAfterOpeningProjects() to close Welcome Frame and send data to datacore.
        # Return values: OpenableProjFiles (list of paths that contain valid and openable projects)
        #       ProjOpenData (list of dict of data for each file, returned from projects.TestProjectsOpenable)
        ProjOpenData = projects.TestProjectsOpenable(
            Filenames,
            ReadOnly=False)  # find out if the projects can be opened
        # expected return value (ProjOpenData): a list of dict, one for each project file in Filenames
        # dict keys are: Openable (bool), Comment (str) - explaining why project is not openable (for user feedback)
        # make list of openable/creatable project files
        OpenableProjFiles = [
            Filenames[i] for i in range(len(Filenames))
            if ProjOpenData[i]['Openable']
            if (IsWritableLocation(os.path.dirname(Filenames[i]))
                or not SaveOnFly)
        ]
        # Note, the writability check is duplicated in projects.SaveEntireProject() and might be redundant here
        if OpenableProjFiles:  # can any of the selected project files be opened?
            if NewProjects:  # tidy up and exit Welcome Frame
                self.WrapUpAfterOpeningProjects(
                    ProjFiles=NewFilenames,
                    TemplateFiles=OpenableProjFiles,
                    SaveOnFly=SaveOnFly)
            else:
                self.WrapUpAfterOpeningProjects(ProjFiles=OpenableProjFiles,
                                                TemplateFiles=[])
        return OpenableProjFiles, ProjOpenData

    def OnOpenRecentButton(self,
                           event=None
                           ):  # handle user request to Open Recent Project
        self.DisableKeypresses()
        OpenSuccess = False  # whether valid project files are identified for opening
        # read recent projects list from cache file
        try:
            recent_projects_list = self.settings_manager.get_config(
                'RecentProjectsList')
        except KeyError:
            #recent_projects_list does not exist - so create it
            recent_projects_list = []
            self.settings_manager.set_value('RecentProjectsList',
                                            recent_projects_list)

        RPDisplayList = [
        ]  # build list of recent projects in display-friendly format
        for ProjFilename in reversed(recent_projects_list):
            RPDisplayList.append(
                _('%s in %s') % (os.path.basename(ProjFilename),
                                 os.path.dirname(ProjFilename)))
        DialogueBox = wx.MultiChoiceDialog(
            self, _('Which project(s) would you like to open?'),
            _('Choose a vizop project file to open'),
            RPDisplayList)  # set up standard selection dialogue
        if DialogueBox.ShowModal() == wx.ID_OK:  # user clicked OK
            FilenamesSelected = []  # make list of filenames selected
            for index in DialogueBox.GetSelections():
                FilenamesSelected.append(recent_projects_list[index])
            OpenableProjFiles, ProjOpenData = self.HandleOpenFileRequest(
                FilenamesSelected)
            OpenSuccess = bool(OpenableProjFiles)
        # allow user to continue working in Welcome Frame if no projects can be opened. TODO give user feedback
        if not OpenSuccess:
            self.ReinstateKeypresses()

    def OnOpenExistingButton(self, Event=None):
        # handle click on Open Existing button
        self.DisableKeypresses()
        FilenamesSelected = projects.GetProjectFilenamesToOpen(self)
        if FilenamesSelected:  # did user select any files to open?
            OpenableProjFiles, ProjOpenData = self.HandleOpenFileRequest(
                FilenamesSelected)
            OpenSuccess = bool(
                OpenableProjFiles
            )  # using OpenSuccess for consistency with other handlers
        else:
            OpenSuccess = False
        # allow user to continue working in Welcome Frame if no projects can be opened. TODO give user feedback
        if not OpenSuccess:
            self.ReinstateKeypresses()

    def OnNewButton(self, event=None):
        # handle click on New project button
        self.DisableKeypresses()
        # get project filename extension
        SettingsMgr = SettingsManager()
        ProjFileExt = SettingsMgr.get_config('ProjFileExt')
        OpenSuccess = False  # whether valid project files are identified for opening
        # let the user select a template
        DialogueBox = SelectTemplateDialogue(
            parent=self,
            title=_('Vizop: Choose a template'),
            ColourScheme=self.ColourScheme,
            ProjTemplates=self.ProjTemplates)
        if DialogueBox.ShowModal() == wx.ID_OK:
            # get the template file and project filename to create from the user
            TargetTemplateFile, ProjFilename, SaveOnFly = DialogueBox.ReturnData
            # force the project filename to have expected extension
            ProjFilename = EnsureFilenameHasExtension(ProjFilename,
                                                      ProjFileExt)
            CreatableProjFiles, ProjOpenData = self.HandleNewFileRequest(
                [TargetTemplateFile],
                NewFilenames=[ProjFilename],
                NewProjects=True,
                SaveOnFly=SaveOnFly)
            OpenSuccess = bool(CreatableProjFiles)
        # allow user to continue working in Welcome Frame if no projects can be created. TODO give user feedback
        if not OpenSuccess:
            self.ReinstateKeypresses()

    def OnJoinCollaborationButton(
            self, Event=None):  # handle user request to join collaboration%%%
        DialogueBox = JoinCollaborationDialogue(
            parent=self,
            title=_('Vizop: Join a collaboration'),
            ColourScheme=self.ColourScheme)
        if DialogueBox.ShowModal() == wx.ID_OK: pass

    def OnAbout(self, event=None):
        OnAboutRequest(Parent=self, event=None)

    def OnExitButton(self, event=None):
        self.DisableKeypresses()
        NoProjectOpenFrameData.Data = {
            'RequestToQuit': True
        }  # store return data used by 'heart' module
        self.Destroy()