Exemple #1
0
    def suggestUpdate(self, confirmationDlg=False):
        """Query user about whether to update (if it's possible to do the update)
        """
        if self.latest == None:  #we haven't checked for updates yet
            self.latest = self.getLatestInfo()

        if self.latest == -1: return -1  #failed to find out about updates
        #have found 'latest'. Is it newer than running version?
        if self.latest['version'] > self.runningVersion and not (
                self.app.prefs.appData['skipVersion']
                == self.latest['version']):
            if self.latest['lastUpdatable'] <= self.runningVersion:
                #go to the updating window
                confirmDlg = SuggestUpdateDialog(self.latest,
                                                 self.runningVersion)
                resp = confirmDlg.ShowModal()
                confirmDlg.Destroy()
                #what did the user ask us to do?
                if resp == wx.ID_CANCEL:
                    return 0  #do nothing
                if resp == wx.ID_NO:
                    self.app.prefs.appData['skipVersion'] = self.latest[
                        'version']
                    self.app.prefs.saveAppData()
                    return 0  #do nothing
                if resp == wx.ID_YES:
                    self.doUpdate()
            else:
                #the latest version needs a full install, rather than an autoupdate
                msg = "PsychoPy v%s is available (you are running %s).\n\n" % (
                    self.latest['version'], self.runningVersion)
                msg += "This version is too big an update to be handled automatically.\n"
                msg += "Please fetch the latest version from www.psychopy.org and install manually."
                confirmDlg = dialogs.MessageDialog(parent=None,
                                                   message=msg,
                                                   type='Warning',
                                                   title='PsychoPy updates')
                confirmDlg.cancelBtn.SetLabel('Go to downloads')
                confirmDlg.cancelBtn.SetDefault()
                confirmDlg.noBtn.SetLabel('Go to changelog')
                confirmDlg.yesBtn.SetLabel('Later')
                resp = confirmDlg.ShowModal()
                confirmDlg.Destroy()
                if resp == wx.ID_CANCEL:
                    self.app.followLink(url=self.app.urls['downloads'])
                if resp == wx.ID_NO:
                    self.app.followLink(url=self.app.urls['changelog'])
        elif not confirmationDlg:  #do nothing
            return 0
        else:
            msg = "You are running the latest version of PsychoPy (%s). " % (
                self.runningVersion)
            confirmDlg = dialogs.MessageDialog(parent=None,
                                               message=msg,
                                               type='Info',
                                               title='PsychoPy updates')
            confirmDlg.ShowModal()
            return -1
Exemple #2
0
 def getLatestInfo(self, warnMsg=False):
     #open page
     URL = "http://www.psychopy.org/version.txt"
     try:
         page = urllib2.urlopen(URL)  #proxies
     except:
         if warnMsg:
             msg="Couldn't connect to psychopy.org to check for updates. \n"+\
                 "Check internet settings (and proxy setting in PsychoPy Preferences)."
             confirmDlg = dialogs.MessageDialog(parent=None,
                                                message=msg,
                                                type='Info',
                                                title='PsychoPy updates')
             confirmDlg.ShowModal()
         return -1
     #parse update file as a dictionary
     latest = {}
     for line in page.readlines():
         #in some odd circumstances (wifi hotspots) you might successfully fetch a
         #page that is not the correct URL but a redirect
         if line.find(':') == -1:
             return -1
         #this will succeed if every line has a key
         key, keyInfo = line.split(':')
         latest[key] = keyInfo.replace('\n', '').replace('\r', '')
     return latest
Exemple #3
0
 def onLogin(self, event):
     """
     Check credentials and login
     """
     if not havePyosf:
         dialogs.MessageDialog(
             parent=self.parent,
             type='Warning',
             title=_translate("pyosf not found"),
             message=_translate("You need pyosf to "
                                "log in to Open Science Framework"),
         )
         return None
     username = self.username.GetValue()
     pword = self.password.GetValue()
     rememberMe = bool(self.rememberMe.GetValue())
     try:
         session = pyosf.Session(username=username,
                                 password=pword,
                                 remember_me=rememberMe)
         self.app.osf_session = session
         self.updateStatus(_translate("Successful authentication"),
                           color=(0, 170, 0))
         time.sleep(0.5)
         self.Destroy()
     except pyosf.AuthError:
         self.updateStatus(_translate("Failed to Authenticate. "
                                      "Check username/password"),
                           color=(255, 0, 0))
 def setPrefsFromCtrls(self):
     # extract values, adjust as needed:
     # a) strip() to remove whitespace
     # b) case-insensitive match for Cmd+ at start of string
     # c) reverse-map locale display names to canonical names (ja_JP)
     re_cmd2ctrl = re.compile('^Cmd\+', re.I)
     for sectionName in self.prefsCfg.keys():
         for prefName in self.prefsSpec[sectionName].keys():
             if prefName in ['version']:  #any other prefs not to show?
                 continue
             ctrlName = sectionName + '.' + prefName
             ctrl = self.ctrls[ctrlName]
             thisPref = ctrl.getValue()
             # remove invisible trailing whitespace:
             if hasattr(thisPref, 'strip'):
                 thisPref = thisPref.strip()
             # regularize the display format for keybindings
             if sectionName == 'keyBindings':
                 thisPref = thisPref.replace(' ', '')
                 thisPref = '+'.join(
                     [part.capitalize() for part in thisPref.split('+')])
                 if platform.system() == 'Darwin':
                     # key-bindings were displayed as 'Cmd+O', revert to 'Ctrl+O' internally
                     thisPref = re_cmd2ctrl.sub('Ctrl+', thisPref)
             self.prefsCfg[sectionName][prefName] = thisPref
             #make sure list values are converted back to being lists (from strings)
             if self.prefsSpec[sectionName][prefName].startswith('list'):
                 try:
                     # if thisPref is not a null string, do eval() to get a list.
                     if thisPref == '':
                         newVal = thisPref
                     else:
                         newVal = eval(thisPref)
                 except:
                     # if eval() failed, show warning dialog and return
                     try:
                         pLabel = _localized[prefName]
                         sLabel = _localized[sectionName]
                     except:
                         pLabel = prefName
                         sLabel = sectionName
                     warnDlg = dialogs.MessageDialog(
                         parent=self,
                         message=_translate(
                             'Invalid value in "%(pref)s" ("%(section)s" Tab)'
                         ) % {
                             'pref': pLabel,
                             'section': sLabel
                         },
                         type='Info',
                         title=_translate('Error'))
                     resp = warnDlg.ShowModal()
                     return
                 if type(newVal) != list:
                     self.prefsCfg[sectionName][prefName] = [newVal]
                 else:
                     self.prefsCfg[sectionName][prefName] = newVal
     self.app.prefs.saveUserPrefs()  #includes a validation
Exemple #5
0
 def getLatestInfo(self, warnMsg=False):
     #open page
     latest=getLatestVersionInfo()
     if latest==-1:
         msg=_translate("Couldn't connect to psychopy.org to check for updates. \n")+\
             _translate("Check internet settings (and proxy setting in PsychoPy Preferences).")
         confirmDlg = dialogs.MessageDialog(parent=None,message=msg,type='Info', title=_translate('PsychoPy updates'))
         confirmDlg.ShowModal()
     return latest
