Extending OpenEV- Tools and Commands

Python Shell Commands

The first method of extending OpenEV's functionality is to add new functions or commands to the python shell. Examples of this would be the "display" function and "newview" command. Functions are regular python functions imported as soon as the python shell is launched via a "from gvshell import *" command. You can import your own functions in OpenEV's python shell if you have placed your module in OpenEV's python path. Commands, such as "newview", follow a more complicated structure and differ from functions in the following way:
  1. They are intercepted rather than being passed to the python shell's interpreter.
  2. They use the syntax "commandname arg1 arg2..." rather than "commandname(arg1,arg2,...)"
  3. They have associated usage strings that are displayed when you enter "commands" at the prompt.
  4. They have argument checking.
Here is an example of the python shell and the results of the display function and newview commands:

The relevant files here are:

Tools

The idea behind the tool mechanism and the methods of registering a tool (automatic and non-automatic) are described in the customization section of OpenEV's help.

The base tool class is defined as follows in gviewapp.py:


class Tool_GViewApp:
    # Abstract base class to derive tools from
    def __init__(self,app=None):
        self.app = app
        self.menu_entries = Tool_GViewAppMenuEntries()
        self.icon_entries = Tool_GViewAppIconEntries()
        self.pymenu_entries = Tool_GViewAppMenuEntries()
        self.pyicon_entries = Tool_GViewAppIconEntries()

class Tool_GViewAppMenuEntries:
    # Class to store entries to be added to openev's menu
    def __init__(self):
        self.entries = {}
    
    def set_entry(self,item,position=0,callback=None,accelerator=None):
        # item = a string describing menu location
        # position = default location in the menu (integer): Ignored if an
        #            xml menu entry is specified for the tool.  Note:
        #            when used, the position refers to position in the
        #            lowest level menu.  Eg. if a menu entry is
        #            'File/menu1/entryN', position refer's to entryN's
        #            position within menu1, not menu1's position in
        #            File.  For more flexibility, use the xml form of
        #            configuration.
        # callback = callback
        # accelerator = shortcut key

        if (type(item) == type('')):
            if (type(position) == type(0)):
                self.entries[item] = (position,callback, accelerator)
            else:
                raise AttributeError,"position should be an integer"
        else:
            raise AttributeError,"Menu entry item must be a string"

(similar class for Icon entries)

This defines the way the tools add menu or icon entries to OpenEV's toolbar, and stores a handle to the application so that the tool can interact with it. Below is a simple tool that adds a new menu entry Tools/Example, and when called prints out a list of the tools loaded in the application.
#!/usr/bin/env python
import gviewapp

class Tool_example(gviewapp.Tool_GViewApp):

    def __init__(self, app=None,startpath=None):
        gviewapp.Tool_GViewApp.__init__(self,app)

        self.init_menu()

    def init_menu(self):
        self.menu_entries.set_entry("Tools/Example...",1,self.example_tool_cb)

    def example_tool_cb(self,*args):
        print self.app.Tool_List


TOOL_LIST=['Tool_example']
Placing this tool in OpenEV's "tools" directory will register it automatically. The relevant sections of gviewapp.py are:

Initialization:

