Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/virtuosotechnologies/asaph/standardmodel/ListHelper.java


1   /*
2   ================================================================================
3   
4     FILE:  ListHelper.java
5     
6     PROJECT:
7     
8       Asaph
9     
10    CONTENTS:
11    
12      Helper for dealing with lists
13    
14    PROGRAMMERS:
15    
16      Daniel Azuma (DA)  <dazuma@kagi.com>
17    
18    COPYRIGHT:
19    
20      Copyright (C) 2003  Daniel Azuma  (dazuma@kagi.com)
21      
22      This program is free software; you can redistribute it and/or
23      modify it under the terms of the GNU General Public License as
24      published by the Free Software Foundation; either version 2
25      of the License, or (at your option) any later version.
26      
27      This program is distributed in the hope that it will be useful,
28      but WITHOUT ANY WARRANTY; without even the implied warranty of
29      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30      GNU General Public License for more details.
31      
32      You should have received a copy of the GNU General Public
33      License along with this program; if not, write to
34        Free Software Foundation, Inc.
35        59 Temple Place, Suite 330
36        Boston, MA 02111-1307 USA
37  
38  ================================================================================
39  */
40  
41  
42  package com.virtuosotechnologies.asaph.standardmodel;
43  
44  
45  import java.util.Map;
46  import java.util.HashMap;
47  import javax.swing.undo.AbstractUndoableEdit;
48  import javax.swing.undo.CannotUndoException;
49  import javax.swing.undo.CannotRedoException;
50  import javax.swing.event.UndoableEditListener;
51  
52  import com.virtuosotechnologies.lib.base.LinkedObject;
53  
54  
55  /**
56   * Helper for dealing with lists
57   */
58  /*package*/ class ListHelper
59  {
60    /*package*/ static abstract class ObjectFilter
61    {
62      protected abstract boolean isRelevant(
63        BaseSongMember member);
64    }
65    
66    
67    /*package*/ static abstract class KeyExtractor
68    {
69      protected abstract String extractKey(
70        BaseSongMember member);
71    }
72    
73    
74    private BaseSongMember owner_;
75    private LinkedObject delimiter_;
76    private Map idMap_;
77    private KeyExtractor keyExtractor_;
78    
79    
80    /*package*/ ListHelper(
81      BaseSongMember owner)
82    {
83      this(owner, null);
84    }
85    
86    
87    /*package*/ ListHelper(
88      BaseSongMember owner,
89      KeyExtractor keyExtractor)
90    {
91      owner_ = owner;
92      delimiter_ = new LinkedObject();
93      keyExtractor_ = keyExtractor;
94      if (keyExtractor_ != null)
95      {
96        idMap_ = new HashMap();
97      }
98    }
99    
100   
101   private LinkedObject getLink(
102     Object obj)
103   {
104     if (obj == null)
105     {
106       return delimiter_;
107     }
108     if (!(obj instanceof BaseSongMember))
109     {
110       throw new IllegalArgumentException("Reference object not a BaseSongMember");
111     }
112     BaseSongMember ret = (BaseSongMember)obj;
113     if (ret.internalGetParent() != owner_)
114     {
115       throw new IllegalArgumentException("Reference object not a child of the owner");
116     }
117     return ret;
118   }
119   
120   
121   private String getKey(
122     BaseSongMember object,
123     boolean checkForDuplicates)
124   {
125     if (idMap_ == null)
126     {
127       return null;
128     }
129     String key = keyExtractor_.extractKey(object);
130     if (key != null && checkForDuplicates)
131     {
132       if (idMap_.containsKey(key))
133       {
134         throw new IllegalStateException("Duplicate key: "+key);
135       }
136     }
137     return key;
138   }
139   
140   
141   /*package*/ int getCount()
142   {
143     int count = 0;
144     for (LinkedObject link = delimiter_.getNext(); link != delimiter_;
145       link = link.getNext())
146     {
147       ++count;
148     }
149     return count;
150   }
151   
152   
153   /*package*/ int getCount(
154     ObjectFilter filter)
155   {
156     int count = 0;
157     for (LinkedObject link = delimiter_.getNext(); link != delimiter_;
158       link = link.getNext())
159     {
160       BaseSongMember member = (BaseSongMember)link;
161       if (filter.isRelevant(member))
162       {
163         ++count;
164       }
165     }
166     return count;
167   }
168   
169   
170   /*package*/ BaseSongMember getNthObject(
171     int n)
172   {
173     if (n < 0)
174     {
175       throw new IndexOutOfBoundsException("n == "+n);
176     }
177     int i = n;
178     for (LinkedObject link = delimiter_.getNext(); link != delimiter_;
179       link = link.getNext())
180     {
181       if (i == 0)
182       {
183         return (BaseSongMember)link;
184       }
185       --i;
186     }
187     throw new IndexOutOfBoundsException("n == "+n);
188   }
189   
190   
191   /*package*/ BaseSongMember getNthObject(
192     int n,
193     ObjectFilter filter)
194   {
195     if (n < 0)
196     {
197       throw new IndexOutOfBoundsException("n == "+n);
198     }
199     int i = n;
200     for (LinkedObject link = delimiter_.getNext(); link != delimiter_;
201       link = link.getNext())
202     {
203       BaseSongMember member = (BaseSongMember)link;
204       if (filter.isRelevant(member))
205       {
206         if (i == 0)
207         {
208           return member;
209         }
210         --i;
211       }
212     }
213     throw new IndexOutOfBoundsException("n == "+n);
214   }
215   
216   
217   /*package*/ BaseSongMember getNextObject(
218     Object reference)
219   {
220     LinkedObject link = getLink(reference).getNext();
221     if (link == delimiter_)
222     {
223       return null;
224     }
225     else
226     {
227       return (BaseSongMember)link;
228     }
229   }
230   
231   
232   /*package*/ BaseSongMember getNextObject(
233     Object reference,
234     ObjectFilter filter)
235   {
236     LinkedObject link = getLink(reference);
237     while (true)
238     {
239       link = link.getNext();
240       if (link == delimiter_)
241       {
242         return null;
243       }
244       BaseSongMember ret = (BaseSongMember)link;
245       if (filter.isRelevant(ret))
246       {
247         return ret;
248       }
249     }
250   }
251   
252   
253   /*package*/ BaseSongMember getPreviousObject(
254     Object reference)
255   {
256     LinkedObject link = getLink(reference).getPrevious();
257     if (link == delimiter_)
258     {
259       return null;
260     }
261     else
262     {
263       return (BaseSongMember)link;
264     }
265   }
266   
267   
268   /*package*/ BaseSongMember getPreviousObject(
269     Object reference,
270     ObjectFilter filter)
271   {
272     LinkedObject link = getLink(reference);
273     while (true)
274     {
275       link = link.getPrevious();
276       if (link == delimiter_)
277       {
278         return null;
279       }
280       BaseSongMember ret = (BaseSongMember)link;
281       if (filter.isRelevant(ret))
282       {
283         return ret;
284       }
285     }
286   }
287   
288   
289   /*package*/ BaseSongMember getObjectForKey(
290     String key)
291   {
292     if (key == null)
293     {
294       throw new NullPointerException();
295     }
296     if (idMap_ == null)
297     {
298       return null;
299     }
300     else
301     {
302       return (BaseSongMember)idMap_.get(key);
303     }
304   }
305   
306   
307   /*package*/ boolean containsObject(
308     Object object)
309   {
310     if (object instanceof BaseSongMember)
311     {
312       return ((BaseSongMember)object).internalGetParent() == owner_;
313     }
314     return false;
315   }
316   
317   
318   /*package*/ void insertObjectBefore(
319     final BaseSongMember object,
320     Object before,
321     UndoableEditListener undoListener)
322   {
323     final LinkedObject link = getLink(before);
324     final String key = getKey(object, true);
325     object.linkThisBefore(link);
326     if (key != null)
327     {
328       idMap_.put(key, object);
329     }
330     if (undoListener != null)
331     {
332       owner_.internalReportUndoableEdit(undoListener,
333         new AbstractUndoableEdit()
334         {
335           public void undo()
336           throws CannotUndoException
337           {
338             super.undo();
339             object.unlinkThis();
340             object.internalSetDefunct();
341             if (key != null)
342             {
343               idMap_.remove(key);
344             }
345           }
346           
347           public void redo()
348           throws CannotRedoException
349           {
350             super.redo();
351             object.internalClearDefunct();
352             object.linkThisBefore(link);
353             if (key != null)
354             {
355               idMap_.put(key, object);
356             }
357           }
358         });
359     }
360   }
361   
362   
363   /*package*/ void insertObjectAfter(
364     final BaseSongMember object,
365     Object after,
366     UndoableEditListener undoListener)
367   {
368     final LinkedObject link = getLink(after);
369     final String key = getKey(object, true);
370     object.linkThisAfter(link);
371     if (key != null)
372     {
373       idMap_.put(key, object);
374     }
375     if (undoListener != null)
376     {
377       owner_.internalReportUndoableEdit(undoListener,
378         new AbstractUndoableEdit()
379         {
380           public void undo()
381           throws CannotUndoException
382           {
383             super.undo();
384             object.unlinkThis();
385             object.internalSetDefunct();
386             if (key != null)
387             {
388               idMap_.remove(key);
389             }
390           }
391           
392           public void redo()
393           throws CannotRedoException
394           {
395             super.redo();
396             object.internalClearDefunct();
397             object.linkThisAfter(link);
398             if (key != null)
399             {
400               idMap_.put(key, object);
401             }
402           }
403         });
404     }
405   }
406   
407   
408   /*package*/ void appendObject(
409     final BaseSongMember object,
410     UndoableEditListener undoListener)
411   {
412     final String key = getKey(object, true);
413     object.linkThisBefore(delimiter_);
414     if (key != null)
415     {
416       idMap_.put(key, object);
417     }
418     if (undoListener != null)
419     {
420       owner_.internalReportUndoableEdit(undoListener,
421         new AbstractUndoableEdit()
422         {
423           public void undo()
424           throws CannotUndoException
425           {
426             super.undo();
427             object.unlinkThis();
428             object.internalSetDefunct();
429             if (key != null)
430             {
431               idMap_.remove(key);
432             }
433           }
434           
435           public void redo()
436           throws CannotRedoException
437           {
438             super.redo();
439             object.internalClearDefunct();
440             object.linkThisBefore(delimiter_);
441             if (key != null)
442             {
443               idMap_.put(key, object);
444             }
445           }
446         });
447     }
448   }
449   
450   
451   /*package*/ void replaceObject(
452     final Object oldObject,
453     final BaseSongMember newObject,
454     UndoableEditListener undoListener)
455   {
456     if (oldObject == null)
457     {
458       throw new NullPointerException();
459     }
460     final BaseSongMember oldLink = (BaseSongMember)getLink(oldObject);
461     final LinkedObject prev = oldLink.getPrevious();
462     final String oldKey = getKey((BaseSongMember)oldObject, false);
463     final String newKey = getKey(newObject, false);
464     if (newKey != null && idMap_.containsKey(newKey) && !newKey.equals(oldKey))
465     {
466       throw new IllegalStateException("Duplicate key: "+newKey);
467     }
468     
469     oldLink.unlinkThis();
470     oldLink.internalSetDefunct();
471     if (oldKey != null)
472     {
473       idMap_.remove(oldKey);
474     }
475     newObject.linkThisAfter(prev);
476     if (newKey != null)
477     {
478       idMap_.put(newKey, newObject);
479     }
480     if (undoListener != null)
481     {
482       owner_.internalReportUndoableEdit(undoListener,
483         new AbstractUndoableEdit()
484         {
485           public void undo()
486           throws CannotUndoException
487           {
488             super.undo();
489             newObject.unlinkThis();
490             newObject.internalSetDefunct();
491             if (newKey != null)
492             {
493               idMap_.remove(newKey);
494             }
495             oldLink.internalClearDefunct();
496             oldLink.linkThisAfter(prev);
497             if (oldKey != null)
498             {
499               idMap_.put(oldKey, oldLink);
500             }
501           }
502           
503           public void redo()
504           throws CannotRedoException
505           {
506             super.redo();
507             oldLink.unlinkThis();
508             oldLink.internalSetDefunct();
509             if (oldKey != null)
510             {
511               idMap_.remove(oldKey);
512             }
513             newObject.internalClearDefunct();
514             newObject.linkThisAfter(prev);
515             if (newKey != null)
516             {
517               idMap_.put(newKey, newObject);
518             }
519           }
520         });
521     }
522   }
523   
524   
525   /*package*/ void removeObject(
526     final Object object,
527     UndoableEditListener undoListener)
528   {
529     if (object == null)
530     {
531       throw new NullPointerException();
532     }
533     final BaseSongMember link = (BaseSongMember)getLink(object);
534     final LinkedObject prev = link.getPrevious();
535     final String key = getKey((BaseSongMember)object, false);
536     link.unlinkThis();
537     link.internalSetDefunct();
538     if (key != null)
539     {
540       idMap_.remove(key);
541     }
542     if (undoListener != null)
543     {
544       owner_.internalReportUndoableEdit(undoListener,
545         new AbstractUndoableEdit()
546         {
547           public void undo()
548           throws CannotUndoException
549           {
550             super.undo();
551             link.internalClearDefunct();
552             link.linkThisAfter(prev);
553             if (key != null)
554             {
555               idMap_.put(key, object);
556             }
557           }
558           
559           public void redo()
560           throws CannotRedoException
561           {
562             super.redo();
563             link.unlinkThis();
564             link.internalSetDefunct();
565             if (key != null)
566             {
567               idMap_.remove(key);
568             }
569           }
570         });
571     }
572   }
573   
574   
575   /*package*/ void clear(
576     UndoableEditListener undoListener)
577   {
578     while (delimiter_.getPrevious() != delimiter_)
579     {
580       final BaseSongMember object = (BaseSongMember)delimiter_.getPrevious();
581       final String key = getKey(object, false);
582       object.unlinkThis();
583       object.internalSetDefunct();
584       if (key != null)
585       {
586         idMap_.remove(key);
587       }
588       if (undoListener != null)
589       {
590         owner_.internalReportUndoableEdit(undoListener,
591           new AbstractUndoableEdit()
592           {
593             public void undo()
594             throws CannotUndoException
595             {
596               super.undo();
597               object.internalClearDefunct();
598               object.linkThisBefore(delimiter_);
599               if (key != null)
600               {
601                 idMap_.put(key, object);
602               }
603             }
604             
605             public void redo()
606             throws CannotRedoException
607             {
608               super.redo();
609               object.unlinkThis();
610               object.internalSetDefunct();
611               if (key != null)
612               {
613                 idMap_.remove(key);
614               }
615             }
616           });
617       }
618     }
619   }
620 }