Added Zope 3 stuff

Completed xmi export using Kid


git-svn-id: file:///Users/arjan/backup/gaphor/trunk/gaphor@610 a8418922-720d-0410-834f-a69b97ada669
This commit is contained in:
slmm 2005-10-27 12:45:05 +00:00
parent e7f98b76fb
commit 0693bcacca
12 changed files with 334 additions and 39 deletions

View File

@ -1,3 +1,11 @@
2005-10-27 Jeroen Vlootuis <jeroen@vloothuis.net>
* Added new object inspector panel at bottom of diagram. This makes use
of the Zope 3 component architecture. Therefore Gaphor now depends on
Zope 3. This dependency should be diminshed to component and
interface. At the moment there is no seperate package for component.
* Made Kid export handle tagged values.
2005-10-27 wrobell <wrobell@pld-linux.org>
* gaphor/diagram/activitynodes.py: object node has upper bound
specification; join node has join specification; initial node naming

View File

@ -39,16 +39,29 @@ def getLowerAndUpperValuesFromAssociationEnd(end):
from gaphor.misc.uniqueid import generate_id
def getTagDefinitions():
items = []
for node in elements:
if hasattr(node, 'taggedValue'):
for tag in node.taggedValue:
items.append(tag)
return items
tagDefinitions = []
class TaggedValue(object):
def __init__(self, name, value):
self.name = name
self.value = value
self.id = generate_id()
def getTypeRef(self):
"""Return a auto generated typeref for use with type definitions."""
return self.id+"_typeref"
typeref = property(getTypeRef)
def convertTaggedValue(taggedValue):
tags = taggedValue.value.split(',')
converted = [map(unicode.strip, tag.split("=")) for tag in tags]
data = dict(converted)
tags = [TaggedValue(key, value) for (key, value) in data.items()]
tagDefinitions.extend(tags)
return tags
?>
<XMI
@ -67,11 +80,9 @@ def getTagDefinitions():
xmi.id = 'I48de81cbm106d41f950cmm7f54' name = 'topModel' isSpecification = 'false'
isRoot = 'false' isLeaf = 'false' isAbstract = 'false'
py:attrs="{'xmi.id':topLevelPackage.id, 'name':topLevelPackage.name}">
<UML:ModelElement.taggedValue
py:replace="processModelElementTaggedValue(topLevelPackage)"/>
<UML:Classifier.feature py:def="processClassifierFeature(item)">
<UML:Classifier.feature py:def="processClassifierFeature(item)">
<UML:Namespace.ownedElement>
<UML:Class py:for="cls in [a.typeValue for a in item.ownedAttribute if a.typeValue]"
visibility='public' isSpecification='false' isRoot='false' isAbstract='false'
@ -85,7 +96,9 @@ def getTagDefinitions():
py:for="attribute in [a for a in item.ownedAttribute if a.typeValue]"
py:attrs="{'xmi.id':attribute.id, 'name':attribute.name}">
<UML:ModelElement.taggedValue
py:replace="processModelElementTaggedValue(attribute)"/>
py:for="taggedValue in convertTaggedValue(attribute.taggedValue)"
py:content="processTaggedValue(taggedValue)">
</UML:ModelElement.taggedValue>
<UML:StructuralFeature.type>
<UML:Class xmi.idref = 'I48de81cbm106d41f950cmm7f24'
py:attrs="{'xmi.idref':attribute.typeValue.id}"/>
@ -126,23 +139,18 @@ def getTagDefinitions():
</UML:Classifier.feature>
<UML:ModelElement.taggedValue
py:def="processModelElementTaggedValue(node)"
py:for="taggedValue in node.taggedValue"
py:content="processTaggedValue(taggedValue)">
</UML:ModelElement.taggedValue>
<UML:TagDefinition py:def="processTagDefinition(tagDefinition)"
xmi.id = 'I5bd6b6fm106dbda4889mm7f24' name = 'someTag'
py:attrs="{'xmi.id':tagDefinition.id+'ref', 'name':tagDefinition.value.split('=')[0]}"
py:attrs="{'xmi.id':tagDefinition.typeref, 'name':tagDefinition.name}"
isSpecification = 'false'>
<UML:TagDefinition.multiplicity>
<UML:Multiplicity xmi.id = 'I5bd6b6fm106dbda4889mm7f23'
py:attrs="{'xmi.id':tagDefinition.id+'multi'}">
py:attrs="{'xmi.id':tagDefinition.typeref+'multi'}">
<UML:Multiplicity.range>
<UML:MultiplicityRange xmi.id = 'I5bd6b6fm106dbda4889mm7f22' lower = '1'
upper = '1'
py:attrs="{'xmi.id':tagDefinition.id+'multirange'}"/>
py:attrs="{'xmi.id':tagDefinition.typeref+'multirange'}"/>
</UML:Multiplicity.range>
</UML:Multiplicity>
</UML:TagDefinition.multiplicity>
@ -153,10 +161,10 @@ def getTagDefinitions():
xmi.id = 'I5bd6b6fm106dbda4889mm7f21' isSpecification = 'false'
py:attrs="{'xmi.id':taggedValue.id}">
<UML:TaggedValue.dataValue
py:content="taggedValue.value.split('=')[-1]">someTagValue</UML:TaggedValue.dataValue>
py:content="taggedValue.value">someTagValue</UML:TaggedValue.dataValue>
<UML:TaggedValue.type>
<UML:TagDefinition xmi.idref = 'I5bd6b6fm106dbda4889mm7f24'
py:attrs="{'xmi.idref':taggedValue.id+'ref'}"/>
py:attrs="{'xmi.idref':taggedValue.typeref}"/>
</UML:TaggedValue.type>
</UML:TaggedValue>
@ -178,8 +186,6 @@ def getTagDefinitions():
<UML:Generalization py:def="processGeneralization(generalization)"
xmi.id = 'I48de81cbm106d41f950cmm7eb4' isSpecification = 'false'
py:attrs="{'xmi.id':generalization.id}">
<UML:ModelElement.taggedValue
py:replace="processModelElementTaggedValue(generalization)"/>
<UML:Generalization.child>
<UML:Class xmi.idref = 'I48de81cbm106d41f950cmm7ec7'
py:attrs="{'xmi.idref':generalization.specific.id}"/>
@ -195,8 +201,6 @@ def getTagDefinitions():
visibility = 'public' isSpecification = 'false' isRoot = 'false' isLeaf = 'false'
isAbstract = 'false'
py:attrs="{'xmi.id':interface.id, 'name':interface.name}">
<UML:ModelElement.taggedValue
py:replace="processModelElementTaggedValue(interface)"/>
<UML:Classifier.feature py:replace="processClassifierFeature(interface)"/>
</UML:Interface>
@ -207,8 +211,6 @@ def getTagDefinitions():
isAbstract = 'true' isActive = 'false'
py:attrs="{'xmi.id':cls.id, 'name':cls.name,
'isAbstract':cls.isAbstract and 'true' or 'false'}">
<UML:ModelElement.taggedValue
py:replace="processModelElementTaggedValue(cls)"/>
<UML:ModelElement.stereotype py:if="cls.appliedStereotype">
<UML:Stereotype xmi.idref = 'I48de81cbm106d41f950cmm7e0c'
@ -235,8 +237,6 @@ def getTagDefinitions():
visibility = 'public' isSpecification = 'false' isRoot = 'false' isLeaf = 'false'
isAbstract = 'false'
py:attrs="{'xml.id':stereotype.id, 'name':stereotype.name}">
<UML:ModelElement.taggedValue
py:replace="processModelElementTaggedValue(stereotype)"/>
<UML:Stereotype.baseClass py:content="stereotype.ownedAttribute.type.name">Class</UML:Stereotype.baseClass>
</UML:Stereotype>
@ -244,8 +244,6 @@ def getTagDefinitions():
xmi.id = 'I48de81cbm106d41f950cmm7e01' name = 'aPackage' visibility = 'public'
isSpecification = 'false' isRoot = 'false' isLeaf = 'false' isAbstract = 'false'
py:attrs="{'xmi.idref':package.id, 'name':package.name}">
<UML:ModelElement.taggedValue
py:replace="processModelElementTaggedValue(package)"/>
<UML:Namespace.ownedElement>
<packageContent py:for="item in getPackageChildNodes(package=package)"
py:replace="modelProcessNode(item)"/>
@ -258,8 +256,6 @@ def getTagDefinitions():
xmi.id = 'I48de81cbm106d41f950cmm7d2f' isSpecification = 'false'
isRoot = 'false' isLeaf = 'false' isAbstract = 'false'
py:attrs="{'xmi.id':association.id, 'name':association.name}">
<UML:ModelElement.taggedValue
py:replace="processModelElementTaggedValue(association)"/>
<UML:Association.connection>
<UML:AssociationEnd xmi.id = 'I48de81cbm106d41f950cmm7d35' visibility = 'public'
isSpecification = 'false' isNavigable = 'false' ordering = 'unordered' aggregation = 'none'
@ -292,7 +288,7 @@ def getTagDefinitions():
py:replace="modelProcessNode(item)"/>
<UML:TagDefinition py:for="tagDef in getTagDefinitions()"
<UML:TagDefinition py:for="tagDef in tagDefinitions"
py:replace="processTagDefinition(tagDef)"/>
</UML:Namespace.ownedElement>

