/*
* (c) Copyright 2010-2011 AgileBirds
*
* This file is part of OpenFlexo.
*
* OpenFlexo 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 3 of the License, or
* (at your option) any later version.
*
* OpenFlexo 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 OpenFlexo. If not, see <http://www.gnu.org/licenses/>.
*
*/
package cb.petal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Random;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
/**
* Top level node (aka. model) containing two children: Petal and Design. To be used in GUI applications it also may be used as the tree
* model for a JTree.
*
* @version $Id: PetalFile.java,v 1.3 2011/09/12 11:46:48 gpolet Exp $
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
*/
public class PetalFile implements PetalNode, TreeModel {
private Petal petal;
private Design design;
private String model_name = "anonymous";
static final long serialVersionUID = 5388875684404513535L;
public PetalFile(Petal petal, Design design) {
setPetal(petal);
setDesign(design);
}
public PetalFile() {
}
@Override
public boolean equals(java.lang.Object o) {
return o instanceof PetalFile && ((PetalFile) o).petal.equals(this.petal) && ((PetalFile) o).design.equals(this.design);
}
@Override
public int hashCode() {
return getPetal() == null ? 0 : getPetal().hashCode();
}
@Override
public java.lang.Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
return null;
}
}
public void setPetal(Petal p) {
petal = p;
}
public Petal getPetal() {
return petal;
}
public void setDesign(Design p) {
design = p;
}
public Design getDesign() {
return design;
}
public String getModelName() {
return model_name;
}
public void setModelName(String v) {
model_name = v;
}
@Override
public void accept(Visitor v) {
v.visit(this);
}
@Override
public String getKind() {
return "root node";
}
@Override
public String toString() {
return petal + cb.util.Constants.getNewLine() + design;
}
private static Random random = new Random();
/**
* @return unique quid - as with Rational Rose this is simply the current time expressed as the number of seconds elapsed since January
* 1, 1970 + some random number. If the resulting string is shorter than 12 characters it is filled up with some random
* characters.
*/
public static String getQuid() {
String s = Long.toHexString(new Date().getTime() + Math.abs(random.nextLong())).toUpperCase();
int diff = 12 - s.length();
for (int i = 0; i < diff; i++) {
int rand = Math.abs(random.nextInt()) % 16;
s = s + Integer.toHexString(rand).toUpperCase();
}
return s;
}
/**
* Register the quids for objects so they can be mapped back to objects.
*/
private HashMap quids = new HashMap(); // Map<String,PetalObject>
/**
* Register class by its quid property.
*/
public final void registerQuidObject(String quid, QuidObject obj) {
quids.put(quid, obj);
}
/**
* Register class by its "quid" property.
*/
public final void registerQuidObject(QuidObject obj) {
registerQuidObject(QuidObject.getQuid(obj), obj);
}
/**
* @return object by its "quid" (if registered via init())
*/
public final QuidObject getQuidObject(String quid) {
return (QuidObject) quids.get(quid);
}
/**
* @return class object by its "quid" property (if registered via init())
*/
public final Class getClassByQuid(String quid) {
return (Class) getQuidObject(quid);
}
/**
* @return class object by the quidu reference, i.e. a HasQuidu contains a reference to a class denoted by the "quidu" property
*/
public final Class getClassByQuidu(HasQuidu obj) {
return (Class) this.getReferencedObject(obj);
}
public final QuidObject getReferencedObject(HasQuidu obj) {
return getQuidObject(obj.getQuidu());
}
private HashMap classes = new HashMap();
/**
* Register class by its fully qualified name
*/
public final void registerClass(Class clazz) {
classes.put(clazz.getQualifiedName(), clazz);
}
/**
* @return class by its fully qualified name
*/
public final Class getClassByQualifiedName(String qual) {
return (Class) classes.get(qual);
}
private HashMap assocs = new HashMap(); // Map<String,List<Association>>
/**
* Register the association internally, i.e. associate it with the given classes. So the classes can look up the associations related to
* them.
*/
public final void registerAssociation(Association a) {
for (Iterator i = a.getRoles().getElements().iterator(); i.hasNext();) {
Role role = (Role) i.next();
try {
String quid = role.getQuidu();
ArrayList list = (java.util.ArrayList) assocs.get(quid);
if (list == null) {
assocs.put(quid, list = new ArrayList());
}
list.add(a);
} catch (RuntimeException e) {
System.err.println("Cannot parse role " + role.getName() + " in association " + a.getName());
continue;
}
}
}
/**
* If the association has registered itself properly (done in Association.init() by default) one can look up what associations a class
* has.
*/
public final java.util.List getAssociations(cb.petal.Class clazz) {
return (java.util.List) assocs.get(clazz.getQuid());
}
/**
* @return top level LogicalCategory
*/
public LogicalCategory getLogicalCategory() {
return (LogicalCategory) design.getProperty("root_category");
}
/**
* @return top level UseCaseCategory
*/
public UseCaseCategory getUseCaseCategory() {
return (UseCaseCategory) design.getProperty("root_usecase_package");
}
private int tag_counter = 1;
/**
* Tags are numbered consecutively within a model file. So we just use in internal counter.
*/
public final int getNewTag() {
return tag_counter++;
}
/**************************** TreeModel methods **********************/
private ArrayList treeModelListeners = new ArrayList();
/**
* @return the root of the tree which is just "this" object.
*/
@Override
public java.lang.Object getRoot() {
return this;
}
/**
* Adds a listener for the TreeModelEvent posted after the tree changes.
*/
@Override
public void addTreeModelListener(TreeModelListener l) {
treeModelListeners.add(l);
}
/**
* Removes a listener previously added with addTreeModelListener().
*/
@Override
public void removeTreeModelListener(TreeModelListener l) {
treeModelListeners.remove(l);
}
/**
* @return true if (petal) node is a leaf.
*/
@Override
public boolean isLeaf(java.lang.Object node) {
return node instanceof Literal;
}
/**
* Returns the number of children of parent.
*/
@Override
public int getChildCount(java.lang.Object node) {
PetalNode p = (PetalNode) node;
return p.getChildCount();
}
/**
* Returns the child of parent at index index in the parent's child array.
*/
@Override
public java.lang.Object getChild(java.lang.Object node, int index) {
if (node instanceof PetalFile) {
PetalFile p = (PetalFile) node;
switch (index) {
case 0:
return petal;
case 1:
return design;
default:
throw new RuntimeException("Illegal index for PetalFile: " + index);
}
} else if (node instanceof PetalObject) {
PetalObject p = (PetalObject) node;
return p.getProperty(index);
} else if (node instanceof List) {
return ((List) node).get(index);
} else {
return null;
}
}
@Override
public int getIndexOfChild(java.lang.Object node, java.lang.Object child) {
if (node instanceof PetalFile) {
if (child == petal) {
return 0;
} else if (child == design) {
return 1;
} else {
throw new RuntimeException("Not a child of PetalFile: " + child);
}
} else if (node instanceof PetalObject) {
PetalObject p = (PetalObject) node;
return p.indexOf((PetalNode) child);
} else {
return 0;
}
}
@Override
public int getChildCount() {
return 2;
}
/**
* Messaged when the user has altered the value for the item identified by path to newValue. TODO
*/
@Override
public void valueForPathChanged(TreePath path, java.lang.Object newValue) {
System.out.println("*** valueForPathChanged : " + path + " --> " + newValue);
}
}