Example #1
0
 def node_icon(self, display_prefs):        
     del display_prefs # unused
     
     if self.all_content_is_hidden():    
         return imagename_to_pixmap( self.hide_iconPath)
     else:
         return imagename_to_pixmap( self.iconPath)        
 def get_icon(self, hidden):
     from utilities.icon_utilities import imagename_to_pixmap
     if hidden:
         return imagename_to_pixmap( self._hide_icon_name)
     else:
         return imagename_to_pixmap( self._icon_name)
     pass
    def node_icon(self, display_prefs):
        del display_prefs  # unused

        if self.all_content_is_hidden():
            return imagename_to_pixmap(self.hide_iconPath)
        else:
            return imagename_to_pixmap(self.iconPath)
 def update_icon(self, print_missing_file=False, found=None):
     """
     Update our icon according to whether our file exists or not (or use the boolean passed as found, if one is passed).
     (Exception: icon looks normal if filename is not set yet.
      Otherwise it looks normal if file is there, not normal if file is missing.)
     If print_missing_file is true, print an error message if the filename is non-null but the file doesn't exist.
     Return "not found" in case callers want to print their own error messages (for example, if they use a different filename).
     """
     #bruce 060620 split this out of readmmp_info_povrayscene_setitem for later use in copy_fixup_at_end (not yet done ###@@@).
     # But its dual function is a mess (some callers use their own filename) so it needs more cleanup. #e
     filename = self.povrayscene_file
     if found is None:
         found = not filename or os.path.exists(filename)
     # otherwise found should have been passed as True or False
     if found:
         self.const_pixmap = imagename_to_pixmap(
             "modeltree/povrayscene.png")
     else:
         self.const_pixmap = imagename_to_pixmap(
             "modeltree/povrayscene-notfound.png")
         if print_missing_file:
             msg = redmsg(
                 "POV-Ray Scene file [" + filename + "] does not exist."
             )  #e some callers would prefer orangemsg, cmd, etc.
             env.history.message(msg)
     return not found
 def get_icon(self, hidden):
     from utilities.icon_utilities import imagename_to_pixmap
     if hidden:
         return imagename_to_pixmap( self._hide_icon_name)
     else:
         return imagename_to_pixmap( self._icon_name)
     pass
Example #6
0
 def node_icon(self, display_prefs):  
     # REVIEW: use common code for this method? [bruce 081217 comment]
     del display_prefs
     
     if self.all_content_is_hidden():    
         return imagename_to_pixmap( self.hide_iconPath)
     else:
         return imagename_to_pixmap( self.iconPath)
Example #7
0
    def node_icon(self, display_prefs):
        # REVIEW: use common code for this method? [bruce 081217 comment]
        del display_prefs

        if self.all_content_is_hidden():
            return imagename_to_pixmap(self.hide_iconPath)
        else:
            return imagename_to_pixmap(self.iconPath)
Example #8
0
    def node_icon(self, display_prefs):
        """
        Model Tree node icon for the dna group node
        @see: Group.all_content_is_hidden()
        """
        del display_prefs  # unused

        if self.all_content_is_hidden():
            return imagename_to_pixmap(self.hide_iconPath)
        else:
            return imagename_to_pixmap(self.iconPath)
Example #9
0
    def node_icon(self, display_prefs):
        """
        Model Tree node icon for the dna group node
        @see: Group.all_content_is_hidden() 
        """
        del display_prefs # unused

        if self.all_content_is_hidden():    
            return imagename_to_pixmap( self.hide_iconPath)
        else:
            return imagename_to_pixmap( self.iconPath)  
Example #10
0
 def node_icon(self, display_prefs):
     """
     Model Tree node icon for the Peptide group node
     @see: Group.all_content_is_hidden() 
     """        
     open = display_prefs.get('open', False)
     if open:
         if self.all_content_is_hidden():    
             return imagename_to_pixmap("modeltree/PeptideGroup-expanded-hide.png")
         else:
             return imagename_to_pixmap("modeltree/PeptideGroup-expanded.png")
     else:
         if self.all_content_is_hidden():    
             return imagename_to_pixmap("modeltree/PeptideGroup-collapsed-hide.png")
         else:
             return imagename_to_pixmap("modeltree/PeptideGroup-collapsed.png")
Example #11
0
 def node_icon(self, display_prefs):
     """
     Model Tree node icon for the nanotube group node
     @see: Group.all_content_is_hidden()
     """
     open = display_prefs.get('open', False)
     if open:
         if self.all_content_is_hidden():
             return imagename_to_pixmap("modeltree/NanotubeGroup-expanded-hide.png")
         else:
             return imagename_to_pixmap("modeltree/NanotubeGroup-expanded.png")
     else:
         if self.all_content_is_hidden():
             return imagename_to_pixmap("modeltree/NanotubeGroup-collapsed-hide.png")
         else:
             return imagename_to_pixmap("modeltree/NanotubeGroup-collapsed.png")
Example #12
0
    def __init__(self, assy, name, scale, pov, zoomFactor, wxyz):
        """
        @param pov: the inverse of the "center of view" in model coordinates
        @type pov: position vector (Numeric.array of 3 ints or floats, as made
                   by V(x,y,z))

        @param wxyz: orientation of view
        @type wxyz: a Quaternion (class VQT.Q), or a sequence of 4 floats
                    which can be passed to that class to make one, e.g.
                    Q(W, x, y, z) is the quaternion with axis vector x,y,z
                    and sin(theta/2) = W
        """
        self.const_pixmap = imagename_to_pixmap("modeltree/NamedView.png")
        if not name:
            name = gensym("%s" % self.sym, assy)
        Node.__init__(self, assy, name)
        self.scale = scale
        assert type(pov) is type(V(1, 0, 0))
        self.pov = V(pov[0], pov[1], pov[2])
        self.zoomFactor = zoomFactor
        self.quat = Q(wxyz)
            #bruce 050518/080303 comment: wxyz is passed as an array of 4 floats
            # (in same order as in mmp file's csys record), when parsing
            # csys mmp records, or with wxyz a quat in other places.
        return
Example #13
0
    def __init__(self, assy, name, scale, pov, zoomFactor, wxyz):
        """
        @param pov: the inverse of the "center of view" in model coordinates
        @type pov: position vector (Numeric.array of 3 ints or floats, as made
                   by V(x,y,z))

        @param wxyz: orientation of view
        @type wxyz: a Quaternion (class VQT.Q), or a sequence of 4 floats
                    which can be passed to that class to make one, e.g.
                    Q(W, x, y, z) is the quaternion with axis vector x,y,z
                    and sin(theta/2) = W
        """
        self.const_pixmap = imagename_to_pixmap("modeltree/NamedView.png")
        if not name:
            name = gensym("%s" % self.sym, assy)
        Node.__init__(self, assy, name)
        self.scale = scale
        assert type(pov) is type(V(1, 0, 0))
        self.pov = V(pov[0], pov[1], pov[2])
        self.zoomFactor = zoomFactor
        self.quat = Q(wxyz)
            #bruce 050518/080303 comment: wxyz is passed as an array of 4 floats
            # (in same order as in mmp file's csys record), when parsing
            # csys mmp records, or with wxyz a quat in other places.
        return
Example #14
0
 def __init__(self, assy, name, text=''):
     self.const_pixmap = imagename_to_pixmap("modeltree/comment.png")
     if not name:
         name = gensym("%s" % self.sym, assy)
     Node.__init__(self, assy, name)
     self.lines = [] # this makes set_text changed() test legal (result of test doesn't matter)
     self.set_text(text)
     return
Example #15
0
 def __init__(self, assy, name, text=''):
     self.const_pixmap = imagename_to_pixmap("modeltree/comment.png")
     if not name:
         name = gensym("%s" % self.sym, assy)
     Node.__init__(self, assy, name)
     self.lines = [] # this makes set_text changed() test legal (result of test doesn't matter)
     self.set_text(text)
     return
Example #16
0
 def imagename_to_pixmap(self, imagename): # KLUGE, see comment where dialog_env is set to self ###@@@ might work but untested ###@@@
     from utilities.icon_utilities import imagename_to_pixmap
     path = None
     for trydir in [self.plugin_dir, os.path.join(self.plugin_dir, "images")]:
         trypath = os.path.join( trydir, imagename )
         if os.path.isfile(trypath):
             # assume it's the one we want
             path = trypath
             break
     if not path:
         path = imagename # use relative name
     return imagename_to_pixmap(path)
Example #17
0
 def update_icon(self, print_missing_file = False, found = None):
     """
     Update our icon according to whether our file exists or not (or use the boolean passed as found, if one is passed).
     (Exception: icon looks normal if filename is not set yet.
      Otherwise it looks normal if file is there, not normal if file is missing.)
     If print_missing_file is true, print an error message if the filename is non-null but the file doesn't exist.
     Return "not found" in case callers want to print their own error messages (for example, if they use a different filename).
     """
     #bruce 060620 split this out of readmmp_info_povrayscene_setitem for later use in copy_fixup_at_end (not yet done ###@@@). 
     # But its dual function is a mess (some callers use their own filename) so it needs more cleanup. #e
     filename = self.povrayscene_file
     if found is None:
         found = not filename or os.path.exists(filename)
     # otherwise found should have been passed as True or False
     if found:
         self.const_pixmap = imagename_to_pixmap("modeltree/povrayscene.png")
     else:
         self.const_pixmap = imagename_to_pixmap("modeltree/povrayscene-notfound.png")
         if print_missing_file:
             msg = redmsg("POV-Ray Scene file [" + filename + "] does not exist.") #e some callers would prefer orangemsg, cmd, etc.
             env.history.message(msg)
     return not found
def _env_imagename_to_QIcon(imagename, _cache = {}): ### to be replaced with env.imagename_to_QIcon for global env or an arg env
    try:
        return _cache[imagename]
    except KeyError:
        pass

    ## pixmap_fname = imagename # stub
    from utilities.icon_utilities import imagename_to_pixmap
    pixmap = imagename_to_pixmap(imagename)
    pixmap_fname = pixmap # will this arg work too?

    res = QIcon()
    res.setPixmap(pixmap_fname, QIcon.Automatic)
    _cache[imagename] = res # memoize, and also keep permanent python reference
    return res
Example #19
0
def _env_imagename_to_QIcon(
    imagename,
    _cache={}
):  ### to be replaced with env.imagename_to_QIcon for global env or an arg env
    try:
        return _cache[imagename]
    except KeyError:
        pass

    ## pixmap_fname = imagename # stub
    from utilities.icon_utilities import imagename_to_pixmap
    pixmap = imagename_to_pixmap(imagename)
    pixmap_fname = pixmap  # will this arg work too?

    res = QIcon()
    res.setPixmap(pixmap_fname, QIcon.Automatic)
    _cache[
        imagename] = res  # memoize, and also keep permanent python reference
    return res
    def __init__(self, assy, name, params=None):
        #bruce 060620 removed name from params list, made that optional, made name a separate argument,
        # all to make this __init__ method compatible with that of other nodes (see above for one reason);
        # also revised this routine in other ways, e.g. to avoid redundant sets of self.assy and self.name
        # (which are set by Node.__init__).
        if not name:
            # [Note: this code might be superceded by code in Node.__init__ once nodename suffix numbers are revised.]
            # If this code is superceded, Node.__init__ must provide a way to verify that the filename (derived from the name)
            # doesn't exist, since this would be an invalid name. Mark 060702.
            name = generate_povrayscene_name(assy, self.sym, self.extension)

        self.const_pixmap = imagename_to_pixmap("modeltree/povrayscene.png")
        # note: this might be changed later; this value is not always correct; that may be a bug when this node is copied.
        # [bruce 060620 comment]

        Node.__init__(self, assy, name)
        if params:
            self.set_parameters(params)
        else:
            def_params = (assy.o.width, assy.o.height, 'png')
            self.set_parameters(def_params)

        return
