source: gli/branches/rtl-gli/src/org/greenstone/gatherer/cdm/DOMProxyListModel.java@ 18368

Last change on this file since 18368 was 14039, checked in by xiao, 17 years ago

Change made in the method getElementAt() not to get element from the 'cache' but directly from the 'children' list because when an element is deleted from the internal DOM tree, 'children' is up to date but 'cache' is not.

  • Property svn:keywords set to Author Date Id Revision
File size: 11.6 KB
Line 
1/**
2 *#########################################################################
3 *
4 * A component of the Gatherer application, part of the Greenstone digital
5 * library suite from the New Zealand Digital Library Project at the
6 * University of Waikato, New Zealand.
7 *
8 * Author: John Thompson, Greenstone Digital Library, University of Waikato
9 *
10 * Copyright (C) 1999 New Zealand Digital Library Project
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *########################################################################
26 */
27package org.greenstone.gatherer.cdm;
28
29import java.util.*;
30import javax.swing.*;
31import org.greenstone.gatherer.DebugStream;
32import org.greenstone.gatherer.util.StaticStrings;
33import org.greenstone.gatherer.util.XMLTools;
34import org.w3c.dom.*;
35
36/** This class provides ListModel like access to a list of nodes within a DOM model.
37 * @author John Thompson, Greenstone Digital Library, University of Waikato
38 * @version 2.3d
39 */
40public class DOMProxyListModel
41extends AbstractListModel {
42 protected Element root;
43 private DOMProxyListEntry class_type;
44 private HashMap cache = new HashMap ();
45 private NodeList children = null;
46 private String tag_name;
47
48 /** Constructor.
49 * @param root the Element at the root of the subtree to be searched for appropriate child elements
50 * @param tag_name the name of appropriate elements as a String
51 * @param class_type the type of object to wrap the elements returned in, as a DOMProxyListEntry
52 */
53 public DOMProxyListModel (Element root, String tag_name, DOMProxyListEntry class_type) {
54 this.class_type = class_type;
55 this.root = root;
56 this.tag_name = tag_name;
57 this.children = this.root.getElementsByTagName (this.tag_name);
58 }
59
60 /** Used to add an element into the underlying dom, and fire the appropriate repaint events. This version always adds the new element at the very head of the DOM. */
61 public synchronized void add (DOMProxyListEntry entry) {
62 Element element = entry.getElement ();
63 if(root.hasChildNodes ()) {
64 Node sibling = root.getFirstChild ();
65 root.insertBefore (element, sibling);
66 sibling = null;
67 }
68 else {
69 root.appendChild (element);
70 }
71 element = null;
72 // Regardless fire update event
73 cache.clear ();
74 fireIntervalAdded (this, 0, 0);
75 }
76
77 /** Used to add an element into the underlying dom, and fire the appropriate repaint events.
78 * @param index the index where the element should be inserted (relative of the other elements in this proxy list)
79 * @param entry the <strong>DOMProxyListEntry</strong> to be inserted
80 */
81 public synchronized void add (int index, DOMProxyListEntry entry) {
82 ///atherer.println("Add entry at " + index + " where size = " + getSize());
83 Element element = entry.getElement ();
84 // retrieve the node where we want to insert
85 if(index < children.getLength ()) {
86 Node sibling = children.item (index);
87 // Find the parent node
88 Node parent_node = sibling.getParentNode ();
89 parent_node.insertBefore (element, sibling);
90 sibling = null;
91 }
92 // If the index is too large, we are adding to the end of our list of entries. However you have to remember that this list is only a viewport on the entire DOM so there might be entries following this group that we actually want to insert before (not append at the very end!)
93 else {
94 // Retrieve the currently last entry
95 index = children.getLength () - 1;
96 Node sibling = null;
97 Node parent_node = null;
98 if(index >= 0) {
99 sibling = children.item (index);
100 parent_node = sibling.getParentNode ();
101 sibling = sibling.getNextSibling ();
102 }
103 if(sibling != null && parent_node != null) {
104 parent_node.insertBefore (element, sibling);
105 }
106 // Add to the root node
107 else {
108 index = 0;
109 root.appendChild (element);
110 }
111 }
112 // Regardless fire update event
113 cache.clear ();
114 fireIntervalAdded (this, index, index);
115 }
116
117 /** Used to add an element into the underlying dom, and fire the appropriate repaint events. This version inserts the new entry immediately -after- the given entry in the DOM.
118 * @param entry the DOMProxyListEntry to be inserted
119 * @param preceeding_entry the DOMProxyListEntry immediately before where we want the new entry
120 */
121 public synchronized void addAfter (DOMProxyListEntry entry, DOMProxyListEntry preceeding_entry) {
122 Element element = entry.getElement ();
123 Element preceeding_sibling = preceeding_entry.getElement ();
124 Node parent_node = preceeding_sibling.getParentNode ();
125 Node following_sibling = preceeding_sibling.getNextSibling ();
126 if(following_sibling != null) {
127 parent_node.insertBefore (element, following_sibling);
128 }
129 else {
130 parent_node.appendChild (element);
131 }
132 // Regardless fire update event
133 cache.clear ();
134 int index = indexOf (entry);
135 fireIntervalAdded (this, index, index);
136 }
137
138 /** Used to add an element into the underlying dom, and fire the appropriate repaint events. This version inserts the new entry immediately -before- the given entry in the DOM.
139 * @param entry the DOMProxyListEntry to be inserted
140 * @param following_entry the DOMProxyListEntry immediately after where we want the new entry
141 */
142 public synchronized void addBefore (DOMProxyListEntry entry, DOMProxyListEntry following_entry) {
143 Element element = entry.getElement ();
144 Element following_sibling = following_entry.getElement ();
145 Node parent_node = following_sibling.getParentNode ();
146 parent_node.insertBefore (element, following_sibling);
147 // Regardless fire update event
148 cache.clear ();
149 int index = indexOf (entry);
150 fireIntervalAdded (this, index, index);
151 }
152
153 public synchronized void add (Node parent, DOMProxyListEntry entry, Node sibling) {
154 Element child = entry.getElement ();
155 if(sibling != null) {
156 parent.insertBefore (child, sibling);
157 }
158 else {
159 parent.appendChild (child);
160 }
161 cache.clear ();
162 int index = indexOf (entry);
163
164
165 fireIntervalAdded (this, index, index);
166 }
167
168 /** Used to add an element into the underlying dom, and fire the appropriate repaint events. This version always adds the new element at the end of the children. */
169 public synchronized void append (DOMProxyListEntry entry) {
170 Element element = entry.getElement ();
171 root.appendChild (element);
172 element = null;
173 // Regardless fire update event
174 cache.clear ();
175 fireIntervalAdded (this, 0, 0);
176 }
177
178 public synchronized ArrayList children () {
179 ArrayList child_list = new ArrayList ();
180 int child_count = children.getLength ();
181 for(int i = 0; i < child_count; i++) {
182 child_list.add (getElementAt (i));
183 }
184 return child_list;
185 }
186
187 public synchronized boolean contains (Object entry) {
188 boolean found = false;
189 int size = getSize ();
190
191 for(int i = 0; !found && i < size; i++) {
192 DOMProxyListEntry sibling = (DOMProxyListEntry) getElementAt (i);
193 if(sibling.equals (entry)) {
194
195 found = true;
196 }
197 }
198 return found;
199 }
200
201 public synchronized Object getElementAt (int index) {
202 /** There are times when the length of the 'cache' is not as same as the length of the 'children', etc. not up to date.
203 eg, when a classifier has been deleted. So we rather not have this efficiency for Format4gs3.java.*/
204 if (class_type instanceof Format4gs3) {
205 Element element = (Element) children.item (index);
206 // Now wrap it in the object of the users choice
207 Object object = class_type.create (element);
208 return object;
209 }
210
211 Object object = cache.get (new Integer (index));
212 if (object != null) {
213 return object;
214 }
215
216 // Retrieve the required element
217 Element element = (Element) children.item (index);
218 DebugStream.println ("Element at index " + index + " not in cache: " + element);
219
220 // Now wrap it in the object of the users choice
221 object = class_type.create (element);
222 cache.put (new Integer (index), object);
223 return object;
224 }
225
226 public synchronized int indexOf (DOMProxyListEntry entry) {
227 Element element = entry.getElement ();
228 int children_length = children.getLength ();
229 for(int i = 0; i < children_length; i++) {
230 Node node = children.item (i);
231 if(element == node) {
232 return i;
233 }
234 }
235 return -1;
236 }
237
238 public synchronized int getSize () {
239
240 if(children == null) {
241 children = root.getElementsByTagName (tag_name);
242 }
243 return children.getLength ();
244 }
245
246 public synchronized void refresh () {
247 fireContentsChanged (this, 0, getSize ());
248 }
249
250 public synchronized void refresh (DOMProxyListEntry entry) {
251 int index = indexOf (entry);
252 fireContentsChanged (this, index, index);
253 }
254
255 public synchronized void remove (DOMProxyListEntry entry) {
256 remove (indexOf (entry));
257 }
258
259 public synchronized void remove (int index) {
260 // Retrieve the required element
261 Node node = children.item (index);
262 // Find its parent
263 Node parent_node = node.getParentNode ();
264 // Now remove it
265 parent_node.removeChild (node);
266 // Refresh model
267 cache.clear ();
268
269 fireIntervalRemoved (this, index, index);
270 }
271
272
273 /** Changes the 'root' element that this list sources its information from.
274 * @param root the new root Element
275 */
276 public synchronized void setRoot (Element root) {
277 this.children = null;
278 cache.clear ();
279 this.root = root;
280 this.children = this.root.getElementsByTagName (this.tag_name);
281 fireContentsChanged (this, 0, getSize ());
282 }
283
284 public synchronized void setAssigned (boolean assigned) {
285 if (assigned) {
286 root.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
287 }
288 else {
289 root.setAttribute (StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.FALSE_STR);
290 }
291 }
292
293 public boolean isAssigned () {
294 return (root.getAttribute (StaticStrings.ASSIGNED_ATTRIBUTE).equals ("") || root.getAttribute (StaticStrings.ASSIGNED_ATTRIBUTE).equals (StaticStrings.TRUE_STR));
295 }
296
297}
Note: See TracBrowser for help on using the repository browser.