commit-gnue
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

r6542 - trunk/gnue-navigator/src


From: johannes
Subject: r6542 - trunk/gnue-navigator/src
Date: Thu, 21 Oct 2004 13:55:45 -0500 (CDT)

Author: johannes
Date: 2004-10-21 13:55:45 -0500 (Thu, 21 Oct 2004)
New Revision: 6542

Modified:
   trunk/gnue-navigator/src/GNClient.py
   trunk/gnue-navigator/src/UIgtk2.py
Log:
Fixed gtk2 frontend for navigator


Modified: trunk/gnue-navigator/src/GNClient.py
===================================================================
--- trunk/gnue-navigator/src/GNClient.py        2004-10-21 16:37:59 UTC (rev 
6541)
+++ trunk/gnue-navigator/src/GNClient.py        2004-10-21 18:55:45 UTC (rev 
6542)
@@ -1,6 +1,9 @@
+# GNU Enterprise Navigator - Client
 #
-# This file is part of GNU Enterprise.
+# Copyright 2001-2004 Free Software Foundation
 #
+# This file is part of GNU Enterprise
+#
 # GNU Enterprise is free software; you can redistribute it
 # and/or modify it under the terms of the GNU General Public
 # License as published by the Free Software Foundation; either
@@ -16,168 +19,197 @@
 # write to the Free Software Foundation, Inc., 59 Temple Place
 # - Suite 330, Boston, MA 02111-1307, USA.
 #
-# Copyright 2002-2004 Free Software Foundation
-#
-# FILE:
-# GNClient.py
-#
-# DESCRIPTION:
-# Client startup file that creates a navigation menu from a file
-#
-# NOTES:
-#
+# $Id$
 
 import pstats
 import os
-import os.path
 import sys
 import urllib
-import string
 
 from gnue.navigator.GNParser import loadProcesses
 from gnue.navigator import Actions
-from gnue.common.apps import GDebug
+from gnue.common.apps import errors
 from gnue.common.utils.FileUtils import openResource, dyn_import
 from gnue.common.datasources import GDataObjects, GConnections
 from gnue.common.apps.GClientApp import *
 from gnue import paths
 from gnue.navigator import VERSION
+from gnue.forms.GFInstance import GFInstance
 
 from GNConfig import ConfigOptions as NavigatorConfigOptions
 
 # TODO: Please go away!!!!!
-try: 
+try:
   from gnue.forms.GFConfig import ConfigOptions
-except: 
-  FORMS_SUPPORT=0
+  FORMS_SUPPORT = True
+
+except:
+  FORMS_SUPPORT = False
   
-try: 
+try:
   from gnue.reports.base.GRConfig import ConfigOptions as ReportsConfigOptions
-  REPORTS_SUPPORT=1
-except: 
-  REPORTS_SUPPORT=0
+
+  REPORTS_SUPPORT = True
+
+except:
+  REPORTS_SUPPORT = False
   
 
-class GNClient(GClientApp):
+# =============================================================================
+# This class implements the navigator client
+# =============================================================================
+
+class GNClient (GClientApp):
   #
   # GClientApp() overrides
   #
   VERSION = VERSION
   COMMAND = "gnue-navigator"
-  NAME = "GNUe Navigator"
-  USAGE = "[options] file"
-  COMMAND_OPTIONS = [
-      [ 'user_interface', 'u', 'user_interface', 1, None, 'type',
-          'The currently supported values for <type> are ' \
-        + 'wx, gtk2, win32, web (a themable web-like interface), and text' ],
-      [ 'splash_screen','s','no-splash', 0, None, None,
-          'Disables the splash screen'],
-      [ 'gnome_menu',None,'install-gnome-menu', 0, None, None,
-          'Installs a menu structure into your local GNOME session'],
-      [ 'kde_menu',None,'install-kde-menu', 0, None, None,
-          'Installs a menu structure into your local KDE session']
-      ]
-  SUMMARY = \
-     "GNUe Navigator is the primary menuing interface to the GNU Enterprise 
system."
+  NAME    = "GNUe Navigator"
+  USAGE   = "[options] file"
+  SUMMARY = _("GNUe Navigator is the primary menuing interface to the GNU "
+              "Enterprise system.")
 
-  #
+  # ---------------------------------------------------------------------------
   # Initialize the class
-  #
-  def __init__(self, connections=None):
-    GClientApp.__init__(self, connections,'forms', ConfigOptions)
-    
self.configurationManager.loadApplicationConfig(section="navigator",defaults=NavigatorConfigOptions)
+  # ---------------------------------------------------------------------------
+
+  def __init__ (self, connections = None):
+
+    self.addCommandOption ('user_interface', 'u', 'interface', argument = "ui",
+        category = "ui",
+        help = _("The name of the user interface to use to display the "
+                 "navigator. Currently supported interfaces are: wx, gtk2, "
+                 "win32, web and text"))
+
+    self.addCommandOption ('no-splash', 's', category = "ui",
+        help = _("Disables the splash screen"))
+
+    self.addCommandOption ('gnome_menu', None, 'install-gnome-menu',
+        help = _('Installs a menu structure into your local GNOME session'))
+
+    self.addCommandOption ('kde_menu', None, 'install-kde-menu',
+        help = _('Installs a menu structure into your local KDE session'))
+
+
+    GClientApp.__init__ (self, connections, 'forms', ConfigOptions)
+
+    self.configurationManager.loadApplicationConfig (section = "navigator",
+                                             defaults = NavigatorConfigOptions)
     
-    if REPORTS_SUPPORT: 
-      
self.configurationManager.loadApplicationConfig(section="reports",defaults=ReportsConfigOptions)
-      self.configurationManager.registerAlias('gConfigReports', 'reports')
+    if REPORTS_SUPPORT:
+      self.configurationManager.loadApplicationConfig (section = "reports",
+                                               defaults = ReportsConfigOptions)
+      self.configurationManager.registerAlias ('gConfigReports', 'reports')
       