Example #21
0
 def __init__(self, assy, name, params = None):
     #bruce 060620 removed name from params list, made that optional, made name a separate argument,
     # all to make this __init__ method compatible with that of other nodes (see above for one reason);
     # also revised this routine in other ways, e.g. to avoid redundant sets of self.assy and self.name
     # (which are set by Node.__init__).
     if not name: 
         # [Note: this code might be superceded by code in Node.__init__ once nodename suffix numbers are revised.]
         # If this code is superceded, Node.__init__ must provide a way to verify that the filename (derived from the name)
         # doesn't exist, since this would be an invalid name. Mark 060702.
         name = generate_povrayscene_name(assy, self.sym, self.extension)
         
     self.const_pixmap = imagename_to_pixmap("modeltree/povrayscene.png")
         # note: this might be changed later; this value is not always correct; that may be a bug when this node is copied.
         # [bruce 060620 comment]
         
     Node.__init__(self, assy, name)
     if params:
         self.set_parameters(params)
     else:
         def_params = (assy.o.width, assy.o.height, 'png')
         self.set_parameters(def_params)
     
     return
Example #22
0
def insert_command_into_menu(menu, menutext, command, options = (), position = -1, raw_command = False, undo_cmdname = None): 
    """
    [This was part of makemenu_helper in the Qt3 version; in Qt4 it's only
     used for the disabled case, presumably for some good reason but not one
     which has been documented. It's also used independently of makemenu_helper.]
    
    Insert a new item into menu (a QMenu), whose menutext, command, and options are as given,
    with undo_cmdname defaulting to menutext (used only if raw_command is false), 
    where options is a list or tuple in the same form as used in "menu_spec" lists
    such as are passed to makemenu_helper (which this function helps implement).
       The caller should have already translated/localized menutext if desired.
       If position is given, insert the new item at that position, otherwise at the end.
    Return the Qt menu item id of the new menu item.
    (I am not sure whether this remains valid if other items are inserted before it. ###k)
       If raw_command is False (default), this function will wrap command with standard logic for nE-1 menu commands
    (presently, wrap_callable_for_undo), and ensure that a python reference to the resulting callable is kept forever.
       If raw_command is True, this function will pass command unchanged into the menu,
    and the caller is responsible for retaining a Python reference to command.
       ###e This might need an argument for the path or function to be used to resolve icon filenames.
    """
    #bruce 060613 split this out of makemenu_helper.
    # Only called for len(options) > 0, though it presumably works
    # just as well for len 0 (try it sometime).
    import types
    from foundation.whatsthis_utilities import turn_featurenames_into_links, ENABLE_WHATSTHIS_LINKS
    if not raw_command:
        command = wrap_callable_for_undo(command, cmdname = undo_cmdname or menutext)
        import foundation.changes as changes
        changes.keep_forever(command)
            # see comments on similar code above about why this is bad in theory, but necessary and ok for now
    iconset = None
    for option in options:
        # some options have to be processed first
        # since they are only usable when the menu item is inserted. [bruce 050614]
        if type(option) is types.TupleType:
            if option[0] == 'iconset':
                # support iconset, pixmap, or pixmap filename [bruce 050614 new feature]
                iconset = option[1]
                if type(iconset) is types.StringType:
                    filename = iconset
                    from utilities.icon_utilities import imagename_to_pixmap
                    iconset = imagename_to_pixmap(filename)
                if isinstance(iconset, QPixmap):
                    # (this is true for imagename_to_pixmap retval)
                    iconset = QIcon(iconset)
    if iconset is not None:
        import foundation.changes as changes
        changes.keep_forever(iconset) #e memory leak; ought to make caller pass a place to keep it, or a unique id of what to keep
        #mitem_id = menu.insertItem( iconset, menutext, -1, position ) #bruce 050614, revised 060613 (added -1, position)
        mitem = menu.addAction( iconset, menutext ) #bruce 050614, revised 060613 (added -1, position)
            # Will this work with checkmark items? Yes, but it replaces the checkmark --
            # instead, the icon looks different for the checked item.
            # For the test case of gamess.png on Mac, the 'checked' item's icon
            # looked like a 3d-depressed button.
            # In the future we can tell the iconset what to display in each case
            # (see QIcon and/or QMenu docs, and helper funcs presently in debug_prefs.py.)
    else:
        # mitem_id = len(menu) -- mitem_id was previously an integer, indexing into the menu
        mitem = menu.addAction(menutext)
    for option in options:
        if option == 'checked':
            mitem.setChecked(True)
        elif option == 'unchecked': #bruce 050614 -- see what this does visually, if anything
            mitem.setChecked(False)
        elif option == 'disabled':
            mitem.setEnabled(False)
        elif type(option) is types.TupleType:
            if option[0] == 'whatsThis':
                text = option[1]
                if ENABLE_WHATSTHIS_LINKS:
                    text = turn_featurenames_into_links(text)
                mitem.setWhatsThis(text)
            elif option[0] == 'iconset':
                pass # this was processed above
            else:
                if debug_flags.atom_debug:
                    print "atom_debug: fyi: don't understand menu_spec option %r", (option,)
            pass
        elif option is None:
            pass # this is explicitly permitted and has no effect
        else:
            if debug_flags.atom_debug:
                print "atom_debug: fyi: don't understand menu_spec option %r", (option,)
        pass
        #e and something to use QMenuData.setShortcut
        #e and something to run whatever func you want on menu and mitem_id
    return mitem # from insert_command_into_menu
Example #23
0
def startup_script(main_globals):
    """
    This is the main startup script for NE1.
    It is intended to be run only once, and only by the code in main.py.
    When this function returns, the caller is intended to immediately exit
    normally.
       Parameter main_globals should be the value of globals() in __main__,
    which is needed in case .atom-debug-rc is executed, since it must be
    executed in that global namespace.
    """

    # Note: importing all of NE1's functionality can take a long time.
    # To the extent possible, we want that time to be spent after
    # something is visible to the user, but (mostly) before the main
    # window is shown to the user (since showing the main window implies
    # that NE1 is almost ready to go). So we display a splashscreen
    # before doing most imports and initializations, then set up most
    # of our data structures and UI commands (thus importing the code
    # needed to implement them), and then show the main window.
    # (Some experimental commands are initialized after that, so that
    # errors that occur then can't prevent the main window from becoming
    # visible.)

    # TODO: turn the sections of code below into named functions or methods,
    # and perhaps split before_most_imports and before_creating_app into
    # more named functions or methods. The biggest split should be between
    # functions that need to be careful to do very few or no imports,
    # and functions that are free to do any imports.

    # Windows machines spawn and remove the shell, so no info is normally
    # captured.  This is a first attempt to try to capture some of the console
    # prints that would normally be lost.  The default for this code is that
    # it's turned off, and should remain that way until it's improved.
    if NE1_Build_Constants.NE1_CONSOLE_REDIRECT and os.name == "nt":
        capture_console = False
        capture_file = ""
        # if it's not reporting as python is the executable
        if not sys.executable.upper().endswith("PYTHON.EXE") and \
           not sys.executable.upper().endswith("PYTHON"):
            try:
                capture_file = u"".join((sys.executable[:-4], "_console.log"))
                sys.stdout = open(capture_file, 'w')
                capture_console = True  # already trapped, don't try more.
            except:
                pass
        if not capture_console:
            # Haven't captured the console log yet.  Find the default user
            # path and try to capture there this happens if we can't write to
            # the normal log location, or if python.exe is the executable.
            tmpFilePath = os.path.normpath(os.path.expanduser("~/Nanorex/"))
            if not os.path.exists(tmpFilePath):  #If it doesn't exist
                try:
                    os.mkdir(tmpFilePath)  #Try making one
                    capture_console = True
                except:
                    pass
                    # we tried, but there's no easy way to capture the console
            if capture_console or os.path.isdir(tmpFilePath):
                try:  # We made the directory or it already existed, try
                    # creating the log file.
                    capture_file = os.path.normpath(u"".join((tmpFilePath, \
                                             "/NE1_console.log")))
                    sys.stdout = open(capture_file, 'w')
                    capture_console = True
                except:
                    print >> sys.__stderr__, \
                          "Failed to create any console log file."
                    capture_console = False
        if capture_console:
            # Next two lines are specifically printed to the original console
            print >> sys.__stdout__, "The console has been redirected into:"
            print >> sys.__stdout__, capture_file.encode("utf_8")
            print
            print "starting NanoEngineer-1 in [%s]," % os.getcwd(
            ), time.asctime()
            print "using Python: " + sys.version
            try:
                print "on path: " + sys.executable
            except:
                pass

    # print the version information including official release candidate if it
    # is not 0 (false)
    if NE1_Build_Constants.NE1_OFFICIAL_RELEASE_CANDIDATE:
        print "Version: NanoEngineer-1 v%s_RC%s" % \
              (NE1_Build_Constants.NE1_RELEASE_VERSION, \
               NE1_Build_Constants.NE1_OFFICIAL_RELEASE_CANDIDATE)
    else:
        print "Version: NanoEngineer-1 v%s" % \
              NE1_Build_Constants.NE1_RELEASE_VERSION

    # "Do things that should be done before most imports occur."

    startup_before_most_imports.before_most_imports(main_globals)

    from PyQt4.Qt import QApplication, QSplashScreen

    # "Do things that should be done before creating the application object."

    startup_before_most_imports.before_creating_app()
    ### TODO: this imports undo, env, debug, and it got moved earlier
    # in the startup process at some point. Those imports are probably not
    # too likely to pull in a lot of others, but if possible we should put up
    # the splash screen before doing most of them. Sometime try to figure out
    # how to do that. The point of this function is mostly to wrap every signal->slot
    # connection -- maybe it's sufficient to do that before creating the main
    # window rather than before creating the app? [bruce 071008 comment]

    # do some imports used for putting up splashscreen

    # (this must be done before any code that loads images from cad/src/ui)
    import utilities.icon_utilities as icon_utilities
    icon_utilities.initialize_icon_utilities()

    # Create the application object (an instance of QApplication).
    QApplication.setColorSpec(QApplication.CustomColor)
    #russ 080505: Make it global so it can be run under debugging below.
    global app
    app = QApplication(sys.argv)

    # Put up the splashscreen (if its image file can be found in cad/images).
    #
    # Note for developers:
    # If you don't want the splashscreen, just rename the splash image file.

    splash_pixmap = icon_utilities.imagename_to_pixmap("images/splash.png")
    # splash_pixmap will be null if the image file was not found
    if not splash_pixmap.isNull():
        splash = QSplashScreen(splash_pixmap)  # create the splashscreen
        splash.show()
        MINIMUM_SPLASH_TIME = 3.0
        # I intend to add a user pref for MINIMUM_SPLASH_TIME for A7. mark 060131.
        splash_start = time.time()
    else:
        print "note: splash.png was not found"

    # connect the lastWindowClosed signal

    from PyQt4.Qt import SIGNAL
    app.connect(app, SIGNAL("lastWindowClosed ()"), app.quit)

    # NOTE: At this point, it is ok to do arbitrary imports as needed,
    # except of experimental code.

    # import MWsemantics.

    # An old comment (I don't know if it's still true -- bruce 071008):
    # this might have side effects other than defining things.

    from ne1_ui.MWsemantics import MWsemantics

    # initialize modules and data structures

    from ne1_startup import startup_misc
    # do this here, not earlier, so it's free to do whatever toplevel imports it wants
    # [bruce 071008 change]

    startup_misc.call_module_init_functions()

    startup_misc.register_MMP_RecordParsers()
    # do this before reading any mmp files

    # create the single main window object

    foo = MWsemantics(
    )  # This does a lot of initialization (in MainWindow.__init__)

    import __main__
    __main__.foo = foo
    # developers often access the main window object using __main__.foo when debugging,
    # so this is explicitly supported

    # initialize CoNTubGenerator
    # TODO: move this into one of the other initialization functions
    #Disabling the following code that initializes the ConTub plugin
    #(in UI it is called Heterojunction.) The Heterojunction generator or
    #ConTubGenerator was never ported to Qt4 platform. The plugin generator
    #needs a code cleanup  -- ninad 2007-11-16
    ##import CoNTubGenerator
    ##CoNTubGenerator.initialize()

    # for developers: run a hook function that .atom-debug-rc might have defined
    # in this module's global namespace, for doing things *before* showing the
    # main window.

    try:
        # do this, if user asked us to by defining it in .atom-debug-rc
        func = atom_debug_pre_main_show
    except NameError:
        pass
    else:
        func()

    # Do other things that should be done just before showing the main window

    startup_misc.pre_main_show(
        foo)  # this sets foo's geometry, among other things

    foo._init_after_geometry_is_set()

    if not splash_pixmap.isNull():
        # If the MINIMUM_SPLASH_TIME duration has not expired, sleep for a moment.
        while time.time() - splash_start < MINIMUM_SPLASH_TIME:
            time.sleep(0.1)
        splash.finish(foo)  # Take away the splashscreen

    # show the main window

    foo.show()

    # for developers: run a hook function that .atom-debug-rc might have defined
    # in this module's global namespace, for doing things *after* showing the
    # main window.

    try:
        # do this, if user asked us to by defining it in .atom-debug-rc
        func = atom_debug_post_main_show
    except NameError:
        pass
    else:
        func()

    # do other things after showing the main window
    startup_misc.post_main_show(foo)

    # start psyco runtime optimizer (EXPERIMENTAL) --
    # for doc see http://psyco.sourceforge.net/
    #
    # Example: it speeds up code like this by 17 times:
    # (in my test, Intel Mac OS 10.4, Python 2.4.4)
    #   x = 17
    #   for i in range(10**7):
    #       x += i % 3 - 1
    #
    #  [bruce 080524]
    from utilities.debug_prefs import debug_pref, Choice_boolean_False
    if debug_pref("Use psyco runtime optimizer (next session)?",
                  Choice_boolean_False,
                  prefs_key=True):
        # Import Psyco if available
        try:
            import psyco
            ## psyco.full() -- insert dna takes a lot of time, then segfaults
            # after printing "inside this what's this";
            # plan: be more conservative about what it should optimize...
            # preferably bind specific functions using psyco.bind().
            # For now, just tell it to only optimize the most important ones.
            psyco.log()  # manual says: log file name looks like xxx.log-psyco
            # by default, where xxx is the name of the script you ran
            # (when I ran "python main.py" in cad/src, it wrote to main.log-psyco there)
            # (maybe we can pass our own pathname as an argument?)
            ## psyco.profile(0.2) # use profiling, optimize funcs that use
            # more than 20% of the time (not sure what that means exactly)
            # (seems safe, but from log file, i guess it doesn't do much)
            psyco.profile(0.05)  # "aggressive"
            print "using psyco"
            pass
        except ImportError:
            print "not using psyco"
            pass
        pass

    # Decide whether to do profiling, and if so, with which
    # profiling command and into what file. Set local variables
    # to record the decision, which are used later when running
    # the Qt event loop.

    # If the user's .atom-debug-rc specifies PROFILE_WITH_HOTSHOT = True,
    # use hotshot, otherwise fall back to vanilla Python profiler.
    # (Note: to work, it probably has to import this module
    #  and set this variable in this module's namespace.)
    try:
        PROFILE_WITH_HOTSHOT
    except NameError:
        PROFILE_WITH_HOTSHOT = False

    try:
        # user can set atom_debug_profile_filename to a filename in .atom-debug-rc,
        # to enable profiling into that file. For example:
        # % cd
        # % cat > .atom-debug-rc
        # atom_debug_profile_filename = '/tmp/profile-output'
        # ^D
        # ... then run NE1, and quit it
        # ... then in a python shell:
        # import pstats
        # p = pstats.Stats('<filename>')
        # p.strip_dirs().sort_stats('time').print_stats(100) # order by internal time (top 100 functions)
        # p.strip_dirs().sort_stats('cumulative').print_stats(100) # order by cumulative time
        atom_debug_profile_filename = main_globals.get(
            'atom_debug_profile_filename')
        if atom_debug_profile_filename:
            print("\nUser's .atom-debug-rc requests profiling into file %r" %
                  (atom_debug_profile_filename, ))
            if not type(atom_debug_profile_filename) in [
                    type("x"), type(u"x")
            ]:
                print "error: atom_debug_profile_filename must be a string"
                assert 0  # caught and ignored, turns off profiling
            if PROFILE_WITH_HOTSHOT:
                try:
                    import hotshot
                except:
                    print "error during 'import hotshot'"
                    raise  # caught and ignored, turns off profiling
            else:
                try:
                    import cProfile as py_Profile
                except ImportError:
                    print "Unable to import cProfile. Using profile module instead."
                    py_Profile = None
                if py_Profile is None:
                    try:
                        import profile as py_Profile
                    except:
                        print "error during 'import profile'"
                        raise  # caught and ignored, turns off profiling
    except:
        print "exception setting up profiling (hopefully reported above); running without profiling"
        atom_debug_profile_filename = None

    # Create a fake "current exception", to help with debugging
    # (in case it's shown inappropriately in a later traceback).
    # One time this is seen is if a developer inserts a call to print_compact_traceback
    # when no exception is being handled (instead of the intended print_compact_stack).
    try:
        assert 0, "if you see this exception in a traceback, it is from the" \
            " startup script called by main.py, not the code that printed the traceback"
    except:
        pass

    # Handle a mmp file passed to it via the command line.  The mmp file
    # must be the first argument (after the program name) found on the
    # command line.  All other arguments are currently ignored and only
    # one mmp file can be loaded from the command line.
    # old revision with --initial-file is at: svn rev 12759
    # Derrick 20080520
    if ((len(sys.argv) >= 2) and sys.argv[1].endswith(".mmp")):
        foo.fileOpen(sys.argv[1])

    # Do other post-startup, pre-event-loop, non-profiled things, if any
    # (such as run optional startup commands for debugging).
    startup_misc.just_before_event_loop()

    if os.environ.has_key('WINGDB_ACTIVE'):
        # Hack to burn some Python bytecode periodically so Wing's
        # debugger can remain responsive while free-running
        # [from http://wingware.com/doc/howtos/pyqt; added by bruce 081227]
        # Addendum [bruce 090107]: this timer doesn't noticeably slow down NE1,
        # but with or without it, NE1 is about 4x slower in Wing than running
        # alone, at least when running test_selection_redraw.py.
        print "running under Wing IDE debugger; setting up timer"
        from PyQt4 import QtCore
        timer = QtCore.QTimer()

        def donothing(*args):
            x = 0
            for i in range(0, 100):
                x += i

        timer.connect(timer, QtCore.SIGNAL("timeout()"), donothing)
        timer.start(200)

    # Finally, run the main Qt event loop --
    # perhaps with profiling, depending on local variables set above.
    # This does not normally return until the user asks NE1 to exit.

    # Note that there are three copies of the statement which runs that loop,
    # two inside string literals, all of which presumably should be the same.

    if atom_debug_profile_filename:
        if PROFILE_WITH_HOTSHOT:
            profile = hotshot.Profile(atom_debug_profile_filename)
            profile.run('app.exec_()')
        else:
            py_Profile.run(
                'from ne1_startup.main_startup import app; app.exec_()',
                atom_debug_profile_filename)
        print("\nProfile data was presumably saved into %r" %
              (atom_debug_profile_filename, ))
    else:
        # if you change this code, also change both string literals just above
        app.exec_()

    # Now return to the caller in order to do a normal immediate exit of NE1.

    return  # from startup_script
