001: package net.xoetrope.xui.data;
002:
003: import net.xoetrope.xui.XProjectManager;
004: import java.util.Vector;
005:
006: /**
007: * The XModel is designed to support an MVC like structure. The model allows data
008: * to be maintained separately from UI code and separately from the control logic.
009: * The model supports an XPath like way of naming nodes and accessing data. The model
010: * is hierarchical and therefore a variety of data can be stored including simple
011: * scalar values to vectors and arrays. The model can be supplemented by adding
012: * custom node types and by using adapters and bindings.
013: * <p>
014: * The XModel is one of the main ideas behind XUI and central to providing the
015: * clean separation of the data. The XUI UI components can be abstractly bound
016: * to the model as instances of XModel although the actual nodes may be
017: * implemented by a range of classes representing tables or lists of even more
018: * complex nodes. All the UI component need know the path to the node in the model.
019: * <br>
020: * In some cases an adapter is used to simplify access to the data and perhaps
021: * maintain additional information needed by the UI component (e.g. the selected
022: * value in a list).
023: * <p>Copyright (c) Xoetrope Ltd., 1998-2003<br>
024: * License: see license.txt
025: * @version $Revision: 1.30 $
026: */
027: public abstract class XModel {
028: protected String tagName;
029: private Vector modelListeners;
030:
031: /**
032: * Get the root instance of the model. This class now delegates to the project manager.
033: * @return the root XModel instance.
034: * 'deprecated since 1.0.3
035: */
036: public static XModel getInstance() {
037: return XProjectManager.getModel();
038: }
039:
040: /**
041: * Reset the whole model, giving a new root node and a new hierarchy
042: * 'deprecated since 1.0.3
043: */
044: public XModel reset() {
045: XProjectManager.getCurrentProject().resetModel();
046: return XProjectManager.getModel();
047: }
048:
049: /**
050: * Return this node to its initial state by removing its children and attributes
051: */
052: public void clear() {
053: resetAttributes();
054: removeChildren();
055: }
056:
057: /**
058: * Reset the attributes of this node
059: */
060: public void resetAttributes() {
061: }
062:
063: /**
064: * Remove the children of this node
065: */
066: public void removeChildren() {
067: }
068:
069: /**
070: * Sets the model element tag name, e.g. 'Component' from the XML fragment
071: * <Component ....
072: * @param name
073: */
074: public void setTagName(String name) {
075: tagName = name;
076: }
077:
078: /**
079: * Gets the model element tag name, e.g. 'Component' from the XML fragment
080: * <Component ....
081: * @return the model name
082: */
083: public String getTagName() {
084: return tagName;
085: }
086:
087: /**
088: * @return true if there was no name for the element in the DataSource, an
089: * example of this is the annonymouse nodes used to represent the record of
090: * a table e.g. <tr><td>...</td><td>...</td></tr>
091: */
092: public boolean hasAutoId() {
093: return false;
094: }
095:
096: /**
097: * Gets the value of the ID attribute
098: * @return the ID attribute
099: */
100: public abstract String getId();
101:
102: /**
103: * Sets the ID attribute
104: * @param newId the new name
105: */
106: public void setId(String newId) {
107: }
108:
109: /**
110: * Get the value of the element located at the path in the element parameter
111: * If the attribName parameter is not null we get the value of the
112: * attributeValues
113: * @param element The path to the XModel we require
114: * @return The value of the XModel or the attribute
115: */
116: public Object get(String element) {
117: return null;
118: }
119:
120: /**
121: * Set the named attribute value of this XModel node. If the attribName is
122: * null then this node's value is updated.
123: * @param elementName The path to the XModel in the format 'base/foo
124: * @param newObject The new value of the XModel
125: */
126: public abstract void set(String attribName, Object newObject);
127:
128: /**
129: * returns the index of the attribiteNames array whose value is the same
130: * as the attribName
131: * @param attribName The name of the attribute we are trying to locate
132: * @return The index of the attributeNames array containg the name
133: */
134: public abstract int getAttribute(String attribName);
135:
136: /**
137: * Sets the attribute value
138: * @param i The index of the attributeValues array whose value we want
139: * @param value the value object
140: */
141: public abstract void setAttribValue(int i, Object value);
142:
143: /**
144: * Sets the attribute name and value
145: * @param i The index of the attributeValues array whose value we want
146: * @param attribName the name of the attribute
147: * @param value the value object
148: */
149: public abstract void setAttribValue(int i, String attribName,
150: Object value);
151:
152: /**
153: * Get the XModel at element i
154: * @param i The index of the values array
155: * @return The XModel at location i
156: */
157: public abstract XModel get(int i);
158:
159: /**
160: * gets the value attribute
161: * @return the value of the model
162: */
163: public abstract Object get();
164:
165: /**
166: * Sets the model value
167: * @param s the new value
168: */
169: public abstract void set(Object s);
170:
171: /**
172: * Used for elements which need a name assigned temporarily because one doesn't
173: * exist in the DataSource.
174: * @param b true if there was no name in the DataSource
175: */
176: public void hasAutoId(boolean b) {
177: }
178:
179: /**
180: * @param i The index of the attributeNames array whose value we want
181: * @return The string value of the attributeNames array at position i
182: */
183: public abstract String getAttribName(int i);
184:
185: /**
186: * @param i The index of the attributeValues array whose value we want
187: * @return The string value of the attributeValues array at position i
188: */
189: public abstract String getAttribValueAsString(int i);
190:
191: /**
192: * @param i The index of the attributeValues array whose value we want
193: * @return The string value of the attributeValues array at position i
194: */
195: public abstract Object getAttribValue(int i);
196:
197: /**
198: * @param i The index of the attributeValues array whose value we want
199: * @return The double value of the attributeValues array at position i
200: */
201: public abstract double getAttribValueAsDouble(int i);
202:
203: /**
204: * @param i The index of the attributeValues array whose value we want
205: * @return The int value of the attributeValues array at position i
206: */
207: public abstract int getAttribValueAsInt(int i);
208:
209: /**
210: * Gets the value attribute as a Double value
211: * @param elementName
212: * @return the value as a double
213: */
214: public abstract double getValueAsDouble(String elementName);
215:
216: /**
217: * Gets the value attribute of the specified node as an int.
218: * @param elementName
219: * @return the value as an int
220: */
221: public abstract int getValueAsInt(String elementName);
222:
223: /**
224: * Gets the value attribute of the specified node as a string.
225: * @param elementName
226: * @return the value as a string
227: */
228: public abstract String getValueAsString(String elementName);
229:
230: /**
231: * Get a hash code for the node.
232: * @return the node's hash code
233: */
234: public abstract int hashCode();
235:
236: /**
237: * Gets the number of immediate children of this node
238: * @return the number of child nodes
239: */
240: public int getNumChildren() {
241: return 0;
242: }
243:
244: /**
245: * Gets the number of attributes of this node
246: * @return the number of attributes
247: */
248: public int getNumAttributes() {
249: return 0;
250: }
251:
252: /**
253: * Set the number of children of this node
254: * @param num the new number of children
255: */
256: public void setNumChildren(int num) {
257: }
258:
259: /**
260: * Append a node
261: * @param childNode the child node
262: */
263: public abstract void append(XModel childNode);
264:
265: /**
266: * Append a new node with the specified name. This method does not replace any
267: * existing nodes.
268: * @param element The immediate path to the XModel required
269: * @return The value of the XModel or the attribute
270: */
271: public abstract Object append(String elementName);
272:
273: /**
274: * Setup the attributeNames and attributeValues arrays. If not already
275: * initialised set the size of each to 2 otherwise store them temporarily
276: * and reassign to the increased size arrays.
277: * @param num The new size of the array
278: */
279: public void setNumAttributes(int num) {
280: }
281:
282: //-Model listener functions---------------------------------------------------
283: /**
284: * Add a new listener to this model node
285: * @param listener the listener object
286: * @param name the name of the metod to be invoked
287: */
288: public void addModelListener(XModelListener listener, String name) {
289: if (modelListeners == null)
290: modelListeners = new Vector();
291:
292: if (!modelListenerExists(name, listener)) {
293: Object[] listenerMethod = { name, listener };
294: modelListeners.addElement(listenerMethod);
295: }
296: }
297:
298: private boolean modelListenerExists(String listenername,
299: XModelListener listener) {
300: int numListeners = modelListeners.size();
301: for (int i = 0; i < numListeners; i++) {
302: Object[] listenerMethod = (Object[]) modelListeners
303: .elementAt(i);
304: String name = (String) listenerMethod[0];
305: XModelListener templistener = (XModelListener) listenerMethod[1];
306: if (listenername.compareTo(name) == 0
307: && templistener.equals(listener))
308: return true;
309: }
310: return false;
311: }
312:
313: /**
314: * Notify the listeners that this model node has changed
315: */
316: public void fireModelUpdated() {
317: if (modelListeners != null) {
318: int numListeners = modelListeners.size();
319: for (int i = 0; i < numListeners; i++) {
320: Object[] listenerMethod = (Object[]) modelListeners
321: .elementAt(i);
322: String name = (String) listenerMethod[0];
323: Object modelListener = listenerMethod[1];
324: ((XModelListener) modelListener).modelUpdated(name,
325: this );
326: }
327: }
328: }
329:
330: //----------------------------------------------------------------------------
331:
332: /**
333: * Prefix the output path if the prefix is not already present
334: * @param path
335: * @return
336: */
337: public static String prefixOutputPath(String path) {
338: if ((path == null) || (path.length() == 0))
339: return path;
340: if (path.charAt(0) == '/')
341: return path;
342: else if (path.indexOf(XDataBinding.DEFAULT_OUTPUT_PATH) == 0)
343: return path;
344:
345: return (XDataBinding.DEFAULT_OUTPUT_PATH + path);
346: }
347: }
|