Exemple #6
0
    def onBtnFindPhotometer(self, event):

        # safer to get by index, but GetStringSelection will work for
        # nonlocalized techincal names:
        photName = self.ctrlPhotomType.GetStringSelection()
        # not sure how
        photPort = self.ctrlPhotomPort.GetValue().strip()
        # [0] == Scan all ports
        if not photPort or photPort == self._photomChoices[0]:
            photPort = None
        elif photPort.isdigit():
            photPort = int(photPort)
        # search all ports
        self.comPortLabel.SetLabel(_translate('Scanning ports...'))
        self.Update()
        self.photom = hardware.findPhotometer(device=photName, ports=photPort)
        if self.photom is not None and self.photom.OK:
            self.btnFindPhotometer.Disable()
            self.btnCalibrateGamma.Enable(True)
            self.btnTestGamma.Enable(True)
            if hasattr(self.photom, 'getLastSpectrum'):
                self.btnCalibrateColor.Enable(True)
            msg = _translate('%(photomType)s found on %(photomPort)s')
            self.comPortLabel.SetLabel(msg %
                                       {'photomType': self.photom.type,
                                        'photomPort': self.photom.portString})
        else:
            self.comPortLabel.SetLabel(_translate('No photometers found'))
            self.photom = None

        # does this device need a dark calibration?
        if (hasattr(self.photom, 'getNeedsCalibrateZero') and
                self.photom.getNeedsCalibrateZero()):
            # prompt user if we need a dark calibration for the device
            if self.photom.getNeedsCalibrateZero():
                dlg = wx.Dialog(self, title=_translate(
                    'Dark calibration of ColorCAL'))
                msg = _translate('Your ColorCAL needs to be calibrated first.'
                                 ' Please block all light from getting into '
                                 'the lens and press OK.')
                while self.photom.getNeedsCalibrateZero():
                    txt = _translate('Dark calibration of ColorCAL')
                    dlg = dialogs.MessageDialog(self, message=msg,
                                                title=txt,
                                                type='Info')
                    # info dlg has only an OK button
                    resp = dlg.ShowModal()
                    if resp == wx.ID_CANCEL:
                        self.photom = None
                        self.comPortLabel.SetLabel('')
                        return 0
                    elif resp == wx.ID_OK:
                        self.photom.calibrateZero()
                    # this failed at least once. Try again.
                    msg = _translate('Try again. Cover the lens fully and '
                                     'press OK')
 def onNew(self, event):
     """Create a new project for OSF
     """
     if self.app.osf_session.user_id:
         projEditor = ProjectEditor()
         projEditor.Show()
     else:
         infoDlg = dialogs.MessageDialog(parent=None, type='Info',
                                         message=_translate(
                                         "You need to log in"
                                         " to create a project"))
         infoDlg.Show()
Exemple #8
0
 def onDeleteCalib(self, event):
     calToDel = self.ctrlCalibList.GetStringSelection()
     #warn user that data will be lost
     dlg = dialogs.MessageDialog(parent=self,
             message=_translate('Are you sure you want to delete this calibration? (cannot be undone)'),
             type='Warning')
     if dlg.ShowModal() == wx.ID_YES:
         #delete it
         self.currentMon.delCalib(calToDel)
         #load most recent calibration instead
         self.onChangeCalibSelection(event=None, newCalib=-1)#this will load calibration "-1" (last calib)
         self.updateCalibList()
     dlg.Destroy()
Exemple #9
0
 def onCloseWindow(self, event):
     if self.unSavedMonitor:
         #warn user that data will be lost
         dlg = dialogs.MessageDialog(self,message=_translate('Save changes to monitor settings before quitting?'),type='Warning')
         resp = dlg.ShowModal()
         if resp  == wx.ID_CANCEL:
             return 1 #return before quitting
         elif resp == wx.ID_YES:
             #save then quit
             self.currentMon.saveMon()
         elif resp == wx.ID_NO:
             pass #don't save just quit
         dlg.Destroy()
     self.onCopyMon() # save current monitor name to clipboard
     self.Destroy()
Exemple #10
0
    def onBtnFindPhotometer(self, event):
        photName = self.ctrlPhotomType.GetStringSelection()
        photPort = self.ctrlPhotomPort.GetValue().strip()
        if not photPort or photPort == "Scan all ports":
            photPort = None
        elif photPort.isdigit():
            photPort = int(photPort)
        #search all ports
        self.comPortLabel.SetLabel('Scanning ports...')
        self.Update()
        self.photom = hardware.findPhotometer(device=photName, ports=photPort)
        if self.photom is not None and self.photom.OK:
            self.btnFindPhotometer.Disable()
            self.btnCalibrateGamma.Enable(True)
            self.btnTestGamma.Enable(True)
            if hasattr(self.photom, 'getLastSpectrum'):
                self.btnCalibrateColor.Enable(True)
            self.comPortLabel.SetLabel(
                '%s found on %s' % (self.photom.type, self.photom.portString))
        else:
            self.comPortLabel.SetLabel('No photometers found')
            self.photom = None

        #does this device need a dark calibration?
        if hasattr(self.photom, 'getNeedsCalibrateZero'
                   ) and self.photom.getNeedsCalibrateZero():
            #prompt user if we need a dark calibration for the device
            if self.photom.getNeedsCalibrateZero():
                dlg = wx.Dialog(self, title='Dark calibration of ColorCAL')
                msg='Your ColorCAL needs to be calibrated first. ' +\
                    'Please block all light from getting into the lens and press OK.'
                while self.photom.getNeedsCalibrateZero():
                    dlg = dialogs.MessageDialog(
                        self,
                        message=msg,
                        title='Dark calibration of ColorCAL',
                        type='Info')  #info dlg has only an OK button
                    resp = dlg.ShowModal()
                    if resp == wx.ID_CANCEL:
                        self.photom = None
                        self.comPortLabel.SetLabel('')
                        return 0
                    elif resp == wx.ID_OK:
                        self.photom.calibrateZero()
                    #this failed at least once. Try again.
                    msg = 'Try again. Cover the lens fully and press OK'
Exemple #11
0
 def onDeleteMon(self, event):
     monToDel = self.currentMonName
     dlg = dialogs.MessageDialog(parent=self,
             message=_translate('Are you sure you want to delete all details for %s? (cannot be undone)') % monToDel,
             type='Warning')
     response = dlg.ShowModal()
     dlg.Destroy()
     if response == wx.ID_YES:
         #delete it
         monitorFileName = os.path.join(monitors.monitorFolder,
             monToDel+".calib")
         os.remove(monitorFileName)
         self.currentMon=None
         self.currentMonName=None
         self.updateMonList()
         #load most recent calibration instead
         self.onChangeMonSelection(event=None)#this will load calibration "-1" (last calib)
         self.updateCalibList()
Exemple #12
0
 def onChangeMonSelection(self, event):
     if self.unSavedMonitor:
         if self.currentMonName == self.ctrlMonList.GetStringSelection():
             # it didnt' really change
             return 1
         # warn user that data will be lost
         msg = _translate('Save changes to monitor?')
         dlg = dialogs.MessageDialog(self, msg, type='Warning')
         resp = dlg.ShowModal()
         dlg.Destroy()
         if resp == wx.ID_CANCEL:
             # revert and return
             self.ctrlMonList.SetStringSelection(self.currentMonName)
             return False  # return before quitting
         elif resp == wx.ID_YES:
             # save then change
             self.currentMon.saveMon()
         elif resp == wx.ID_NO:
             pass  # don't save just change
     self.currentMonName = self.ctrlMonList.GetStringSelection()
     self.loadMonitor(self.currentMonName)