Example #24
0
    def __init__(self,
                 parent=None,
                 desc=None,
                 name=None,
                 modal=0,
                 fl=0,
                 env=None,
                 type="QDialog"):
        if env is None:
            import foundation.env as env  # this is a little weird... probably it'll be ok, and logically it seems correct.

        self.desc = desc

        self.typ = type
        if type == "QDialog":
            QDialog.__init__(self, parent, name, modal, fl)
        elif type == "QTextEdit":
            QTextEdit.__init__(self, parent, name)
        elif type == "QFrame":
            QFrame.__init__(self, parent, name)
        else:
            print "don't know about type == %r" % (type, )

        self.image1 = QPixmap()
        self.image1.loadFromData(image1_data,
                                 "PNG")  # should be: title_icon ####
        self.image3 = QPixmap()
        self.image3.loadFromData(image3_data, "PNG")
        self.image4 = QPixmap()
        self.image4.loadFromData(image4_data, "PNG")
        self.image5 = QPixmap()
        self.image5.loadFromData(image5_data, "PNG")
        self.image6 = QPixmap()
        self.image6.loadFromData(image6_data, "PNG")
        self.image7 = QPixmap()
        self.image7.loadFromData(image7_data, "PNG")
        self.image0 = QPixmap(image0_data)  # should be: border_icon ####
        self.image2 = QPixmap(image2_data)  # should be: sponsor_pixmap ####

        try:
            ####@@@@
            title_icon_name = self.desc.options.get('title_icon')
            border_icon_name = self.desc.options.get('border_icon')
            if title_icon_name:
                self.image1 = imagename_to_pixmap(
                    title_icon_name)  ###@@@ pass icon_path
                ###@@@ import imagename_to_pixmap or use env function
                # or let that func itself be an arg, or have an env arg for it
                ###e rename it icon_name_to_pixmap, or find_icon? (the latter only if it's ok if it returns an iconset)
                ###e use iconset instead?
            if border_icon_name:
                self.image0 = imagename_to_pixmap(border_icon_name)
        except:
            print_compact_traceback(
                "bug in icon-setting code, using fallback icons: ")
            pass

        if not name:
            self.setName("parameter_dialog_or_frame")  ###

        ###k guess this will need: if type == 'QDialog'
        self.setIcon(self.image0)  # should be: border_icon ####

        nanotube_dialogLayout = QVBoxLayout(self, 0, 0,
                                            "nanotube_dialogLayout")

        self.heading_frame = QFrame(self, "heading_frame")
        self.heading_frame.setPaletteBackgroundColor(QColor(122, 122, 122))
        self.heading_frame.setFrameShape(QFrame.NoFrame)
        self.heading_frame.setFrameShadow(QFrame.Plain)
        heading_frameLayout = QHBoxLayout(self.heading_frame, 0, 3,
                                          "heading_frameLayout")

        self.heading_pixmap = QLabel(self.heading_frame, "heading_pixmap")
        self.heading_pixmap.setSizePolicy(
            QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed, 0, 0,
                        self.heading_pixmap.sizePolicy().hasHeightForWidth()))
        self.heading_pixmap.setPixmap(
            self.image1)  # should be: title_icon ####
        self.heading_pixmap.setScaledContents(1)
        heading_frameLayout.addWidget(self.heading_pixmap)

        self.heading_label = QLabel(self.heading_frame, "heading_label")
        self.heading_label.setPaletteForegroundColor(QColor(255, 255, 255))
        heading_label_font = QFont(self.heading_label.font())
        heading_label_font.setPointSize(12)
        heading_label_font.setBold(1)
        self.heading_label.setFont(heading_label_font)
        heading_frameLayout.addWidget(self.heading_label)
        nanotube_dialogLayout.addWidget(self.heading_frame)

        self.body_frame = QFrame(self, "body_frame")
        self.body_frame.setFrameShape(QFrame.StyledPanel)
        self.body_frame.setFrameShadow(QFrame.Raised)
        body_frameLayout = QVBoxLayout(self.body_frame, 3, 3,
                                       "body_frameLayout")

        self.sponsor_frame = QFrame(self.body_frame, "sponsor_frame")
        self.sponsor_frame.setPaletteBackgroundColor(QColor(255, 255, 255))
        self.sponsor_frame.setFrameShape(QFrame.StyledPanel)
        self.sponsor_frame.setFrameShadow(QFrame.Raised)
        sponsor_frameLayout = QHBoxLayout(self.sponsor_frame, 0, 0,
                                          "sponsor_frameLayout")

        self.sponsor_btn = QPushButton(self.sponsor_frame, "sponsor_btn")
        self.sponsor_btn.setAutoDefault(0)  #bruce 060703 bugfix
        self.sponsor_btn.setSizePolicy(
            QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred, 0, 0,
                        self.sponsor_btn.sizePolicy().hasHeightForWidth()))
        self.sponsor_btn.setPaletteBackgroundColor(QColor(255, 255, 255))
        self.sponsor_btn.setPixmap(
            self.image2
        )  # should be: sponsor_pixmap #### [also we'll need to support >1 sponsor]
        self.sponsor_btn.setFlat(1)
        sponsor_frameLayout.addWidget(self.sponsor_btn)
        body_frameLayout.addWidget(self.sponsor_frame)

        layout59 = QHBoxLayout(None, 0, 6, "layout59")
        left_spacer = QSpacerItem(20, 20, QSizePolicy.Expanding,
                                  QSizePolicy.Minimum)
        layout59.addItem(left_spacer)

        self.done_btn = QToolButton(self.body_frame, "done_btn")
        self.done_btn.setIcon(QIcon(self.image3))
        layout59.addWidget(self.done_btn)

        self.abort_btn = QToolButton(self.body_frame, "abort_btn")
        self.abort_btn.setIcon(QIcon(self.image4))
        layout59.addWidget(self.abort_btn)

        self.preview_btn = QToolButton(self.body_frame, "preview_btn")
        self.preview_btn.setIcon(QIcon(self.image5))
        layout59.addWidget(self.preview_btn)

        self.whatsthis_btn = QToolButton(self.body_frame, "whatsthis_btn")
        self.whatsthis_btn.setIcon(QIcon(self.image6))
        layout59.addWidget(self.whatsthis_btn)
        right_spacer = QSpacerItem(20, 20, QSizePolicy.Expanding,
                                   QSizePolicy.Minimum)
        layout59.addItem(right_spacer)
        body_frameLayout.addLayout(layout59)

        self.groups = []
        self.param_getters = {
        }  # map from param name to get-function (which gets current value out of its widget or controller)

        for group_desc in self.desc.kids('group'):

            # == start parameters_grpbox ### this will differ for Windows style

            header_refs = [
            ]  # keep python refcounted refs to all objects we make (at least the ones pyuic stored in self attrs)

            self.parameters_grpbox = QGroupBox(self.body_frame,
                                               "parameters_grpbox")
            self.parameters_grpbox.setFrameShape(QGroupBox.StyledPanel)
            self.parameters_grpbox.setFrameShadow(QGroupBox.Sunken)
            self.parameters_grpbox.setMargin(0)
            self.parameters_grpbox.setColumnLayout(0, Qt.Vertical)
            self.parameters_grpbox.layout().setSpacing(1)
            self.parameters_grpbox.layout().setMargin(4)
            parameters_grpboxLayout = QVBoxLayout(
                self.parameters_grpbox.layout())
            parameters_grpboxLayout.setAlignment(Qt.AlignTop)

            layout20 = QHBoxLayout(None, 0, 6, "layout20")

            self.nt_parameters_grpbtn = QPushButton(self.parameters_grpbox,
                                                    "nt_parameters_grpbtn")
            self.nt_parameters_grpbtn.setSizePolicy(
                QSizePolicy(
                    QSizePolicy.Minimum, QSizePolicy.Fixed, 0, 0,
                    self.nt_parameters_grpbtn.sizePolicy().hasHeightForWidth())
            )
            self.nt_parameters_grpbtn.setMaximumSize(QSize(16, 16))
            self.nt_parameters_grpbtn.setAutoDefault(0)
            self.nt_parameters_grpbtn.setIcon(QIcon(
                self.image7))  ### not always right, but doesn't matter
            self.nt_parameters_grpbtn.setFlat(1)
            layout20.addWidget(self.nt_parameters_grpbtn)

            self.parameters_grpbox_label = QLabel(self.parameters_grpbox,
                                                  "parameters_grpbox_label")
            self.parameters_grpbox_label.setSizePolicy(
                QSizePolicy(
                    QSizePolicy.Preferred, QSizePolicy.Minimum, 0, 0,
                    self.parameters_grpbox_label.sizePolicy().
                    hasHeightForWidth()))
            self.parameters_grpbox_label.setAlignment(QLabel.AlignVCenter)
            layout20.addWidget(self.parameters_grpbox_label)
            gbx_spacer1 = QSpacerItem(67, 16, QSizePolicy.Expanding,
                                      QSizePolicy.Minimum)
            layout20.addItem(gbx_spacer1)
            parameters_grpboxLayout.addLayout(layout20)

            nt_parameters_body_layout = QGridLayout(
                None, 1, 1, 0, 6, "nt_parameters_body_layout"
            )  ### what is 6 -- is it related to number of items???
            # is it 6 in all the ones we got, but that could be a designer error so i better look it up sometime.

            # == start its kids

            # will use from above: self.parameters_grpbox, nt_parameters_body_layout

            nextrow = 0  # which row of the QGridLayout to start filling next (loop variable)
            hidethese = [
            ]  # set of objects to hide or show, when this group is closed or opened

            for param in group_desc.kids('parameter'):
                # param (a group subobj desc) is always a parameter, but we already plan to extend this beyond that,
                # so we redundantly test for this here.
                getter = None
                paramname = None
                # set these for use by uniform code at the end (e.g. for tooltips)
                editfield = None
                label = None
                if param.isa('parameter'):
                    label = QLabel(self.parameters_grpbox, "members_label")
                    label.setAlignment(QLabel.AlignVCenter | QLabel.AlignRight)
                    nt_parameters_body_layout.addWidget(label, nextrow, 0)
                    hidethese.append(label)
                    thisrow = nextrow
                    nextrow += 1
                    #e following should be known in a place that knows the input language, not here
                    paramname = param.options.get('name') or (
                        param.args and param.args[0]) or "?"
                    paramlabel = param.options.get(
                        'label'
                    ) or paramname  ##e wrong, label "" or none ought to be possible
                    # QtGui.QApplication.translate(self.__class__.__name__, "xyz")
                    label.setText(
                        QtGui.QApplication.translate(self.__class__.__name__,
                                                     paramlabel))

                if param.isa('parameter',
                             widget='combobox',
                             type=('str', None)):
                    self.members_combox = QComboBox(
                        0, self.parameters_grpbox,
                        "members_combox")  ###k  what's 0?
                    editfield = self.members_combox
                    #### it probably needs a handler class, and then that could do this setup
                    self.members_combox.clear()
                    default = param.options.get(
                        'default', None)  # None is not equal to any string
                    thewidgetkid = param.kids(
                        'widget'
                    )[-1]  # kluge; need to think what the desc method for this should be
                    for item in thewidgetkid.kids('item'):
                        itemval = item.args[0]
                        itemtext = itemval
                        self.members_combox.insertItem(
                            QtGui.QApplication.translate(
                                self.__class__.__name__,
                                itemtext))  #k __tr ok??
                        if itemval == default:  #k or itemtext?
                            pass  ##k i find no setItem in our py code, so not sure yet what to do for this.
                    nt_parameters_body_layout.addWidget(
                        self.members_combox, thisrow, 1)
                    hidethese.append(self.members_combox)
                    getter = (lambda combobox=self.members_combox: str(
                        combobox.currentText()))
                    ##e due to __tr or non-str values, it might be better to use currentIndex and look it up in a table
                    # (though whether __tr is good here might depend on what it's used for)

                elif param.isa('parameter',
                               widget=('lineedit', None),
                               type=('str', None)):
                    # this covers explicit str|lineedit, and 3 default cases str, lineedit, neither.
                    # (i.e. if you say parameter and nothing else, it's str lineedit by default.)
                    self.length_linedit = QLineEdit(self.parameters_grpbox,
                                                    "length_linedit")
                    editfield = self.length_linedit
                    nt_parameters_body_layout.addWidget(
                        self.length_linedit, thisrow, 1)
                    hidethese.append(self.length_linedit)
                    default = str(param.options.get('default', ""))
                    self.length_linedit.setText(
                        QtGui.QApplication.translate(self.__class__.__name__,
                                                     default))  # __tr ok?
                    getter = (lambda lineedit=self.length_linedit: str(
                        lineedit.text()))

                elif param.isa('parameter',
                               widget=('lineedit', None),
                               type='float'):
                    self.length_linedit = QLineEdit(self.parameters_grpbox,
                                                    "length_linedit")
                    editfield = self.length_linedit
                    nt_parameters_body_layout.addWidget(
                        self.length_linedit, thisrow, 1)
                    hidethese.append(self.length_linedit)
                    controller = FloatLineeditController_Qt(
                        self, param, self.length_linedit)
                    header_refs.append(controller)
                    getter = controller.get_value

                elif param.isa('parameter', widget = ('spinbox', None), type = 'int') or \
                     param.isa('parameter', widget = ('spinbox'), type = None):
                    self.chirality_N_spinbox = QSpinBox(
                        self.parameters_grpbox, "chirality_N_spinbox"
                    )  # was chirality_m_spinbox, now chirality_N_spinbox
                    editfield = self.chirality_N_spinbox
                    ### seems like Qt defaults for min and max are 0,100 -- way too small a range!
                    if param.options.has_key('min') or 1:
                        self.chirality_N_spinbox.setMinimum(
                            param.options.get('min', -999999999))  # was 0
                    if param.options.has_key('max') or 1:
                        self.chirality_N_spinbox.setMaximum(
                            param.options.get(
                                'max',
                                +999999999))  # wasn't in egcode, but needed
                    self.chirality_N_spinbox.setValue(
                        param.options.get('default', 0))  # was 5
                    ##e note: i suspect this default 0 should come from something that knows this desc grammar.
                    suffix = param.options.get('suffix', '')
                    if suffix:
                        self.chirality_N_spinbox.setSuffix(
                            QtGui.QApplication.translate(
                                self.__class__.__name__, suffix))
                    else:
                        self.chirality_N_spinbox.setSuffix(
                            QString.null)  # probably not needed
                    nt_parameters_body_layout.addWidget(
                        self.chirality_N_spinbox, thisrow, 1)
                    hidethese.append(self.chirality_N_spinbox)
                    getter = self.chirality_N_spinbox.value  # note: it also has .text, which includes suffix

                else:
                    print "didn't match:", param  ###e improve this

                # things done the same way for all kinds of param-editing widgets
                if 1:  #bruce 060703 moved this down here, as bugfix
                    # set tooltip (same one for editfield and label)
                    tooltip = param.options.get('tooltip', '')
                    ###e do it for more kinds of params; share the code somehow; do it in controller, or setup-aid?
                    ###k QToolTip appropriateness; tooltip option might be entirely untested
                    if tooltip and label:
                        QToolTip.add(
                            label,
                            QtGui.QApplication.translate(
                                self.__class__.__name__, tooltip))
                    if tooltip and editfield:
                        QToolTip.add(
                            editfield,
                            QtGui.QApplication.translate(
                                self.__class__.__name__, tooltip)
                        )  ##k ok?? review once not all params have same-row labels.

                if getter and paramname and paramname != '?':
                    self.param_getters[paramname] = getter
                ### also bind these params to actions...
                continue  # next param

            header_refs.extend([
                self.parameters_grpbox, self.nt_parameters_grpbtn,
                self.parameters_grpbox_label
            ])

            # now create the logic/control object for the group
            group = CollapsibleGroupController_Qt(self, group_desc,
                                                  header_refs, hidethese,
                                                  self.nt_parameters_grpbtn)
            ### maybe ask env for the class to use for this?
            self.groups.append(
                group
            )  ### needed?? only for scanning the params, AFAIK -- oh, and to maintain a python refcount.

            # from languageChange:
            if 1:  # i don't know if these are needed:
                self.parameters_grpbox.setTitle(QString.null)
                self.nt_parameters_grpbtn.setText(QString.null)
            self.parameters_grpbox_label.setText(
                QtGui.QApplication.translate(
                    self.__class__.__name__,
                    group_desc.args[0]))  # was "Nanotube Parameters"
            ##e note that it's questionable in the syntax design for this property of a group (overall group label)
            # to be in that position (desc arg 0).

            # == end its kids

            parameters_grpboxLayout.addLayout(nt_parameters_body_layout)
            body_frameLayout.addWidget(self.parameters_grpbox)

            # == end parameters groupbox

            continue  # next group

        nanotube_dialogLayout.addWidget(self.body_frame)
        spacer14 = QSpacerItem(20, 20, QSizePolicy.Minimum,
                               QSizePolicy.Expanding)
        nanotube_dialogLayout.addItem(spacer14)

        layout42 = QHBoxLayout(None, 4, 6, "layout42")
        btm_spacer = QSpacerItem(59, 20, QSizePolicy.Expanding,
                                 QSizePolicy.Minimum)
        layout42.addItem(btm_spacer)

        self.cancel_btn = QPushButton(self, "cancel_btn")
        self.cancel_btn.setAutoDefault(0)  #bruce 060703 bugfix
        layout42.addWidget(self.cancel_btn)

        self.ok_btn = QPushButton(self, "ok_btn")
        self.ok_btn.setAutoDefault(0)  #bruce 060703 bugfix
        layout42.addWidget(self.ok_btn)
        nanotube_dialogLayout.addLayout(layout42)

        self.languageChange()

        self.resize(
            QSize(246, 618).expandedTo(self.minimumSizeHint())
        )  ### this size will need to be adjusted (guess -- it's only place overall size is set)
        qt4todo('self.clearWState(Qt.WState_Polished)')

        ## self.connect(self.nt_parameters_grpbtn,SIGNAL("clicked()"),self.toggle_nt_parameters_grpbtn) ####

        # new:
        for button, methodname in (
            (self.sponsor_btn,
             'do_sponsor_btn'),  #e generalize to more than one sponsor button
            (self.done_btn, 'do_done_btn'),
            (self.abort_btn, 'do_abort_btn'),
            (self.preview_btn, 'do_preview_btn'),
            (self.whatsthis_btn, 'do_whatsthis_btn'),
            (self.cancel_btn, 'do_cancel_btn'),
            (self.ok_btn, 'do_ok_btn')):
            if hasattr(self, methodname):
                self.connect(button, SIGNAL("clicked()"),
                             getattr(self, methodname))
        return