-    self.configurationManager.registerAlias('gConfigNav', 'navigator')
-    self.configurationManager.registerAlias('gConfigForms', 'forms')
+    self.configurationManager.registerAlias ('gConfigNav'  , 'navigator')
+    self.configurationManager.registerAlias ('gConfigForms', 'forms')
 
-    self._formInstances = {}
+    self._formInstances    = {}
     self._lastSerialNumber = 0
 
 
-  #
+  # ---------------------------------------------------------------------------
   # Run the client application
-  #
-  # GClientApp().run() override
-  #
-  def run(self):
+  # ---------------------------------------------------------------------------
 
+  def run (self):
+
     #
     # Initialize user interface
     #
-    self.ui_type = self.OPTIONS['user_interface']
+    self.ui_type = self.OPTIONS ['user_interface']
     if self.ui_type:
-      SPECIFIC_UI = 1
+      SPECIFIC_UI = True
     else:
-      SPECIFIC_UI = 0
-      self.ui_type = gConfigForms('DefaultUI')
+      SPECIFIC_UI = False
+      self.ui_type = gConfigForms ('DefaultUI')
 
-    while 1:
+    while True:
       try:
-        self._ui = dyn_import("gnue.navigator.UI%s" % (self.ui_type))
+        self._ui = dyn_import ("gnue.navigator.UI%s" % self.ui_type)
         break
-      except ImportError, err:
-        GDebug.printMesg(1,_("Unable to load UI driver")+" %s" % self.ui_type)
-        GDebug.printMesg(1,err)
 
+      except ImportError:
+        gDebug (1, "Unable to load UI driver %s" % self.ui_type)
+        gDebug (1, "Error: %s" % errors.getException () [2])
+
         # If user specified a specific UI, don't cycle...
         if SPECIFIC_UI:
