001/*
002// This software is subject to the terms of the Eclipse Public License v1.0
003// Agreement, available at the following URL:
004// http://www.eclipse.org/legal/epl-v10.html.
005// You must accept the terms of that agreement to use this software.
006//
007// Copyright (C) 2002-2005 Julian Hyde
008// Copyright (C) 2005-2010 Pentaho and others
009// Copyright (C) 2006-2007 CINCOM SYSTEMS, INC.
010// All Rights Reserved.
011*/
012package mondrian.gui;
013
014import mondrian.util.CompositeList;
015
016import java.util.*;
017import javax.swing.tree.*;
018
019/**
020 * @author sean
021 */
022public class SchemaTreeModel extends DefaultTreeModel {
023    /**
024     * Creates a SchemaTreeModel.
025     */
026    public SchemaTreeModel() {
027        super(null);
028        // TODO Auto-generated constructor stub
029    }
030
031    MondrianGuiDef.Schema schema;
032
033    /**
034     * Creates a new instance of SchemaTreeModel
035     */
036    public SchemaTreeModel(MondrianGuiDef.Schema s) {
037        super(new DefaultMutableTreeNode(s.name));
038        this.schema = s;
039    }
040
041
042    /**
043     * Returns the child of <code>parent</code> at index <code>index</code>
044     * in the parent's
045     * child array.  <code>parent</code> must be a node previously obtained
046     * from this data source. This should not return <code>null</code>
047     * if <code>index</code>
048     * is a valid index for <code>parent</code> (that is <code>index >= 0 &&
049     * index < getChildCount(parent</code>)).
050     *
051     * @param parent a node in the tree, obtained from this data source
052     * @return the child of <code>parent</code> at index <code>index</code>
053     */
054    public Object getChild(Object parent, int index) {
055        return getChildList(parent).get(index);
056    }
057
058    /**
059     * Returns an immutable list of child elements of a given element.
060     *
061     * @param parent Parent element
062     * @return List of children
063     */
064    private List<Object> getChildList(Object parent) {
065        if (parent instanceof MondrianGuiDef.Cube) {
066            MondrianGuiDef.Cube c = (MondrianGuiDef.Cube) parent;
067            // Return children in this order: fact table, dimensions, measures,
068            // calculatedMembers, namedSets
069            return new CompositeList<Object>(
070                ifList(c.fact),
071                Arrays.asList(c.dimensions),
072                Arrays.asList(c.measures),
073                Arrays.asList(c.calculatedMembers),
074                Arrays.asList(c.namedSets),
075                ifList(c.annotations));
076        } else if (parent instanceof MondrianGuiDef.Dimension) {
077            MondrianGuiDef.Dimension d = (MondrianGuiDef.Dimension) parent;
078            return new CompositeList<Object>(
079                Arrays.asList((Object[]) d.hierarchies),
080                ifList(d.annotations));
081        } else if (parent instanceof MondrianGuiDef.UserDefinedFunction) {
082            MondrianGuiDef.UserDefinedFunction udf =
083                (MondrianGuiDef.UserDefinedFunction) parent;
084            return new CompositeList<Object>(
085                ifList(udf.script));
086        } else if (parent instanceof MondrianGuiDef.ExpressionView) {
087            MondrianGuiDef.ExpressionView ev =
088                (MondrianGuiDef.ExpressionView) parent;
089            return Arrays.asList((Object[]) ev.expressions);
090        } else if (parent instanceof MondrianGuiDef.Hierarchy) {
091            MondrianGuiDef.Hierarchy h = (MondrianGuiDef.Hierarchy) parent;
092            return new CompositeList<Object>(
093                Arrays.asList(h.levels),
094                Arrays.asList(h.memberReaderParameters),
095                ifList(h.relation),
096                ifList(h.annotations));
097        } else if (parent instanceof MondrianGuiDef.Join) {
098            MondrianGuiDef.Join j = (MondrianGuiDef.Join) parent;
099            return Arrays.<Object>asList(
100                j.left,
101                j.right);
102        } else if (parent instanceof MondrianGuiDef.Level) {
103            MondrianGuiDef.Level level = (MondrianGuiDef.Level) parent;
104            return new CompositeList<Object>(
105                Arrays.asList(level.properties),
106                ifList(level.keyExp),
107                ifList(level.nameExp),
108                ifList(level.ordinalExp),
109                ifList(level.captionExp),
110                ifList(level.parentExp),
111                ifList(level.closure),
112                ifList(level.memberFormatter),
113                ifList(level.annotations));
114        } else if (parent instanceof MondrianGuiDef.CellFormatter) {
115            MondrianGuiDef.CellFormatter f =
116                (MondrianGuiDef.CellFormatter) parent;
117            return new CompositeList<Object>(
118                ifList(f.script));
119        } else if (parent instanceof MondrianGuiDef.MemberFormatter) {
120            MondrianGuiDef.MemberFormatter f =
121                (MondrianGuiDef.MemberFormatter) parent;
122            return new CompositeList<Object>(
123                ifList(f.script));
124        } else if (parent instanceof MondrianGuiDef.PropertyFormatter) {
125            MondrianGuiDef.PropertyFormatter f =
126                (MondrianGuiDef.PropertyFormatter) parent;
127            return new CompositeList<Object>(
128                ifList(f.script));
129        } else if (parent instanceof MondrianGuiDef.Property) {
130            MondrianGuiDef.Property property =
131                (MondrianGuiDef.Property) parent;
132            return new CompositeList<Object>(
133                ifList(property.propertyFormatter));
134        } else if (parent instanceof MondrianGuiDef.CalculatedMember) {
135            MondrianGuiDef.CalculatedMember c =
136                (MondrianGuiDef.CalculatedMember) parent;
137            return new CompositeList<Object>(
138                ifList(c.formulaElement),
139                arrayList(c.memberProperties),
140                ifList(c.annotations),
141                ifList(c.cellFormatter));
142        } else if (parent instanceof MondrianGuiDef.Measure) {
143            MondrianGuiDef.Measure m = (MondrianGuiDef.Measure) parent;
144            return new CompositeList<Object>(
145                ifList(m.measureExp),
146                arrayList(m.memberProperties),
147                ifList(m.annotations),
148                ifList(m.cellFormatter));
149        } else if (parent instanceof MondrianGuiDef.NamedSet) {
150            MondrianGuiDef.NamedSet m = (MondrianGuiDef.NamedSet) parent;
151            return new CompositeList<Object>(
152                ifList((Object) m.formulaElement),
153                ifList(m.annotations));
154        } else if (parent instanceof MondrianGuiDef.Schema) {
155            MondrianGuiDef.Schema s = (MondrianGuiDef.Schema) parent;
156            // Return children in this order: cubes, dimensions, namedSets,
157            // userDefinedFunctions, virtual cubes, roles
158            return new CompositeList<Object>(
159                Arrays.asList(s.cubes),
160                Arrays.asList(s.dimensions),
161                Arrays.asList(s.namedSets),
162                Arrays.asList(s.namedSets),
163                Arrays.asList(s.userDefinedFunctions),
164                Arrays.asList(s.virtualCubes),
165                Arrays.asList(s.roles),
166                Arrays.asList(s.parameters),
167                ifList(s.annotations));
168        } else if (parent instanceof MondrianGuiDef.Table) {
169            MondrianGuiDef.Table t = (MondrianGuiDef.Table) parent;
170            return new CompositeList<Object>(
171                arrayList(t.aggTables),
172                arrayList(t.aggExcludes));
173        } else if (parent instanceof MondrianGuiDef.AggTable) {
174            MondrianGuiDef.AggTable t = (MondrianGuiDef.AggTable) parent;
175            return new CompositeList<Object>(
176                ifList(t.factcount),
177                Arrays.asList(t.ignoreColumns),
178                Arrays.asList(t.foreignKeys),
179                Arrays.asList(t.measures),
180                Arrays.asList(t.levels),
181                (t instanceof MondrianGuiDef.AggPattern)
182                    ? Arrays.asList(((MondrianGuiDef.AggPattern) t).excludes)
183                    : Collections.emptyList());
184        } else if (parent instanceof MondrianGuiDef.View) {
185            MondrianGuiDef.View v = (MondrianGuiDef.View) parent;
186            return Arrays.asList((Object[]) v.selects);
187        } else if (parent instanceof MondrianGuiDef.VirtualCube) {
188            MondrianGuiDef.VirtualCube c = (MondrianGuiDef.VirtualCube) parent;
189            return new CompositeList<Object>(
190                Arrays.asList(c.dimensions),
191                Arrays.asList(c.measures),
192                Arrays.asList(c.calculatedMembers),
193                ifList(c.annotations));
194        } else if (parent instanceof MondrianGuiDef.VirtualCubeDimension) {
195            MondrianGuiDef.VirtualCubeDimension d =
196                (MondrianGuiDef.VirtualCubeDimension) parent;
197            return ifList((Object)d.annotations);
198        } else if (parent instanceof MondrianGuiDef.VirtualCubeMeasure) {
199            MondrianGuiDef.VirtualCubeMeasure m =
200                (MondrianGuiDef.VirtualCubeMeasure) parent;
201            return ifList((Object)m.annotations);
202        } else if (parent instanceof MondrianGuiDef.Role) {
203            MondrianGuiDef.Role c = (MondrianGuiDef.Role) parent;
204            return new CompositeList<Object>(
205                Arrays.asList((Object[]) c.schemaGrants),
206                ifList((Object)c.annotations));
207        } else if (parent instanceof MondrianGuiDef.SchemaGrant) {
208            MondrianGuiDef.SchemaGrant c = (MondrianGuiDef.SchemaGrant) parent;
209            return Arrays.asList((Object[]) c.cubeGrants);
210        } else if (parent instanceof MondrianGuiDef.CubeGrant) {
211            MondrianGuiDef.CubeGrant c = (MondrianGuiDef.CubeGrant) parent;
212            return new CompositeList<Object>(
213                Arrays.asList(c.dimensionGrants),
214                Arrays.asList(c.hierarchyGrants));
215        } else if (parent instanceof MondrianGuiDef.HierarchyGrant) {
216            MondrianGuiDef.HierarchyGrant c =
217                (MondrianGuiDef.HierarchyGrant) parent;
218            return Arrays.asList((Object[]) c.memberGrants);
219        } else if (parent instanceof MondrianGuiDef.Closure) {
220            MondrianGuiDef.Closure c = (MondrianGuiDef.Closure) parent;
221            return ifList((Object) c.table);
222        } else if (parent instanceof MondrianGuiDef.Annotations) {
223            MondrianGuiDef.Annotations annotations =
224                (MondrianGuiDef.Annotations) parent;
225            return Arrays.asList((Object[]) annotations.array);
226        } else {
227            // In particular: Column, SQL, DimensionUsage have no children.
228            return Collections.emptyList();
229        }
230    }
231
232    /**
233     * Returns a list with zero or one elements.
234     *
235     * @param e Element
236     * @param <T> Element type
237     * @return List containing element if it is not null, otherwise empty list
238     */
239    private <T> List<T> ifList(T e) {
240        return e == null
241            ? Collections.<T>emptyList()
242            : Collections.singletonList(e);
243    }
244
245    /**
246     * Returns a list with a given set of elements, or an empty list if the
247     * array is null.
248     *
249     * @param e Element
250     * @param <T> Element type
251     * @return List containing element if it is not null, otherwise empty list
252     */
253    private <T> List<T> arrayList(T... e) {
254        return e == null || e.length == 0
255            ? Collections.<T>emptyList()
256            : e.length == 1
257            ? Collections.singletonList(e[0])
258            : Arrays.asList(e);
259    }
260
261    /**
262     * Returns the number of children of <code>parent</code>.
263     * Returns 0 if the node
264     * is a leaf or if it has no children.  <code>parent</code> must be a node
265     * previously obtained from this data source.
266     *
267     * @param parent a node in the tree, obtained from this data source
268     * @return the number of children of the node <code>parent</code>
269     */
270    public int getChildCount(Object parent) {
271        return getChildList(parent).size();
272    }
273
274    /**
275     * Returns the index of child in parent.  If <code>parent</code>
276     * is <code>null</code> or <code>child</code> is <code>null</code>,
277     * returns -1.
278     *
279     * @param parent a note in the tree, obtained from this data source
280     * @param child  the node we are interested in
281     * @return the index of the child in the parent, or -1 if either
282     *         <code>child</code> or <code>parent</code> are <code>null</code>
283     */
284    public int getIndexOfChild(Object parent, Object child) {
285        if (parent == null) {
286            return -1;
287        }
288        final List<Object> list = getChildList(parent);
289        int i = 0;
290        for (Object o : list) {
291            if (equal(o, child)) {
292                return i;
293            }
294            ++i;
295        }
296        return -1;
297    }
298
299    /**
300     * Returns whether two XML objects are equal.
301     *
302     * @param o1 First object
303     * @param o2 Second object
304     * @return Whether objects are equal
305     */
306    private boolean equal(Object o1, Object o2) {
307        if (o1 == null) {
308            return o2 == null;
309        } else if (o1 instanceof MondrianGuiDef.Hierarchy
310             || o1 instanceof MondrianGuiDef.SQL)
311        {
312            return o1 == o2;
313        } else {
314            return o1.equals(o2);
315        }
316    }
317
318    /**
319     * Returns the root of the tree.  Returns <code>null</code>
320     * only if the tree has no nodes.
321     *
322     * @return the root of the tree
323     */
324    public Object getRoot() {
325        return schema;
326    }
327
328    /**
329     * Returns <code>true</code> if <code>node</code> is a leaf.
330     * It is possible for this method to return <code>false</code>
331     * even if <code>node</code> has no children.
332     * A directory in a filesystem, for example,
333     * may contain no files; the node representing
334     * the directory is not a leaf, but it also has no children.
335     *
336     * @param node a node in the tree, obtained from this data source
337     * @return true if <code>node</code> is a leaf
338     */
339    public boolean isLeaf(Object node) {
340        return getChildCount(node) == 0;
341    }
342
343    public void valueForPathChanged(TreePath path, Object newValue) {
344        //super.valueForPathChanged(path, newValue);
345    }
346
347}
348
349// End SchemaTreeModel.java