Example #25
0
    def __init__(self, parent = None, desc = None, name = None, modal = 0, fl = 0, env = None, type = "QDialog"):
        if env is None:
            import foundation.env as env # this is a little weird... probably it'll be ok, and logically it seems correct.
        
        self.desc = desc

        self.typ = type
        if type == "QDialog":
            QDialog.__init__(self,parent,name,modal,fl)
        elif type == "QTextEdit":
            QTextEdit.__init__(self, parent, name)
        elif type == "QFrame":
            QFrame.__init__(self,parent,name)
        else:
            print "don't know about type == %r" % (type,)
        
        self.image1 = QPixmap()
        self.image1.loadFromData(image1_data,"PNG") # should be: title_icon ####
        self.image3 = QPixmap()
        self.image3.loadFromData(image3_data,"PNG")
        self.image4 = QPixmap()
        self.image4.loadFromData(image4_data,"PNG")
        self.image5 = QPixmap()
        self.image5.loadFromData(image5_data,"PNG")
        self.image6 = QPixmap()
        self.image6.loadFromData(image6_data,"PNG")
        self.image7 = QPixmap()
        self.image7.loadFromData(image7_data,"PNG")
        self.image0 = QPixmap(image0_data) # should be: border_icon ####
        self.image2 = QPixmap(image2_data) # should be: sponsor_pixmap ####

        try:
            ####@@@@
            title_icon_name = self.desc.options.get('title_icon')
            border_icon_name = self.desc.options.get('border_icon')
            if title_icon_name:
                self.image1 = imagename_to_pixmap(title_icon_name) ###@@@ pass icon_path
                    ###@@@ import imagename_to_pixmap or use env function
                    # or let that func itself be an arg, or have an env arg for it
                    ###e rename it icon_name_to_pixmap, or find_icon? (the latter only if it's ok if it returns an iconset)
                    ###e use iconset instead?
            if border_icon_name:
                self.image0 = imagename_to_pixmap(border_icon_name)
        except:
            print_compact_traceback("bug in icon-setting code, using fallback icons: ")
            pass

        if not name:
            self.setName("parameter_dialog_or_frame") ###

        ###k guess this will need: if type == 'QDialog'
        self.setIcon(self.image0) # should be: border_icon ####

        nanotube_dialogLayout = QVBoxLayout(self,0,0,"nanotube_dialogLayout")

        self.heading_frame = QFrame(self,"heading_frame")
        self.heading_frame.setPaletteBackgroundColor(QColor(122,122,122))
        self.heading_frame.setFrameShape(QFrame.NoFrame)
        self.heading_frame.setFrameShadow(QFrame.Plain)
        heading_frameLayout = QHBoxLayout(self.heading_frame,0,3,"heading_frameLayout")

        self.heading_pixmap = QLabel(self.heading_frame,"heading_pixmap")
        self.heading_pixmap.setSizePolicy(QSizePolicy(QSizePolicy.Fixed,QSizePolicy.Fixed,0,0,self.heading_pixmap.sizePolicy().hasHeightForWidth()))
        self.heading_pixmap.setPixmap(self.image1) # should be: title_icon ####
        self.heading_pixmap.setScaledContents(1)
        heading_frameLayout.addWidget(self.heading_pixmap)

        self.heading_label = QLabel(self.heading_frame,"heading_label")
        self.heading_label.setPaletteForegroundColor(QColor(255,255,255))
        heading_label_font = QFont(self.heading_label.font())
        heading_label_font.setPointSize(12)
        heading_label_font.setBold(1)
        self.heading_label.setFont(heading_label_font)
        heading_frameLayout.addWidget(self.heading_label)
        nanotube_dialogLayout.addWidget(self.heading_frame)

        self.body_frame = QFrame(self,"body_frame")
        self.body_frame.setFrameShape(QFrame.StyledPanel)
        self.body_frame.setFrameShadow(QFrame.Raised)
        body_frameLayout = QVBoxLayout(self.body_frame,3,3,"body_frameLayout")

        self.sponsor_frame = QFrame(self.body_frame,"sponsor_frame")
        self.sponsor_frame.setPaletteBackgroundColor(QColor(255,255,255))
        self.sponsor_frame.setFrameShape(QFrame.StyledPanel)
        self.sponsor_frame.setFrameShadow(QFrame.Raised)
        sponsor_frameLayout = QHBoxLayout(self.sponsor_frame,0,0,"sponsor_frameLayout")

        self.sponsor_btn = QPushButton(self.sponsor_frame,"sponsor_btn")
        self.sponsor_btn.setAutoDefault(0) #bruce 060703 bugfix
        self.sponsor_btn.setSizePolicy(QSizePolicy(QSizePolicy.Preferred,QSizePolicy.Preferred,0,0,self.sponsor_btn.sizePolicy().hasHeightForWidth()))
        self.sponsor_btn.setPaletteBackgroundColor(QColor(255,255,255))
        self.sponsor_btn.setPixmap(self.image2) # should be: sponsor_pixmap #### [also we'll need to support >1 sponsor]
        self.sponsor_btn.setFlat(1)
        sponsor_frameLayout.addWidget(self.sponsor_btn)
        body_frameLayout.addWidget(self.sponsor_frame)

        layout59 = QHBoxLayout(None,0,6,"layout59")
        left_spacer = QSpacerItem(20,20,QSizePolicy.Expanding,QSizePolicy.Minimum)
        layout59.addItem(left_spacer)

        self.done_btn = QToolButton(self.body_frame,"done_btn")
        self.done_btn.setIcon(QIcon(self.image3))
        layout59.addWidget(self.done_btn)

        self.abort_btn = QToolButton(self.body_frame,"abort_btn")
        self.abort_btn.setIcon(QIcon(self.image4))
        layout59.addWidget(self.abort_btn)

        self.preview_btn = QToolButton(self.body_frame,"preview_btn")
        self.preview_btn.setIcon(QIcon(self.image5))
        layout59.addWidget(self.preview_btn)

        self.whatsthis_btn = QToolButton(self.body_frame,"whatsthis_btn")
        self.whatsthis_btn.setIcon(QIcon(self.image6))
        layout59.addWidget(self.whatsthis_btn)
        right_spacer = QSpacerItem(20,20,QSizePolicy.Expanding,QSizePolicy.Minimum)
        layout59.addItem(right_spacer)
        body_frameLayout.addLayout(layout59)

        self.groups = []
        self.param_getters = {} # map from param name to get-function (which gets current value out of its widget or controller)

        for group_desc in self.desc.kids('group'):
            
            # == start parameters_grpbox ### this will differ for Windows style

            header_refs = [] # keep python refcounted refs to all objects we make (at least the ones pyuic stored in self attrs)
            
            self.parameters_grpbox = QGroupBox(self.body_frame,"parameters_grpbox")
            self.parameters_grpbox.setFrameShape(QGroupBox.StyledPanel)
            self.parameters_grpbox.setFrameShadow(QGroupBox.Sunken)
            self.parameters_grpbox.setMargin(0)
            self.parameters_grpbox.setColumnLayout(0,Qt.Vertical)
            self.parameters_grpbox.layout().setSpacing(1)
            self.parameters_grpbox.layout().setMargin(4)
            parameters_grpboxLayout = QVBoxLayout(self.parameters_grpbox.layout())
            parameters_grpboxLayout.setAlignment(Qt.AlignTop)

            layout20 = QHBoxLayout(None,0,6,"layout20")

            self.nt_parameters_grpbtn = QPushButton(self.parameters_grpbox,"nt_parameters_grpbtn")
            self.nt_parameters_grpbtn.setSizePolicy(QSizePolicy(QSizePolicy.Minimum,QSizePolicy.Fixed,0,0,self.nt_parameters_grpbtn.sizePolicy().hasHeightForWidth()))
            self.nt_parameters_grpbtn.setMaximumSize(QSize(16,16))
            self.nt_parameters_grpbtn.setAutoDefault(0)
            self.nt_parameters_grpbtn.setIcon(QIcon(self.image7)) ### not always right, but doesn't matter
            self.nt_parameters_grpbtn.setFlat(1)
            layout20.addWidget(self.nt_parameters_grpbtn)

            self.parameters_grpbox_label = QLabel(self.parameters_grpbox,"parameters_grpbox_label")
            self.parameters_grpbox_label.setSizePolicy(QSizePolicy(QSizePolicy.Preferred,QSizePolicy.Minimum,0,0,self.parameters_grpbox_label.sizePolicy().hasHeightForWidth()))
            self.parameters_grpbox_label.setAlignment(QLabel.AlignVCenter)
            layout20.addWidget(self.parameters_grpbox_label)
            gbx_spacer1 = QSpacerItem(67,16,QSizePolicy.Expanding,QSizePolicy.Minimum)
            layout20.addItem(gbx_spacer1)
            parameters_grpboxLayout.addLayout(layout20)

            nt_parameters_body_layout = QGridLayout(None,1,1,0,6,"nt_parameters_body_layout") ### what is 6 -- is it related to number of items???
                # is it 6 in all the ones we got, but that could be a designer error so i better look it up sometime.

            # == start its kids

            # will use from above: self.parameters_grpbox, nt_parameters_body_layout
            
            nextrow = 0 # which row of the QGridLayout to start filling next (loop variable)
            hidethese = [] # set of objects to hide or show, when this group is closed or opened
            
            for param in group_desc.kids('parameter'):
                # param (a group subobj desc) is always a parameter, but we already plan to extend this beyond that,
                # so we redundantly test for this here.
                getter = None
                paramname = None
                # set these for use by uniform code at the end (e.g. for tooltips)
                editfield = None
                label = None
                if param.isa('parameter'):
                    label = QLabel(self.parameters_grpbox,"members_label")
                    label.setAlignment(QLabel.AlignVCenter | QLabel.AlignRight)
                    nt_parameters_body_layout.addWidget(label,nextrow,0)
                    hidethese.append(label)
                    thisrow = nextrow
                    nextrow += 1
                    #e following should be known in a place that knows the input language, not here
                    paramname = param.options.get('name') or (param.args and param.args[0]) or "?"
                    paramlabel = param.options.get('label') or paramname ##e wrong, label "" or none ought to be possible
                    # QtGui.QApplication.translate(self.__class__.__name__, "xyz")
                    label.setText(QtGui.QApplication.translate(self.__class__.__name__, paramlabel))
                    
                if param.isa('parameter', widget = 'combobox', type = ('str',None)):
                    self.members_combox = QComboBox(0,self.parameters_grpbox,"members_combox") ###k  what's 0?
                    editfield = self.members_combox
                    #### it probably needs a handler class, and then that could do this setup
                    self.members_combox.clear()
                    default = param.options.get('default', None) # None is not equal to any string
                    thewidgetkid = param.kids('widget')[-1] # kluge; need to think what the desc method for this should be
                    for item in thewidgetkid.kids('item'):
                        itemval = item.args[0]
                        itemtext = itemval
                        self.members_combox.insertItem(QtGui.QApplication.translate(self.__class__.__name__, itemtext)) #k __tr ok??
                        if itemval == default: #k or itemtext?
                            pass ##k i find no setItem in our py code, so not sure yet what to do for this.
                    nt_parameters_body_layout.addWidget(self.members_combox,thisrow,1)
                    hidethese.append(self.members_combox)
                    getter = (lambda combobox = self.members_combox: str(combobox.currentText()))
                        ##e due to __tr or non-str values, it might be better to use currentIndex and look it up in a table
                        # (though whether __tr is good here might depend on what it's used for)
                                    
                elif param.isa('parameter', widget = ('lineedit', None), type = ('str',None)):
                    # this covers explicit str|lineedit, and 3 default cases str, lineedit, neither.
                    # (i.e. if you say parameter and nothing else, it's str lineedit by default.)
                    self.length_linedit = QLineEdit(self.parameters_grpbox,"length_linedit")
                    editfield = self.length_linedit
                    nt_parameters_body_layout.addWidget(self.length_linedit,thisrow,1)
                    hidethese.append(self.length_linedit)
                    default = str(param.options.get('default', ""))
                    self.length_linedit.setText(QtGui.QApplication.translate(self.__class__.__name__, default)) # __tr ok?
                    getter = (lambda lineedit = self.length_linedit: str(lineedit.text()))
                    
                elif param.isa('parameter', widget = ('lineedit', None), type = 'float'):
                    self.length_linedit = QLineEdit(self.parameters_grpbox,"length_linedit")
                    editfield = self.length_linedit
                    nt_parameters_body_layout.addWidget(self.length_linedit,thisrow,1)
                    hidethese.append(self.length_linedit)
                    controller = FloatLineeditController_Qt(self, param, self.length_linedit)
                    header_refs.append(controller)
                    getter = controller.get_value
                    
                elif param.isa('parameter', widget = ('spinbox', None), type = 'int') or \
                     param.isa('parameter', widget = ('spinbox'), type = None):
                    self.chirality_N_spinbox = QSpinBox(self.parameters_grpbox,"chirality_N_spinbox") # was chirality_m_spinbox, now chirality_N_spinbox
                    editfield = self.chirality_N_spinbox
                    ### seems like Qt defaults for min and max are 0,100 -- way too small a range!
                    if param.options.has_key('min') or 1:
                        self.chirality_N_spinbox.setMinimum(param.options.get('min', -999999999)) # was 0
                    if param.options.has_key('max') or 1:
                        self.chirality_N_spinbox.setMaximum(param.options.get('max', +999999999)) # wasn't in egcode, but needed
                    self.chirality_N_spinbox.setValue(param.options.get('default', 0)) # was 5
                        ##e note: i suspect this default 0 should come from something that knows this desc grammar.
                    suffix = param.options.get('suffix', '')
                    if suffix:
                        self.chirality_N_spinbox.setSuffix(QtGui.QApplication.translate(self.__class__.__name__, suffix))
                    else:
                        self.chirality_N_spinbox.setSuffix(QString.null) # probably not needed
                    nt_parameters_body_layout.addWidget(self.chirality_N_spinbox,thisrow,1)
                    hidethese.append(self.chirality_N_spinbox)
                    getter = self.chirality_N_spinbox.value # note: it also has .text, which includes suffix
                    
                else:
                    print "didn't match:",param ###e improve this

                # things done the same way for all kinds of param-editing widgets
                if 1: #bruce 060703 moved this down here, as bugfix
                    # set tooltip (same one for editfield and label)
                    tooltip = param.options.get('tooltip', '')
                    ###e do it for more kinds of params; share the code somehow; do it in controller, or setup-aid?
                    ###k QToolTip appropriateness; tooltip option might be entirely untested
                    if tooltip and label:
                        QToolTip.add(label, QtGui.QApplication.translate(self.__class__.__name__, tooltip))
                    if tooltip and editfield:
                        QToolTip.add(editfield, QtGui.QApplication.translate(self.__class__.__name__, tooltip)) ##k ok?? review once not all params have same-row labels.
                
                if getter and paramname and paramname != '?':
                    self.param_getters[paramname] = getter
                ### also bind these params to actions...
                continue # next param

            header_refs.extend( [self.parameters_grpbox, self.nt_parameters_grpbtn, self.parameters_grpbox_label] )
            
            # now create the logic/control object for the group
            group = CollapsibleGroupController_Qt(self, group_desc, header_refs, hidethese, self.nt_parameters_grpbtn)
                ### maybe ask env for the class to use for this?
            self.groups.append(group) ### needed?? only for scanning the params, AFAIK -- oh, and to maintain a python refcount.

            # from languageChange:
            if 1: # i don't know if these are needed:
                self.parameters_grpbox.setTitle(QString.null)
                self.nt_parameters_grpbtn.setText(QString.null)
            self.parameters_grpbox_label.setText(QtGui.QApplication.translate(self.__class__.__name__, group_desc.args[0])) # was "Nanotube Parameters"
                ##e note that it's questionable in the syntax design for this property of a group (overall group label)
                # to be in that position (desc arg 0).
        
            # == end its kids
            
            parameters_grpboxLayout.addLayout(nt_parameters_body_layout)
            body_frameLayout.addWidget(self.parameters_grpbox)

            # == end parameters groupbox
            
            continue # next group

        nanotube_dialogLayout.addWidget(self.body_frame)
        spacer14 = QSpacerItem(20,20,QSizePolicy.Minimum,QSizePolicy.Expanding)
        nanotube_dialogLayout.addItem(spacer14)

        layout42 = QHBoxLayout(None,4,6,"layout42")
        btm_spacer = QSpacerItem(59,20,QSizePolicy.Expanding,QSizePolicy.Minimum)
        layout42.addItem(btm_spacer)

        self.cancel_btn = QPushButton(self,"cancel_btn")
        self.cancel_btn.setAutoDefault(0) #bruce 060703 bugfix
        layout42.addWidget(self.cancel_btn)

        self.ok_btn = QPushButton(self,"ok_btn")
        self.ok_btn.setAutoDefault(0) #bruce 060703 bugfix
        layout42.addWidget(self.ok_btn)
        nanotube_dialogLayout.addLayout(layout42)

        self.languageChange()

        self.resize(QSize(246,618).expandedTo(self.minimumSizeHint())) ### this size will need to be adjusted (guess -- it's only place overall size is set)
        qt4todo('self.clearWState(Qt.WState_Polished)')

        ## self.connect(self.nt_parameters_grpbtn,SIGNAL("clicked()"),self.toggle_nt_parameters_grpbtn) ####

        # new:
        for button, methodname in ((self.sponsor_btn, 'do_sponsor_btn'),  #e generalize to more than one sponsor button
                                   (self.done_btn, 'do_done_btn'),
                                   (self.abort_btn, 'do_abort_btn'),
                                   (self.preview_btn, 'do_preview_btn'),
                                   (self.whatsthis_btn, 'do_whatsthis_btn'),
                                   (self.cancel_btn, 'do_cancel_btn'),
                                   (self.ok_btn, 'do_ok_btn')):
            if hasattr(self, methodname):
                self.connect(button, SIGNAL("clicked()"), getattr(self, methodname))
        return
