/* $Id: $ ***************************************************************************** * Copyright (c) 2010 Contributors - see below * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Bob Tarling ***************************************************************************** */ package org.argouml.activity2.diagram; import java.beans.PropertyVetoException; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.Action; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.apache.log4j.Logger; import org.argouml.model.Model; import org.argouml.uml.diagram.UMLMutableGraphSupport; import org.argouml.uml.diagram.UmlDiagramRenderer; import org.argouml.uml.diagram.ui.ActionSetMode; import org.argouml.uml.diagram.ui.RadioAction; import org.argouml.uml.diagram.ui.UMLDiagram; import org.tigris.gef.base.LayerPerspective; import org.tigris.gef.base.LayerPerspectiveMutable; import org.tigris.gef.base.ModeCreatePolyEdge; import org.tigris.gef.graph.MutableGraphModel; import org.tigris.gef.presentation.FigNode; import org.w3c.dom.DOMException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; abstract class BaseDiagram extends UMLDiagram { private static final Logger LOG = Logger .getLogger(BaseDiagram.class); BaseDiagram(Object owner) { super(); MutableGraphModel gm = createGraphModel(); setGraphModel(gm); // Create the layer LayerPerspective lay = new LayerPerspectiveMutable(this.getName(), gm); setLayer(lay); // Create the renderer UmlDiagramRenderer renderer = createDiagramRenderer(); lay.setGraphNodeRenderer(renderer); lay.setGraphEdgeRenderer(renderer); if (LOG.isDebugEnabled()) { LOG.debug("Constructing diagram for " + owner); } try { this.setName(getNewDiagramName()); } catch (PropertyVetoException e) { LOG.error("Exception", e); } } abstract UmlDiagramRenderer createDiagramRenderer(); abstract UMLMutableGraphSupport createGraphModel(); private Map<String, Class<?>> metaTypeByName; private Map<Class<?>, String> nameByMetaType; @Override protected Object[] getUmlActions() { try { final Document doc = getDocument(); final Element element = getElement(doc.getDocumentElement(), "classes"); final int size = element.getChildNodes().getLength(); nameByMetaType = new HashMap<Class<?>, String>(size); metaTypeByName = new HashMap<String, Class<?>>(size); populateClassMaps(element, nameByMetaType, metaTypeByName); final Element toolbarElement = getElement(doc.getDocumentElement(), "toolbar"); return getToolbarActions(toolbarElement); } catch (DOMException e) { LOG.error("", e); } catch (IOException e) { LOG.error("", e); } catch (ParserConfigurationException e) { LOG.error("", e); } catch (SAXException e) { LOG.error("", e); } return null; } /** * Get the single (or first) child Element of the given element * that has the given tag name. * @param element * @param tagName * @return the child element */ private Element getElement(Element element, String tagName) { final NodeList nl = element.getElementsByTagName(tagName); if (nl.getLength() == 0) { return null; } return (Element) nl.item(0); } private Object[] getToolbarActions(Element toolbarNode) { final NodeList nl = toolbarNode.getChildNodes(); List<Element> elements = new ArrayList<Element>(); for (int i = 0; i < nl.getLength(); ++i) { final Node n = nl.item(i); if (n instanceof Element) { elements.add((Element) n); } } final Object[] toolbarActions = new Object[elements.size()]; for (int i = 0; i < elements.size(); ++i) { final Element itemNode = elements.get(i); Object o; String style = itemNode.getNodeName(); if (style.equals("dropdown")) { o = getToolbarActions(itemNode); } else if (style.equals("poly-edge")) { final String type = itemNode.getAttribute("type"); final Class<?> metaType = metaTypeByName.get(type); o = getCreateEdgeAction(metaType); } else { final String type = itemNode.getAttribute("type"); final Class<?> metaType = metaTypeByName.get(type); o = new CreateDiagramElementAction( metaType, style, Model.getMetaTypes().getName(metaType), this); } toolbarActions[i] = o; } return toolbarActions; } // TODO: This is currently duplicated from MetaDataCache - must find a // common place in model facade private void populateClassMaps( final Element classesNode, final Map<Class<?>, String> nameByMetaType, final Map<String, Class<?>> metaTypeByName) { final NodeList nl = classesNode.getElementsByTagName("class"); for (int i = 0; i < nl.getLength(); ++i) { Element classNode = (Element) nl.item(i); String className = classNode.getTextContent(); try { final String name = classNode.getAttribute("name"); Class<?> clazz = Class.forName(className); metaTypeByName.put(name, clazz); nameByMetaType.put(clazz, name); } catch (ClassNotFoundException e) { LOG.error("Class not found " + className, e); } } } /** * Get the diagram definition XML document * @return * @throws IOException * @throws DOMException * @throws ParserConfigurationException * @throws SAXException */ private Document getDocument() throws IOException, DOMException, ParserConfigurationException, SAXException { final String filename = getDiagramXmlFile(); InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(filename); InputSource inputSource = new InputSource(inputStream); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); return db.parse(inputSource); } protected abstract String getDiagramXmlFile(); protected Action getCreateEdgeAction(Object metaType) { String label = Model.getMetaTypes().getName(metaType); return new RadioAction( new ActionSetMode( ModeCreatePolyEdge.class, "edgeClass", metaType, label)); } @Override public void encloserChanged(FigNode enclosed, FigNode oldEncloser, FigNode newEncloser) { // Do nothing. } /* * @see org.argouml.uml.diagram.ui.UMLDiagram#isRelocationAllowed(java.lang.Object) */ public boolean isRelocationAllowed(Object base) { return false; } public Collection getRelocationCandidates(Object root) { return Collections.EMPTY_LIST; } public boolean relocate(Object base) { return false; } }