Example #1
0
    def setcurfile(self,appname):
        """Set the current application or script.

        appname is either an application module name or a script file.
        """
        is_app = not utils.is_script(appname)
        if is_app:
            # application
            label = 'App:'
            name = appname
            import apps
            app = apps.load(appname)
            if app is None:
                self.canPlay = False
                try:
                    self.canEdit = os.path.exists(apps.findAppSource(appname))
                except:
                    self.canEdit = False
            else:
                self.canPlay = hasattr(app,'run')
                self.canEdit = os.path.exists(apps.findAppSource(app))
        else:
            # script file
            label = 'Script:'
            name = os.path.basename(appname)
            self.canPlay = self.canEdit = utils.is_pyFormex(appname) or appname.endswith('.pye')

        pf.prefcfg['curfile'] = appname
        #self.curfile.label.setText(label)
        self.curfile.setText(label,0)
        self.curfile.setText(name,1)
        self.enableButtons(self.actions,['Play','Info'],self.canPlay)
        self.enableButtons(self.actions,['Edit'],self.canEdit)
        self.enableButtons(self.actions,['ReRun'],is_app and(self.canEdit or self.canPlay))
        self.enableButtons(self.actions,['Step','Continue'],False)
        icon = 'ok' if self.canPlay else 'notok'
        self.curfile.setIcon(QtGui.QIcon(QtGui.QPixmap(os.path.join(pf.cfg['icondir'],icon)+pf.cfg['gui/icontype'])),1)
Example #2
0
    def add(self, name, icon=None, text=None):
        """Add a new name to the actions list and create a matching DAction.

        If the actions list has an associated menu or toolbar,
        a matching button will be inserted in each of these.
        If an icon is specified, it will be used on the menu and toolbar.
        The icon is either a filename or a QIcon object.
        If text is specified, it is displayed instead of the action's name.
        """
        if type(icon) == str:
            if os.path.exists(icon):
                icon = QtGui.QIcon(QtGui.QPixmap(icon))
            else:
                raise RuntimeError, 'Icons not installed properly'
        if text is None:
            text = name
        a = DAction(text, icon, name)
        if self.function:
            a.signal.connect(self.function)
        self.actions.append([name, a])
        if self.menu:
            self.menu.addAction(a)
        if self.toolbar:
            self.toolbar.addAction(a)
Example #3
0
    def insertItems(self, items, before=None, debug=False):
        """Insert a list of items in the menu.

        Parameters:

        - `items`: a list of menuitem tuples. Each item is a tuple of two
          or three elements: (text, action, options):

          - `text`: the text that will be displayed in the menu item.
            It is stored in a normalized way: all lower case and with
            '&' removed.

          - `action`: can be any of the following:

            - a Python function or instance method : it will be called when the
              item is selected,
            - a string with the name of a function/method,
            - a list of Menu Items: a popup Menu will be created that will
              appear when the item is selected,
            - an existing Menu,
            - None : this will create a separator item with no action.

          - `options`: optional dictionary with following honoured fields:

            - `icon`: the name of an icon to be displayed with the item text.
              This name should be that of one of the icons in the pyFormex
              icondir.
            - `shortcut`: is an optional key combination to select the item.
            - `tooltip`: a text that is displayed as popup help.

        - `before`: if specified, should be the text *or* the action of one
          of the items in the Menu (not the items list!): the new list of
          items will be inserted before the specified item.
        """
        if debug:
            print("Inserting %s items in menu %s" % (len(items), self.title()))
        before = self.action(before)
        for item in items:
            txt, val = item[:2]
            if debug:
                print("INSERTING %s: %s" % (txt, val))
            if len(item) > 2:
                options = item[2]
            else:
                options = {}
            if val is None:
                a = self.insert_sep(before)
                self.separators[txt] = a
            elif isinstance(val, list):
                a = Menu(txt, parent=self, before=before)
                a.insertItems(val)
            elif isinstance(val, BaseMenu):
                #print("INSERTING MENU %s"%txt)
                self.insert_menu(val, before=before)
            else:
                if type(val) == str:
                    val = eval(val)
                if 'data' in options:
                    # DActions should be saved to keep them alive !!!
                    if debug:
                        print("INSERTING DAction %s" % txt)
                    a = DAction(txt, data=options['data'])
                    a.signal.connect(val)
                    self.insert_action(a, before)
                    # We need to store the DActions, or else they are
                    # destroyed. QActions are stroed by Qt
                    self._actions_.append(a)
                else:
                    if debug:
                        print("INSERTING QAction %s" % txt)
                    if before is not None:
                        raise RuntimeError, "I can not insert a QAction menu item before an existing one."
                    a = self.create_insert_action(txt, val, before)
                for k, v in options.items():
                    if k == 'icon':
                        a.setIcon(QtGui.QIcon(QtGui.QPixmap(
                            utils.findIcon(v))))
                    elif k == 'shortcut':
                        a.setShortcut(v)
                    elif k == 'tooltip':
                        a.setToolTip(v)
                    elif k == 'checkable':
                        a.setCheckable(v)
                    elif k == 'checked':
                        a.setCheckable(True)
                        a.setChecked(v)
                    elif k == 'disabled':
                        a.setDisabled(True)