Example #26
0
def startup_script( main_globals):
    """
    This is the main startup script for NE1.
    It is intended to be run only once, and only by the code in main.py.
    When this function returns, the caller is intended to immediately exit
    normally.
       Parameter main_globals should be the value of globals() in __main__,
    which is needed in case .atom-debug-rc is executed, since it must be
    executed in that global namespace.
    """

    # Note: importing all of NE1's functionality can take a long time.
    # To the extent possible, we want that time to be spent after
    # something is visible to the user, but (mostly) before the main
    # window is shown to the user (since showing the main window implies
    # that NE1 is almost ready to go). So we display a splashscreen
    # before doing most imports and initializations, then set up most
    # of our data structures and UI commands (thus importing the code
    # needed to implement them), and then show the main window.
    # (Some experimental commands are initialized after that, so that
    # errors that occur then can't prevent the main window from becoming
    # visible.)

    # TODO: turn the sections of code below into named functions or methods,
    # and perhaps split before_most_imports and before_creating_app into
    # more named functions or methods. The biggest split should be between
    # functions that need to be careful to do very few or no imports,
    # and functions that are free to do any imports.

    # Windows machines spawn and remove the shell, so no info is normally
    # captured.  This is a first attempt to try to capture some of the console
    # prints that would normally be lost.  The default for this code is that
    # it's turned off, and should remain that way until it's improved.
    if NE1_Build_Constants.NE1_CONSOLE_REDIRECT and os.name == "nt":
        capture_console = False
        capture_file = ""
        # if it's not reporting as python is the executable
        if not sys.executable.upper().endswith("PYTHON.EXE") and \
           not sys.executable.upper().endswith("PYTHON"):
            try:
                capture_file = u"".join((sys.executable[:-4], "_console.log"))
                sys.stdout = open(capture_file, 'w')
                capture_console = True # already trapped, don't try more.
            except:
                pass
        if not capture_console:
            # Haven't captured the console log yet.  Find the default user
            # path and try to capture there this happens if we can't write to
            # the normal log location, or if python.exe is the executable.
            tmpFilePath = os.path.normpath(os.path.expanduser("~/Nanorex/"))
            if not os.path.exists(tmpFilePath): #If it doesn't exist
                try:
                    os.mkdir(tmpFilePath) #Try making one
                    capture_console = True
                except:
                    pass
                    # we tried, but there's no easy way to capture the console
            if capture_console or os.path.isdir(tmpFilePath):
                try: # We made the directory or it already existed, try
                     # creating the log file.
                    capture_file = os.path.normpath(u"".join((tmpFilePath, \
                                             "/NE1_console.log")))
                    sys.stdout = open(capture_file, 'w')
                    capture_console = True
                except:
                    print >> sys.__stderr__, \
                          "Failed to create any console log file."
                    capture_console = False
        if capture_console:
            # Next two lines are specifically printed to the original console
            print >> sys.__stdout__, "The console has been redirected into:"
            print >> sys.__stdout__, capture_file.encode("utf_8")
            print
            print "starting NanoEngineer-1 in [%s]," % os.getcwd(), time.asctime()
            print "using Python: " + sys.version
            try:
                print "on path: " + sys.executable
            except:
                pass


    # print the version information including official release candidate if it
    # is not 0 (false)
    if NE1_Build_Constants.NE1_OFFICIAL_RELEASE_CANDIDATE:
        print "Version: NanoEngineer-1 v%s_RC%s" % \
              (NE1_Build_Constants.NE1_RELEASE_VERSION, \
               NE1_Build_Constants.NE1_OFFICIAL_RELEASE_CANDIDATE)
    else:
        print "Version: NanoEngineer-1 v%s" % \
              NE1_Build_Constants.NE1_RELEASE_VERSION

    # "Do things that should be done before most imports occur."

    startup_before_most_imports.before_most_imports( main_globals )


    from PyQt4.Qt import QApplication, QSplashScreen


    # "Do things that should be done before creating the application object."

    startup_before_most_imports.before_creating_app()
        ### TODO: this imports undo, env, debug, and it got moved earlier
        # in the startup process at some point. Those imports are probably not
        # too likely to pull in a lot of others, but if possible we should put up
        # the splash screen before doing most of them. Sometime try to figure out
        # how to do that. The point of this function is mostly to wrap every signal->slot
        # connection -- maybe it's sufficient to do that before creating the main
        # window rather than before creating the app? [bruce 071008 comment]


    # do some imports used for putting up splashscreen

    # (this must be done before any code that loads images from cad/src/ui)
    import utilities.icon_utilities as icon_utilities
    icon_utilities.initialize_icon_utilities()


    # Create the application object (an instance of QApplication).
    QApplication.setColorSpec(QApplication.CustomColor)
    #russ 080505: Make it global so it can be run under debugging below.
    global app
    app = QApplication(sys.argv)


    # Put up the splashscreen (if its image file can be found in cad/images).
    #
    # Note for developers:
    # If you don't want the splashscreen, just rename the splash image file.

    splash_pixmap = icon_utilities.imagename_to_pixmap( "images/splash.png" )
        # splash_pixmap will be null if the image file was not found
    if not splash_pixmap.isNull():
        splash = QSplashScreen(splash_pixmap) # create the splashscreen
        splash.show()
        MINIMUM_SPLASH_TIME = 3.0
            # I intend to add a user pref for MINIMUM_SPLASH_TIME for A7. mark 060131.
        splash_start = time.time()
    else:
        print "note: splash.png was not found"


    # connect the lastWindowClosed signal

    from PyQt4.Qt import SIGNAL
    app.connect(app, SIGNAL("lastWindowClosed ()"), app.quit)


    # NOTE: At this point, it is ok to do arbitrary imports as needed,
    # except of experimental code.


    # import MWsemantics.

    # An old comment (I don't know if it's still true -- bruce 071008):
    # this might have side effects other than defining things.

    from ne1_ui.MWsemantics import MWsemantics


    # initialize modules and data structures

    from ne1_startup import startup_misc
        # do this here, not earlier, so it's free to do whatever toplevel imports it wants
        # [bruce 071008 change]

    startup_misc.call_module_init_functions()

    startup_misc.register_MMP_RecordParsers()
        # do this before reading any mmp files

    # create the single main window object

    foo = MWsemantics() # This does a lot of initialization (in MainWindow.__init__)

    import __main__
    __main__.foo = foo
        # developers often access the main window object using __main__.foo when debugging,
        # so this is explicitly supported


    # initialize CoNTubGenerator
    # TODO: move this into one of the other initialization functions
    #Disabling the following code that initializes the ConTub plugin
    #(in UI it is called Heterojunction.) The Heterojunction generator or
    #ConTubGenerator was never ported to Qt4 platform. The plugin generator
    #needs a code cleanup  -- ninad 2007-11-16
    ##import CoNTubGenerator
    ##CoNTubGenerator.initialize()


    # for developers: run a hook function that .atom-debug-rc might have defined
    # in this module's global namespace, for doing things *before* showing the
    # main window.

    try:
        # do this, if user asked us to by defining it in .atom-debug-rc
        func = atom_debug_pre_main_show
    except NameError:
        pass
    else:
        func()


    # Do other things that should be done just before showing the main window

    startup_misc.pre_main_show(foo) # this sets foo's geometry, among other things

    foo._init_after_geometry_is_set()

    if not splash_pixmap.isNull():
        # If the MINIMUM_SPLASH_TIME duration has not expired, sleep for a moment.
        while time.time() - splash_start < MINIMUM_SPLASH_TIME:
            time.sleep(0.1)
        splash.finish( foo ) # Take away the splashscreen


    # show the main window

    foo.show()

    # for developers: run a hook function that .atom-debug-rc might have defined
    # in this module's global namespace, for doing things *after* showing the
    # main window.

    try:
        # do this, if user asked us to by defining it in .atom-debug-rc
        func = atom_debug_post_main_show
    except NameError:
        pass
    else:
        func()


    # do other things after showing the main window
    startup_misc.post_main_show(foo)


    # start psyco runtime optimizer (EXPERIMENTAL) --
    # for doc see http://psyco.sourceforge.net/
    #
    # Example: it speeds up code like this by 17 times:
    # (in my test, Intel Mac OS 10.4, Python 2.4.4)
    #   x = 17
    #   for i in range(10**7):
    #       x += i % 3 - 1
    #
    #  [bruce 080524]
    from utilities.debug_prefs import debug_pref, Choice_boolean_False
    if debug_pref("Use psyco runtime optimizer (next session)?",
                  Choice_boolean_False,
                  prefs_key = True ):
        # Import Psyco if available
        try:
            import psyco
            ## psyco.full() -- insert dna takes a lot of time, then segfaults
            # after printing "inside this what's this";
            # plan: be more conservative about what it should optimize...
            # preferably bind specific functions using psyco.bind().
            # For now, just tell it to only optimize the most important ones.
            psyco.log() # manual says: log file name looks like xxx.log-psyco
                # by default, where xxx is the name of the script you ran
                # (when I ran "python main.py" in cad/src, it wrote to main.log-psyco there)
                # (maybe we can pass our own pathname as an argument?)
            ## psyco.profile(0.2) # use profiling, optimize funcs that use
                # more than 20% of the time (not sure what that means exactly)
                # (seems safe, but from log file, i guess it doesn't do much)
            psyco.profile(0.05) # "aggressive"
            print "using psyco"
            pass
        except ImportError:
            print "not using psyco"
            pass
        pass


    # Decide whether to do profiling, and if so, with which
    # profiling command and into what file. Set local variables
    # to record the decision, which are used later when running
    # the Qt event loop.

    # If the user's .atom-debug-rc specifies PROFILE_WITH_HOTSHOT = True,
    # use hotshot, otherwise fall back to vanilla Python profiler.
    # (Note: to work, it probably has to import this module
    #  and set this variable in this module's namespace.)
    try:
        PROFILE_WITH_HOTSHOT
    except NameError:
        PROFILE_WITH_HOTSHOT = False

    try:
        # user can set atom_debug_profile_filename to a filename in .atom-debug-rc,
        # to enable profiling into that file. For example:
        # % cd
        # % cat > .atom-debug-rc
        # atom_debug_profile_filename = '/tmp/profile-output'
        # ^D
        # ... then run NE1, and quit it
        # ... then in a python shell:
        # import pstats
        # p = pstats.Stats('<filename>')
        # p.strip_dirs().sort_stats('time').print_stats(100) # order by internal time (top 100 functions)
        # p.strip_dirs().sort_stats('cumulative').print_stats(100) # order by cumulative time
        atom_debug_profile_filename = main_globals.get('atom_debug_profile_filename')
        if atom_debug_profile_filename:
            print ("\nUser's .atom-debug-rc requests profiling into file %r" %
                   (atom_debug_profile_filename,))
            if not type(atom_debug_profile_filename) in [type("x"), type(u"x")]:
                print "error: atom_debug_profile_filename must be a string"
                assert 0 # caught and ignored, turns off profiling
            if PROFILE_WITH_HOTSHOT:
                try:
                    import hotshot
                except:
                    print "error during 'import hotshot'"
                    raise # caught and ignored, turns off profiling
            else:
                try:
                    import cProfile as py_Profile
                except ImportError:
                    print "Unable to import cProfile. Using profile module instead."
                    py_Profile = None
                if py_Profile is None:
                    try:
                        import profile as py_Profile
                    except:
                        print "error during 'import profile'"
                        raise # caught and ignored, turns off profiling
    except:
        print "exception setting up profiling (hopefully reported above); running without profiling"
        atom_debug_profile_filename = None


    # Create a fake "current exception", to help with debugging
    # (in case it's shown inappropriately in a later traceback).
    # One time this is seen is if a developer inserts a call to print_compact_traceback
    # when no exception is being handled (instead of the intended print_compact_stack).
    try:
        assert 0, "if you see this exception in a traceback, it is from the" \
            " startup script called by main.py, not the code that printed the traceback"
    except:
        pass


    # Handle a mmp file passed to it via the command line.  The mmp file
    # must be the first argument (after the program name) found on the
    # command line.  All other arguments are currently ignored and only
    # one mmp file can be loaded from the command line.
    # old revision with --initial-file is at: svn rev 12759
    # Derrick 20080520
    if ((len(sys.argv) >= 2) and sys.argv[1].endswith(".mmp")):
        foo.fileOpen(sys.argv[1])

    # Do other post-startup, pre-event-loop, non-profiled things, if any
    # (such as run optional startup commands for debugging).
    startup_misc.just_before_event_loop()

    if os.environ.has_key('WINGDB_ACTIVE'):
        # Hack to burn some Python bytecode periodically so Wing's
        # debugger can remain responsive while free-running
        # [from http://wingware.com/doc/howtos/pyqt; added by bruce 081227]
        # Addendum [bruce 090107]: this timer doesn't noticeably slow down NE1,
        # but with or without it, NE1 is about 4x slower in Wing than running
        # alone, at least when running test_selection_redraw.py.
        print "running under Wing IDE debugger; setting up timer"
        from PyQt4 import QtCore
        timer = QtCore.QTimer()
        def donothing(*args):
            x = 0
            for i in range(0, 100):
                x += i
        timer.connect(timer, QtCore.SIGNAL("timeout()"), donothing)
        timer.start(200)

    # Finally, run the main Qt event loop --
    # perhaps with profiling, depending on local variables set above.
    # This does not normally return until the user asks NE1 to exit.

    # Note that there are three copies of the statement which runs that loop,
    # two inside string literals, all of which presumably should be the same.

    if atom_debug_profile_filename:
        if PROFILE_WITH_HOTSHOT:
            profile = hotshot.Profile(atom_debug_profile_filename)
            profile.run('app.exec_()')
        else:
            py_Profile.run('from ne1_startup.main_startup import app; app.exec_()',
                           atom_debug_profile_filename)
        print ("\nProfile data was presumably saved into %r" %
               (atom_debug_profile_filename,))
    else:
        # if you change this code, also change both string literals just above
        app.exec_()


    # Now return to the caller in order to do a normal immediate exit of NE1.

    return # from startup_script