Exemple #13
0
    def onInit(self, showSplash=True, testMode=False):
        """
        :Parameters:

          testMode: bool
            If set to True then startup wizard won't appear and stdout/stderr
            won't be redirected to the Coder
        """
        self.version = psychopy.__version__
        self.SetAppName('PsychoPy2')

        # import localization after wx:
        from psychopy.app import localization  # needed by splash screen
        self.localization = localization
        self.locale = localization.wxlocale
        self.locale.AddCatalog(self.GetAppName())

        # set default paths and prefs
        self.prefs = psychopy.prefs
        if self.prefs.app['debugMode']:
            logging.console.setLevel(logging.DEBUG)
        # indicates whether we're running for testing purposes
        self.testMode = testMode
        self.osf_session = None

        if showSplash:
            # show splash screen
            splashFile = os.path.join(
                self.prefs.paths['resources'], 'psychopySplash.png')
            splashBitmap = wx.Image(name=splashFile).ConvertToBitmap()
            splash = AS.AdvancedSplash(None, bitmap=splashBitmap,
                                       timeout=3000,
                                       style=AS.AS_TIMEOUT | wx.FRAME_SHAPED,
                                       shadowcolour=wx.RED)  # transparency?
            splash.SetTextPosition((10, 240))
            splash.SetText(_translate("  Loading libraries..."))
        else:
            splash = None

        # SLOW IMPORTS - these need to be imported after splash screen starts
        # but then that they end up being local so keep track in self
        if splash:
            splash.SetText(_translate("  Loading PsychoPy2..."))
        from psychopy.compatibility import checkCompatibility
        # import coder and builder here but only use them later
        from psychopy.app import coder, builder, dialogs, urls
        self.keys = self.prefs.keys
        self.prefs.pageCurrent = 0  # track last-viewed page, can return there
        self.IDs = IDStore()
        self.urls = urls.urls
        self.quitting = False
        # check compatibility with last run version (before opening windows)
        self.firstRun = False

        if '--firstrun' in sys.argv:
            del sys.argv[sys.argv.index('--firstrun')]
            self.firstRun = True
        if 'lastVersion' not in self.prefs.appData:
            # must be before 1.74.00
            last = self.prefs.appData['lastVersion'] = '1.73.04'
            self.firstRun = True
        else:
            last = self.prefs.appData['lastVersion']

        if self.firstRun and not self.testMode:
            self.firstrunWizard()

        # setup links for URLs
        # on a mac, don't exit when the last frame is deleted, just show menu
        if sys.platform == 'darwin':
            self.menuFrame = MenuFrame(parent=None, app=self)
        # get preferred view(s) from prefs and previous view
        if self.prefs.app['defaultView'] == 'last':
            mainFrame = self.prefs.appData['lastFrame']
        else:
            # configobjValidate should take care of this situation
            allowed = ['last', 'coder', 'builder', 'both']
            if self.prefs.app['defaultView'] in allowed:
                mainFrame = self.prefs.app['defaultView']
            else:
                self.prefs.app['defaultView'] = 'both'
                mainFrame = 'both'
        # fetch prev files if that's the preference
        if self.prefs.coder['reloadPrevFiles']:
            scripts = self.prefs.appData['coder']['prevFiles']
        else:
            scripts = []
        appKeys = list(self.prefs.appData['builder'].keys())
        if self.prefs.builder['reloadPrevExp'] and ('prevFiles' in appKeys):
            exps = self.prefs.appData['builder']['prevFiles']
        else:
            exps = []
        # then override the prev files by command options and passed files
        if len(sys.argv) > 1:
            if sys.argv[1] == __name__:
                # program was executed as "python.exe PsychoPyIDE.py %1'
                args = sys.argv[2:]
            else:
                # program was executed as "PsychoPyIDE.py %1'
                args = sys.argv[1:]
            # choose which frame to start with
            if args[0] in ['builder', '--builder', '-b']:
                mainFrame = 'builder'
                args = args[1:]  # can remove that argument
            elif args[0] in ['coder', '--coder', '-c']:
                mainFrame = 'coder'
                args = args[1:]  # can remove that argument
            # did we get .py or .psyexp files?
            elif args[0][-7:] == '.psyexp':
                mainFrame = 'builder'
                exps = [args[0]]
            elif args[0][-3:] == '.py':
                mainFrame = 'coder'
                scripts = [args[0]]
        else:
            args = []

        self.dpi = int(wx.GetDisplaySize()[0] /
                       float(wx.GetDisplaySizeMM()[0]) * 25.4)
        if not (50 < self.dpi < 120):
            self.dpi = 80  # dpi was unreasonable, make one up

        if sys.platform == 'win32':
            # wx.SYS_DEFAULT_GUI_FONT is default GUI font in Win32
            self._mainFont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
        else:
            self._mainFont = wx.SystemSettings.GetFont(wx.SYS_ANSI_FIXED_FONT)
        self._codeFont = wx.SystemSettings.GetFont(wx.SYS_ANSI_FIXED_FONT)
        self._codeFont.SetFaceName(self.prefs.coder['codeFont'])

        # removed Aug 2017: on newer versions of wx (at least on mac)
        # this looks too big
        # if hasattr(self._mainFont, 'Larger'):
        #     # Font.Larger is available since wyPython version 2.9.1
        #     # PsychoPy still supports 2.8 (see ensureMinimal above)
        #     self._mainFont = self._mainFont.Larger()
        #     self._codeFont.SetPointSize(
        #         self._mainFont.GetPointSize())  # unify font size

        # create both frame for coder/builder as necess
        if splash:
            splash.SetText(_translate("  Creating frames..."))
        self.coder = None
        self.copiedRoutine = None
        self.copiedCompon = None
        self._allFrames = []  # ordered; order updated with self.onNewTopWindow
        if mainFrame in ['both', 'coder']:
            self.showCoder(fileList=scripts)
        if mainFrame in ['both', 'builder']:
            self.showBuilder(fileList=exps)

        # send anonymous info to www.psychopy.org/usage.php
        # please don't disable this, it's important for PsychoPy's development
        self._latestAvailableVersion = None
        self.updater = None
        prefsConn = self.prefs.connections
        if prefsConn['checkForUpdates'] or prefsConn['allowUsageStats']:
            connectThread = threading.Thread(
                target=connections.makeConnections, args=(self,))
            connectThread.start()
        # query github in the background to populate a local cache about
        # what versions are available for download:
        from psychopy.tools import versionchooser as vc
        versionsThread = threading.Thread(target=vc._remoteVersions,
                                          args=(True,))
        versionsThread.start()

        ok, msg = checkCompatibility(last, self.version, self.prefs, fix=True)
        # tell the user what has changed
        if not ok and not self.firstRun and not self.testMode:
            title = _translate("Compatibility information")
            dlg = dialogs.MessageDialog(parent=None, message=msg, type='Info',
                                        title=title)
            dlg.ShowModal()

        if self.prefs.app['showStartupTips'] and not self.testMode:
            tipFile = os.path.join(
                self.prefs.paths['resources'], _translate("tips.txt"))
            tipIndex = self.prefs.appData['tipIndex']
            tp = wx.CreateFileTipProvider(tipFile, tipIndex)
            showTip = wx.ShowTip(None, tp)
            self.prefs.appData['tipIndex'] = tp.GetCurrentTip()
            self.prefs.saveAppData()
            self.prefs.app['showStartupTips'] = showTip
            self.prefs.saveUserPrefs()

        if self.prefs.connections['checkForUpdates']:
            self.Bind(wx.EVT_IDLE, self.checkUpdates)
        else:
            self.Bind(wx.EVT_IDLE, self.onIdle)

        # doing this once subsequently enables the app to open & switch among
        # wx-windows on some platforms (Mac 10.9.4) with wx-3.0:
        if wx.version() >= '3.0' and sys.platform == 'darwin':
            _Showgui_Hack()  # returns ~immediately, no display
            # focus stays in never-land, so bring back to the app:
            if mainFrame in ['both', 'builder']:
                self.showBuilder()
            else:
                self.showCoder()

        return True