The tools are loaded up and stored in self.Tool_List. Tools passed as a command line argument are loaded using self.load_tools_file; auto-registering tools (those in OpenEV's "tools" directory) are loaded using self.scan_tools_directories. These create an instance of the tool, tool_inst, and append a tuple consisting of (tool_name,tool_inst) to the Tool_List.

class GViewApp(Signaler):
    def __init__(self,toolfile=None,menufile=None,iconfile=None,pyshellfile=None):
        self.view_manager = ViewManager()
        self.sel_manager = gvselbrowser.GvSelectionManager( self.view_manager )
        self.pref_dialog = None
        self.filename = None

        # Toolbar
        self.toolbar = Toolbar()
        self.view_manager.set_toolbar( self.toolbar )

        # Other dialogs, etc.
        self.layerdlg = layerdlg.Launch()
        self.view_manager.set_layerdlg(self.layerdlg)

        self.publish('quit')
        self.publish('rfl-change')

        # Verify that float() works properly.
        try:
            x = float('0.9')
        except:
            gvutils.warning( 'It appears that float() doesn\'t work properly on your system.\nThis is likely due to use of a numeric locale with an alternate decimal\nrepresentation.  Please try setting the LC_NUMERIC environment variable\nto C and restarting OpenEV.' )

        # Default configuration files for view and python shell
        self.menufile=menufile
        self.iconfile=iconfile
        self.pyshellfile=pyshellfile
        
        # External tools to import and add to view menu
        self.Tool_List = []
        if toolfile is not None:
            self.load_tools_file( toolfile )

        self.scan_tools_directories()

        # Tool index: a dictionary with the tool name as a
        # key and the tool's position in the list as the value
        self.tool_index = {}
        for idx in range(len(self.Tool_List)):
            self.tool_index[self.Tool_List[idx][0]]=idx

        self.shell = None
New views:

When a new view is created, the main application cycles through its tool list, and appends their menu and icon entries to the menu/icon bars.

    def new_view(self, title=None, menufile=None,iconfile=None, *args):
        # If menu/icon files aren't specified, use application-wide
        # defaults
        if ((menufile is None) and (self.menufile is not None)):
            menufile=self.menufile
        if ((iconfile is None) and (self.iconfile is not None)):
            iconfile=self.iconfile

        view_window = gvviewwindow.GvViewWindow(app=self, title=title, menufile=menufile, 
                      iconfile=iconfile)
        view_name=view_window.title
        view_menu = view_window.menuf    
              
        if ((len(self.Tool_List) > 0) and (menufile is None)):
            # If no menu configuration file is specified, put
            # tools in the default positions specified by
            # the tool menu entry's position parameter.
            for cur_tool_list in self.Tool_List:
                cur_tool = cur_tool_list[1]
                if hasattr(cur_tool.menu_entries.entries,'keys'):
                    for item in cur_tool.menu_entries.entries.keys():
                        view_menu.insert_entry(
                            cur_tool.menu_entries.entries[item][0],
                            item,
                            cur_tool.menu_entries.entries[item][2],
                            cur_tool.menu_entries.entries[item][1],
                            (view_name))

        # Icons- Note: currently it is assumed that the tool icons are
        #        xpms.  Support for pixmaps and widgets will be added
        #        later if necessary (icon type would have to be detected
        #        from last entry of the relevant tool icon entry, and
        #        a function would have to be created to deal with them.
        #        They are slightly more complicated than the xpm case
        #        and wouldn't use insert_tool_icon.  Would also need
        #        code in the complextoolentry case to avoid an icon
        #        of one type (eg. xpm) being replaced by another type
        #        (eg. widget, pixmap).
        #
        #        ALSO: GtkToolbar does not allow callback information
        #              to be specified, so the viewname cannot be
        #              passed as an argument to tool icon callbacks
        #              the way it is for menu callbacks. However,
        #              if the view is needed, it can be obtained
        #              using:
        #              view=args[0].get_toplevel()
        #              The view title is under:
        #              view['title'].  Note that this is not quite
        #              the same as the view's self.title, but is based
        #              on it (usually 'OpenEV: '+self.title)
            
        if ((len(self.Tool_List) > 0) and (iconfile is None)):
            for cur_tool_list in self.Tool_List:
                cur_tool=cur_tool_list[1]
                for item in cur_tool.icon_entries.entries:
                    view_window.insert_tool_icon(
                        item[0], # filename
                        item[1], # label
                        item[2], # hint text
                        item[4], # callback
                        item[5], # help topic
                        item[3],  # position
                            )
        view_window.show()
        return view_window


Next
Developer Course Outline
OpenEV Help