Example #27
0
def insert_command_into_menu(menu,
                             menutext,
                             command,
                             options=(),
                             position=-1,
                             raw_command=False,
                             undo_cmdname=None):
    """
    [This was part of makemenu_helper in the Qt3 version; in Qt4 it's only
     used for the disabled case, presumably for some good reason but not one
     which has been documented. It's also used independently of makemenu_helper.]
    
    Insert a new item into menu (a QMenu), whose menutext, command, and options are as given,
    with undo_cmdname defaulting to menutext (used only if raw_command is false), 
    where options is a list or tuple in the same form as used in "menu_spec" lists
    such as are passed to makemenu_helper (which this function helps implement).
       The caller should have already translated/localized menutext if desired.
       If position is given, insert the new item at that position, otherwise at the end.
    Return the Qt menu item id of the new menu item.
    (I am not sure whether this remains valid if other items are inserted before it. ###k)
       If raw_command is False (default), this function will wrap command with standard logic for nE-1 menu commands
    (presently, wrap_callable_for_undo), and ensure that a python reference to the resulting callable is kept forever.
       If raw_command is True, this function will pass command unchanged into the menu,
    and the caller is responsible for retaining a Python reference to command.
       ###e This might need an argument for the path or function to be used to resolve icon filenames.
    """
    #bruce 060613 split this out of makemenu_helper.
    # Only called for len(options) > 0, though it presumably works
    # just as well for len 0 (try it sometime).
    import types
    from foundation.whatsthis_utilities import turn_featurenames_into_links, ENABLE_WHATSTHIS_LINKS
    if not raw_command:
        command = wrap_callable_for_undo(command,
                                         cmdname=undo_cmdname or menutext)
        import foundation.changes as changes
        changes.keep_forever(command)
        # see comments on similar code above about why this is bad in theory, but necessary and ok for now
    iconset = None
    for option in options:
        # some options have to be processed first
        # since they are only usable when the menu item is inserted. [bruce 050614]
        if type(option) is types.TupleType:
            if option[0] == 'iconset':
                # support iconset, pixmap, or pixmap filename [bruce 050614 new feature]
                iconset = option[1]
                if type(iconset) is types.StringType:
                    filename = iconset
                    from utilities.icon_utilities import imagename_to_pixmap
                    iconset = imagename_to_pixmap(filename)
                if isinstance(iconset, QPixmap):
                    # (this is true for imagename_to_pixmap retval)
                    iconset = QIcon(iconset)
    if iconset is not None:
        import foundation.changes as changes
        changes.keep_forever(
            iconset
        )  #e memory leak; ought to make caller pass a place to keep it, or a unique id of what to keep
        #mitem_id = menu.insertItem( iconset, menutext, -1, position ) #bruce 050614, revised 060613 (added -1, position)
        mitem = menu.addAction(
            iconset,
            menutext)  #bruce 050614, revised 060613 (added -1, position)
        # Will this work with checkmark items? Yes, but it replaces the checkmark --
        # instead, the icon looks different for the checked item.
        # For the test case of gamess.png on Mac, the 'checked' item's icon
        # looked like a 3d-depressed button.
        # In the future we can tell the iconset what to display in each case
        # (see QIcon and/or QMenu docs, and helper funcs presently in debug_prefs.py.)
    else:
        # mitem_id = len(menu) -- mitem_id was previously an integer, indexing into the menu
        mitem = menu.addAction(menutext)
    for option in options:
        if option == 'checked':
            mitem.setChecked(True)
        elif option == 'unchecked':  #bruce 050614 -- see what this does visually, if anything
            mitem.setChecked(False)
        elif option == 'disabled':
            mitem.setEnabled(False)
        elif type(option) is types.TupleType:
            if option[0] == 'whatsThis':
                text = option[1]
                if ENABLE_WHATSTHIS_LINKS:
                    text = turn_featurenames_into_links(text)
                mitem.setWhatsThis(text)
            elif option[0] == 'iconset':
                pass  # this was processed above
            else:
                if debug_flags.atom_debug:
                    print "atom_debug: fyi: don't understand menu_spec option %r", (
                        option, )
            pass
        elif option is None:
            pass  # this is explicitly permitted and has no effect
        else:
            if debug_flags.atom_debug:
                print "atom_debug: fyi: don't understand menu_spec option %r", (
                    option, )
        pass
        #e and something to use QMenuData.setShortcut
        #e and something to run whatever func you want on menu and mitem_id
    return mitem  # from insert_command_into_menu