Exemple #14
0
    def onInit(self, showSplash=True, testMode=False):
        """This is launched immediately *after* the app initialises with wx
        :Parameters:

          testMode: bool
        """
        self.SetAppName('PsychoPy3')

        # Single instance check is done here prior to loading any GUI stuff.
        # This permits one instance of PsychoPy from running at any time.
        # Clicking on files will open them in the extant instance rather than
        # loading up a new one.
        #
        # Inter-process messaging is done via a memory-mapped file created by
        # the first instance. Successive instances will write their args to
        # this file and promptly close. The main instance will read this file
        # periodically for data and open and file names stored to this buffer.
        #
        # This uses similar logic to this example:
        # https://github.com/wxWidgets/wxPython-Classic/blob/master/wx/lib/pydocview.py

        # Create the memory-mapped file if not present, this is handled
        # differently between Windows and UNIX-likes.
        if wx.Platform == '__WXMSW__':
            tfile = tempfile.TemporaryFile(prefix="ag", suffix="tmp")
            fno = tfile.fileno()
            self._sharedMemory = mmap.mmap(fno, self.mmap_sz, "shared_memory")
        else:
            tfile = open(
                os.path.join(
                    tempfile.gettempdir(),
                    tempfile.gettempprefix() + self.GetAppName() + '-' +
                    wx.GetUserId() + "AGSharedMemory"), 'w+b')

            # insert markers into the buffer
            tfile.write(b"*")
            tfile.seek(self.mmap_sz)
            tfile.write(b" ")
            tfile.flush()
            fno = tfile.fileno()
            self._sharedMemory = mmap.mmap(fno, self.mmap_sz)

        # use wx to determine if another instance is running
        self._singleInstanceChecker = wx.SingleInstanceChecker(
            self.GetAppName() + '-' + wx.GetUserId(), tempfile.gettempdir())

        # If another instance is running, message our args to it by writing the
        # path the the buffer.
        if self._singleInstanceChecker.IsAnotherRunning():
            # Message the extant running instance the arguments we want to
            # process.
            args = sys.argv[1:]

            # if there are no args, tell the user another instance is running
            if not args:
                errMsg = "Another instance of PsychoPy is already running."
                errDlg = wx.MessageDialog(None,
                                          errMsg,
                                          caption="PsychoPy Error",
                                          style=wx.OK | wx.ICON_ERROR,
                                          pos=wx.DefaultPosition)
                errDlg.ShowModal()
                errDlg.Destroy()

                self.quit(None)

            # serialize the data
            data = pickle.dumps(args)

            # Keep alive until the buffer is free for writing, this allows
            # multiple files to be opened in succession. Times out after 5
            # seconds.
            attempts = 0
            while attempts < 5:
                # try to write to the buffer
                self._sharedMemory.seek(0)
                marker = self._sharedMemory.read(1)
                if marker == b'\0' or marker == b'*':
                    self._sharedMemory.seek(0)
                    self._sharedMemory.write(b'-')
                    self._sharedMemory.write(data)
                    self._sharedMemory.seek(0)
                    self._sharedMemory.write(b'+')
                    self._sharedMemory.flush()
                    break
                else:
                    # wait a bit for the buffer to become free
                    time.sleep(1)
                    attempts += 1
            else:
                if not self.testMode:
                    # error that we could not access the memory-mapped file
                    errMsg = \
                        "Cannot communicate with running PsychoPy instance!"
                    errDlg = wx.MessageDialog(None,
                                              errMsg,
                                              caption="PsychoPy Error",
                                              style=wx.OK | wx.ICON_ERROR,
                                              pos=wx.DefaultPosition)
                    errDlg.ShowModal()
                    errDlg.Destroy()

            # since were not the main instance, exit ...
            self.quit(None)

        # ----

        if showSplash:
            # show splash screen
            splashFile = os.path.join(self.prefs.paths['resources'],
                                      'psychopySplash.png')
            splashImage = wx.Image(name=splashFile)
            splashImage.ConvertAlphaToMask()
            splash = AS.AdvancedSplash(None,
                                       bitmap=splashImage.ConvertToBitmap(),
                                       timeout=3000,
                                       agwStyle=AS.AS_TIMEOUT
                                       | AS.AS_CENTER_ON_SCREEN)
            w, h = splashImage.GetSize()
            splash.SetTextPosition((340, h - 30))
            splash.SetText(
                _translate("Copyright (C) 2022 OpenScienceTools.org"))
        else:
            splash = None

        # SLOW IMPORTS - these need to be imported after splash screen starts
        # but then that they end up being local so keep track in self

        from psychopy.compatibility import checkCompatibility
        # import coder and builder here but only use them later
        from psychopy.app import coder, builder, runner, dialogs

        if '--firstrun' in sys.argv:
            del sys.argv[sys.argv.index('--firstrun')]
            self.firstRun = True
        if 'lastVersion' not in self.prefs.appData:
            # must be before 1.74.00
            last = self.prefs.appData['lastVersion'] = '1.73.04'
            self.firstRun = True
        else:
            last = self.prefs.appData['lastVersion']

        if self.firstRun and not self.testMode:
            pass

        # setup links for URLs
        # on a mac, don't exit when the last frame is deleted, just show menu
        if sys.platform == 'darwin':
            self.menuFrame = MenuFrame(parent=None, app=self)
        # fetch prev files if that's the preference
        if self.prefs.coder['reloadPrevFiles']:
            scripts = self.prefs.appData['coder']['prevFiles']
        else:
            scripts = []
        appKeys = list(self.prefs.appData['builder'].keys())
        if self.prefs.builder['reloadPrevExp'] and ('prevFiles' in appKeys):
            exps = self.prefs.appData['builder']['prevFiles']
        else:
            exps = []
        runlist = []

        self.dpi = int(wx.GetDisplaySize()[0] /
                       float(wx.GetDisplaySizeMM()[0]) * 25.4)
        # detect retina displays
        self.isRetina = self.dpi > 80 and wx.Platform == '__WXMAC__'
        if self.isRetina:
            fontScale = 1.2  # fonts are looking tiny on macos (only retina?) right now
            # mark icons as being retina
            icons.retStr = "@2x"
        else:
            fontScale = 1
        # adjust dpi to something reasonable
        if not (50 < self.dpi < 120):
            self.dpi = 80  # dpi was unreasonable, make one up

        # Manage fonts
        if sys.platform == 'win32':
            # wx.SYS_DEFAULT_GUI_FONT is default GUI font in Win32
            self._mainFont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
        else:
            self._mainFont = wx.SystemSettings.GetFont(wx.SYS_ANSI_FIXED_FONT)
            # rescale for tiny retina fonts

        if hasattr(wx.Font, "AddPrivateFont") and sys.platform != "darwin":
            # Load packaged fonts if possible
            for fontFile in (Path(__file__).parent / "Resources" /
                             "fonts").glob("*"):
                if fontFile.suffix in ['.ttf', '.truetype']:
                    wx.Font.AddPrivateFont(str(fontFile))
            # Set fonts as those loaded
            self._codeFont = wx.Font(
                wx.FontInfo(
                    self._mainFont.GetPointSize()).FaceName("JetBrains Mono"))
        else:
            # Get system defaults if can't load fonts
            try:
                self._codeFont = wx.SystemSettings.GetFont(
                    wx.SYS_ANSI_FIXED_FONT)
            except wx._core.wxAssertionError:
                # if no SYS_ANSI_FIXED_FONT then try generic FONTFAMILY_MODERN
                self._codeFont = wx.Font(self._mainFont.GetPointSize(),
                                         wx.FONTFAMILY_TELETYPE,
                                         wx.FONTSTYLE_NORMAL,
                                         wx.FONTWEIGHT_NORMAL)

        if self.isRetina:
            self._codeFont.SetPointSize(
                int(self._codeFont.GetPointSize() * fontScale))
            self._mainFont.SetPointSize(
                int(self._mainFont.GetPointSize() * fontScale))

        # that gets most of the properties of _codeFont but the FaceName
        # FaceName is set in the setting of the theme:
        self.theme = prefs.app['theme']

        # removed Aug 2017: on newer versions of wx (at least on mac)
        # this looks too big
        # if hasattr(self._mainFont, 'Larger'):
        #     # Font.Larger is available since wyPython version 2.9.1
        #     # PsychoPy still supports 2.8 (see ensureMinimal above)
        #     self._mainFont = self._mainFont.Larger()
        #     self._codeFont.SetPointSize(
        #         self._mainFont.GetPointSize())  # unify font size

        # create both frame for coder/builder as necess
        if splash:
            splash.SetText(_translate("  Creating frames..."))

        # Parse incoming call
        parser = argparse.ArgumentParser(prog=self)
        parser.add_argument('--builder', dest='builder', action="store_true")
        parser.add_argument('-b', dest='builder', action="store_true")
        parser.add_argument('--coder', dest='coder', action="store_true")
        parser.add_argument('-c', dest='coder', action="store_true")
        parser.add_argument('--runner', dest='runner', action="store_true")
        parser.add_argument('-r', dest='runner', action="store_true")
        parser.add_argument('-x', dest='direct', action='store_true')
        view, args = parser.parse_known_args(sys.argv)
        # Check from filetype if any windows need to be open
        if any(arg.endswith('.psyexp') for arg in args):
            view.builder = True
            exps = [file for file in args if file.endswith('.psyexp')]
        if any(arg.endswith('.psyrun') for arg in args):
            view.runner = True
            runlist = [file for file in args if file.endswith('.psyrun')]
        # If still no window specified, use default from prefs
        if not any(
                getattr(view, key) for key in ['builder', 'coder', 'runner']):
            if self.prefs.app['defaultView'] in view:
                setattr(view, self.prefs.app['defaultView'], True)
            elif self.prefs.app['defaultView'] == 'all':
                view.builder = True
                view.coder = True
                view.runner = True

        # set the dispatcher for standard output
        # self.stdStreamDispatcher = console.StdStreamDispatcher(self)
        # self.stdStreamDispatcher.redirect()

        # Create windows
        if view.runner:
            self.showRunner(fileList=runlist)
        if view.coder:
            self.showCoder(fileList=scripts)
        if view.builder:
            self.showBuilder(fileList=exps)
        if view.direct:
            self.showRunner()
            for exp in [
                    file for file in args
                    if file.endswith('.psyexp') or file.endswith('.py')
            ]:
                self.runner.panel.runFile(exp)

        # send anonymous info to www.psychopy.org/usage.php
        # please don't disable this, it's important for PsychoPy's development
        self._latestAvailableVersion = None
        self.updater = None
        self.news = None
        self.tasks = None

        prefsConn = self.prefs.connections

        ok, msg = checkCompatibility(last, self.version, self.prefs, fix=True)
        # tell the user what has changed
        if not ok and not self.firstRun and not self.testMode:
            title = _translate("Compatibility information")
            dlg = dialogs.MessageDialog(parent=None,
                                        message=msg,
                                        type='Info',
                                        title=title)
            dlg.ShowModal()

        if self.prefs.app['showStartupTips'] and not self.testMode:
            tipFile = os.path.join(self.prefs.paths['resources'],
                                   _translate("tips.txt"))
            tipIndex = self.prefs.appData['tipIndex']
            if parse_version(wx.__version__) >= parse_version('4.0.0a1'):
                tp = wx.adv.CreateFileTipProvider(tipFile, tipIndex)
                showTip = wx.adv.ShowTip(None, tp)
            else:
                tp = wx.CreateFileTipProvider(tipFile, tipIndex)
                showTip = wx.ShowTip(None, tp)

            self.prefs.appData['tipIndex'] = tp.GetCurrentTip()
            self.prefs.saveAppData()
            self.prefs.app['showStartupTips'] = showTip
            self.prefs.saveUserPrefs()

        self.Bind(wx.EVT_IDLE, self.onIdle)

        # doing this once subsequently enables the app to open & switch among
        # wx-windows on some platforms (Mac 10.9.4) with wx-3.0:
        v = parse_version
        if sys.platform == 'darwin':
            if v('3.0') <= v(wx.version()) < v('4.0'):
                _Showgui_Hack()  # returns ~immediately, no display
                # focus stays in never-land, so bring back to the app:
                if prefs.app['defaultView'] in [
                        'all', 'builder', 'coder', 'runner'
                ]:
                    self.showBuilder()
                else:
                    self.showCoder()
        # after all windows are created (so errors flushed) create output
        self._appLoaded = True
        if self.coder:
            self.coder.setOutputWindow()  # takes control of sys.stdout

        # flush any errors to the last run log file
        logging.flush()
        sys.stdout.flush()
        # we wanted debug mode while loading but safe to go back to info mode
        if not self.prefs.app['debugMode']:
            logging.console.setLevel(logging.INFO)

        # if the program gets here, there are no other instances running
        self._timer = wx.PyTimer(self._bgCheckAndLoad)
        self._timer.Start(250)

        return True
