[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[gnue] r8929 - in trunk/gnue-designer: . src src/app src/base src/forms
From: |
jcater |
Subject: |
[gnue] r8929 - in trunk/gnue-designer: . src src/app src/base src/forms src/standalone utils |
Date: |
Wed, 25 Oct 2006 18:59:36 -0500 (CDT) |
Author: jcater
Date: 2006-10-25 18:59:35 -0500 (Wed, 25 Oct 2006)
New Revision: 8929
Added:
trunk/gnue-designer/src/base/document.py
trunk/gnue-designer/src/base/parsertoobj.py
trunk/gnue-designer/src/standalone/
trunk/gnue-designer/src/standalone/__init__.py
trunk/gnue-designer/utils/
trunk/gnue-designer/utils/package_standalone_definitions.py
Removed:
trunk/gnue-designer/src/base/Document.py
Modified:
trunk/gnue-designer/src/app/documents.py
trunk/gnue-designer/src/forms/document.py
Log:
* Added a script to be run when packaging Designer releases
(utils/package_standalone_definitions.py) that takes the tool's G*Parser.py
files and creates standalone versions using proxy classes, so designer does not
require each individual tool to be installed
* Misc cleanup as I get back into coding
Modified: trunk/gnue-designer/src/app/documents.py
===================================================================
--- trunk/gnue-designer/src/app/documents.py 2006-10-25 16:22:31 UTC (rev
8928)
+++ trunk/gnue-designer/src/app/documents.py 2006-10-25 23:59:35 UTC (rev
8929)
@@ -35,19 +35,19 @@
document_types = []
-class Properties:
- """
+class Properties:
+ """
A container class to hold our property values
"""
pass
-def register_document_type(instance, name, title,
- fileExtensions, defaultFileExtension="",
+def register_document_type(instance, name, title,
+ fileExtensions, defaultFileExtension="",
description="", nickname="", xmlOpeningTag=""):
"""
- Register a new document handler.
- """
+ Register a new document handler.
+ """
properties = Properties()
properties.instance = instance
properties.name = name
@@ -58,12 +58,12 @@
properties.defaultFileExtension = defaultFileExtension or \
fileExtensions.keys()[0]
properties.xmlOpeningTag = xmlOpeningTag
-
+
document_types.append(properties)
- if instance:
+ if instance:
document_types_valid.append(properties)
- else:
+ else:
document_types_invalid.append(properties)
-
+
return properties
Deleted: trunk/gnue-designer/src/base/Document.py
===================================================================
--- trunk/gnue-designer/src/base/Document.py 2006-10-25 16:22:31 UTC (rev
8928)
+++ trunk/gnue-designer/src/base/Document.py 2006-10-25 23:59:35 UTC (rev
8929)
@@ -1,891 +0,0 @@
-# GNU Enterprise Designer - Basic Framework
-#
-# Copyright 2001-2006 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
-# version 2, or (at your option) any later version.
-#
-# GNU Enterprise is distributed in the hope that it will be
-# useful, but WITHOUT ANY WARRANTY; without even the implied
-# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-# PURPOSE. See the GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public
-# License along with program; see the file COPYING. If not,
-# write to the Free Software Foundation, Inc., 59 Temple Place
-# - Suite 330, Boston, MA 02111-1307, USA.
-#
-# $Id$
-
-"""
-This is the base instance class for a designer session. Every
-open file will be associated with its own document instance.
-"""
-
-__all__ = ['BaseInstance']
-
-# -----------------------------------------------------------------
-# System imports
-# -----------------------------------------------------------------
-import sys
-import os
-import time
-import dircache
-import new
-
-# -----------------------------------------------------------------
-# GNUe Imports
-# -----------------------------------------------------------------
-from gnue.common.apps import GDebug
-from gnue.common.apps import RuntimeSettings
-from gnue.common.utils.FileUtils import dyn_import
-from gnue.common.events import EventController, Event
-
-from gnue.designer.base.MenuBar import MenuBar
-from gnue.designer.base.UndoManager import UndoManager
-from gnue.designer.base.tools import TriggerEditor
-from gnue.designer.base.ToolBase import ToolBase
-from gnue.designer.base.ObjectList import ObjectList
-from gnue.designer.base import TemplateBase
-from gnue.designer.base.TemplateParser import WizardRunner
-from gnue.designer import VERSION, PACKAGE as TITLE
-
-from gnue.designer.app.documents import document_types_valid
-
-
-# ===================================================================
-# Base document class
-# ===================================================================
-class BaseDocument(EventController):
-
-
- # ===============================================================
- # Virtual functions (Override these functions in your Instance)
- # ===============================================================
- wizardRunner = WizardRunner
-
- def init(self):
- """
- initialize the instance (called at the
- beginning of the __init__ process)
- """
-
- def init(self):
- """
- Finalize the instance (called at the
- end of the __init__ process)
- """
-
- def loadFile(self, buffer):
- """
- Called to load the object from a file buffer/handle
- """
- return None
-
- def loadEmpty(self, style=None):
- """
- Called to load an "empty" (new) object. Create the root
- object and any initial child objects (if appropriate)
- """
- return None
-
- def inventoryObject(self, object):
- """
- Called in a tree-like fashion for every object
- whether loaded in the beginning or later added.
- """
- pass
-
- def preSave(self):
- """
- Called just before saving the file using GObject's dumpTree
- You might do some sanity checks, etc.
- """
- return
-
- def createTools(self):
- """
- Add any ToolBase instances
- """
- pass
-
- def createEditors(self):
- """
- Add any EditorComponent instances
- """
- pass
-
- def createWizards(self):
- """
- Add any runtime-loadable wizards/tools
- """
- pass
-
- def initMenu(self):
- """
- Add any tool-specific functions to the menu bar
- """
- pass
-
- def initToolBar(self):
- """
- Add any tool-specific functions to the tool bar
- """
- pass
-
-
- def buildWizardCurrentDict(self):
- """
- Used by TemplateParser to build a wizard.current dict
- """
- return {'object': self._currentObject}
-
-
- # ===============================================================
- # Public Functions
- # ===============================================================
-
-
- # ---------------------------------------------------------------
- # Register interface elements
- # ---------------------------------------------------------------
- def addTool(self, id, title, baseclass, hotkey=None, menuGroup=499):
- """
- Add a ToolBase instance
- """
- self._toolCache.append((id, title, baseclass, hotkey, menuGroup))
-
-
- def registerEditor(self, baseclass, gtype, filter=None):
- """
- Register an editor class
-
- Parameters:
-
- baseclass: An EditorComponent class
-
- gtype: A string indicating a GObject._type identifier,
- or a list of such strings.
-
- filter: A function that is passed a GObject and should
- return True/False indicating if an editor instance
- should be created.
-
- """
- if isinstance(gtype,basestring):
- gtype = [gtype]
- for gtype1 in gtype:
- self._editorMapping[gtype1] = (filter, baseclass)
-
-
- # ---------------------------------------------------------------
- # Set the saved/unsaved status
- # ---------------------------------------------------------------
-
- def save(self):
-
- if self.preSave():
- print "Not saving definition"
- return
-
- location = self._path
- fileHandle = None
- fileHandle2 = None
- if self._makeBackup:
- try:
- fileHandle = open(location,'r')
- fileHandle2 = open(location + "~",'w')
- fileHandle2.writelines(fileHandle.readlines())
- except:
- pass
- else:
- if fileHandle != None:
- fileHandle.close()
- if fileHandle2 != None:
- fileHandle2.close()
-
- self._makeBackup = 0
-
- fileHandle = open(location,'w')
-
- fileHandle.write('<?xml version="1.0" encoding="UTF-8"?>\n\n')
-
- for comment in self.rootObject._rootComments:
- if comment.find(TITLE) > 0:
- self.rootObject._rootComments.remove(comment)
-
- # Place a timestamp in the XML as a comment
- # TODO: Replace with Dublin Core?
- fileHandle.write(('<!-- %s (%s)\n%s Saved on: %s -->\n\n' \
- % (TITLE, VERSION, (len(self.wizardName) and (
- " Created by " + self.wizardName + "\n") or ""),\
- time.strftime("%Y-%m-%d %H:%M:%S",
- time.localtime(time.time())))).encode('UTF-8'))
-
- fileHandle.write(''.join(["<!--%s-->\n\n" % comment.encode('UTF-8') \
- for comment in self.rootObject._rootComments]))
-
-
fileHandle.write(self.rootObject.dumpXML(treeDump=True).encode('UTF-8'))
- fileHandle.close()
-
- self.app.mru.addLocation(location)
- self.makeClean()
-
-
- # Mark our form as "dirty" (unsaved changes)
- def makeDirty(self):
- if not self._isdirty:
- self._isdirty = True
- if self._path == "":
- self.ui.setTitle( u_("Untitled %s*") %
self.properties.nickname)
- else:
- self.ui.setTitle(self._path + "*")
- self.dispatchEvent('MakeDirty')
-
-
- # Mark our form as "clean" (no unsaved changes)
- def makeClean(self):
- self._isdirty = 0
- self._isnew = 0
- if self._path == "":
- self.ui.setTitle( u_("Untitled %s") % self.properties.nickname)
- else:
- self.ui.setTitle( self._path)
- self.dispatchEvent('MakeClean')
-
-
- # ---------------------------------------------------------------
- # GObject convenience methods
- # ---------------------------------------------------------------
- def getNextGenericName (self, type):
- return self.getUniqueName(type.capitalize() + '1')
-
-
- def getUniqueName(self, name, limitingObject=None):
-
- try:
- usedNames = limitingObject.usedNames
- except:
- usedNames = self.usedNames
-
- if name.lower() not in usedNames:
- usedNames.append(name.lower())
- return name
-
- index = len(name) - 1
-
- while index > 0 and '0' <= name[index] <= '9':
- index -= 1
-
- index += 1
- if index >= len(name):
- start = 1
- base = name
- else:
- start = int(name[index:])
- base = name[:index]
-
- while ("%s%s" % (base, start)).lower() in usedNames:
- start += 1
-
- rv = "%s%s" % (base, start)
- usedNames.append(rv.lower())
- if rv.lower() not in self.usedNames:
- self.usedNames.append(rv.lower())
- return rv
-
-
- # ---------------------------------------------------------------
- # Return, or create, an ObjectList based on the xml tag
- # ---------------------------------------------------------------
- def getObjectList(self, tag):
- try:
- return self.objectLists[tag]
- except KeyError:
- defin = self.incubator.elements[tag]
- baseClass = defin['BaseClass']
-
- # Determine the "name" attribute"
- nameAttr = None
- try:
- if defin['Attributes'].has_key('name'):
- nameAttr = 'name'
- else:
- for attribute, props in defin['Attributes'].items():
- try:
- if props['Unique']:
- nameAttr = attribute
- break
- except KeyError:
- pass
- except KeyError:
- pass
-
- list = ObjectList(self, baseClass, nameAttr)
- self.objectLists[tag] = list
- return list
-
-
- # ================================================================
- # Private functions
- # ================================================================
-
- def __init__(self, app, properties, location=None,
- buffer=None, style=None):
- EventController.__init__(self)
-
- self.app = app
- self.properties = properties
-
- # During startup, we will cache all events
- # so we can execute them when everything has
- # been initialized.
- self.startCachingEvents()
-
- self.ui = app.ui.createInstance(self)
-
- # Local variables
- self.wizardName = ""
- self._isdirty = False
- self._makeBackup = True
- self._isNew = True
- self.connections = app.connections
- self.nameMappings = {}
- self.usedNames = []
-
- # Create the supplemental tools
- self._toolCache = []
- self._editorMapping = {}
- self._pages = []
- self.objectLists = {}
- self._path = ""
-
- self.globalAccelerators = []
- self.globalAcceleratorListeners = []
-
- self._nameMappers = {} # {GDataSource: {'name': [(GFBlock,'name')]}}
-
-
- self.registerEventListeners({
- # Menu/Toolbar stuff
- 'RequestSave' : self._OnSave,
- 'RequestSaveAs' : self._OnSaveAs,
- 'RequestClose' : self._OnClose,
-
- # Object stuff
- 'ObjectSelected' :
self.__object_selected_event,
- 'ObjectCreated' : self.__object_created_event,
- 'ObjectModified' :
self.__object_modified_event,
- 'ObjectDeleted' : self.__object_deleted_event,
- })
-
-
- # Call the document-specific init method
- self.init()
-
- # Register ourself with RuntimeSettings
- RuntimeSettings.init(configFilename="gnue-des.ini",
- homeConfigDir=".gnue")
- RuntimeSettings.registerInstance(self)
-
- # Tell RuntimeSettings that we have information to save
- self.runtime_section = self.properties.nickname + 'Layout'
- RuntimeSettings.registerRuntimeSettingHandler(self, self)
-
- # And the "Most Recenty Used" manager
- RuntimeSettings.registerRuntimeSettingHandler(self, app.mru)
-
- # Set up the Undo/Redo Manager
- UndoManager(self)
-
- # Load any files specified on the command
- # line, or create a new document
- if location == None:
-
- if buffer != None:
- self.__loadFromBuffer(buffer)
- self.makeDirty()
- else:
- self.__createEmptyInstance(style)
-
- else:
- if not os.access (location, os.R_OK):
- self.show()
- if not self.app.ui.dialogYesNo(
- u_('The requested file does not exist.\n') +
- u_('Do you want to create this file?') +
- u_('\n\nFile: %s') \
- % location, u_("File Not Found"), self.ui):
- # TODO: Is this right?
- sys.exit()
- self.hide()
- self.__createEmptyInstance(style)
- self._path = location
- self.makeDirty()
-
- elif not os.access (location, os.W_OK):
- self.show()
- if not self.app.ui.dialogCancel(
- u_('The requested file is Read Only.\n') +
- u_('To save any changes, you will \n') +
- u_('be required to do a "Save As..."\n\nFile: %s') \
- % location, u_("Read Only Warning"), self.ui) :
- # TODO: Is this right?
- sys.exit()
- self.hide()
- self.__loadFromFile(location)
- else:
- self.__loadFromFile(location)
-
- self.menubar = MenuBar(self)
-
-
- gStartupStatus(u_('Creating User Interface'))
-
- # Set up the menu system
- # ... our common menu
- self._initMenu()
- # ... and the document-centric menu
- self.initMenu()
-
- self.createWizards()
-
- # Set up the editor components...
- # ... common
- self.registerEditor(TriggerEditor.TriggerEditor, 'GCTrigger',
- TriggerEditor.EditorFilter)
- # ... and document-centric
- self.createEditors()
-
- # Create the document-centric tools
- self.createTools()
-
- # And tell the UI driver to create the UI portions
- self.ui.initTools()
-
- # Finalize menu bar
- self.menubar.finalize()
- self.app.mru.addMenu(self.menubar.getMenu('File|Open Recent|'), self)
-
- self.toolbar = self.ui.toolbar
- self.initToolBar()
-
- # TODO: This is a hack to disable any menu items
- # TODO: for actions we've yet to implement
- for action in ('RequestRevert','RequestRedo','RequestCopy',
- 'RequestPaste','RequestPasteSpecial','RequestCut'):
- self.dispatchEvent('Disable:%s' % action)
-
-
- # Add ourselve to the main app's instance list
- self.app.addDocument(self)
-
-
- self.dispatchEvent('ObjectSelected', originator=self,
- object=self.rootObject)
-
- # Inventory the objects
- gStartupStatus(u_('Inventorying Document Objects'))
- self.rootObject.walk(self.__inventory)
-
- self.finalize()
- self.ui.finalize()
-
- self.stopCachingEvents()
-
-
- def _initMenu(self):
- # Add the [sub]menus
- for location, text, grouping in (
- ('File', u_('&File'), 100),
- ('File|New', u_('&New'), 100),
- ('File|Open Recent', u_('&Open Recent'), 200.1),
- ('File|Connect To', u_('&Connect To'), 400),
- ('Edit', u_('&Edit'), 200),
- ('Insert',u_('&Insert'), 300),
- ('Modify',u_('&Modify'), 400),
- ('Tools',u_('&Tools'), 500),
- ('View',u_('&View'), 800),
- ('Help',u_('&Help'), 999)):
-
- self.menubar.addMenu(location, text, grouping)
-
- for location, event, text, hotkey, help, grouping in (
- ('File', 'RequestOpen', u_('&Open'), 'Ctrl+O',
- u_("Open an existing document"), 200.1),
- ('File|Open Recent', 'XXXX', u_('&Foo'), None,
- u_("This is a placeholder for the Open Recent menu"), 200.1),
- ('File|New', 'RequestNewWizard', u_('From &Wizard...'), None,
- u_("Create a new document using a wizard"), 900.1),
- ('File', 'RequestSave', u_("&Save"), 'Ctrl+S',
- u_("Save the current document"),300.1),
- ('File', 'RequestSaveAs', u_("Save &As..."),None,
- u_("Save the current document under a new name"), 300.2),
- ('File', 'RequestSaveAll', u_("Save A&ll"),None,
- u_("Save all open document"),300.3),
- ('File', 'RequestRevert', u_("Reload"), None,
- u_("Reload the current document as of its last save " + \
- "(abandoning any changes)"), 500),
- ('File', 'RequestClose', u_("&Close"), 'Ctrl+W',
- u_("Close the current document"), 990),
- ('File', 'RequestExit', u_("E&xit"), None,
- u_("Exit GNUe Designer"), 995),
- ('Edit', 'RequestUndo', u_("&Undo"), 'Ctrl+Z',
- u_("Undo the last action"), 100.1),
- ('Edit', 'RequestRedo', u_("&Redo"), 'Ctrl+Y',
- u_("Redo the last undo action"), 100.2),
- ('Edit', 'RequestCut', u_("Cu&t"), 'Ctrl+X',
- u_("Cut the current object and move to the clipboard"), 200.1),
- ('Edit', 'RequestCopy', u_("&Copy"), 'Ctrl+C',
- u_("Copy the current object to the clipboard"), 200.2),
- ('Edit', 'RequestPaste', u_("&Paste"), 'Ctrl+V',
- u_("Paste the current object on the clipboard"), 200.3),
- ('Edit', 'RequestPasteSpecial', u_("Paste &Special..."), None,
- u_("Paste the current object on the clipboard " + \
- "with special attributes"), 200.4),
- ('Modify','RequestDelete', u_("&Delete Item"), 'Delete',
- u_("Delete the current object"),100),
- ('Help', 'RequestAbout', u_("&About GNUe Designer"), None,
- u_("More information about GNUe Designer"), 900),
- ):
- self.menubar.addAction(location, text, event,
- grouping, canDisable=True,
- icon=None, hotkey=hotkey, help=help)
-
- # Add supported tools to File|New
- for tool in document_types_valid:
- self.menubar.addAction(
- 'File|New', '&%s' % tool.nickname,
- 'RequestNew', 100,
- help=u_('Create a new %s') % tool.description,
- eventdata={'type': tool.instance})
-
- # Add connections
- for conn in self.connections.getAllConnectionParameters().keys():
- self.menubar.addAction('File|Connect To', conn,
- 'Connect:%s' % conn,
- help=u_("Login to %s connection") % conn,
- eventdata={'connection': conn})
- self.registerEventListeners(
- {'Connect:%s' % conn: self.__OnConnectTo})
-
-
- def __loadFromFile(self, location):
- try:
- self._path = location
- fileHandle = open(location,'r')
- self.__loadFromBuffer(fileHandle)
- fileHandle.close()
- self.makeClean()
- self._isNew = 0
- except IOError, msg:
- print "\n%s %s\n\nUnable to open file '%s'. \n" + \
- "Unexpected read error:\n %s.\n" % (
- TITLE, VERSION, location, msg)
- sys.exit()
- self.app.mru.addLocation(location)
-
-
- def addNameMapper(self, instance, attribute, childinst, childattr):
- try:
- instm = self._nameMappers[instance]
- except KeyError:
- instm = {}
- self._nameMappers[instance] = instm
- try:
- attrm = instm[attribute]
- except KeyError:
- attrm = []
- instm[attribute] = attrm
- attrm.append ( (childinst, childattr) )
-
-
- def __loadFromBuffer(self, fileHandle):
- self.rootObject = self.loadBuffer(fileHandle)
-
-
- def __createEmptyInstance(self, style):
- self.rootObject = self.loadEmpty(style)
- self.makeClean()
- self._isNew = True
-
-
- # ---------------------------------------------------------------
- #
- # ---------------------------------------------------------------
- #
- # Used by RuntimeSettings
- #
- def saveRuntimeSettings(self):
- return ( self.runtime_section, self.ui.getRuntimeSettings() )
-
-
- # ---------------------------------------------------------------
- #
- # ---------------------------------------------------------------
- # Do we need to be saved?
- def isDirty(self):
- return self._isdirty
-
-
- # ---------------------------------------------------------------
- #
- # ---------------------------------------------------------------
- # Take an object and mangle it all up
- # until it is useful to us
- def __inventory (self, object):
-
- # Add a GObjectHelper to intercept __getitem__ calls on GObject
- add_GObject_hooks(object, self)
-
- if object != self.rootObject:
-
- # Assign an ID if none exists
- if hasattr(object, 'name'):
- if object.name == None or object.name.startswith(object._type):
- object.name = self.getNextGenericName(object._type[2:])
- self.nameMappings[object.name.lower()] = object
- self.usedNames.append(object.name.lower())
-
- # Do we create an EditorComponent instance?
- if object._type in self._editorMapping.keys():
- filter = self._editorMapping[object._type][0]
- if filter is None or filter(object):
- self.ui.createEditor(object,
- *self._editorMapping[object._type][1:])
-
- # Now, give the tool-specific instances a chance
- object.dispatch_designer_event('InventoryObject')
- self.inventoryObject(object)
-
-
- def __object_selected_event (self, event):
- object = event.object
- handler = event.originator
- self._currentObject = object
-
- def __object_created_event (self, event):
- self.__inventory(event.object)
- self.makeDirty()
-
- def __object_modified_event (self, event):
- object = event.object
- # Check for any name dependencies
- # (i.e., GFEntry is dependent on GFBlock.name and GFField.name)
- # Automatically create any change events for the child objects
- if hasattr(object, '_nameDependencies'):
- for key in object._nameDependencies.keys():
- masterattr, slaveattr = object._nameDependencies[key]
- if masterattr in event.new.keys():
- key[slaveattr] = object[masterattr]
-
- self.makeDirty()
-
-
- def __object_deleted_event (self, event):
- object = event.object
-
- # Delete the actual object from its parent
- object.getParent()._children.remove(object)
-
- self.makeDirty()
-
-
-
- def __OnConnectTo(self, event):
- conn = event.connection
- try:
- tempDO = self.connections.getConnection(conn, 'object')
- self.dispatchEvent('ConnectionEstablished',connection=conn)
- self.dispatchEvent('Disable:Connect:%s' % conn)
- except:
- print u_("Unable to connect to %s") % conn
-
-
- # ---------------------------------------------------------------
- #
- # ---------------------------------------------------------------
- def _OnSave(self, event):
- if not len(self._path):
- self._OnSaveAs(event)
- else:
- self.save()
-
-
- def _OnSaveAs(self, event):
- wildcards = []
- # Make the "default" file extension for a tool
- # appear before the other extensions.
- filterIndex = [self.properties.defaultFileExtension]
- wildcards += [
- ( self.properties.defaultFileExtension,
-
self.properties.fileExtensions[self.properties.defaultFileExtension]) ]
-
- for type in self.properties.fileExtensions.keys():
- if type != self.properties.defaultFileExtension:
- wildcards += [
- ( type, self.properties.fileExtensions[type]) ]
- filterIndex.append(type)
-
- path = self.app.ui.dialogSaveFile(
- u_("Save %s As...") % self.properties.description,
- wildcards=wildcards,
- parentWindow=self.ui)
-
- if path:
- if os.path.isfile(path):
- overwrite = self.app.ui.dialogYesNo(
- u_('The file "%s".\n' % path) +
- u_("exists. Overwrite?"),
- u_("Unsaved Changes"),
- icon="warn", parentWindow=self.ui)
- if not overwrite:
- self.OnSaveAs(event)
- return
-
- self._path = path
- self.ui.setTitle (self._path)
- self.save()
-
-
-
- def _OnClose(self, event):
- if self.isDirty():
- save = self.app.ui.dialogYesNoCancel(
- u_("This document has unsaved changes.\n") +
- u_("Save changes before closing?"),
- u_("Unsaved Changes"), icon="warn", parentWindow=self.ui)
- if save == True:
- self.OnSave(event)
- elif save == -1:
- event.Veto()
- return
-
- RuntimeSettings.saveRuntimeSettings(self)
- self.app.mru.removeMenu(
- self.menubar.getMenu('File|Open Recent|'), self)
- self.app.removeDocument(self)
- self.dispatchEvent('DocumentClosing')
- self.ui.close()
-
-
- # ---------------------------------------------------------------
- #
- # ---------------------------------------------------------------
- def loadWizards(self, package):
- templates = []
-
- basedir = os.path.dirname(package.__file__)
- processed = [] # Base file names processed (e.g., base of Simple.py*
- # is Simple) This will keep us from importing Simple
- # three times if Simple.py, Simple.pyc, and Simple.lib
- # all exist.
-
- for dir in dircache.listdir(basedir):
- base = dir.split('.')[0]
- if not dir[0] in ('.','_') and not base in processed:
- processed.append(base)
- try:
- templates.append(dyn_import(
- '%s.%s' % (package.__name__,base)).TemplateInformation)
- except ImportError, mesg:
- assert gDebug(2,
- "%s.%s doesn't appear to be a valid wizard" % (
- package.__name__, base))
- assert gDebug(5,' --> %s' % (mesg))
- except AttributeError:
- assert gDebug(2,'Wizard %s for package %s is missing'
- ' a \'TemplateInformation\' attribute.' %
- (base,package.__name__))
-
- for template in templates:
- try:
- location = template['MenuLocation']
- try:
- location, translation, grouping = location
- grouping = float(grouping)
- except:
- location, translation = location
- grouping = 499.0
-
- if location:
- self.wizardRunner(template, self)
- self.menubar.addAction(location=location, text=translation,
- event='Wizard:%s' % (
- template['BaseID']),
- grouping=grouping,
- canDisable=True,
- eventdata={'template':template},
- help=template['Description'])
- except ValueError:
- continue
-
-
-
-# =================================================================
-# GObject Hooks
-# =================================================================
-def add_GObject_hooks(object, document):
- """
- Capture the _setItemHook event, so that setting atttributes like:
-
- gobject['text'] = newtext
-
- will automatically cause ObjectModified events to fire.
-
- Also, add a .dispatch_designer_event method that calls the
- Document.dispatchEvent method, automatically passing in
- object=self
-
- """
- object._dispatch_designer_event = document.dispatchEvent
- object.dispatch_designer_event = new.instancemethod(
- _gobject_dispatch_event, object, object.__class__)
- object._setItemHook = new.instancemethod(_gobject_set_item_hook,
- object,
- object.__class__)
-
- object.gparser_definition = \
- document.incubator.elements[object._type[2:].lower()]
-
-
-def _gobject_dispatch_event(self, event, **params):
- params['object'] = self
- if not params.has_key('originator'):
- params['originator'] = '__inline__'
- self._dispatch_designer_event(event, **params)
-
-
-def _gobject_set_item_hook(self, key, value):
- """
- Hook into the GObject._setItemHook
-
- Here, "self" is any arbitrary GObject.
- """
- dict_key = key.replace(':','__')
- try:
- old_values = {key: object.__dict__[dict_key]}
- except KeyError:
- old_values = {}
-
- self.__dict__[dict_key] = value
- self._dispatch_designer_event('ObjectModified',
- object = self, new={key:value}, old=old_values,
- originator = '__inline__')
-
-
-
-# =================================================================
-# Helper class used by the tool-specific packages
-# =================================================================
-class ModuleProperties:
- xmlOpeningTag = 'undefined'
- short = 'undefined'
- application = 'GNUe Tool'
- description = 'undefined'
- fileExtensions = {}
- defaultFileExtension = 'undefined'
Copied: trunk/gnue-designer/src/base/document.py (from rev 8916,
trunk/gnue-designer/src/base/Document.py)
===================================================================
--- trunk/gnue-designer/src/base/Document.py 2006-10-24 05:49:19 UTC (rev
8916)
+++ trunk/gnue-designer/src/base/document.py 2006-10-25 23:59:35 UTC (rev
8929)
@@ -0,0 +1,891 @@
+# GNU Enterprise Designer - Basic Framework
+#
+# Copyright 2001-2006 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
+# version 2, or (at your option) any later version.
+#
+# GNU Enterprise is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied
+# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+# PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public
+# License along with program; see the file COPYING. If not,
+# write to the Free Software Foundation, Inc., 59 Temple Place
+# - Suite 330, Boston, MA 02111-1307, USA.
+#
+# $Id$
+
+"""
+This is the base instance class for a designer session. Every
+open file will be associated with its own document instance.
+"""
+
+__all__ = ['BaseDocument']
+
+# -----------------------------------------------------------------
+# System imports
+# -----------------------------------------------------------------
+import sys
+import os
+import time
+import dircache
+import new
+
+# -----------------------------------------------------------------
+# GNUe Imports
+# -----------------------------------------------------------------
+from gnue.common.apps import GDebug
+from gnue.common.apps import RuntimeSettings
+from gnue.common.utils.FileUtils import dyn_import
+from gnue.common.events import EventController, Event
+
+from gnue.designer.base.MenuBar import MenuBar
+from gnue.designer.base.UndoManager import UndoManager
+from gnue.designer.base.tools import TriggerEditor
+from gnue.designer.base.ToolBase import ToolBase
+from gnue.designer.base.ObjectList import ObjectList
+from gnue.designer.base import TemplateBase
+from gnue.designer.base.TemplateParser import WizardRunner
+from gnue.designer import VERSION, PACKAGE as TITLE
+
+from gnue.designer.app.documents import document_types_valid
+
+
+# ===================================================================
+# Base document class
+# ===================================================================
+class BaseDocument(EventController):
+
+
+ # ===============================================================
+ # Virtual functions (Override these functions in your Instance)
+ # ===============================================================
+ wizardRunner = WizardRunner
+
+ def init(self):
+ """
+ initialize the instance (called at the
+ beginning of the __init__ process)
+ """
+
+ def init(self):
+ """
+ Finalize the instance (called at the
+ end of the __init__ process)
+ """
+
+ def loadFile(self, buffer):
+ """
+ Called to load the object from a file buffer/handle
+ """
+ return None
+
+ def loadEmpty(self, style=None):
+ """
+ Called to load an "empty" (new) object. Create the root
+ object and any initial child objects (if appropriate)
+ """
+ return None
+
+ def inventoryObject(self, object):
+ """
+ Called in a tree-like fashion for every object
+ whether loaded in the beginning or later added.
+ """
+ pass
+
+ def preSave(self):
+ """
+ Called just before saving the file using GObject's dumpTree
+ You might do some sanity checks, etc.
+ """
+ return
+
+ def createTools(self):
+ """
+ Add any ToolBase instances
+ """
+ pass
+
+ def createEditors(self):
+ """
+ Add any EditorComponent instances
+ """
+ pass
+
+ def createWizards(self):
+ """
+ Add any runtime-loadable wizards/tools
+ """
+ pass
+
+ def initMenu(self):
+ """
+ Add any tool-specific functions to the menu bar
+ """
+ pass
+
+ def initToolBar(self):
+ """
+ Add any tool-specific functions to the tool bar
+ """
+ pass
+
+
+ def buildWizardCurrentDict(self):
+ """
+ Used by TemplateParser to build a wizard.current dict
+ """
+ return {'object': self._currentObject}
+
+
+ # ===============================================================
+ # Public Functions
+ # ===============================================================
+
+
+ # ---------------------------------------------------------------
+ # Register interface elements
+ # ---------------------------------------------------------------
+ def addTool(self, id, title, baseclass, hotkey=None, menuGroup=499):
+ """
+ Add a ToolBase instance
+ """
+ self._toolCache.append((id, title, baseclass, hotkey, menuGroup))
+
+
+ def registerEditor(self, baseclass, gtype, filter=None):
+ """
+ Register an editor class
+
+ Parameters:
+
+ baseclass: An EditorComponent class
+
+ gtype: A string indicating a GObject._type identifier,
+ or a list of such strings.
+
+ filter: A function that is passed a GObject and should
+ return True/False indicating if an editor instance
+ should be created.
+
+ """
+ if isinstance(gtype,basestring):
+ gtype = [gtype]
+ for gtype1 in gtype:
+ self._editorMapping[gtype1] = (filter, baseclass)
+
+
+ # ---------------------------------------------------------------
+ # Set the saved/unsaved status
+ # ---------------------------------------------------------------
+
+ def save(self):
+
+ if self.preSave():
+ print "Not saving definition"
+ return
+
+ location = self._path
+ fileHandle = None
+ fileHandle2 = None
+ if self._makeBackup:
+ try:
+ fileHandle = open(location,'r')
+ fileHandle2 = open(location + "~",'w')
+ fileHandle2.writelines(fileHandle.readlines())
+ except:
+ pass
+ else:
+ if fileHandle != None:
+ fileHandle.close()
+ if fileHandle2 != None:
+ fileHandle2.close()
+
+ self._makeBackup = 0
+
+ fileHandle = open(location,'w')
+
+ fileHandle.write('<?xml version="1.0" encoding="UTF-8"?>\n\n')
+
+ for comment in self.rootObject._rootComments:
+ if comment.find(TITLE) > 0:
+ self.rootObject._rootComments.remove(comment)
+
+ # Place a timestamp in the XML as a comment
+ # TODO: Replace with Dublin Core?
+ fileHandle.write(('<!-- %s (%s)\n%s Saved on: %s -->\n\n' \
+ % (TITLE, VERSION, (len(self.wizardName) and (
+ " Created by " + self.wizardName + "\n") or ""),\
+ time.strftime("%Y-%m-%d %H:%M:%S",
+ time.localtime(time.time())))).encode('UTF-8'))
+
+ fileHandle.write(''.join(["<!--%s-->\n\n" % comment.encode('UTF-8') \
+ for comment in self.rootObject._rootComments]))
+
+
fileHandle.write(self.rootObject.dumpXML(treeDump=True).encode('UTF-8'))
+ fileHandle.close()
+
+ self.app.mru.addLocation(location)
+ self.makeClean()
+
+
+ # Mark our form as "dirty" (unsaved changes)
+ def makeDirty(self):
+ if not self._isdirty:
+ self._isdirty = True
+ if self._path == "":
+ self.ui.setTitle( u_("Untitled %s*") %
self.properties.nickname)
+ else:
+ self.ui.setTitle(self._path + "*")
+ self.dispatchEvent('MakeDirty')
+
+
+ # Mark our form as "clean" (no unsaved changes)
+ def makeClean(self):
+ self._isdirty = 0
+ self._isnew = 0
+ if self._path == "":
+ self.ui.setTitle( u_("Untitled %s") % self.properties.nickname)
+ else:
+ self.ui.setTitle( self._path)
+ self.dispatchEvent('MakeClean')
+
+
+ # ---------------------------------------------------------------
+ # GObject convenience methods
+ # ---------------------------------------------------------------
+ def getNextGenericName (self, type):
+ return self.getUniqueName(type.capitalize() + '1')
+
+
+ def getUniqueName(self, name, limitingObject=None):
+
+ try:
+ usedNames = limitingObject.usedNames
+ except:
+ usedNames = self.usedNames
+
+ if name.lower() not in usedNames:
+ usedNames.append(name.lower())
+ return name
+
+ index = len(name) - 1
+
+ while index > 0 and '0' <= name[index] <= '9':
+ index -= 1
+
+ index += 1
+ if index >= len(name):
+ start = 1
+ base = name
+ else:
+ start = int(name[index:])
+ base = name[:index]
+
+ while ("%s%s" % (base, start)).lower() in usedNames:
+ start += 1
+
+ rv = "%s%s" % (base, start)
+ usedNames.append(rv.lower())
+ if rv.lower() not in self.usedNames:
+ self.usedNames.append(rv.lower())
+ return rv
+
+
+ # ---------------------------------------------------------------
+ # Return, or create, an ObjectList based on the xml tag
+ # ---------------------------------------------------------------
+ def getObjectList(self, tag):
+ try:
+ return self.objectLists[tag]
+ except KeyError:
+ defin = self.incubator.elements[tag]
+ baseClass = defin['BaseClass']
+
+ # Determine the "name" attribute"
+ nameAttr = None
+ try:
+ if defin['Attributes'].has_key('name'):
+ nameAttr = 'name'
+ else:
+ for attribute, props in defin['Attributes'].items():
+ try:
+ if props['Unique']:
+ nameAttr = attribute
+ break
+ except KeyError:
+ pass
+ except KeyError:
+ pass
+
+ list = ObjectList(self, baseClass, nameAttr)
+ self.objectLists[tag] = list
+ return list
+
+
+ # ================================================================
+ # Private functions
+ # ================================================================
+
+ def __init__(self, app, properties, location=None,
+ buffer=None, style=None):
+ EventController.__init__(self)
+
+ self.app = app
+ self.properties = properties
+
+ # During startup, we will cache all events
+ # so we can execute them when everything has
+ # been initialized.
+ self.startCachingEvents()
+
+ self.ui = app.ui.createInstance(self)
+
+ # Local variables
+ self.wizardName = ""
+ self._isdirty = False
+ self._makeBackup = True
+ self._isNew = True
+ self.connections = app.connections
+ self.nameMappings = {}
+ self.usedNames = []
+
+ # Create the supplemental tools
+ self._toolCache = []
+ self._editorMapping = {}
+ self._pages = []
+ self.objectLists = {}
+ self._path = ""
+
+ self.globalAccelerators = []
+ self.globalAcceleratorListeners = []
+
+ self._nameMappers = {} # {GDataSource: {'name': [(GFBlock,'name')]}}
+
+
+ self.registerEventListeners({
+ # Menu/Toolbar stuff
+ 'RequestSave' : self._OnSave,
+ 'RequestSaveAs' : self._OnSaveAs,
+ 'RequestClose' : self._OnClose,
+
+ # Object stuff
+ 'ObjectSelected' :
self.__object_selected_event,
+ 'ObjectCreated' : self.__object_created_event,
+ 'ObjectModified' :
self.__object_modified_event,
+ 'ObjectDeleted' : self.__object_deleted_event,
+ })
+
+
+ # Call the document-specific init method
+ self.init()
+
+ # Register ourself with RuntimeSettings
+ RuntimeSettings.init(configFilename="gnue-des.ini",
+ homeConfigDir=".gnue")
+ RuntimeSettings.registerInstance(self)
+
+ # Tell RuntimeSettings that we have information to save
+ self.runtime_section = self.properties.nickname + 'Layout'
+ RuntimeSettings.registerRuntimeSettingHandler(self, self)
+
+ # And the "Most Recenty Used" manager
+ RuntimeSettings.registerRuntimeSettingHandler(self, app.mru)
+
+ # Set up the Undo/Redo Manager
+ UndoManager(self)
+
+ # Load any files specified on the command
+ # line, or create a new document
+ if location == None:
+
+ if buffer != None:
+ self.__loadFromBuffer(buffer)
+ self.makeDirty()
+ else:
+ self.__createEmptyInstance(style)
+
+ else:
+ if not os.access (location, os.R_OK):
+ self.show()
+ if not self.app.ui.dialogYesNo(
+ u_('The requested file does not exist.\n') +
+ u_('Do you want to create this file?') +
+ u_('\n\nFile: %s') \
+ % location, u_("File Not Found"), self.ui):
+ # TODO: Is this right?
+ sys.exit()
+ self.hide()
+ self.__createEmptyInstance(style)
+ self._path = location
+ self.makeDirty()
+
+ elif not os.access (location, os.W_OK):
+ self.show()
+ if not self.app.ui.dialogCancel(
+ u_('The requested file is Read Only.\n') +
+ u_('To save any changes, you will \n') +
+ u_('be required to do a "Save As..."\n\nFile: %s') \
+ % location, u_("Read Only Warning"), self.ui) :
+ # TODO: Is this right?
+ sys.exit()
+ self.hide()
+ self.__loadFromFile(location)
+ else:
+ self.__loadFromFile(location)
+
+ self.menubar = MenuBar(self)
+
+
+ gStartupStatus(u_('Creating User Interface'))
+
+ # Set up the menu system
+ # ... our common menu
+ self._initMenu()
+ # ... and the document-centric menu
+ self.initMenu()
+
+ self.createWizards()
+
+ # Set up the editor components...
+ # ... common
+ self.registerEditor(TriggerEditor.TriggerEditor, 'GCTrigger',
+ TriggerEditor.EditorFilter)
+ # ... and document-centric
+ self.createEditors()
+
+ # Create the document-centric tools
+ self.createTools()
+
+ # And tell the UI driver to create the UI portions
+ self.ui.initTools()
+
+ # Finalize menu bar
+ self.menubar.finalize()
+ self.app.mru.addMenu(self.menubar.getMenu('File|Open Recent|'), self)
+
+ self.toolbar = self.ui.toolbar
+ self.initToolBar()
+
+ # TODO: This is a hack to disable any menu items
+ # TODO: for actions we've yet to implement
+ for action in ('RequestRevert','RequestRedo','RequestCopy',
+ 'RequestPaste','RequestPasteSpecial','RequestCut'):
+ self.dispatchEvent('Disable:%s' % action)
+
+
+ # Add ourselve to the main app's instance list
+ self.app.addDocument(self)
+
+
+ self.dispatchEvent('ObjectSelected', originator=self,
+ object=self.rootObject)
+
+ # Inventory the objects
+ gStartupStatus(u_('Inventorying Document Objects'))
+ self.rootObject.walk(self.__inventory)
+
+ self.finalize()
+ self.ui.finalize()
+
+ self.stopCachingEvents()
+
+
+ def _initMenu(self):
+ # Add the [sub]menus
+ for location, text, grouping in (
+ ('File', u_('&File'), 100),
+ ('File|New', u_('&New'), 100),
+ ('File|Open Recent', u_('&Open Recent'), 200.1),
+ ('File|Connect To', u_('&Connect To'), 400),
+ ('Edit', u_('&Edit'), 200),
+ ('Insert',u_('&Insert'), 300),
+ ('Modify',u_('&Modify'), 400),
+ ('Tools',u_('&Tools'), 500),
+ ('View',u_('&View'), 800),
+ ('Help',u_('&Help'), 999)):
+
+ self.menubar.addMenu(location, text, grouping)
+
+ for location, event, text, hotkey, help, grouping in (
+ ('File', 'RequestOpen', u_('&Open'), 'Ctrl+O',
+ u_("Open an existing document"), 200.1),
+ ('File|Open Recent', 'XXXX', u_('&Foo'), None,
+ u_("This is a placeholder for the Open Recent menu"), 200.1),
+ ('File|New', 'RequestNewWizard', u_('From &Wizard...'), None,
+ u_("Create a new document using a wizard"), 900.1),
+ ('File', 'RequestSave', u_("&Save"), 'Ctrl+S',
+ u_("Save the current document"),300.1),
+ ('File', 'RequestSaveAs', u_("Save &As..."),None,
+ u_("Save the current document under a new name"), 300.2),
+ ('File', 'RequestSaveAll', u_("Save A&ll"),None,
+ u_("Save all open document"),300.3),
+ ('File', 'RequestRevert', u_("Reload"), None,
+ u_("Reload the current document as of its last save " + \
+ "(abandoning any changes)"), 500),
+ ('File', 'RequestClose', u_("&Close"), 'Ctrl+W',
+ u_("Close the current document"), 990),
+ ('File', 'RequestExit', u_("E&xit"), None,
+ u_("Exit GNUe Designer"), 995),
+ ('Edit', 'RequestUndo', u_("&Undo"), 'Ctrl+Z',
+ u_("Undo the last action"), 100.1),
+ ('Edit', 'RequestRedo', u_("&Redo"), 'Ctrl+Y',
+ u_("Redo the last undo action"), 100.2),
+ ('Edit', 'RequestCut', u_("Cu&t"), 'Ctrl+X',
+ u_("Cut the current object and move to the clipboard"), 200.1),
+ ('Edit', 'RequestCopy', u_("&Copy"), 'Ctrl+C',
+ u_("Copy the current object to the clipboard"), 200.2),
+ ('Edit', 'RequestPaste', u_("&Paste"), 'Ctrl+V',
+ u_("Paste the current object on the clipboard"), 200.3),
+ ('Edit', 'RequestPasteSpecial', u_("Paste &Special..."), None,
+ u_("Paste the current object on the clipboard " + \
+ "with special attributes"), 200.4),
+ ('Modify','RequestDelete', u_("&Delete Item"), 'Delete',
+ u_("Delete the current object"),100),
+ ('Help', 'RequestAbout', u_("&About GNUe Designer"), None,
+ u_("More information about GNUe Designer"), 900),
+ ):
+ self.menubar.addAction(location, text, event,
+ grouping, canDisable=True,
+ icon=None, hotkey=hotkey, help=help)
+
+ # Add supported tools to File|New
+ for tool in document_types_valid:
+ self.menubar.addAction(
+ 'File|New', '&%s' % tool.nickname,
+ 'RequestNew', 100,
+ help=u_('Create a new %s') % tool.description,
+ eventdata={'type': tool.instance})
+
+ # Add connections
+ for conn in self.connections.getAllConnectionParameters().keys():
+ self.menubar.addAction('File|Connect To', conn,
+ 'Connect:%s' % conn,
+ help=u_("Login to %s connection") % conn,
+ eventdata={'connection': conn})
+ self.registerEventListeners(
+ {'Connect:%s' % conn: self.__OnConnectTo})
+
+
+ def __loadFromFile(self, location):
+ try:
+ self._path = location
+ fileHandle = open(location,'r')
+ self.__loadFromBuffer(fileHandle)
+ fileHandle.close()
+ self.makeClean()
+ self._isNew = 0
+ except IOError, msg:
+ print "\n%s %s\n\nUnable to open file '%s'. \n" + \
+ "Unexpected read error:\n %s.\n" % (
+ TITLE, VERSION, location, msg)
+ sys.exit()
+ self.app.mru.addLocation(location)
+
+
+ def addNameMapper(self, instance, attribute, childinst, childattr):
+ try:
+ instm = self._nameMappers[instance]
+ except KeyError:
+ instm = {}
+ self._nameMappers[instance] = instm
+ try:
+ attrm = instm[attribute]
+ except KeyError:
+ attrm = []
+ instm[attribute] = attrm
+ attrm.append ( (childinst, childattr) )
+
+
+ def __loadFromBuffer(self, fileHandle):
+ self.rootObject = self.loadBuffer(fileHandle)
+
+
+ def __createEmptyInstance(self, style):
+ self.rootObject = self.loadEmpty(style)
+ self.makeClean()
+ self._isNew = True
+
+
+ # ---------------------------------------------------------------
+ #
+ # ---------------------------------------------------------------
+ #
+ # Used by RuntimeSettings
+ #
+ def saveRuntimeSettings(self):
+ return ( self.runtime_section, self.ui.getRuntimeSettings() )
+
+
+ # ---------------------------------------------------------------
+ #
+ # ---------------------------------------------------------------
+ # Do we need to be saved?
+ def isDirty(self):
+ return self._isdirty
+
+
+ # ---------------------------------------------------------------
+ #
+ # ---------------------------------------------------------------
+ # Take an object and mangle it all up
+ # until it is useful to us
+ def __inventory (self, object):
+
+ # Add a GObjectHelper to intercept __getitem__ calls on GObject
+ add_GObject_hooks(object, self)
+
+ if object != self.rootObject:
+
+ # Assign an ID if none exists
+ if hasattr(object, 'name'):
+ if object.name == None or object.name.startswith(object._type):
+ object.name = self.getNextGenericName(object._type[2:])
+ self.nameMappings[object.name.lower()] = object
+ self.usedNames.append(object.name.lower())
+
+ # Do we create an EditorComponent instance?
+ if object._type in self._editorMapping.keys():
+ filter = self._editorMapping[object._type][0]
+ if filter is None or filter(object):
+ self.ui.createEditor(object,
+ *self._editorMapping[object._type][1:])
+
+ # Now, give the tool-specific instances a chance
+ object.dispatch_designer_event('InventoryObject')
+ self.inventoryObject(object)
+
+
+ def __object_selected_event (self, event):
+ object = event.object
+ handler = event.originator
+ self._currentObject = object
+
+ def __object_created_event (self, event):
+ self.__inventory(event.object)
+ self.makeDirty()
+
+ def __object_modified_event (self, event):
+ object = event.object
+ # Check for any name dependencies
+ # (i.e., GFEntry is dependent on GFBlock.name and GFField.name)
+ # Automatically create any change events for the child objects
+ if hasattr(object, '_nameDependencies'):
+ for key in object._nameDependencies.keys():
+ masterattr, slaveattr = object._nameDependencies[key]
+ if masterattr in event.new.keys():
+ key[slaveattr] = object[masterattr]
+
+ self.makeDirty()
+
+
+ def __object_deleted_event (self, event):
+ object = event.object
+
+ # Delete the actual object from its parent
+ object.getParent()._children.remove(object)
+
+ self.makeDirty()
+
+
+
+ def __OnConnectTo(self, event):
+ conn = event.connection
+ try:
+ tempDO = self.connections.getConnection(conn, 'object')
+ self.dispatchEvent('ConnectionEstablished',connection=conn)
+ self.dispatchEvent('Disable:Connect:%s' % conn)
+ except:
+ print u_("Unable to connect to %s") % conn
+
+
+ # ---------------------------------------------------------------
+ #
+ # ---------------------------------------------------------------
+ def _OnSave(self, event):
+ if not len(self._path):
+ self._OnSaveAs(event)
+ else:
+ self.save()
+
+
+ def _OnSaveAs(self, event):
+ wildcards = []
+ # Make the "default" file extension for a tool
+ # appear before the other extensions.
+ filterIndex = [self.properties.defaultFileExtension]
+ wildcards += [
+ ( self.properties.defaultFileExtension,
+
self.properties.fileExtensions[self.properties.defaultFileExtension]) ]
+
+ for type in self.properties.fileExtensions.keys():
+ if type != self.properties.defaultFileExtension:
+ wildcards += [
+ ( type, self.properties.fileExtensions[type]) ]
+ filterIndex.append(type)
+
+ path = self.app.ui.dialogSaveFile(
+ u_("Save %s As...") % self.properties.description,
+ wildcards=wildcards,
+ parentWindow=self.ui)
+
+ if path:
+ if os.path.isfile(path):
+ overwrite = self.app.ui.dialogYesNo(
+ u_('The file "%s".\n' % path) +
+ u_("exists. Overwrite?"),
+ u_("Unsaved Changes"),
+ icon="warn", parentWindow=self.ui)
+ if not overwrite:
+ self.OnSaveAs(event)
+ return
+
+ self._path = path
+ self.ui.setTitle (self._path)
+ self.save()
+
+
+
+ def _OnClose(self, event):
+ if self.isDirty():
+ save = self.app.ui.dialogYesNoCancel(
+ u_("This document has unsaved changes.\n") +
+ u_("Save changes before closing?"),
+ u_("Unsaved Changes"), icon="warn", parentWindow=self.ui)
+ if save == True:
+ self.OnSave(event)
+ elif save == -1:
+ event.Veto()
+ return
+
+ RuntimeSettings.saveRuntimeSettings(self)
+ self.app.mru.removeMenu(
+ self.menubar.getMenu('File|Open Recent|'), self)
+ self.app.removeDocument(self)
+ self.dispatchEvent('DocumentClosing')
+ self.ui.close()
+
+
+ # ---------------------------------------------------------------
+ #
+ # ---------------------------------------------------------------
+ def loadWizards(self, package):
+ templates = []
+
+ basedir = os.path.dirname(package.__file__)
+ processed = [] # Base file names processed (e.g., base of Simple.py*
+ # is Simple) This will keep us from importing Simple
+ # three times if Simple.py, Simple.pyc, and Simple.lib
+ # all exist.
+
+ for dir in dircache.listdir(basedir):
+ base = dir.split('.')[0]
+ if not dir[0] in ('.','_') and not base in processed:
+ processed.append(base)
+ try:
+ templates.append(dyn_import(
+ '%s.%s' % (package.__name__,base)).TemplateInformation)
+ except ImportError, mesg:
+ assert gDebug(2,
+ "%s.%s doesn't appear to be a valid wizard" % (
+ package.__name__, base))
+ assert gDebug(5,' --> %s' % (mesg))
+ except AttributeError:
+ assert gDebug(2,'Wizard %s for package %s is missing'
+ ' a \'TemplateInformation\' attribute.' %
+ (base,package.__name__))
+
+ for template in templates:
+ try:
+ location = template['MenuLocation']
+ try:
+ location, translation, grouping = location
+ grouping = float(grouping)
+ except:
+ location, translation = location
+ grouping = 499.0
+
+ if location:
+ self.wizardRunner(template, self)
+ self.menubar.addAction(location=location, text=translation,
+ event='Wizard:%s' % (
+ template['BaseID']),
+ grouping=grouping,
+ canDisable=True,
+ eventdata={'template':template},
+ help=template['Description'])
+ except ValueError:
+ continue
+
+
+
+# =================================================================
+# GObject Hooks
+# =================================================================
+def add_GObject_hooks(object, document):
+ """
+ Capture the _setItemHook event, so that setting atttributes like:
+
+ gobject['text'] = newtext
+
+ will automatically cause ObjectModified events to fire.
+
+ Also, add a .dispatch_designer_event method that calls the
+ Document.dispatchEvent method, automatically passing in
+ object=self
+
+ """
+ object._dispatch_designer_event = document.dispatchEvent
+ object.dispatch_designer_event = new.instancemethod(
+ _gobject_dispatch_event, object, object.__class__)
+ object._setItemHook = new.instancemethod(_gobject_set_item_hook,
+ object,
+ object.__class__)
+
+ object.gparser_definition = \
+ document.incubator.elements[object._type[2:].lower()]
+
+
+def _gobject_dispatch_event(self, event, **params):
+ params['object'] = self
+ if not params.has_key('originator'):
+ params['originator'] = '__inline__'
+ self._dispatch_designer_event(event, **params)
+
+
+def _gobject_set_item_hook(self, key, value):
+ """
+ Hook into the GObject._setItemHook
+
+ Here, "self" is any arbitrary GObject.
+ """
+ dict_key = key.replace(':','__')
+ try:
+ old_values = {key: object.__dict__[dict_key]}
+ except KeyError:
+ old_values = {}
+
+ self.__dict__[dict_key] = value
+ self._dispatch_designer_event('ObjectModified',
+ object = self, new={key:value}, old=old_values,
+ originator = '__inline__')
+
+
+
+# =================================================================
+# Helper class used by the tool-specific packages
+# =================================================================
+class ModuleProperties:
+ xmlOpeningTag = 'undefined'
+ short = 'undefined'
+ application = 'GNUe Tool'
+ description = 'undefined'
+ fileExtensions = {}
+ defaultFileExtension = 'undefined'
Added: trunk/gnue-designer/src/base/parsertoobj.py
===================================================================
--- trunk/gnue-designer/src/base/parsertoobj.py 2006-10-25 16:22:31 UTC (rev
8928)
+++ trunk/gnue-designer/src/base/parsertoobj.py 2006-10-25 23:59:35 UTC (rev
8929)
@@ -0,0 +1,189 @@
+# GNU Enterprise Designer - Basic Framework
+#
+# Copyright 2001-2006 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
+# version 2, or (at your option) any later version.
+#
+# GNU Enterprise is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied
+# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+# PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public
+# License along with program; see the file COPYING. If not,
+# write to the Free Software Foundation, Inc., 59 Temple Place
+# - Suite 330, Boston, MA 02111-1307, USA.
+#
+# $Id: documents.py 8389 2006-04-07 02:44:20Z jcater $
+
+"""
+Take a GParser definition and create a Designer document model
+"""
+
+__all__ = ['create_proxy_definition']
+
+import copy
+import weakref
+import types
+
+from gnue.common.definitions.GParserHelpers import ParserObj
+
+
+class BaseObject(ParserObj):
+ """
+ This class is used by ProxyObjectFactory.
+ If used by itself, you will get plenty of
+ attribute errors as it depends on attributes
+ set on ProxyObject.
+ """
+
+ def __new__(cls, *args, **kwargs):
+ obj = object.__new__(cls, *args, **kwargs)
+
+
+ def __init__(self, parent=None, **kwargs):
+ """
+ """
+ # Set any initial attribute values
+ ParserObj.__init__(self, parent, self.__gobj_tag__)
+ self._attributes = self.__gobj_defaults__.copy()
+ for key, value in kwargs:
+ self._attributes[key] = value
+
+ self.parent = self._parent = weakref.proxy(parent)
+
+ def create_required_children(self):
+ """
+ Create any of the "required" child tags
+ """
+ for child_tag in self.__gobj_validchildren__:
+ if self.__gobj_tags__[child_tag].get('Required',False):
+ child = self.__gobj_tags__[child_tag]['BaseClass'](child)
+ child.create_required_children()
+
+
+ def __getitem__(self, name):
+ """
+ """
+ return self._attributes[name]
+
+
+ def __setitem__(self, name, value):
+ """
+ """
+ return self._attributes[name]
+
+
+ def get(self, name, default=None):
+ """
+ """
+ return self._attributes.get(name, default)
+
+
+
+# ===================================================================
+# Dynamic class
+# ===================================================================
+def ProxyObjectFactory():
+
+ # ---------------------------------------------------------------
+ class ProxyObject(BaseObject):
+
+ __gobj_defaults__ = {}
+ __gobj_tag__ = ''
+ __gobj_description__ = ''
+ __gobj_real_class__ = ''
+ __gobj_parenttags__ = ()
+ __gobj_validchildren__ = ()
+ __gobj_singleinstance__ = False
+ __gobj_required__ = False
+
+ # ---------------------------------------------------------------
+
+ return ProxyObject
+
+
+
+# ===================================================================
+# Create GObject classes from a GParser definition
+# ===================================================================
+def create_proxy_definition(definition):
+ tag_mappings = {}
+ tag_to_proxy = {}
+
+ for tag, tag_definition in definition.items():
+
+ tag_definition = copy.deepcopy(tag_definition)
+ # Build a reverse mapping from parent tags,
+ # indicating which child tags are valid for a tag.
+ for parent_tag in definition.get('ParentTags',[]):
+ if tag_mappings.has_key(parent_tag):
+ tag_mappings[parent_tag] = {'ValidChildren': [tag]}
+ else:
+ tag_mappings[parent_tag]['ValidChildren'].append(tag)
+
+ if tag_mappings.has_key(tag):
+ tag_mappings[tag].update(tag_definition)
+ tag_definition = tag_mappings[tag]
+ else:
+ tag_mappings[tag] = tag_definition
+ tag_definition['ValidChildren'] = []
+
+
+ base_class = ProxyObjectFactory()
+
+ base_class.__gobj_defaults__ = defaults = {}
+ base_class.__gobj_tag__ = tag
+ base_class.__gobj_real_class__ = _get_class_importable_name(
+ tag_definition['BaseClass'])
+
+ for key, values in tag_definition.items():
+ if key not in ('Attributes'):
+ setattr(base_class,
+ '__gobj_%s__' % key.lower().replace('-','_'),
+ values)
+
+ tag_definition['BaseClass'] = base_class
+
+ # This creates a circular reference, but that's okay
+ # given this is very static over the lifetime of a running app.
+ base_class.__gobj_tags__ = tag_mappings
+
+
+ return tag_mappings
+
+
+# ===================================================================
+# Helpers
+# ===================================================================
+def _get_class_importable_name(obj, *args):
+ """
+ Take a class definition and create a string that can be
+ eval'd to return the original class.
+ """
+
+ if type(obj) in (types.ClassType, types.FunctionType, types.TypeType):
+ return '%s.%s' % (obj.__module__, obj.__name__)
+ else:
+ return str(obj)
+
+
+
+# ===================================================================
+# Testing/Development
+# ===================================================================
+if __name__ == '__main__':
+ # Test using form definition
+ from gnue.forms.GFParser import getXMLelements
+ create_proxy_definition(getXMLelements())
+
+ from gnue.designer.standalone.gfd import getXMLelements
+ create_proxy_definition(getXMLelements())
+
+
+
Modified: trunk/gnue-designer/src/forms/document.py
===================================================================
--- trunk/gnue-designer/src/forms/document.py 2006-10-25 16:22:31 UTC (rev
8928)
+++ trunk/gnue-designer/src/forms/document.py 2006-10-25 23:59:35 UTC (rev
8929)
@@ -37,7 +37,7 @@
# ---------------------------------------------------------------------------
# GNUe Imports
# ---------------------------------------------------------------------------
-from gnue.designer.base.Document import BaseDocument
+from gnue.designer.base.document import BaseDocument
from gnue.designer.base import PopupMenu
from gnue.designer.base.ObjectList import ObjectList
from gnue.designer.base.PopupMenu import ObjectMenu
@@ -313,18 +313,18 @@
# =========================================================================
# Public methods specific to a Forms document
# =========================================================================
- def find_gflabel_for(self, name):
- labels = self.rootObject.findChildrenOfType('GFLabel',
+ def find_gflabel_for(self, name):
+ labels = self.rootObject.findChildrenOfType('GFLabel',
allowAllChildren=True)
-
+
results = []
append = results.append
-
- for label in labels:
- if hasattr(label,'for') and label['for'] == name:
+
+ for label in labels:
+ if hasattr(label,'for') and label['for'] == name:
append(label)
return results
-
+
# =========================================================================
# Private methods
# =========================================================================
Added: trunk/gnue-designer/src/standalone/__init__.py
===================================================================
Added: trunk/gnue-designer/utils/package_standalone_definitions.py
===================================================================
--- trunk/gnue-designer/utils/package_standalone_definitions.py 2006-10-25
16:22:31 UTC (rev 8928)
+++ trunk/gnue-designer/utils/package_standalone_definitions.py 2006-10-25
23:59:35 UTC (rev 8929)
@@ -0,0 +1,178 @@
+# GNU Enterprise Designer - Utilities - Create standalone XML definitions
+#
+# Copyright 2006 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
+# version 2, or (at your option) any later version.
+#
+# GNU Enterprise is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied
+# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+# PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public
+# License along with program; see the file COPYING. If not,
+# write to the Free Software Foundation, Inc., 59 Temple Place
+# - Suite 330, Boston, MA 02111-1307, USA.
+#
+# $Id$
+"""
+This takes a GParser definition from a GNUe tool, and
+creates a .py file that extracts a standalone-version of the
+getXMLelements() dict that can be used by Designer so
+Designer can know the .
+
+Designer will check to see if a product is installed and
+use that definition intead of the standalone. It will simply
+fall-back to these pre-compiled ones.
+"""
+
+# ===================================================================
+default_files = (
+ ('gfd.py', 'gnue.forms.GFParser'),
+ ('grd.py', 'gnue.reports.GRParser'),
+ ('gld.py', 'gnue.appserver.gld.GLParser'),
+ ('gcd.py', 'gnue.appserver.gcd.GCParser'),
+ )
+# ===================================================================
+
+import sys
+import os
+import pprint
+import sys
+import types
+import __builtin__
+import copy
+
+from gnue.common.utils.FileUtils import dyn_import
+
+
+def _get_class_importable_name(obj, *args):
+ """
+ Take a class definition and create a string that can be
+ eval'd to return the original class.
+ """
+
+ if type(obj) in (types.ClassType, types.FunctionType, types.TypeType):
+ return '%s.%s' % (obj.__module__, obj.__name__)
+ else:
+ return str(obj)
+
+def _replace_classes(target):
+ """
+ This converts class/function instances (gnue.common.foo.bar)
+ with an eval'able string ('gnue.common.foo.bar')
+ """
+ if type(target) == types.DictType:
+ for key in target.keys():
+ target[key] = _replace_classes(target[key])
+ return target
+ elif type(target) in (types.ClassType, types.FunctionType,
+ types.TypeType):
+ return _get_class_importable_name(target)
+ elif type(target) in (types.ListType, types.TupleType):
+ return [_replace_classes(t) for t in target]
+ else:
+ return target
+
+# ===================================================================
+#
+# ===================================================================
+def create_standalone_proxy_definition(module, outfile):
+ """
+ Designed to be run by the packaging scripts.
+ This takes a product's GParser definition and creates
+ a standalone version that Designer can use without requiring
+ that product to be installed.
+ """
+
+ # ------------------------------------------------------
+ # These classes replace the built-in _() and u_()
+ # by not actually translating the text and returning a
+ # pretty-printable represenation of themself. This way,
+ # i18n stays intact.
+
+ # This has to be done after all other gnue.* classes are
+ # imported.
+ class _u_string(unicode):
+ def __repr__(self):
+ return 'u_(%s)' % unicode.__repr__(self)
+
+ class ___string(unicode):
+ def __repr__(self):
+ return '_(%s)' % unicode.__repr__(self)
+
+ __builtin__.__dict__['u_'] = _u_string
+ __builtin__.__dict__['_'] = ___string
+ # ------------------------------------------------------
+
+ mod = dyn_import(module)
+
+ if not hasattr(mod, 'getXMLelements'):
+ print "%s does not define getXMLelements" % module
+ return
+
+ xml_elements = _replace_classes(copy.deepcopy(mod.getXMLelements()))
+
+ out = open(outfile,'w')
+
+ out.write("""
+ # GNU Enterprise Designer - Standalone File Format Stubs
+ #
+ # Copyright 2005-2006 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
+ # version 2, or (at your option) any later version.
+ #
+ # GNU Enterprise is distributed in the hope that it will be
+ # useful, but WITHOUT ANY WARRANTY; without even the implied
+ # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ # PURPOSE. See the GNU General Public License for more details.
+ #
+ # You should have received a copy of the GNU General Public
+ # License along with program; see the file COPYING. If not,
+ # write to the Free Software Foundation, Inc., 59 Temple Place
+ # - Suite 330, Boston, MA 02111-1307, USA.
+ #
+ # $Id$
+
+ # THIS FILE WAS AUTOMATICALLY GENERATED.
+ # DO NOT EDIT DIRECTLY.
+
+ definition = """.replace('\n ','\n'))
+
+ pp = pprint.PrettyPrinter(indent=4)
+ out.write(pp.pformat(copy.deepcopy(xml_elements)))
+ out.write('\n\ndef getXMLelements(): return definition\n\n')
+ out.close()
+
+
+if __name__ == '__main__':
+
+ default_files = (
+ ('gfd.py', 'gnue.forms.GFParser'),
+ ('grd.py', 'gnue.reports.base.GRParser'),
+ ('gld.py', 'gnue.appserver.gld.GLParser'),
+ ('gcd.py', 'gnue.appserver.gcd.GCParser'),
+ )
+
+ if sys.argv[1:]:
+ create_standalone_proxy_definition(*sys.argv[1:])
+ else:
+ dest_path = os.path.join(os.path.join(*os.path.split(__file__)[:-1]),
+ '..','src','standalone')
+ for out, package in default_files:
+ print "Writing %s" % os.path.join(dest_path, out)
+ create_standalone_proxy_definition(package,
+ os.path.join(dest_path, out))
+
+
+
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [gnue] r8929 - in trunk/gnue-designer: . src src/app src/base src/forms src/standalone utils,
jcater <=