def startup_script( main_globals):
    """
    This is the main startup script for NE1.
    It is intended to be run only once, and only by the code in main.py.
    When this function returns, the caller is intended to immediately exit
    normally.
       Parameter main_globals should be the value of globals() in __main__,
    which is needed in case .atom-debug-rc is executed, since it must be
    executed in that global namespace.
    """

    # Note: importing all of NE1's functionality can take a long time.
    # To the extent possible, we want that time to be spent after
    # something is visible to the user, but (mostly) before the main
    # window is shown to the user (since showing the main window implies
    # that NE1 is almost ready to go). So we display a splashscreen
    # before doing most imports and initializations, then set up most
    # of our data structures and UI commands (thus importing the code
    # needed to implement them), and then show the main window.
    # (Some experimental commands are initialized after that, so that
    # errors that occur then can't prevent the main window from becoming
    # visible.)

    # TODO: turn the sections of code below into named functions or methods,
    # and perhaps split before_most_imports and before_creating_app into
    # more named functions or methods. The biggest split should be between
    # functions that need to be careful to do very few or no imports,
    # and functions that are free to do any imports.
    
    # print the version information including official release candidate if it
    # is not 0 (false)
    if NE1_Build_Constants.NE1_OFFICIAL_RELEASE_CANDIDATE:
        print "Version: NanoEngineer-1 v%s_RC%s" % \
              (NE1_Build_Constants.NE1_RELEASE_VERSION, \
               NE1_Build_Constants.NE1_OFFICIAL_RELEASE_CANDIDATE)
    else:
        print "Version: NanoEngineer-1 v%s" % \
              NE1_Build_Constants.NE1_RELEASE_VERSION 
    
    # "Do things that should be done before most imports occur."
    
    startup_before_most_imports.before_most_imports( main_globals )


    from PyQt4.Qt import QApplication, QSplashScreen

    
    # "Do things that should be done before creating the application object."
    
    startup_before_most_imports.before_creating_app()
        ### TODO: this imports undo, env, debug, and it got moved earlier
        # in the startup process at some point. Those imports are probably not
        # too likely to pull in a lot of others, but if possible we should put up
        # the splash screen before doing most of them. Sometime try to figure out
        # how to do that. The point of this function is mostly to wrap every signal->slot
        # connection -- maybe it's sufficient to do that before creating the main
        # window rather than before creating the app? [bruce 071008 comment]
    

    # Create the application object (an instance of QApplication).
    QApplication.setColorSpec(QApplication.CustomColor)
    #russ 080505: Make it global so it can be run under debugging below.
    global app
    app = QApplication(sys.argv)

    # do some imports used for putting up splashscreen
    
    import utilities.icon_utilities as icon_utilities
    icon_utilities.initialize() 


    # Put up the splashscreen (if its image file can be found in cad/images).
    #    
    # Note for developers:
    # If you don't want the splashscreen, just rename the splash image file.

    splash_pixmap = icon_utilities.imagename_to_pixmap( "images/splash.png" )
        # splash_pixmap will be null if the image file was not found
    if not splash_pixmap.isNull():
        splash = QSplashScreen(splash_pixmap) # create the splashscreen
        splash.show()
        MINIMUM_SPLASH_TIME = 3.0 
            # I intend to add a user pref for MINIMUM_SPLASH_TIME for A7. mark 060131.
        splash_start = time.time()
    else:
        print "note: splash.png was not found"


    # connect the lastWindowClosed signal
    
    from PyQt4.Qt import SIGNAL
    app.connect(app, SIGNAL("lastWindowClosed ()"), app.quit)


    # NOTE: At this point, it is ok to do arbitrary imports as needed,
    # except of experimental code.


    # import MWsemantics.
    
    # An old comment (I don't know if it's still true -- bruce 071008):
    # this might have side effects other than defining things.

    from ne1_ui.MWsemantics import MWsemantics 


    # initialize modules and data structures

    from ne1_startup import startup_misc
        # do this here, not earlier, so it's free to do whatever toplevel imports it wants
        # [bruce 071008 change]
    
    startup_misc.call_module_init_functions()
    
    startup_misc.register_MMP_RecordParsers()
        # do this before reading any mmp files

    # create the single main window object
    
    foo = MWsemantics() # This does a lot of initialization (in MainWindow.__init__)

    import __main__
    __main__.foo = foo
        # developers often access the main window object using __main__.foo when debugging,
        # so this is explicitly supported


    # initialize CoNTubGenerator
    # TODO: move this into one of the other initialization functions   
    #Disabling the following code that initializes the ConTub plugin 
    #(in UI it is called Heterojunction.) The Heterojunction generator or 
    #ConTubGenerator was never ported to Qt4 platform. The plugin generator 
    #needs a code cleanup  -- ninad 2007-11-16
    ##import CoNTubGenerator
    ##CoNTubGenerator.initialize()


    # for developers: run a hook function that .atom-debug-rc might have defined
    # in this module's global namespace, for doing things *before* showing the
    # main window.
    
    try:
        # do this, if user asked us to by defining it in .atom-debug-rc
        func = atom_debug_pre_main_show
    except NameError:
        pass
    else:
        func()


    # Do other things that should be done just before showing the main window
    
    startup_misc.pre_main_show(foo) # this sets foo's geometry, among other things
    
    foo._init_after_geometry_is_set()
    
    if not splash_pixmap.isNull():
        # If the MINIMUM_SPLASH_TIME duration has not expired, sleep for a moment.
        while time.time() - splash_start < MINIMUM_SPLASH_TIME:
            time.sleep(0.1)
        splash.finish( foo ) # Take away the splashscreen


    # show the main window
    
    foo.show() 


    # set up the sponsors system and perhaps show the permission dialog
    
    if sys.platform != 'darwin':
        #bruce 070515 added condition to disable this on Mac, until Brian fixes the hang on Mac.
        # Note: this is enabled in the Mac released version, due to a patch during the release
        # building process, at least in A9.1.
        from sponsors.Sponsors import PermissionDialog