Exemple #15
0
    def onInit(self, showSplash=True, testMode=False):
        """This is launched immediately *after* the app initialises with wx
        :Parameters:

          testMode: bool
        """
        self.SetAppName('PsychoPy3')

        if showSplash:  #showSplash:
            # show splash screen
            splashFile = os.path.join(self.prefs.paths['resources'],
                                      'psychopySplash.png')
            splashImage = wx.Image(name=splashFile)
            splashImage.ConvertAlphaToMask()
            splash = AS.AdvancedSplash(
                None,
                bitmap=splashImage.ConvertToBitmap(),
                timeout=3000,
                agwStyle=AS.AS_TIMEOUT | AS.AS_CENTER_ON_SCREEN,
            )  # transparency?
            w, h = splashImage.GetSize()
            splash.SetTextPosition((int(340), h - 30))
            splash.SetText(
                _translate("Copyright (C) 2020 OpenScienceTools.org"))
        else:
            splash = None

        # SLOW IMPORTS - these need to be imported after splash screen starts
        # but then that they end up being local so keep track in self

        from psychopy.compatibility import checkCompatibility
        # import coder and builder here but only use them later
        from psychopy.app import coder, builder, runner, dialogs

        if '--firstrun' in sys.argv:
            del sys.argv[sys.argv.index('--firstrun')]
            self.firstRun = True
        if 'lastVersion' not in self.prefs.appData:
            # must be before 1.74.00
            last = self.prefs.appData['lastVersion'] = '1.73.04'
            self.firstRun = True
        else:
            last = self.prefs.appData['lastVersion']

        if self.firstRun and not self.testMode:
            pass

        # setup links for URLs
        # on a mac, don't exit when the last frame is deleted, just show menu
        if sys.platform == 'darwin':
            self.menuFrame = MenuFrame(parent=None, app=self)
        # fetch prev files if that's the preference
        if self.prefs.coder['reloadPrevFiles']:
            scripts = self.prefs.appData['coder']['prevFiles']
        else:
            scripts = []
        appKeys = list(self.prefs.appData['builder'].keys())
        if self.prefs.builder['reloadPrevExp'] and ('prevFiles' in appKeys):
            exps = self.prefs.appData['builder']['prevFiles']
        else:
            exps = []
        runlist = []

        self.dpi = int(wx.GetDisplaySize()[0] /
                       float(wx.GetDisplaySizeMM()[0]) * 25.4)
        if not (50 < self.dpi < 120):
            self.dpi = 80  # dpi was unreasonable, make one up

        if sys.platform == 'win32':
            # wx.SYS_DEFAULT_GUI_FONT is default GUI font in Win32
            self._mainFont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
        else:
            self._mainFont = wx.SystemSettings.GetFont(wx.SYS_ANSI_FIXED_FONT)

        try:
            self._codeFont = wx.SystemSettings.GetFont(wx.SYS_ANSI_FIXED_FONT)
        except wx._core.wxAssertionError:
            # if no SYS_ANSI_FIXED_FONT then try generic FONTFAMILY_MODERN
            self._codeFont = wx.Font(self._mainFont.GetPointSize(),
                                     wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL,
                                     wx.FONTWEIGHT_NORMAL)
        # that gets most of the properties of _codeFont but the FaceName
        # FaceName is set in the setting of the theme:
        self.theme = self.prefs.app['theme']

        # removed Aug 2017: on newer versions of wx (at least on mac)
        # this looks too big
        # if hasattr(self._mainFont, 'Larger'):
        #     # Font.Larger is available since wyPython version 2.9.1
        #     # PsychoPy still supports 2.8 (see ensureMinimal above)
        #     self._mainFont = self._mainFont.Larger()
        #     self._codeFont.SetPointSize(
        #         self._mainFont.GetPointSize())  # unify font size

        # create both frame for coder/builder as necess
        if splash:
            splash.SetText(_translate("  Creating frames..."))

        # Parse incoming call
        parser = argparse.ArgumentParser(prog=self)
        parser.add_argument('--builder', dest='builder', action="store_true")
        parser.add_argument('-b', dest='builder', action="store_true")
        parser.add_argument('--coder', dest='coder', action="store_true")
        parser.add_argument('-c', dest='coder', action="store_true")
        parser.add_argument('--runner', dest='runner', action="store_true")
        parser.add_argument('-r', dest='runner', action="store_true")
        view, args = parser.parse_known_args(sys.argv)
        print(args)
        # Check from filetype if any windows need to be open
        if any(arg.endswith('.psyexp') for arg in args):
            view.builder = True
            exps = [file for file in args if file.endswith('.psyexp')]
        if any(arg.endswith('.psyrun') for arg in args):
            view.runner = True
            runlist = [file for file in args if file.endswith('.psyrun')]
        # If still no window specified, use default from prefs
        if not any(
                getattr(view, key) for key in ['builder', 'coder', 'runner']):
            if self.prefs.app['defaultView'] in view:
                setattr(view, self.prefs.app['defaultView'], True)
            elif self.prefs.app['defaultView'] == 'all':
                view.builder = True
                view.coder = True
                view.runner = True

        # Create windows
        if view.runner:
            self.showRunner(fileList=runlist)
        if view.coder:
            self.showCoder(fileList=scripts)
        if view.builder:
            self.showBuilder(fileList=exps)

        # if darwin, check for inaccessible keyboard
        if sys.platform == 'darwin':
            from psychopy.hardware import keyboard
            if keyboard.macPrefsBad:
                title = _translate("Mac keyboard security")
                if platform.mac_ver()[0] < '10.15':
                    settingName = 'Accessibility'
                    setting = 'Privacy_Accessibility'
                else:
                    setting = 'Privacy_ListenEvent'
                    settingName = 'Input Monitoring'
                msg = _translate(
                    "To use high-precision keyboard timing you should "
                    "enable {} for PsychoPy in System Preferences. "
                    "Shall we go there (and you can drag PsychoPy app into "
                    "the box)?").format(settingName)
                dlg = dialogs.MessageDialog(title=title,
                                            message=msg,
                                            type='Query')
                resp = dlg.ShowModal()
                if resp == wx.ID_YES:
                    from AppKit import NSWorkspace
                    from Foundation import NSURL

                    sys_pref_link = ('x-apple.systempreferences:'
                                     'com.apple.preference.security?'
                                     '{}'.format(setting))

                    # create workspace object
                    workspace = NSWorkspace.sharedWorkspace()

                    # Open System Preference
                    workspace.openURL_(NSURL.URLWithString_(sys_pref_link))

        # send anonymous info to www.psychopy.org/usage.php
        # please don't disable this, it's important for PsychoPy's development
        self._latestAvailableVersion = None
        self.updater = None
        self.news = None
        self.tasks = None

        prefsConn = self.prefs.connections

        ok, msg = checkCompatibility(last, self.version, self.prefs, fix=True)
        # tell the user what has changed
        if not ok and not self.firstRun and not self.testMode:
            title = _translate("Compatibility information")
            dlg = dialogs.MessageDialog(parent=None,
                                        message=msg,
                                        type='Info',
                                        title=title)
            dlg.ShowModal()

        if (self.prefs.app['showStartupTips'] and not self.testMode
                and not blockTips):
            tipFile = os.path.join(self.prefs.paths['resources'],
                                   _translate("tips.txt"))
            tipIndex = self.prefs.appData['tipIndex']
            if parse_version(wx.__version__) >= parse_version('4.0.0a1'):
                tp = wx.adv.CreateFileTipProvider(tipFile, tipIndex)
                showTip = wx.adv.ShowTip(None, tp)
            else:
                tp = wx.CreateFileTipProvider(tipFile, tipIndex)
                showTip = wx.ShowTip(None, tp)

            self.prefs.appData['tipIndex'] = tp.GetCurrentTip()
            self.prefs.saveAppData()
            self.prefs.app['showStartupTips'] = showTip
            self.prefs.saveUserPrefs()

        self.Bind(wx.EVT_IDLE, self.onIdle)

        # doing this once subsequently enables the app to open & switch among
        # wx-windows on some platforms (Mac 10.9.4) with wx-3.0:
        v = parse_version
        if sys.platform == 'darwin':
            if v('3.0') <= v(wx.version()) < v('4.0'):
                _Showgui_Hack()  # returns ~immediately, no display
                # focus stays in never-land, so bring back to the app:
                if prefs.app['defaultView'] in [
                        'all', 'builder', 'coder', 'runner'
                ]:
                    self.showBuilder()
                else:
                    self.showCoder()
        # after all windows are created (so errors flushed) create output
        self._appLoaded = True
        if self.coder:
            self.coder.setOutputWindow()  # takes control of sys.stdout

        # flush any errors to the last run log file
        logging.flush()
        sys.stdout.flush()
        # we wanted debug mode while loading but safe to go back to info mode
        if not self.prefs.app['debugMode']:
            logging.console.setLevel(logging.INFO)
        # Runner captures standard streams until program closed
        if self.runner and not self.testMode:
            sys.stdout = self.runner.stdOut
            sys.stderr = self.runner.stdOut

        return True