-          raise  # TODO: TEMPORARY
-          self.handleStartupError(_("Unable to load any valid UI drivers.  
Aborting.\n\nTraceback\n%s") % err)
+          raise StartupError, \
+              u_("Unable to load any valid UI drivers: %s") \
+              % errors.getException () [2]
 
         if self.ui_type != 'text':
           self.ui_type = 'text'
+
         else:
-          self.handleStartupError(_("Unable to load any valid UI drivers.  
Aborting."))
+          raise StartupError, u_("Unable to load any valid UI driver.")
 
+    # if we have a forms-uidriver available take over it's exception handling
+    # and set the login handler for the connection manager.
+    if hasattr (self._ui, 'ui'):
+      instance = GFInstance (self, self.connections, self._ui.ui, False)
+      self._showException = instance._uiinstance.showException
 
+      loginHandler = self._ui.ui.UILoginHandler ()
+      loginHandler.uiDriver = instance._uiinstance
+      self.connections.setLoginHandler (loginHandler)
+
     #
     # assign menu file from 1st free argument
     #
+    if len (self.ARGUMENTS):
+      processFile = self.ARGUMENTS [0]
+
+    else:
+      basename = os.path.basename (sys.argv [0]).lower ().split ('.') [0]
+      if basename not in ['gnue-navigator','gncvs']:
+        processFile = os.path.join (paths.data, gConfigNav ('ProcessDir'),
+                                    os.path.basename (sys.argv [0])) + ".gpd"
+      else:
+        raise StartupError, u_("No process definition file specified")
+
+
+    fileHandle = openResource (processFile)
     try:
-      processFile = self.ARGUMENTS[0]
-    except:
-      try:
-        if string.split(string.lower(os.path.basename(sys.argv[0])),'.')[0] 
not in ('gnue-navigator','gncvs'):
-          processFile = 
paths.data+'/'+gConfigNav('ProcessDir')+"/"+os.path.basename(sys.argv[0])+".gpd"
-        else:
-          raise IndexError
-      except IndexError:
-        self.handleStartupError ("No Process Definition File Specified.")
+      nav = loadProcesses (fileHandle)
 
+    finally:
+      fileHandle.close ()
 
-    fileHandle = openResource(processFile)
-    nav = loadProcesses (fileHandle)
-    fileHandle.close()
 
-
     # Handle any action commands
-    if self.OPTIONS['kde_menu']:
+    if self.OPTIONS ['kde_menu']:
       from gnue.navigator.Actions import kde_menu
-      kde_menu.run(nav, self.ARGUMENTS[1:])
-      sys.exit()
 
-    if self.OPTIONS['gnome_menu']:
+      kde_menu.run (nav, self.ARGUMENTS [1:])
+      sys.exit ()
+
+    if self.OPTIONS ['gnome_menu']:
       from gnue.navigator.Actions import gnome_menu
-      gnome_menu.run(nav, self.ARGUMENTS[1:])
-      sys.exit()
 
+      gnome_menu.run (nav, self.ARGUMENTS [1:])
+      sys.exit ()
 
-    if gConfigNav('disableSplash') == True:
-      self.disableSplash = 1
+
+    if gConfigNav ('disableSplash'):
+      self.disableSplash = True
     else:
-      self.disableSplash = self.OPTIONS['splash_screen']
+      self.disableSplash = self.OPTIONS ['splash_screen']
 
 
     # add connections object to top object
-    nav._connections=self.connections
+    nav._connections = self.connections
     
-    self._ui.Instance(nav).run(self.connections)
+    self._ui.Instance (nav).run (self.connections)
 
+
+# =============================================================================
+# Main program
+# =============================================================================
+
 if __name__ == '__main__':
-  GNClient().run()
+  GNClient ().run ()
 
 


Property changes on: trunk/gnue-navigator/src/GNClient.py
___________________________________________________________________
Name: svn:keywords
   + Id

Modified: trunk/gnue-navigator/src/UIgtk2.py
===================================================================
--- trunk/gnue-navigator/src/UIgtk2.py  2004-10-21 16:37:59 UTC (rev 6541)
+++ trunk/gnue-navigator/src/UIgtk2.py  2004-10-21 18:55:45 UTC (rev 6542)
@@ -1,7 +1,8 @@
+# GNU Enterprise Navigator - GTK Frontent
 #
-# Copyright 2002-2004 Free Software Foundation
+# Copyright 2001-2004 Free Software Foundation
 #
-# This file is part of GNU Enterprise.
+# This file is part of GNU Enterprise
 #
 # GNU Enterprise is free software; you can redistribute it
 # and/or modify it under the terms of the GNU General Public
@@ -18,436 +19,700 @@
 # write to the Free Software Foundation, Inc., 59 Temple Place
 # - Suite 330, Boston, MA 02111-1307, USA.
 #
-# FILE:
-# UIgtk2.py
-#
-# DESCRIPTION:
-# Set of classes that provide a menuing interface via wxPython
-#
-# NOTES:
-# This file is nothing but a temporary hack.  Navigator should
-# reuse GNUe Form's UI* classes if at all possible.
+# $Id$
 
-
 import pygtk
 pygtk.require('2.0')
 
 import gtk
-import pango
 import gtkhtml2
-import gobject
+import urllib
+import urlparse
+import os
 
-__gtk_mainloop = None
-
-from time import sleep
-import os, sys, string
-from gnue.common.datasources import GDataObjects, GConnections
-from gnue.common.utils.FileUtils import dyn_import, openResource
 from gnue.common.apps import GConfig
+from gnue.common.utils.FileUtils import openResource
 from gnue.navigator import VERSION
+from gnue.navigator import GNParser
 
 try:
   from gnue.forms.GFInstance import GFInstance
-  from gnue.forms import GFParser
   from gnue.forms.uidrivers import gtk2 as ui
-  FORMS_SUPPORT=0
+
 except ImportError:
-  FORMS_SUPPORT=1
+  FORMS_SUPPORT = False
   print 'GNUe Forms is not installed on your system'
 
-images_dir = GConfig.getInstalledBase('forms_images','common_images') + '/'
+images_dir = GConfig.getInstalledBase ('forms_images','common_images') + '/'
 
-import urllib
 
+# =============================================================================
+# This class implements the GTK-UI of the navigator client
+# =============================================================================
 
-class ProcessTree(gtk.TreeView):
-  def __init__(self, processes, on_selected, on_activated):
-    self._callbacks={}
-    self._callbacks['on_selected']=on_selected
-    self._callbacks['on_activated']=on_activated
-    
-    # a) the model
-    self._treeStore = gtk.TreeStore(gobject.TYPE_STRING)
-    self._mapping = {}
-    processes.walk(self.__buildTreeStore)
-    processes.walk(self.__removeNodes)
+class Instance:
 
-    #  b) the widget (i.e. "my-self")
-    gtk.TreeView.__init__(self, self._treeStore)
-    cell = gtk.CellRendererText()
-    column = gtk.TreeViewColumn("tuples", cell, text=0)
-    self.append_column(column)
-    self.connect("row-activated",self._row_activated)
-    self.connect("cursor-changed",self._row_selected)
-    self.set_headers_visible(gtk.FALSE)
-    self.expand_row((0,),gtk.FALSE)
-    self._oldpath=(0,)
+  # ---------------------------------------------------------------------------
+  # Constructor
+  # ---------------------------------------------------------------------------
 
-  def __buildTreeStore(self, object):
+  def __init__ (self, processes):
+    """
+    @param processes: GNObjects tree describing the current loaded gpd
+    """
 
-    if object._type == 'GNProcesses':
-      # add parent (top) object
-      node=self._treeStore.append(None)
-      self._treeStore.set(node, 0, object.title)
-      
-    elif object._type in ('GNStep','GNProcess'):
-      # add child
-      node=self._treeStore.append(object._parent.__node)
-      self._treeStore.set(node, 0, object.title)
-    else:
-      return
+    self.processes         = processes
+    self._formInstances    = {}
+    self._lastSerialNumber = 0
+    self._treeModel        = None
 
-    object.__node = node 
-    self._mapping[self._treeStore.get_path(node)] = object
+    self.__currentURL      = None
+    self.__opener          = urllib.FancyURLopener ()
 
-  ## TODO: Is this necessary?
-  def __removeNodes(self, object):
-    if hasattr(object,"__node"):
-      del object.__node
+    self.app = ui.getApp ()
 
-  def _row_selected(self, tree):
-    (path,column)=self.get_cursor()
-#    print  'selected:', path
-    if path != self._oldpath:
-      self._callbacks['on_selected'](self._mapping[path])
-      self._oldpath=path
+         
+  # ---------------------------------------------------------------------------
+  # Build the UI and start the navigator client
+  # ---------------------------------------------------------------------------
 
-  def _row_activated(self,  view, path, column):
-#    print  'activated:', path
-    
-    # 1. try to expand
-    self.expand_row(path,gtk.FALSE)
-    # 2. pass event further
-    self._callbacks['on_activated'](self._mapping[path])
+  def run (self, connections):
+    """
+    This function creates the user interface and starts the main loop
+    """
 
-  def reload_definitions(self, processes):
-    # remove elements from tree
-    self.treeStore.clear()
-    self._mapping = {}
-    processes.walk(self.__buildTreeStore)
-    processes.walk(self.__removeNodes)
-    self.expand_row((0,),gtk.FALSE)
+    self.connections = connections
 
-class Instance:
-  def __init__(self, processes):
-    self.processes = processes
-    self._formInstances = {}
-    self._lastSerialNumber = 0
+    self.__buildInterface ()
 
-    self.titlePage = _("""
-    <html>
-      <body>
-        <center>
-         <B>GNUe Navigator</B>
-         <p><img src="%s"></p>
-         <p>A part of the <a href="http://www.gnuenteprise.org/";>GNU 
Enterprise Project</a></p>
-        </center>
-      </body>
-    </html>
-    """) % (images_dir+"/ship2.png")
+    # Transform the GNObjects tree into a tree store and activate it
+    self.__treeStore = self.__buildTreeModel (self.processes)
+    self.treeView.set_model (self.__treeStore)
+    self.treeView.expand_row ((0,), False)
+    self.__lastItem = None
 
-    self.app = ui.getApp()
-         
-  def run(self, connections):
-    #
-    # Assign the proper login handler based upon the user interface choice
-    #
-    self.connections = connections
-    self.connections.setLoginHandler(ui.UILoginHandler())
+    self.processes.setClientHandlers ({'form': self.runForm})
 
-    self.mainWindow = gtk.Window()
-    self.mainWindow.set_resizable(gtk.TRUE)
-    self.content_table = gtk.Table(4, 1, gtk.FALSE)
-    self.mainWindow.add(self.content_table)    
-    self.mainWindow.set_title('GNUe Navigator')
-    self.mainWindow.set_default_size(600,400)
-    self.mainWindow.connect('delete_event', self.OnClose)
+    self.treeView.set_cursor ((0,))
 
-    #
+    self.mainWindow.show_all ()
+    self.app.mainLoop ()
+  
+
+  # ---------------------------------------------------------------------------
+  # display a message in the status bar
+  # ---------------------------------------------------------------------------
+
+  def setStatus (self, message = None):
+    """
+    This function removes the last message from the status bar and adds a new
+    one if specified.
+
+    @param message: message to put into the status bar or None
+    """
+
+    self.statusbar.pop (0)
+    if message is not None:
+      self.statusbar.push (0, message)
+
+
+  # ---------------------------------------------------------------------------
+  # Build up the user interface
+  # ---------------------------------------------------------------------------
+
+  def __buildInterface (self):
+    """
+    This function creates the user interface and connects all signal handlers
+    """
+
+    self.mainWindow = gtk.Window ()
+    self.mainWindow.set_resizable (True)
+    self.content_table = gtk.Table (3, 1, False)
+
+    self.mainWindow.add (self.content_table)
+    self.mainWindow.set_title ('GNUe Navigator')
+    self.mainWindow.set_default_size (600, 400)
+    self.mainWindow.connect ('delete_event', self.__windowExit)
+
     # StatusBar
-    #
-    self.statusbar = gtk.Statusbar();
-    self.content_table.attach(self.statusbar,
+    self.statusbar = gtk.Statusbar ()
+    self.content_table.attach (self.statusbar,
                  # X direction           Y direction
-                 0, 1,                   3, 4,
+                 0, 1,                   2, 3,
                  gtk.EXPAND | gtk.FILL,  0,
                  0,                      0)
 
-    #
-    # MenuBar
-    #
-    self.menu = self.createMenuBar()
-    self.content_table.attach(self.menu,
+    # Menu-Bar
+    self.handleBox = gtk.HandleBox ()
+    self.menu = self.__createMenuBar ()
+    self.handleBox.add (self.menu)
+    self.menu.show ()
+
+    self.content_table.attach (self.handleBox,
                  # X direction           Y direction
-                 0, 1,                      0, 1,
-                 gtk.EXPAND | gtk.FILL,     0,
-                 0,                         0)
+                 0, 1,                   0, 1,
+                 gtk.EXPAND | gtk.FILL,  0,
+                 0,                      0)
 
-
-    #
     # main part of window
-    #
-    self.splitter= gtk.HPaned()
-    self.content_table.attach(self.splitter,
+    self.splitter = gtk.HPaned ()
+    self.content_table.attach (self.splitter,
                  # X direction           Y direction
-                 0, 1,                   2, 3,
+                 0, 1,                   1, 2,
                  gtk.EXPAND | gtk.FILL,  gtk.EXPAND | gtk.FILL,
                  0,                      0)
 
-    self.panel1 = gtk.ScrolledWindow()
-    self.panel1.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC)
-    #self.panel1.set_border_width(2)
-    self.panel1.set_shadow_type(gtk.SHADOW_IN)
+    self.treePane = gtk.ScrolledWindow ()
+    self.treePane.set_policy (gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+    self.treePane.set_shadow_type (gtk.SHADOW_IN)
 
-    self.splitter.add1(self.panel1)
+    self.treeView = gtk.TreeView ()
+    self.treeView.set_headers_visible (False)
 
-    self.panel2 = gtk.ScrolledWindow()
-    self.panel2.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC)
-#    self.panel2.set_border_width(2)
-    self.panel2.set_shadow_type(gtk.SHADOW_IN)
-    self.splitter.add2(self.panel2)
+    col = gtk.TreeViewColumn ('Title', gtk.CellRendererText (), text = 0)
+    self.treeView.append_column (col)
+    self.treeView.connect ('row_activated', self.__row_activated)
+    self.treeView.connect ('cursor_changed', self.__row_selected)
 
-    self.splitter.set_position(200)
-    
-    # Panel 1 contents
-    self.tree = ProcessTree(self.processes,
-                            self.loadDescription,
-                            self.executeStep)
-    self.panel1.add(self.tree)
+    self.treePane.add (self.treeView)
 
 
-    # Panel 2 contents
-    self.document = gtkhtml2.Document()
-    self.document.connect('request_url', self.request_url)
-    self.document.connect('link_clicked', self.link_clicked)
-                                                                               
 
-    self.document.clear()
-    self.document.open_stream('text/html')
-    self.document.write_stream(self.titlePage)
-    self.document.close_stream()
-                                                                               
  
-    view = gtkhtml2.View()
-    view.set_document(self.document)
-    self.panel2.add(view)
+    self.splitter.add1 (self.treePane)
+
+    self.viewPane = gtk.ScrolledWindow ()
+    self.viewPane.set_policy (gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+    self.viewPane.set_shadow_type (gtk.SHADOW_IN)
+    self.splitter.add2 (self.viewPane)
+
+    self.view = gtkhtml2.View ()
+    self.view.connect ('on_url', self.__onURL)
+    self.viewPane.add (self.view)
+
+    self.__startNewDocument ()
+
+    self.splitter.set_position (200)
+
+
+  # ---------------------------------------------------------------------------
+  # Create the menu bar
+  # ---------------------------------------------------------------------------
+
+  def __createMenuBar (self):
+    """
+    This function creates the menu bar for the navigator.
+    """
+
+    menu_items = ( \
+        (u_('/_File'), None, None, 0, '<Branch>'),
+        (u_('/_File/_Open'), '<control>O', self.__openFile, 0, '<StockItem>',
+                                                               gtk.STOCK_OPEN),
+        (u_('/_File/_Quit'), '<control>Q', self.__windowExit, 0, '<StockItem>',
+                                                               gtk.STOCK_QUIT),
+
+        (u_('/_Favorites'), None, None, 0, '<Branch>'),
+        (u_('/_Favorites/_Add Favorite'), None, None, 0, ''),
+        (u_('/_Favorites/_Organize Favorites'), None, None, 0, ''),
+ 
+        (u_('/_Help'), None, None, 0, '<Branch>'),
+        (u_('/Help/_About'), None, self.__about, 0, ''),
+      )
+
+    self.accel_group = gtk.AccelGroup ()
+    self.mainWindow.add_accel_group (self.accel_group)
     
-    self.processes.setClientHandlers({'form':self.runForm})
+    self.item_factory = gtk.ItemFactory (gtk.MenuBar, '<main>',
+                                         self.accel_group)
+    
+    self.item_factory.create_items (menu_items, self.mainWindow)
+    
+    return self.item_factory.get_widget ('<main>')
 
-    self.mainWindow.show_all()
-    self.app.mainLoop()
 
+  # ---------------------------------------------------------------------------
+  # Close the navigator
+  # ---------------------------------------------------------------------------
 
-  def request_url(self,obj,url,stream):    
-#    print "request url",url
-    opener = urllib.FancyURLopener()
-    f = opener.open(url)
-    stream.write(f.read())
+  def __windowExit (self, widget, event, data = None):
+    """
+    This function quits the main loop
+    """
 
-  def link_clicked(self,obj,link):
-#    print "Link clicked",link
-    opener = urllib.FancyURLopener()
-    try:
-        f = opener.open(link)
-    except OSError:
-        print "failed to open", link
-        return
-    currentUrl = resolve_uri(link)
-    document.clear()
-    headers = f.info()
-    mime = headers.getheader('Content-type')
-    # TODO: test content type for gnue/process, if yes, load process file into 
tree widget
-    if mime:
-        document.open_stream(mime)
-    else:
-        document.open_stream('text/plain')
-    document.write_stream(f.read())
-    document.close_stream()
+    # TODO: can we keep track of all windows opened ?
+    self.app.quit ()
 
-  def setStatus(self,mesg):
-    self.statusbar.pop(0)
-    self.statusbar.push(0,mesg)
 
-  def OnClose(self, obj, more, muchmore=1):
-    # close down
-    # TODO: use GFgtkAPP instead, so open form widgets wouldn't get closed by 
accident.
-    self.app.quit()
+  # ---------------------------------------------------------------------------
+  # Create a new tree model
+  # ---------------------------------------------------------------------------
 
-  def OnAbout(self, obj, more, muchmore):
-    # TODO: Create a more beautiful about box
-    text = _("GNUE Navigator")+"\n"+      \
-    _("    Version : ")+"%s\n"+         \
-    _("    Driver  : UIgtk2")+"\n"+ \
-    _("-= Process Info =-                  ")+"\n"+        \
-    _("    Name   : ")+"%s\n"+          \
-    _("    Version: ")+"%s\n"+          \
-    _("    Author : ")+"%s\n"+          \
-    _("    Description: ")+"%s\n"
-    dlg = gtk.MessageDialog(self.mainWindow,
-                            gtk.DIALOG_DESTROY_WITH_PARENT + gtk.DIALOG_MODAL,
-                            gtk.MESSAGE_INFO,
-                            gtk.BUTTONS_CLOSE,
-                            text % (VERSION,'-','-','-','-'))
-    dlg.connect('response', lambda dlg, response: dlg.destroy())
-    dlg.show()
+  def __buildTreeModel (self, GNTree):
+    """
+    This function creates a new tree store and populates the given GNObjects
+    tree into that store
 
-  def OnOpen(self, obj, more, muchmore):
-    # TODO: Implement for other uidrivers
-    self.fs=fs=gtk.FileSelection()
-    fs.complete('*.gpd') # todo: make this work
-    fs.hide_fileop_buttons()
-    fs.ok_button.connect('clicked',lambda obj, self: 
self.reloadProcesses(self.fs.get_filename()),self)
-    fs.cancel_button.connect('clicked',lambda obj, self: 
self.fs.destroy(),self)
-    fs.ok_button.connect_after('clicked',lambda obj, self: 
self.fs.destroy(),self)
-    fs.show()
+    @param GNTree: GNObjects tree to be added to the gtk.TreeStore
+    @return: gtk.TreeStore holding the given GNObjects tree. The tree store has
+        two columns: Title of the element, the element instance itself.
+    """
 
-  def reloadProcesses(self,filename):
-    # TODO: 1. finish 2. move this part into ui independent part
-    print filename
-    return
-    self.processes=loadDefinition(filename)
-    self.tree.reload_definitions(self.processes)
+    result = gtk.TreeStore (str, object)
+    GNTree.walk (self.__addToTreeModel, store = result)
 
-  def loadDescription(self,obj):
-    # a) get description
-    newDescr="<HTML><HEAD></HEAD><BODY></BODY></HTML>"
-    for item in obj._children:
-      if item._type == 'GNDescription':
-        newDescr=item.getChildrenAsContent()
-        break
-      
-    # b) write to document
-    self.document.clear()
-    self.document.open_stream('text/html')
-    self.document.write_stream(newDescr)
-    self.document.close_stream()
+    return result
 
 
-  def executeStep(self,step):
-    print "executing step:", step
-    if step._type != 'GNStep':
-      pass
+  # ---------------------------------------------------------------------------
+  # Add an item of a GNObjects tree to the TreeStore
+  # ---------------------------------------------------------------------------
+
+  def __addToTreeModel (self, gnObject, store):
+    """
+    This function adds an item of a GNObjects tree to the given tree store
+
+    @param gnObject: GNObject instance to be added
+    @param store: gtk.TreeStore the gnObject should be added to
+    """
+
+    if gnObject._type == 'GNProcesses':
+      node = store.append (None, [gnObject.title, gnObject])
+
+    elif gnObject._type in ['GNStep', 'GNProcess']:
+      node = store.append (gnObject._parent.__node, [gnObject.title, gnObject])
+
     else:
-      step.run()
+      return
 
-  # Called whenever forms goes into a "wait" state in which user cannot
-  # interact with interface (e.g., while waiting for a query or a commit)
+    # Remember the iterator of the current node
+    gnObject.__node = node
+
+
+  # ---------------------------------------------------------------------------
+  # Activate a row in the tree view
+  # ---------------------------------------------------------------------------
+
+  def __row_activated (self, tree, path, column):
+    """
+    This function is called on the 'row-activated' signal of the tree view,
+    which happens if an element of the tree get's selected by the enter-key or
+    a double-click.
+
+    @param tree: the tree view widget which emitted the signal
+    @param path: the path tuple of the selected item
+    @param column: the tree view column instance which has been activated
+    """
+
+    try:
+      self.beginWait ()
+
+      tree.expand_row (path, False)
+      item = self.__treeStore.get_iter (path)
+
+      # Fetch the associated GN* instance, which is hold in the first column
+      gnObject = self.__treeStore.get_value (item, 1)
+      if gnObject._type == 'GNStep':
+        gnObject.run ()
+
+    finally:
+      self.endWait ()
+
+
+  # ---------------------------------------------------------------------------
+  # A row has been selected in the tree
+  # ---------------------------------------------------------------------------
+
+  def __row_selected (self, tree):
+    """
+    This function get's called when the focus in the tree view widget has
+    changed.
+
+    @param tree: the tree view widget which emitted the signal
+    """
+
+    try:
+      self.beginWait ()
+    
+      (path, column) = tree.get_cursor ()
+      if path != self.__lastItem:
+        self.__lastItem = path
+
+        item     = self.__treeStore.get_iter (path)
+        gnObject = self.__treeStore.get_value (item, 1)
+        descr    = gnObject.findChildOfType ('GNDescription')
+
+        if descr is not None:
+          stream = descr.getChildrenAsContent ()
+        else:
+          stream = self.__getTitlePage ()
+
+        self.__startNewDocument ()
+        self.__loadDocument ('text/html', stream)
+
+    finally:
+      self.endWait ()
+
+
+  # ---------------------------------------------------------------------------
+  # Create a HTML stream with the title page
+  # ---------------------------------------------------------------------------
+
+  def __getTitlePage (self):
+    """
+    This function creates a HTML string containing the title page
+
+    @return: stream with the HTML code for the titlepage
+    """
+
+    return '<HTML><BODY><CENTER><B>GNUe Navigator</B>' \
+           '<p><img src="%s"></p>' \
+           '<p>A part of the <a href="http://www.gnuenterprise.org/";>' \
+           'GNU Enterprise Project</a></p>' \
+           '</center></body></html>' % (images_dir + "/ship2.png")
+
+
+  # --------------------------------------------------------------------------
+  # Change the mouse pointer in an hour-glass
+  # --------------------------------------------------------------------------
+
   def beginWait (self):
-    pass #wxBeginBusyCursor()
+    """
+    This function changes the mouse pointer to an hour glass.
+    """
 
-  # Called whenever forms leaves a "wait" state
+    if self.mainWindow.window is not None:
+      self.mainWindow.window.set_cursor (gtk.gdk.Cursor (gtk.gdk.WATCH))
+
+
+  # --------------------------------------------------------------------------
+  # Change the mouse pointer back to it's normal apperance
+  # --------------------------------------------------------------------------
+
   def endWait (self):
-    pass #wxEndBusyCursor()
+    """
+    This function changes the mouse pointer back to the normal state.
+    """
 
+    if self.mainWindow.window is not None:
+      self.mainWindow.window.set_cursor (gtk.gdk.Cursor (gtk.gdk.LEFT_PTR))
 
-  def getNextSerialNumber (self):
-     self._lastSerialNumber = self._lastSerialNumber + 1
-     return self._lastSerialNumber
 
-  # forms compatibility
-  def handleStartupError(self, mesg):
-    self.handleError(mesg)
-                         
-  def handleError(self, mesg):
-    dlg = gtk.MessageDialog(self.mainWindow,
-                            gtk.DIALOG_DESTROY_WITH_PARENT + gtk.DIALOG_MODAL,
-                            gtk.MESSAGE_ERROR,
-                            gtk.BUTTONS_CLOSE,
-                             "Error: %s!" % mesg)
-    dlg.connect('response', lambda dlg, response: dlg.destroy())
-    dlg.show()
+  # ===========================================================================
+  # gtkhtml stuff
+  # ===========================================================================
 
-  def runFormFromTrigger(self, form, parameters = {}):
-    self.setStatus('running form %s from trigger' % formfile)
-    self._runForm(form, self._params)
 
-  def runForm(self, step, parameters = {}):
-    # This is the code executing in the new thread. Simulation of
-    # a long process (well, 10s here) as a simple loop - you will
-    # need to structure your processing so that you periodically
-    # peek at the abort variable
+  # ---------------------------------------------------------------------------
+  # Start a fresh document
+  # ---------------------------------------------------------------------------
 
-    # TODO: Pass parameters
+  def __startNewDocument (self):
+    """
+    This function creates a new instance of a fresh document, connects the
+    signal handlers and resets the global URL.
+    """
 
-    if os.path.basename(step.location) == step.location:
+    self.__currentURL = None
+    self.document = gtkhtml2.Document ()
+    self.document.connect ('request_url' , self.__requestURL)
+    self.document.connect ('link_clicked', self.__linkClicked)
+
+    self.view.set_document (self.document)
+
+
+  # ---------------------------------------------------------------------------
+  # Load a given stream into the current document
+  # ---------------------------------------------------------------------------
+
+  def __loadDocument (self, contenttype, stream):
+    """
+    This function loads a stream of a given type into the current document
+    which get's cleared first.
+
+    @param contenttype: type of the contents, e.g. 'text/html'
+    @param stream: string with the actual data
+    """
+
+    self.document.clear ()
+    self.document.open_stream (contenttype)
+    self.document.write_stream (stream)
+    self.document.close_stream ()
+
+
+  # ---------------------------------------------------------------------------
+  # Check if a given URL is relative or absolute
+  # ---------------------------------------------------------------------------
+
+  def __isRelativeToServer (self, url):
+    """
+    This function determines wether the given URL is absolute or relative
+
+    @param url: URL to be checked
+    @return: True if URL is relative, False if it is absolute
+    """
+
+    parts = urlparse.urlparse (url)
+    if parts [0] or parts [1]:
+      return False
+
+    return True
+
+
+  # ---------------------------------------------------------------------------
+  # Resolve a URI so we have an absolute one afterwards
+  # ---------------------------------------------------------------------------
+
+  def __resolveURI (self, uri):
+    """
+    This function returns a resolved URI. If it is a relative URL it will be
+    joined with the current 'global' URL.
+
+    @param uri: URI to be resolved
+    @return: complete URI
+    """
+
+    if self.__isRelativeToServer (uri):
+      return urlparse.urljoin (self.__currentURL, uri)
+
+    return uri
+
+
+  # ---------------------------------------------------------------------------
+  # Resolve a given URL and open it
+  # ---------------------------------------------------------------------------
+
+  def __openURL (self, url):
+    """
+    This function opens a given URL and returns a file-like object.
+    @param url: URL to be opened. This URL will be resolved.
+
+    @return: file object for the url.
+    """
+
+    uri = self.__resolveURI (url)
+    return self.__opener.open (uri)
+
+
+  # ---------------------------------------------------------------------------
+  # download a given url into a stream
+  # ---------------------------------------------------------------------------
+
+  def __requestURL (self, document, url, stream):
+    """
+    This function get's called when the given document needs data from an URL.
+    It opens the given URL and writes it's contents into the given stream.
+
+    @param document: the document which requested the resource
+    @param url: the URL from where we can get the resource
+    @param stream: the stream where the result get's written to
+    """
+
+    try:
+      self.beginWait ()
+
+      self.setStatus (u_("Requesting %s" % url))
+      stream.write (self.__openURL (url).read ())
+
+    finally:
+      self.setStatus ()
+      self.endWait ()
+
+
+  # ---------------------------------------------------------------------------
+  # Process the click to a link in the current document
+  # ---------------------------------------------------------------------------
+
+  def __linkClicked (self, document, link):
+    """
+    This function get's called when the user clicks a link in the given
+    document. The specified URL will then be loaded and displayed in the
+    current document.
+
+    @param document: the document where the link should be displayed in
+    @param link: URL of the link which has been selected
+    """
+
+    try:
+      self.beginWait ()
+
+      fhd = self.__openURL (link)
+      self.__currentURL = self.__resolveURI (link)
+
+      headers = fhd.info ()
+      document.clear ()
+
+      ctype = headers.getheader ('Content-type') or 'text/plain'
+      document.open_stream (ctype)
+      document.write_stream (fhd.read ())
+      document.close_stream ()
+
+    finally:
+      self.endWait ()
+
+
+  # ---------------------------------------------------------------------------
+  # On URL
+  # ---------------------------------------------------------------------------
+
+  def __onURL (self, view, url):
+    """
+    This function get's called when the mouse is over an url. This url get's
+    displayed in the status bar. If the mouse has left the url this function
+    will be called with an url value of None.
+    """
+
+    self.setStatus (url)
+
+  # ---------------------------------------------------------------------------
+  # Run a form
+  # ---------------------------------------------------------------------------
+
+  def runForm (self, step, parameters = {}):
+    """
+    This function runs a GNStep with a GNUe Form definition.
+
+    @param step: the GNStep instance describing the form
+    @param paramters: dictionary with user parameters for the form
+    """
+
+    # TODO: this code *should* be executed in a new thread.
+    if os.path.basename (step.location) == step.location:
       try:
-        formdir = gConfigNav('FormDir')
+        formdir = gConfigNav ('FormDir')
+
       except KeyError:
         formdir = ""
-      formfile = formdir+"/"+step.location
+
+      formfile = os.path.join (formdir, step.location)
+
     else:
       formfile = step.location
 
-    self.setStatus('running form %s' % formfile)
-    self._runForm(formfile, parameters)
+    try:
+      self.beginWait ()
+      self.setStatus ('running form %s' % formfile)
+      self._runForm (formfile, parameters)
 
+    finally:
+      self.endWait ()
+      self.setStatus ()
 
-  def _runForm(self, formfile, parameters):
+
+  # ---------------------------------------------------------------------------
+  # Run a form from a trigger
+  # ---------------------------------------------------------------------------
+
+  def runFormFromTrigger (self, form, parameters = {}):
+    """
+    This function runs a form from trigger code.
+
+    @param form: URL of the form
+    @param parameters: dictionary with user parameters for the form
+    """
+
     try:
-      #
-      # Create the instance
-      #
-      #instance = GFInstance(id(self),
-      #    connections=self.connections,
-      #    ui=ui, disableSplash=1)
-      instance = GFInstance(self,connections=self.connections,
-                            ui=ui,disableSplash=1, parameters=parameters)
-      self._formInstances[id(self)] = instance
+      self.beginWait ()
+      self.setStatus ('running form %s from trigger' % formfile)
+
+      self._runForm (form, self._params)
+
+    finally:
+      self.endWait ()
+      self.setStatus ()
+
+
+  # ---------------------------------------------------------------------------
+  # Do the dirty work of running a form
+  # ---------------------------------------------------------------------------
+
+  def _runForm (self, formfile, parameters):
+    """
+    This function starts a new form.
+
+    @param formfile: URL of the form to be started
+    @param parameters: dictionary with user parameters for the form
+    """
+
+    instance = GFInstance (self, self.connections, ui, True, parameters)
+    self._formInstances [id (self)] = instance
          
-      #
-      # Build the form tree
-      #
-      instance.addFormFromFile(formfile)
+    instance.addFormFromFile (formfile)
+    instance.addDialogs ()
+    instance.activate ()
 
-      #
-      # Start the instance
-      #
-      instance.addDialogs()
-          
-      #instance.buildForm(form)
-      instance.activate()
 
-    except GConnections.Error, mesg:
-      self.handleError(mesg)
+  # ---------------------------------------------------------------------------
+  # Open another process definition file
+  # ---------------------------------------------------------------------------
 
-    except IOError, mesg:
-      self.handleError(_("Unable to open file\n\n     %s")%mesg)
+  def __openFile (self, obj, more, muchmore):
+    """
+    This function displays a 'FileSelection' dialog to select other GPD files.
+    If a file was selected it will be loaded into a new process tree.
+    """
 
-    except GDataObjects.ConnectError, mesg:
-      self.handleError(\
-         _("Unable to login to datasource.\n\n       %s") %mesg)
+    self.filesel = gtk.FileSelection ( \
+        u_("Select another process definition file"))
+    self.filesel.ok_button.connect ('clicked', \
+        lambda w, self: self.__reload (self.filesel.get_filename ()), self)
+    self.filesel.cancel_button.connect ('clicked', \
+        lambda obj, self: self.filesel.destroy (), self)
+    self.filesel.hide_fileop_buttons ()
+    self.filesel.complete ('*.gpd')
 
-    except GDataObjects.ConnectionError, mesg:
-      self.handleError(\
-         _("Error while communicating with datasource.\n\n       %s") %mesg)
+    self.filesel.show ()
 
-    except GDataObjects.Error, mesg:
-      self.handleError(mesg)
-    print 'closed'
 
+  # ---------------------------------------------------------------------------
+  # Load another process definition file
+  # ---------------------------------------------------------------------------
 
-  def createMenuBar(self):    
+  def __reload (self, filename):
+    """
+    This function loads a new process tree from the given filename and replaces
+    the current tree view with the new process tree.
 
-    menu_items = (
-      ('/_File',            None,         None,        0, '<Branch>' ),
-#      ('/File/_New',        '<control>N', menuitem_cb, 0, '<StockItem>', 
gtk.STOCK_NEW),
-      ('/File/_Open',       '<control>O', self.OnOpen, 0, '<StockItem>', 
gtk.STOCK_OPEN),
-#      ('/File/_Save',       '<control>S', menuitem_cb, 0, '<StockItem>', 
gtk.STOCK_SAVE),
-#      ('/File/Save _As...', None,         menuitem_cb, 0, '<StockItem>', 
gtk.STOCK_SAVE),
-      ('/File/_Quit',       '<control>Q', self.OnClose, 0, '<StockItem>', 
gtk.STOCK_QUIT),
-      
-      ('/_Favorites',          None,        None,  0, '<Branch>'),
-      ('/_Favorites/_Add Favorite',       None,        None,  0, ''),
-      ('/_Favorites/_Organize Favorites', None,        None,  0, ''),
- 
-      ('/_Help',               None,        None,  0, '<Branch>'),
-      ('/Help/_About',         None, self.OnAbout, 0,''),
-      )
+    @param filename: name of the GPD file to be loaded
+    """
 
-    self.accel_group = gtk.AccelGroup()
-    self.mainWindow.add_accel_group(self.accel_group)
-    
-    self.item_factory = gtk.ItemFactory(gtk.MenuBar, '<main>', 
self.accel_group)
-    
-    self.item_factory.create_items(menu_items, self.mainWindow)
-    
-    return self.item_factory.get_widget('<main>')
+    if self.filesel is not None:
+      self.filesel.destroy ()
 
+    fhd = openResource (filename)
+
+    try:
+      processes = GNParser.loadProcesses (fhd)
+      newModel  = self.__buildTreeModel (processes)
+      self.processes = processes
+      self.__treeStore = newModel
+      self.treeView.set_model (newModel)
+      self.treeView.expand_row ((0,), False)
+      self.treeView.set_cursor ((0,))
+      self.treeView.grab_focus ()
+
+    finally:
+      fhd.close ()
+
+
+  # ---------------------------------------------------------------------------
+  # Display a nice about message
+  # ---------------------------------------------------------------------------
+
+  def __about (self, obj, more, muchmore):
+    """
+    This function displays an about box.
+    """
+
+    text = _("GNUE Navigator")+"\n"+      \
+    _("    Version : ")+"%s\n"+         \
+    _("    Driver  : UIgtk2")+"\n"+ \
+    _("-= Process Info =-                  ")+"\n"+        \
+    _("    Name   : ")+"%s\n"+          \
+    _("    Version: ")+"%s\n"+          \
+    _("    Author : ")+"%s\n"+          \
+    _("    Description: ")+"%s\n"
+    dlg = gtk.MessageDialog(self.mainWindow,
+                            gtk.DIALOG_DESTROY_WITH_PARENT + gtk.DIALOG_MODAL,
+                            gtk.MESSAGE_INFO,
+                            gtk.BUTTONS_CLOSE,
+                            text % (VERSION,'-','-','-','-'))
+    dlg.connect ('response', lambda dlg, response: dlg.destroy ())
+    dlg.show ()


Property changes on: trunk/gnue-navigator/src/UIgtk2.py
___________________________________________________________________
Name: svn:keywords
   + Id





reply via email to

[Prev in Thread] Current Thread [Next in Thread]