##        print "start sponsors startup code"
        # Show the dialog that asks permission to download the sponsor logos, then
        # launch it as a thread to download and process the logos.
        #
        permdialog = PermissionDialog(foo)
        if permdialog.needToAsk:
            permdialog.exec_()
        permdialog.start()
##        print "end sponsors startup code"


    # for developers: run a hook function that .atom-debug-rc might have defined
    # in this module's global namespace, for doing things *after* showing the
    # main window.

    try:
        # do this, if user asked us to by defining it in .atom-debug-rc
        func = atom_debug_post_main_show 
    except NameError:
        pass
    else:
        func()


    # do other things after showing the main window
    startup_misc.post_main_show(foo)


    # start psyco runtime optimizer (EXPERIMENTAL) --
    # for doc see http://psyco.sourceforge.net/
    #
    # Example: it speeds up code like this by 17 times:
    # (in my test, Intel Mac OS 10.4, Python 2.4.4)
    #   x = 17
    #   for i in range(10**7):
    #       x += i % 3 - 1
    #
    #  [bruce 080524]
    from utilities.debug_prefs import debug_pref, Choice_boolean_False
    if debug_pref("Use psyco runtime optimizer (next session)?",
                  Choice_boolean_False,
                  prefs_key = True ):
        # Import Psyco if available
        try:
            import psyco
            ## psyco.full() -- insert dna takes a lot of time, then segfaults
            # after printing "inside this what's this";
            # plan: be more conservative about what it should optimize...
            # preferably bind specific functions using psyco.bind().
            # For now, just tell it to only optimize the most important ones.
            psyco.log() # manual says: log file name looks like xxx.log-psyco
                # by default, where xxx is the name of the script you ran
                # (when I ran "python main.py" in cad/src, it wrote to main.log-psyco there)
                # (maybe we can pass our own pathname as an argument?)
            ## psyco.profile(0.2) # use profiling, optimize funcs that use
                # more than 20% of the time (not sure what that means exactly)
                # (seems safe, but from log file, i guess it doesn't do much)
            psyco.profile(0.05) # "aggressive"
            print "using psyco"
            pass
        except ImportError:
            print "not using psyco"
            pass
        pass


    # Decide whether to do profiling, and if so, with which
    # profiling command and into what file. Set local variables
    # to record the decision, which are used later when running
    # the Qt event loop.
    
    # If the user's .atom-debug-rc specifies PROFILE_WITH_HOTSHOT = True, use hotshot, otherwise
    # fall back to vanilla Python profiler.
    try:
        PROFILE_WITH_HOTSHOT
    except NameError:
        PROFILE_WITH_HOTSHOT = False
    
    try:
        # user can set this to a filename in .atom-debug-rc,
        # to enable profiling into that file
        atom_debug_profile_filename = main_globals['atom_debug_profile_filename']
        if atom_debug_profile_filename:
            print ("\nUser's .atom-debug-rc requests profiling into file %r" %
                   (atom_debug_profile_filename,))
            if not type(atom_debug_profile_filename) in [type("x"), type(u"x")]:
                print ("error: atom_debug_profile_filename must be a string;" +
                       "running without profiling")
                assert 0 # caught and ignored, turns off profiling
            if PROFILE_WITH_HOTSHOT:
                try:
                    import hotshot
                except:
                    print "error during 'import hotshot'; running without profiling"
                    raise # caught and ignored, turns off profiling
            else:
                try:
                    import cProfile
                except:
                    print "error during 'import profile'; running without profiling"
                    raise # caught and ignored, turns off profiling
    except:
        atom_debug_profile_filename = None


    # Create a fake "current exception", to help with debugging
    # (in case it's shown inappropriately in a later traceback).
    # One time this is seen is if a developer inserts a call to print_compact_traceback
    # when no exception is being handled (instead of the intended print_compact_stack).
    try:
        assert 0, "if you see this exception in a traceback, it is from the" \
            " startup script called by main.py, not the code that printed the traceback"
    except:
        pass


    # Handle a mmp file passed to it via the command line.  The mmp file
    # must be the first argument (after the program name) found on the 
    # command line.  All other arguments are currently ignored and only
    # one mmp file can be loaded from the command line.
    # old revision with --initial-file is at: svn rev 12759
    # Derrick 20080520
    if ((len(sys.argv) >= 2) and sys.argv[1].endswith(".mmp")):
        foo.fileOpen(sys.argv[1])
            
    # Finally, run the main Qt event loop --
    # perhaps with profiling, depending on local variables set above.
    # This does not normally return until the user asks NE1 to exit.
    
    # Note that there are three copies of the statement which runs that loop,
    # two inside string literals, all of which presumably should be the same.

    if atom_debug_profile_filename:
        if PROFILE_WITH_HOTSHOT:
            profile = hotshot.Profile(atom_debug_profile_filename)
            profile.run('app.exec_()')
        else:
            cProfile.run('from ne1_startup.main_startup import app; app.exec_()',
                         atom_debug_profile_filename)
        print ("\nProfile data was presumably saved into %r" %
               (atom_debug_profile_filename,))
    else:
        # if you change this code, also change the string literals just above
        app.exec_() 


    # Now return to the caller in order to do a normal immediate exit of NE1.
    
    return # from startup_script