Exemple #16
0
    def onInit(self, showSplash=True, testMode=False):
        """This is launched immediately *after* the app initialises with wx
        :Parameters:

          testMode: bool
        """
        self.SetAppName('PsychoPy3')

        if False:
            # show splash screen
            splashFile = os.path.join(self.prefs.paths['resources'],
                                      'psychopySplash.png')
            splashImage = wx.Image(name=splashFile)
            splashImage.ConvertAlphaToMask()
            splash = AS.AdvancedSplash(
                None,
                bitmap=splashImage.ConvertToBitmap(),
                timeout=3000,
                agwStyle=AS.AS_TIMEOUT | AS.AS_CENTER_ON_SCREEN,
            )  # transparency?
            w, h = splashImage.GetSize()
            splash.SetTextPosition((int(w - 130), h - 20))
            splash.SetText(_translate("Loading libraries..."))
            wx.Yield()
        else:
            splash = None

        # SLOW IMPORTS - these need to be imported after splash screen starts
        # but then that they end up being local so keep track in self
        if splash:
            splash.SetText(_translate("Loading PsychoPy3..."))
            wx.Yield()
        from psychopy.compatibility import checkCompatibility
        # import coder and builder here but only use them later
        from psychopy.app import coder, builder, dialogs

        if '--firstrun' in sys.argv:
            del sys.argv[sys.argv.index('--firstrun')]
            self.firstRun = True
        if 'lastVersion' not in self.prefs.appData:
            # must be before 1.74.00
            last = self.prefs.appData['lastVersion'] = '1.73.04'
            self.firstRun = True
        else:
            last = self.prefs.appData['lastVersion']

        if self.firstRun and not self.testMode:
            pass

        # setup links for URLs
        # on a mac, don't exit when the last frame is deleted, just show menu
        if sys.platform == 'darwin':
            self.menuFrame = MenuFrame(parent=None, app=self)
        # get preferred view(s) from prefs and previous view
        if self.prefs.app['defaultView'] == 'last':
            mainFrame = self.prefs.appData['lastFrame']
        else:
            # configobjValidate should take care of this situation
            allowed = ['last', 'coder', 'builder', 'both']
            if self.prefs.app['defaultView'] in allowed:
                mainFrame = self.prefs.app['defaultView']
            else:
                self.prefs.app['defaultView'] = 'both'
                mainFrame = 'both'
        # fetch prev files if that's the preference
        if self.prefs.coder['reloadPrevFiles']:
            scripts = self.prefs.appData['coder']['prevFiles']
        else:
            scripts = []
        appKeys = list(self.prefs.appData['builder'].keys())
        if self.prefs.builder['reloadPrevExp'] and ('prevFiles' in appKeys):
            exps = self.prefs.appData['builder']['prevFiles']
        else:
            exps = []

        # then override the prev files by command options and passed files
        if len(sys.argv) > 1:
            if sys.argv[1] == __name__:
                # program was executed as "python.exe psychopyApp.py %1'
                args = sys.argv[2:]
            else:
                # program was executed as "psychopyApp.py %1'
                args = sys.argv[1:]
            # choose which frame to start with
            if args[0] in ['builder', '--builder', '-b']:
                mainFrame = 'builder'
                args = args[1:]  # can remove that argument
            elif args[0] in ['coder', '--coder', '-c']:
                mainFrame = 'coder'
                args = args[1:]  # can remove that argument
            # did we get .py or .psyexp files?
            elif args[0][-7:] == '.psyexp':
                mainFrame = 'builder'
                exps = [args[0]]
            elif args[0][-3:] == '.py':
                mainFrame = 'coder'
                scripts = [args[0]]
        else:
            args = []

        self.dpi = int(wx.GetDisplaySize()[0] /
                       float(wx.GetDisplaySizeMM()[0]) * 25.4)
        if not (50 < self.dpi < 120):
            self.dpi = 80  # dpi was unreasonable, make one up

        if sys.platform == 'win32':
            # wx.SYS_DEFAULT_GUI_FONT is default GUI font in Win32
            self._mainFont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
        else:
            self._mainFont = wx.SystemSettings.GetFont(wx.SYS_ANSI_FIXED_FONT)
        self._codeFont = wx.SystemSettings.GetFont(wx.SYS_ANSI_FIXED_FONT)
        self._codeFont.SetFaceName(self.prefs.coder['codeFont'])

        # removed Aug 2017: on newer versions of wx (at least on mac)
        # this looks too big
        # if hasattr(self._mainFont, 'Larger'):
        #     # Font.Larger is available since wyPython version 2.9.1
        #     # PsychoPy still supports 2.8 (see ensureMinimal above)
        #     self._mainFont = self._mainFont.Larger()
        #     self._codeFont.SetPointSize(
        #         self._mainFont.GetPointSize())  # unify font size

        # create both frame for coder/builder as necess
        if splash:
            splash.SetText(_translate("  Creating frames..."))
        if mainFrame in ['both', 'coder']:
            self.showCoder(fileList=scripts)
        if mainFrame in ['both', 'builder']:
            self.showBuilder(fileList=exps)

        # send anonymous info to www.psychopy.org/usage.php
        # please don't disable this, it's important for PsychoPy's development
        self._latestAvailableVersion = None
        self.updater = None
        prefsConn = self.prefs.connections
        if prefsConn['checkForUpdates'] or prefsConn['allowUsageStats']:
            connectThread = threading.Thread(
                target=connections.makeConnections, args=(self, ))
            connectThread.start()
        # query github in the background to populate a local cache about
        # what versions are available for download:
        from psychopy.tools import versionchooser as vc
        versionsThread = threading.Thread(target=vc._remoteVersions,
                                          args=(True, ))
        versionsThread.start()

        try:
            import imageio
            haveImageio = True
        except ImportError:
            haveImageio = False

        if haveImageio:
            # Use pre-installed ffmpeg if available.
            # Otherwise, download ffmpeg binary.
            try:
                imageio.plugins.ffmpeg.get_exe()
            except imageio.core.NeedDownloadError:
                ffmpegDownloader = threading.Thread(
                    target=imageio.plugins.ffmpeg.download)
                ffmpegDownloader.start()

        ok, msg = checkCompatibility(last, self.version, self.prefs, fix=True)
        # tell the user what has changed
        if not ok and not self.firstRun and not self.testMode:
            title = _translate("Compatibility information")
            dlg = dialogs.MessageDialog(parent=None,
                                        message=msg,
                                        type='Info',
                                        title=title)
            dlg.ShowModal()

        if self.prefs.app['showStartupTips'] and not self.testMode:
            tipFile = os.path.join(self.prefs.paths['resources'],
                                   _translate("tips.txt"))
            tipIndex = self.prefs.appData['tipIndex']
            if parse_version(wx.__version__) >= parse_version('4.0.0a1'):
                tp = wx.adv.CreateFileTipProvider(tipFile, tipIndex)
                showTip = wx.adv.ShowTip(None, tp)
            else:
                tp = wx.CreateFileTipProvider(tipFile, tipIndex)
                showTip = wx.ShowTip(None, tp)

            self.prefs.appData['tipIndex'] = tp.GetCurrentTip()
            self.prefs.saveAppData()
            self.prefs.app['showStartupTips'] = showTip
            self.prefs.saveUserPrefs()

        if self.prefs.connections['checkForUpdates']:
            self.Bind(wx.EVT_IDLE, self.checkUpdates)
        else:
            self.Bind(wx.EVT_IDLE, self.onIdle)

        # doing this once subsequently enables the app to open & switch among
        # wx-windows on some platforms (Mac 10.9.4) with wx-3.0:
        v = parse_version
        if sys.platform == 'darwin':
            if v('3.0') <= v(wx.version()) < v('4.0'):
                _Showgui_Hack()  # returns ~immediately, no display
                # focus stays in never-land, so bring back to the app:
                if mainFrame in ['both', 'builder']:
                    self.showBuilder()
                else:
                    self.showCoder()
        # after all windows are created (so errors flushed) create output
        self._appLoaded = True
        if self.coder:
            self.coder.setOutputWindow()  # takes control of sys.stdout
        return True