View File

@ -8,7 +8,11 @@ from gaphor.diagram import initialize_item
from feature import FeatureItem
from zope import interface
from gaphor.interfaces import IAttributeView
class AttributeItem(FeatureItem):
interface.implements(IAttributeView)
popup_menu = FeatureItem.popup_menu + (
'EditItem',

View File

@ -19,6 +19,8 @@ from classifier import ClassifierItem
from attribute import AttributeItem
from operation import OperationItem
from gaphor.interfaces import IClassView
from zope import interface
class ClassItem(ClassifierItem, diacanvas.CanvasGroupable):
"""This item visualizes a Class instance.
@ -29,6 +31,8 @@ class ClassItem(ClassifierItem, diacanvas.CanvasGroupable):
Items can be added by callling class.add() and class.remove().
This is used to handle CanvasItems, not UML objects!
"""
interface.implements(IClassView)
__gproperties__ = {
'show-attributes': (gobject.TYPE_BOOLEAN, 'show attributes',
'',

View File

@ -169,7 +169,12 @@ class TextElement(diacanvas.CanvasItem, diacanvas.CanvasEditable, DiagramItem):
from zope import interface
from gaphor.interfaces import INamedItemView
class NamedItem(ElementItem, diacanvas.CanvasEditable):
interface.implements(INamedItemView)
__gproperties__ = {
'name': (gobject.TYPE_STRING, 'name', '', '', gobject.PARAM_READWRITE)
}

8
gaphor/event.py Normal file
View File

@ -0,0 +1,8 @@
from zope import interface
from gaphor.interfaces import *
class DiagramItemFocused(object):
interface.implements(IDiagramElementReceivedFocus)
def __init__(self, diagramItem):
self.diagramItem = diagramItem

57
gaphor/interfaces.py Normal file
View File

@ -0,0 +1,57 @@
from zope import interface
from zope import component
class IGaphorAction(interface.Interface):
"""Action interface for use in Gaphor"""
class IMenuAction(interface.Interface):
"""An interface to hook up items to."""
class TestAdapter(object):
def __init__(self, context):
self.context = context
#component.provideAdapter(
#factory=TestAdapter,
#adapts=[IGaphorAction],
#provides=IZopeMenu,
#name="Test adapter name")
#class TestAdapter2(object):
#def __init__(self, context):
#self.context = context
#component.provideAdapter(
#factory=TestAdapter2,
#adapts=[IGaphorAction],
#provides=IZopeMenu,
#name="Test adapter 2 name")
#class TestAction(object):
#interface.implements(IGaphorAction)
class IDiagramElementReceivedFocus(interface.Interface):
"""A diagram item received focus"""
diagramItem = interface.Attribute("The diagram item that received focus")
class IWidget(interface.Interface):
"""A GTK widget"""
class IDetailsPage(IWidget):
"""A property page which can display itself in a notebook"""
class IDiagramElement(interface.Interface):
"""A diagram element"""
subject = interface.Attribute("The model element connect to this view")
class INamedItemView(IDiagramElement):
"""A view on an attribute (part of a class, interface etc.)."""
class IClassView(INamedItemView):
"""The graphical view on a class."""
class IAttributeView(INamedItemView):
"""A view on an attribute (part of a class, interface etc.)."""

View File

@ -14,6 +14,9 @@ from gaphor.ui.abstractwindow import AbstractWindow
import gaphor.ui.diagramactions
import gaphor.diagram.placementactions
from gaphor.event import DiagramItemFocused
from zope import component
class DiagramTab(object):
def __init__(self, owning_window):
@ -126,6 +129,7 @@ class DiagramTab(object):
def __on_view_focus_item(self, view, focus_item):
self.owning_window.execute_action('ItemFocus')
component.handle(DiagramItemFocused(focus_item))
def __on_view_select_item(self, view, select_item):
self.owning_window.execute_action('ItemSelect')

View File

@ -109,6 +109,7 @@ class NewAction(Action):
weave_method(NewAction.execute, ErrorHandlerAspect, message='Could not create a new model.')
register_action(NewAction)
class RevertAction(Action):
id = 'FileRevert'
label = _('_Revert...')

View File

@ -15,6 +15,11 @@ from gaphor.ui.menufactory import toolbox_to_menu
# Load actions
from gaphor.ui import mainactions, diagramactions
from gaphor.ui.objectinspector import ObjectInspector
from gaphor.interfaces import *
from zope import component
class MainWindow(AbstractWindow):
"""The main window for the application.
@ -122,7 +127,7 @@ class MainWindow(AbstractWindow):
_('_Help'), (
'Manual',
'About',
'<HelpSlot>')
'<HelpSlot>'),
)
toolbar = ('FileOpen',
@ -243,6 +248,7 @@ class MainWindow(AbstractWindow):
paned = gtk.HPaned()
paned.set_property('position', 160)
paned.pack1(vbox)
notebook = gtk.Notebook()
#notebook.popup_enable()
notebook.set_scrollable(True)
@ -250,7 +256,17 @@ class MainWindow(AbstractWindow):
notebook.connect_after('switch-page', self.on_notebook_switch_page)
paned.pack2(notebook)
self.objectInspector = ObjectInspector()
diagramReceivedFocus = component.adapter(IDiagramElementReceivedFocus)(
self.objectInspector)
component.provideHandler(diagramReceivedFocus)
secondPaned = gtk.VPaned()
secondPaned.set_property('position', 600)
secondPaned.pack1(notebook)
secondPaned.pack2(self.objectInspector)
secondPaned.show_all()
paned.pack2(secondPaned)
paned.show_all()
self.notebook = notebook
@ -360,6 +376,7 @@ class MainWindow(AbstractWindow):
a Diagram).
"""
path = self.get_model().path_from_element(element)
#log.debug("PATH = %s" % path)
# Expand the first row:
self.get_tree_view().expand_row(path[:-1], False)
# Select the diagram, so it can be opened by the OpenModelElement action

View File

@ -0,0 +1,180 @@
import gtk
from gaphor.interfaces import *
from zope import component
from gaphor.UML.uml2 import LiteralSpecification
class TestDiagramElement(object):
interface.implements(IDiagramElement)
class NamedItemPropertyPage(gtk.Table):
"""An adapter which works for any named item view.
It also sets up a table view which can be extended."""
def __init__(self, context):
super(NamedItemPropertyPage, self).__init__(rows=1, columns=1)
self.context = context
self.attach(gtk.Label("Name"), 0, 1, 0, 1, xoptions=gtk.FILL, yoptions=0)
nameEntry = gtk.Entry()
nameEntry.set_text(context.subject.name or '')
nameEntry.connect('changed', self.changeName)
self.attach(nameEntry, 1, 2, 0, 1, xoptions=gtk.FILL|gtk.EXPAND, yoptions=0)
def changeName(self, entry):
self.context.subject.name = entry.get_text()
component.provideAdapter(
factory=NamedItemPropertyPage,
adapts=[INamedItemView],
provides=IDetailsPage,
name='Properties')
class PropertyPropertyPage(NamedItemPropertyPage):
"""Adapter which shows a property page for a property (attributes etc.)."""
component.provideAdapter(
factory=PropertyPropertyPage,
adapts=[IAttributeView],
provides=IDetailsPage,
name='Properties')
class ClassPropertyPage(NamedItemPropertyPage):
"""Adapter which shows a property page for a class view."""
def __init__(self, context):
super(ClassPropertyPage, self).__init__(context)
# Abstract toggle
self.attach(gtk.Label("Abstract"), 0, 1, 1, 2, xoptions=gtk.FILL, yoptions=0)
abstractCheckButton = gtk.CheckButton()
abstractCheckButton.set_active(context.subject.isAbstract)
abstractCheckButton.connect('toggled', self.changeAbstract)
self.attach(abstractCheckButton, 1, 2, 1, 2, xoptions=gtk.FILL|gtk.EXPAND, yoptions=0)
# Attributes
attributes = gtk.ListStore(str)
for attr in context.subject.ownedAttribute:
attributes.append([attr.name])
attributesTreeView = gtk.TreeView(attributes)
attributesTreeView.set_rules_hint(True)
textRenderer = gtk.CellRendererText()
attributesColumn = gtk.TreeViewColumn('Attributes', textRenderer, text=0)
attributesTreeView.append_column(attributesColumn)
self.attach(attributesTreeView, 0, 2, 2, 3, xoptions=gtk.FILL|gtk.EXPAND, yoptions=0)
def changeName(self, entry):
self.context.subject.name = entry.get_text()
def changeAbstract(self, checkButton):
self.context.subject.isAbstract=checkButton.get_active()
component.provideAdapter(
factory=ClassPropertyPage,
adapts=[IClassView],
provides=IDetailsPage,
name='Properties')
class TaggedValuePage(gtk.VBox):
"""An editor for tagged values associated with elements."""
def __init__(self, context):
super(TaggedValuePage, self).__init__()
self.context = context
taggedValues = gtk.ListStore(str, str)
for taggedValue in self.context.subject.taggedValue:
tag, value = taggedValue.value.split("=")
taggedValues.append([tag, value])
taggedValues.append(['',''])
self.taggedValues = taggedValues
treeView = gtk.TreeView(taggedValues)
treeView.set_rules_hint(True)
tagTextRenderer = gtk.CellRendererText()
tagTextRenderer.set_property('editable', True)
tagTextRenderer.connect("edited", self.cellEdited, 0)
valueTextRenderer = gtk.CellRendererText()
valueTextRenderer.set_property('editable', True)
valueTextRenderer.connect("edited", self.cellEdited, 1)
tagColumn = gtk.TreeViewColumn('Tag', tagTextRenderer, text=0)
treeView.append_column(tagColumn)
valueColumn = gtk.TreeViewColumn('Value', valueTextRenderer, text=1)
treeView.append_column(valueColumn)
self.pack_start(treeView)
def cellEdited(self, cellrenderertext, path, new_text, col):
self.taggedValues[path][col]=new_text
iter = self.taggedValues.get_iter(path)
if not new_text and not self.taggedValues[path][1-col] and self.isLastRow(self.taggedValues, iter):
self.taggedValues.remove(iter)
# Create a new row to enter next value
elif new_text and not self.isLastRow(self.taggedValues, iter):
self.taggedValues.append(['',''])
self.updateTaggedValuesInModel()
def updateTaggedValuesInModel(self):
"""Write the current list out the model."""
klass = self.context.subject
while klass.taggedValue:
klass.taggedValue[0].unlink()
for tag, value in self.taggedValues:
taggedValue = klass._factory.create(LiteralSpecification)
taggedValue.value = "%s=%s"%(tag, value)
klass.taggedValue.append(taggedValue)
def isLastRow(self, model, iter):
return bool(model.iter_next(iter))
component.provideAdapter(
factory=TaggedValuePage,
adapts=[INamedItemView],
provides=IDetailsPage,
name='Tagged values')
class ObjectInspector(gtk.Notebook):
def __init__(self):
super(ObjectInspector, self).__init__()
self.set_scrollable(False)
self.set_show_border(True)
def loadTabsForCurrentItem(self, item):
"""Load all tabs that can operate on the given item."""
for name, adapter in component.getAdapters(
[item,], IDetailsPage):
self.prepend_page(adapter, gtk.Label(name))
self.show_all()
def clearAllTabs(self):
"""Remove all tabs from the notebook."""
[self.remove_page(0) for i in range(self.get_n_pages())]
def __call__(self, event):
"""Called when a diagram item receives focus.
This reloads all tabs based on the current selection."""
diagramItem = event.diagramItem
self.clearAllTabs()
if diagramItem is None:
return
self.loadTabsForCurrentItem(diagramItem.item)

View File

@ -371,7 +371,18 @@ setup(name='gaphor',
'gaphor.UML',
'gaphor.diagram',
'gaphor.ui',
'gaphor.misc'
'gaphor.misc',
'zope',
'zope.interface',
'zope.component.bbb',
'zope.component.bbb.tests',
'zope.interface.common',
'zope.component',
'zope.exceptions',
'zope.proxy',
'zope.deprecation',
'zope.testing',
],
# ext_modules=ext_modules,
# data files are relative to <prefix>/share/gaphor (see setup.cfg)