Example #4
0
def startGUI(args):
    """Create the QT4 application and GUI.

    A (possibly empty) list of command line options should be provided.
    QT4 wil remove the recognized QT4 and X11 options.
    """
    # This seems to be the only way to make sure the numeric conversion is
    # always correct
    #
    QtCore.QLocale.setDefault(QtCore.QLocale.c())
    #
    #pf.options.debug = -1
    pf.debug("Arguments passed to the QApplication: %s" % args,pf.DEBUG.INFO)
    pf.app = Application(args)
    #
    pf.debug("Arguments left after constructing the QApplication: %s" % args,pf.DEBUG.INFO)
    pf.debug("Arguments left after constructing the QApplication: %s" % '\n'.join(pf.app.arguments()),pf.DEBUG.INFO)
    #pf.options.debug = 0
    # As far as I have been testing this, the args passed to the Qt application are
    # NOT acknowledged and neither are they removed!!


    pf.debug("Setting application attributes",pf.DEBUG.INFO)
    pf.app.setOrganizationName("pyformex.org")
    pf.app.setOrganizationDomain("pyformex.org")
    pf.app.setApplicationName("pyFormex")
    pf.app.setApplicationVersion(pf.__version__)
    ## pf.settings = QtCore.QSettings("pyformex.org", "pyFormex")
    ## pf.settings.setValue("testje","testvalue")

    # Quit application if last window closed
    pf.app.lastWindowClosed.connect(pf.app.quit)

    # Check if we have DRI
    pf.debug("Setting OpenGL format",pf.DEBUG.OPENGL)
    dri = hasDRI()

    # Check for existing pyFormex processes
    pf.debug("Checking for running pyFormex",pf.DEBUG.INFO)
    if pf.X11:
        windowname,running = findOldProcesses()
    else:
        windowname,running = "UNKOWN",[]
    pf.debug("%s,%s" % (windowname,running),pf.DEBUG.INFO)


    while len(running) > 0:
        if len(running) >= 16:
            print("Too many open pyFormex windows --- bailing out")
            return -1

        pids = [ i[2] for i in running if i[2] is not None ]
        warning = """..

pyFormex is already running on this screen
------------------------------------------
A main pyFormex window already exists on your screen.

If you really intended to start another instance of pyFormex, you
can just continue now.

The window might however be a leftover from a previously crashed pyFormex
session, in which case you might not even see the window anymore, nor be able
to shut down that running process. In that case, you would better bail out now
and try to fix the problem by killing the related process(es).

If you think you have already killed those processes, you may check it by
rerunning the tests.
"""
        actions = ['Really Continue','Rerun the tests','Bail out and fix the problem']
        if pids:
            warning += """

I have identified the process(es) by their PID as::

%s

If you trust me enough, you can also have me kill this processes for you.
""" % pids
            actions[2:2] = ['Kill the running processes']

        if dri:
            answer = draw.ask(warning,actions)
        else:
            warning += """
I have detected that the Direct Rendering Infrastructure
is not activated on your system. Continuing with a second
instance of pyFormex may crash your XWindow system.
You should seriously consider to bail out now!!!
"""
            answer = draw.warning(warning,actions)


        if answer == 'Really Continue':
            break # OK, Go ahead

        elif answer == 'Rerun the tests':
            windowname,running = findOldProcesses() # try again

        elif answer == 'Kill the running processes':
            killProcesses(pids)
            windowname,running = findOldProcesses() # try again

        else:
            return -1 # I'm out of here!


    # Load the splash image
    pf.debug("Loading the splash image",pf.DEBUG.GUI)
    splash = None
    if os.path.exists(pf.cfg['gui/splash']):
        pf.debug('Loading splash %s' % pf.cfg['gui/splash'],pf.DEBUG.GUI)
        splashimage = QtGui.QPixmap(pf.cfg['gui/splash'])
        splash = QtGui.QSplashScreen(splashimage)
        splash.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint|QtCore.Qt.SplashScreen)
        splash.setFont(QtGui.QFont("Helvetica",20))
        splash.showMessage(pf.Version,QtCore.Qt.AlignHCenter|QtCore.Qt.AlignTop,QtCore.Qt.red)
        splash.show()

    # create GUI, show it, run it

    pf.debug("Creating the GUI",pf.DEBUG.GUI)
    desktop = pf.app.desktop()
    pf.maxsize = Size(desktop.availableGeometry())
    size = pf.cfg.get('gui/size',(800,600))
    pos = pf.cfg.get('gui/pos',(0,0))
    bdsize = pf.cfg.get('gui/bdsize',(800,600))
    size = MinSize(size,pf.maxsize)

    # Create the GUI
    pf.GUI = Gui(windowname,
                 pf.cfg.get('gui/size',(800,600)),
                 pf.cfg.get('gui/pos',(0,0)),
                 pf.cfg.get('gui/bdsize',(800,600)),
                 )


    # set the appearance
    pf.debug("Setting Appearence",pf.DEBUG.GUI)
    pf.GUI.setAppearence()


    # setup the message board
    pf.board = pf.GUI.board
    pf.board.write("""%s   (C) Benedict Verhegghe

pyFormex comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under the conditions of the GNU General Public License, version 3 or later. See Help->License or the file COPYING for details.
""" % pf.fullVersion())

    # Set interaction functions


    def show_warning(message,category,filename,lineno,file=None,line=None):
        """Replace the default warnings.showwarning

        We display the warnings using our interactive warning widget.
        This feature can be turned off by setting
        cfg['warnings/popup'] = False
        """
        full_message = warnings.formatwarning(message,category,filename,lineno,line)
        pf.message(full_message)
        res,check = draw.showMessage(full_message,level='warning',check="Do not show this warning anymore in future sessions")
        if check[0]:
            utils.filterWarning(str(message))
            utils.saveWarningFilter(str(message))

    if pf.cfg['warnings/popup']:
        warnings.showwarning = show_warning


    pf.message = draw.message
    pf.warning = draw.warning
    pf.error = draw.error


    # setup the canvas
    pf.debug("Setting the canvas",pf.DEBUG.GUI)
    pf.GUI.processEvents()
    pf.GUI.viewports.changeLayout(1)
    pf.GUI.viewports.setCurrent(0)
    #pf.canvas = pf.GUI.viewports.current
    pf.canvas.setRenderMode(pf.cfg['draw/rendermode'])

    #
    # PYSIDE: raises (intercepted) exception on startup
    #
    draw.reset()

    # setup the status bar
    pf.debug("Setup status bar",pf.DEBUG.GUI)
    pf.GUI.addInputBox()
    pf.GUI.toggleInputBox(False)
    pf.GUI.addCoordsTracker()
    pf.GUI.toggleCoordsTracker(pf.cfg.get('gui/coordsbox',False))
    pf.debug("Using window name %s" % pf.GUI.windowTitle(),pf.DEBUG.GUI)

    # Script menu
    pf.GUI.scriptmenu = appMenu.createAppMenu(mode='script',parent=pf.GUI.menu,before='help')

    # App menu
    pf.GUI.appmenu = appMenu.createAppMenu(parent=pf.GUI.menu,before='help')


    # BV: removed, because they are in the script/app menus,
    # and the file menu is alredy very loaded

    ## # Link History Menus also in the File menu
    ## parent = pf.GUI.menu.item('file')
    ## before = parent.item('---1')
    ## if pf.GUI.apphistory:
    ##     parent.insert_menu(pf.GUI.apphistory,before)

    ## if pf.GUI.scripthistory:
    ##     parent.insert_menu(pf.GUI.scripthistory,before)

    # Create databases
    createDatabases()

    # Plugin menus
    import plugins
    filemenu = pf.GUI.menu.item('file')
    pf.gui.plugin_menu = plugins.create_plugin_menu(filemenu,before='---1')
    # Load configured plugins, ignore if not found
    plugins.loadConfiguredPlugins()

    # show current application/file
    appname = pf.cfg['curfile']
    pf.GUI.setcurfile(appname)

    # Last minute menu modifications can go here

    # cleanup
    pf.GUI.setBusy(False)         # HERE
    pf.GUI.addStatusBarButtons()

    if splash is not None:
        # remove the splash window
        splash.finish(pf.GUI)

    pf.GUI.setBusy(False)        # OR HERE

    pf.debug("Showing the GUI",pf.DEBUG.GUI)
    pf.GUI.show()

    # redirect standard output to board
    # TODO: this should disappear when we have buffered stdout
    # and moved this up into GUI init
    pf.GUI.board.redirect(pf.cfg['gui/redirect'])


    pf.GUI.update()

    if pf.cfg['gui/fortune']:
        sta,out = utils.runCommand(pf.cfg['fortune'])
        if sta == 0:
            draw.showInfo(out)

    #pf.app.setQuitOnLastWindowClosed(False)
    pf.app_started = True
    pf.GUI.processEvents()

    # load last project
    #
    #  TODO
    if pf.cfg['openlastproj']:
        fn = pf.cfg['curproj']
        if fn:
            try:
                proj = fileMenu.readProjectFile(fn)
                fileMenu.setProject(proj)
            except:
                # Avoid crashes from a faulty project file
                # TODO: should we push this up to fileMenu.readProjectFile ?
                #
                pf.message("Could not load the current project %s" % fn)
    #
    return 0