Exemple #17
0
    def onInit(self, showSplash=True, testMode=False):
        """This is launched immediately *after* the app initialises with wx
        :Parameters:

          testMode: bool
        """
        self.SetAppName('PsychoPy3')
        if showSplash:  #showSplash:
            # show splash screen
            splashFile = os.path.join(self.prefs.paths['resources'],
                                      'psychopySplash.png')
            splashImage = wx.Image(name=splashFile)
            splashImage.ConvertAlphaToMask()
            splash = AS.AdvancedSplash(
                None,
                bitmap=splashImage.ConvertToBitmap(),
                timeout=3000,
                agwStyle=AS.AS_TIMEOUT | AS.AS_CENTER_ON_SCREEN,
            )  # transparency?
            w, h = splashImage.GetSize()
            splash.SetTextPosition((int(340), h - 30))
            splash.SetText(
                _translate("Copyright (C) 2021 OpenScienceTools.org"))
        else:
            splash = None

        # SLOW IMPORTS - these need to be imported after splash screen starts
        # but then that they end up being local so keep track in self

        from psychopy.compatibility import checkCompatibility
        # import coder and builder here but only use them later
        from psychopy.app import coder, builder, runner, dialogs

        if '--firstrun' in sys.argv:
            del sys.argv[sys.argv.index('--firstrun')]
            self.firstRun = True
        if 'lastVersion' not in self.prefs.appData:
            # must be before 1.74.00
            last = self.prefs.appData['lastVersion'] = '1.73.04'
            self.firstRun = True
        else:
            last = self.prefs.appData['lastVersion']

        if self.firstRun and not self.testMode:
            pass

        # setup links for URLs
        # on a mac, don't exit when the last frame is deleted, just show menu
        if sys.platform == 'darwin':
            self.menuFrame = MenuFrame(parent=None, app=self)
        # fetch prev files if that's the preference
        if self.prefs.coder['reloadPrevFiles']:
            scripts = self.prefs.appData['coder']['prevFiles']
        else:
            scripts = []
        appKeys = list(self.prefs.appData['builder'].keys())
        if self.prefs.builder['reloadPrevExp'] and ('prevFiles' in appKeys):
            exps = self.prefs.appData['builder']['prevFiles']
        else:
            exps = []
        runlist = []

        self.dpi = int(wx.GetDisplaySize()[0] /
                       float(wx.GetDisplaySizeMM()[0]) * 25.4)
        # detect retina displays
        self.isRetina = self.dpi > 80 and wx.Platform == '__WXMAC__'
        if self.isRetina:
            fontScale = 1.2  # fonts are looking tiny on macos (only retina?) right now
        else:
            fontScale = 1
        # adjust dpi to something reasonable
        if not (50 < self.dpi < 120):
            self.dpi = 80  # dpi was unreasonable, make one up

        # Manage fonts
        if sys.platform == 'win32':
            # wx.SYS_DEFAULT_GUI_FONT is default GUI font in Win32
            self._mainFont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
        else:
            self._mainFont = wx.SystemSettings.GetFont(wx.SYS_ANSI_FIXED_FONT)
            # rescale for tiny retina fonts

        if hasattr(wx.Font, "AddPrivateFont") and sys.platform != "darwin":
            # Load packaged fonts if possible
            for fontFile in (Path(__file__).parent / "Resources" /
                             "fonts").glob("*"):
                if fontFile.suffix in ['.ttf', '.truetype']:
                    wx.Font.AddPrivateFont(str(fontFile))
            # Set fonts as those loaded
            self._codeFont = wx.Font(
                wx.FontInfo(
                    self._mainFont.GetPointSize()).FaceName("JetBrains Mono"))
        else:
            # Get system defaults if can't load fonts
            try:
                self._codeFont = wx.SystemSettings.GetFont(
                    wx.SYS_ANSI_FIXED_FONT)
            except wx._core.wxAssertionError:
                # if no SYS_ANSI_FIXED_FONT then try generic FONTFAMILY_MODERN
                self._codeFont = wx.Font(self._mainFont.GetPointSize(),
                                         wx.FONTFAMILY_TELETYPE,
                                         wx.FONTSTYLE_NORMAL,
                                         wx.FONTWEIGHT_NORMAL)

        if self.isRetina:
            self._codeFont.SetPointSize(
                int(self._codeFont.GetPointSize() * fontScale))
            self._mainFont.SetPointSize(
                int(self._mainFont.GetPointSize() * fontScale))

        # that gets most of the properties of _codeFont but the FaceName
        # FaceName is set in the setting of the theme:
        self.theme = self.prefs.app['theme']

        # removed Aug 2017: on newer versions of wx (at least on mac)
        # this looks too big
        # if hasattr(self._mainFont, 'Larger'):
        #     # Font.Larger is available since wyPython version 2.9.1
        #     # PsychoPy still supports 2.8 (see ensureMinimal above)
        #     self._mainFont = self._mainFont.Larger()
        #     self._codeFont.SetPointSize(
        #         self._mainFont.GetPointSize())  # unify font size

        # create both frame for coder/builder as necess
        if splash:
            splash.SetText(_translate("  Creating frames..."))

        # Parse incoming call
        parser = argparse.ArgumentParser(prog=self)
        parser.add_argument('--builder', dest='builder', action="store_true")
        parser.add_argument('-b', dest='builder', action="store_true")
        parser.add_argument('--coder', dest='coder', action="store_true")
        parser.add_argument('-c', dest='coder', action="store_true")
        parser.add_argument('--runner', dest='runner', action="store_true")
        parser.add_argument('-r', dest='runner', action="store_true")
        parser.add_argument('-x', dest='direct', action='store_true')
        view, args = parser.parse_known_args(sys.argv)
        # Check from filetype if any windows need to be open
        if any(arg.endswith('.psyexp') for arg in args):
            view.builder = True
            exps = [file for file in args if file.endswith('.psyexp')]
        if any(arg.endswith('.psyrun') for arg in args):
            view.runner = True
            runlist = [file for file in args if file.endswith('.psyrun')]
        # If still no window specified, use default from prefs
        if not any(
                getattr(view, key) for key in ['builder', 'coder', 'runner']):
            if self.prefs.app['defaultView'] in view:
                setattr(view, self.prefs.app['defaultView'], True)
            elif self.prefs.app['defaultView'] == 'all':
                view.builder = True
                view.coder = True
                view.runner = True

        # set the dispatcher for standard output
        self.stdStreamDispatcher = console.StdStreamDispatcher(self)
        self.stdStreamDispatcher.redirect()

        # Create windows
        if view.runner:
            self.showRunner(fileList=runlist)
        if view.coder:
            self.showCoder(fileList=scripts)
        if view.builder:
            self.showBuilder(fileList=exps)
        if view.direct:
            self.showRunner()
            for exp in [
                    file for file in args
                    if file.endswith('.psyexp') or file.endswith('.py')
            ]:
                self.runner.panel.runFile(exp)

        # send anonymous info to www.psychopy.org/usage.php
        # please don't disable this, it's important for PsychoPy's development
        self._latestAvailableVersion = None
        self.updater = None
        self.news = None
        self.tasks = None

        prefsConn = self.prefs.connections

        ok, msg = checkCompatibility(last, self.version, self.prefs, fix=True)
        # tell the user what has changed
        if not ok and not self.firstRun and not self.testMode:
            title = _translate("Compatibility information")
            dlg = dialogs.MessageDialog(parent=None,
                                        message=msg,
                                        type='Info',
                                        title=title)
            dlg.ShowModal()

        if (self.prefs.app['showStartupTips'] and not self.testMode
                and not blockTips):
            tipFile = os.path.join(self.prefs.paths['resources'],
                                   _translate("tips.txt"))
            tipIndex = self.prefs.appData['tipIndex']
            if parse_version(wx.__version__) >= parse_version('4.0.0a1'):
                tp = wx.adv.CreateFileTipProvider(tipFile, tipIndex)
                showTip = wx.adv.ShowTip(None, tp)
            else:
                tp = wx.CreateFileTipProvider(tipFile, tipIndex)
                showTip = wx.ShowTip(None, tp)

            self.prefs.appData['tipIndex'] = tp.GetCurrentTip()
            self.prefs.saveAppData()
            self.prefs.app['showStartupTips'] = showTip
            self.prefs.saveUserPrefs()

        self.Bind(wx.EVT_IDLE, self.onIdle)

        # doing this once subsequently enables the app to open & switch among
        # wx-windows on some platforms (Mac 10.9.4) with wx-3.0:
        v = parse_version
        if sys.platform == 'darwin':
            if v('3.0') <= v(wx.version()) < v('4.0'):
                _Showgui_Hack()  # returns ~immediately, no display
                # focus stays in never-land, so bring back to the app:
                if prefs.app['defaultView'] in [
                        'all', 'builder', 'coder', 'runner'
                ]:
                    self.showBuilder()
                else:
                    self.showCoder()
        # after all windows are created (so errors flushed) create output
        self._appLoaded = True
        if self.coder:
            self.coder.setOutputWindow()  # takes control of sys.stdout

        # flush any errors to the last run log file
        logging.flush()
        sys.stdout.flush()
        # we wanted debug mode while loading but safe to go back to info mode
        if not self.prefs.app['debugMode']:
            logging.console.setLevel(logging.INFO)

        return True
Exemple #18
0
    def onInit(self, showSplash=True, testMode=False):
        """
        :Parameters:

          testMode: bool
            If set to True then startup wizard won't appear and stdout/stderr
            won't be redirected to the Coder
        """
        self.version=psychopy.__version__
        self.SetAppName('PsychoPy2')
        #set default paths and prefs
        self.prefs = psychopy.prefs
        if self.prefs.app['debugMode']:
            logging.console.setLevel(logging.DEBUG)
        self.testMode = testMode #indicates whether we're running for testing purposes

        if showSplash:
            #show splash screen
            splashFile = os.path.join(self.prefs.paths['resources'], 'psychopySplash.png')
            splashBitmap = wx.Image(name = splashFile).ConvertToBitmap()
            splash = AS.AdvancedSplash(None, bitmap=splashBitmap, timeout=3000, style=AS.AS_TIMEOUT|wx.FRAME_SHAPED,
                                      shadowcolour=wx.RED)#could use this in future for transparency
            splash.SetTextPosition((10,240))
            splash.SetText("  Loading libraries...")
        else:
            splash=None

        #LONG IMPORTS - these need to be imported after splash screen starts (they're slow)
        #but then that they end up being local so keep track in self
        if splash: splash.SetText("  Loading PsychoPy2...")
        from psychopy import compatibility
        from psychopy.app import coder, builder, dialogs, wxIDs, urls #import coder and builder here but only use them later
        self.keys = self.prefs.keys
        self.prefs.pageCurrent = 0  # track last-viewed page of prefs, to return there
        self.IDs=wxIDs
        self.urls=urls.urls
        self.quitting=False
        #check compatibility with last run version (before opening windows)
        self.firstRun = False

        if '--firstrun' in sys.argv:
            del sys.argv[sys.argv.index('--firstrun')]
            self.firstRun = True
        if 'lastVersion' not in self.prefs.appData.keys():
            last=self.prefs.appData['lastVersion']='1.73.04'#must be before 1.74.00
            self.firstRun = True
        else:
            last=self.prefs.appData['lastVersion']

        if self.firstRun and not self.testMode:
            self.firstrunWizard()

        #setup links for URLs
        #on a mac, don't exit when the last frame is deleted, just show a menu
        if sys.platform=='darwin':
            self.menuFrame=MenuFrame(parent=None, app=self)
        #get preferred view(s) from prefs and previous view
        if self.prefs.app['defaultView']=='last':
            mainFrame = self.prefs.appData['lastFrame']
        else:
            # configobjValidate should take care of this situation (?), but doesn't:
            if self.prefs.app['defaultView'] in ['last', 'coder', 'builder', 'both']:
                mainFrame = self.prefs.app['defaultView']
            else:
                self.prefs.app['defaultView'] = 'both'
                mainFrame = 'both'
        #fetch prev files if that's the preference
        if self.prefs.coder['reloadPrevFiles']:
            scripts=self.prefs.appData['coder']['prevFiles']
        else: scripts=[]
        if self.prefs.builder['reloadPrevExp'] and ('prevFiles' in self.prefs.appData['builder'].keys()):
            exps=self.prefs.appData['builder']['prevFiles']
        else:
            exps=[]
        #then override the prev files by command options and passed files
        if len(sys.argv)>1:
            if sys.argv[1]==__name__:
                args = sys.argv[2:] # program was executed as "python.exe PsychoPyIDE.py %1'
            else:
                args = sys.argv[1:] # program was executed as "PsychoPyIDE.py %1'
            #choose which frame to start with
            if args[0] in ['builder', '--builder', '-b']:
                    mainFrame='builder'
                    args = args[1:]#can remove that argument
            elif args[0] in ['coder','--coder', '-c']:
                    mainFrame='coder'
                    args = args[1:]#can remove that argument
            #did we get .py or .psyexp files?
            elif args[0][-7:]=='.psyexp':
                    mainFrame='builder'
                    exps=[args[0]]
            elif args[0][-3:]=='.py':
                    mainFrame='coder'
                    scripts=[args[0]]
        else:
            args=[]

        self.dpi = int(wx.GetDisplaySize()[0]/float(wx.GetDisplaySizeMM()[0])*25.4)
        if not (50<self.dpi<120): self.dpi=80#dpi was unreasonable, make one up

        #create both frame for coder/builder as necess
        if splash: splash.SetText("  Creating frames...")
        self.coder = None
        self.builderFrames = []
        self.copiedRoutine=None
        self.allFrames=[]#these are ordered and the order is updated with self.onNewTopWindow
        if mainFrame in ['both', 'coder']:
            self.showCoder(fileList=scripts)
        if mainFrame in ['both', 'builder']:
            self.showBuilder(fileList=exps)

        #send anonymous info to www.psychopy.org/usage.php
        #please don't disable this - it's important for PsychoPy's development
        self._latestAvailableVersion=None
        self.updater=None
        if self.prefs.connections['checkForUpdates'] or self.prefs.connections['allowUsageStats']:
            connectThread = threading.Thread(target=connections.makeConnections, args=(self,))
            connectThread.start()

        ok, msg = compatibility.checkCompatibility(last, self.version, self.prefs, fix=True)
        if not ok and not self.firstRun and not self.testMode:  #tell the user what has changed
            dlg = dialogs.MessageDialog(parent=None,message=msg,type='Info', title="Compatibility information")
            dlg.ShowModal()

        if self.prefs.app['showStartupTips'] and not self.testMode:
            tipIndex = self.prefs.appData['tipIndex']
            tp = wx.CreateFileTipProvider(os.path.join(self.prefs.paths['resources'],"tips.txt"), tipIndex)
            showTip = wx.ShowTip(None, tp)
            self.prefs.appData['tipIndex'] = tp.GetCurrentTip()
            self.prefs.saveAppData()
            self.prefs.app['showStartupTips'] = showTip
            self.prefs.saveUserPrefs()

        if self.prefs.connections['checkForUpdates']:
            self.Bind(wx.EVT_IDLE, self.checkUpdates)
        else:
            self.Bind(wx.EVT_IDLE, self.onIdle)
        return True