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

Quick Search    Search Deep

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


1   /*
2   ================================================================================
3   
4     FILE:  StdSongLine.java
5     
6     PROJECT:
7     
8       Asaph
9     
10    CONTENTS:
11    
12      Standard implementation of SongLine
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.List;
46  import java.util.ArrayList;
47  import java.util.Iterator;
48  import java.io.IOException;
49  import javax.swing.undo.AbstractUndoableEdit;
50  import javax.swing.undo.CannotUndoException;
51  import javax.swing.undo.CannotRedoException;
52  import javax.swing.event.UndoableEditListener;
53  import org.xml.sax.SAXException;
54  import org.xml.sax.Attributes;
55  import org.xml.sax.ErrorHandler;
56  import org.xml.sax.Locator;
57  
58  import com.virtuosotechnologies.lib.xml.XMLUnparser;
59  
60  import com.virtuosotechnologies.asaph.model.SongLine;
61  import com.virtuosotechnologies.asaph.model.SongLineMember;
62  import com.virtuosotechnologies.asaph.model.SongBlock;
63  import com.virtuosotechnologies.asaph.model.TextString;
64  import com.virtuosotechnologies.asaph.model.CommentString;
65  import com.virtuosotechnologies.asaph.model.ChordAnnotation;
66  import com.virtuosotechnologies.asaph.model.ChordSet;
67  import com.virtuosotechnologies.asaph.model.notation.Chord;
68  import com.virtuosotechnologies.asaph.model.notation.NotationFactory;
69  
70  
71  /**
72   * Standard implementation of SongLine
73   */
74  /*package*/ class StdSongLine
75  extends BaseSongMember
76  implements
77    SongLine
78  {
79    private static final String STR_xml_AnnotationNoDefaultChordSet =
80      ResourceAccess.Strings.buildString("xml_AnnotationNoDefaultChordSet");
81    
82    private int indentLevel_;
83    private ListHelper memberList_;
84    
85    
86    /*package*/ StdSongLine(
87      BaseSongBlock parent)
88    {
89      this(parent, 0);
90    }
91    
92    
93    /*package*/ StdSongLine(
94      BaseSongBlock parent,
95      int indentLevel)
96    {
97      super(parent);
98      indentLevel_ = indentLevel;
99      memberList_ = new ListHelper(this);
100   }
101   
102   
103   /*package*/ void handleChordSetDeleted(
104     StdChordSet chordSet,
105     UndoableEditListener undoListener)
106   {
107     List toRemove = new ArrayList();
108     for (SongLineMember member = (SongLineMember)memberList_.getNextObject(null);
109       member != null; member = (SongLineMember)memberList_.getNextObject(member))
110     {
111       if (member instanceof StdChordAnnotation &&
112         ((StdChordAnnotation)member).getChordSet() == chordSet)
113       {
114         toRemove.add(member);
115       }
116     }
117     for (Iterator iter = toRemove.iterator(); iter.hasNext(); )
118     {
119       memberList_.removeObject(iter.next(), undoListener);
120     }
121   }
122   
123   
124   /*package*/ void unparse(
125     XMLUnparser unparser)
126   throws
127     IOException
128   {
129     unparser.startSingleLineElement(XMLConstants.LINE_ELEMENT);
130     if (indentLevel_ != 0)
131     {
132       unparser.addAttribute(XMLConstants.LINE_INDENT_ATTRIBUTE,
133         Integer.toString(indentLevel_));
134     }
135     for (Object member = memberList_.getNextObject(null);
136       member != null; member = memberList_.getNextObject(member))
137     {
138       if (member instanceof BaseStringSongLineMember)
139       {
140         ((BaseStringSongLineMember)member).unparse(unparser);
141       }
142       else if (member instanceof StdChordAnnotation)
143       {
144         ((StdChordAnnotation)member).unparse(unparser);
145       }
146     }
147     unparser.endElement(XMLConstants.LINE_ELEMENT);
148   }
149   
150   
151   /*package*/ class ParseHandler
152   extends ParseHandlerBase
153   {
154     private StdSong song_;
155     private StdChordSet defaultChordSet_;
156     private NotationFactory notationFactory_;
157     
158     /*package*/ ParseHandler(
159       ErrorHandler errorHandler,
160       Locator locator,
161       StdSong song,
162       NotationFactory notationFactory)
163     {
164       super(errorHandler, locator, XMLConstants.LINE_ELEMENT);
165       song_ = song;
166       defaultChordSet_ = (StdChordSet)song_.getDefaultChordSet();
167       notationFactory_ = notationFactory;
168     }
169     
170     /*package*/ ParseHandlerBase localStartElement(
171       String uri,
172       String localName,
173       String qName,
174       Attributes attributes)
175     throws
176       SAXException
177     {
178       if (localName.equals(XMLConstants.COMMENT_ELEMENT))
179       {
180         StdCommentString nstring = new StdCommentString(StdSongLine.this, "");
181         memberList_.appendObject(nstring, null);
182         return nstring.new ParseHandler(getErrorHandler(), getDocumentLocator());
183       }
184       else if (localName.equals(XMLConstants.TEXT_ELEMENT))
185       {
186         StdTextString nstring = new StdTextString(StdSongLine.this, "");
187         memberList_.appendObject(nstring, null);
188         return nstring.new ParseHandler(getErrorHandler(), getDocumentLocator());
189       }
190       else if (localName.equals(XMLConstants.ANNOTATION_ELEMENT))
191       {
192         String chordSetStr = attributes.getValue(XMLConstants.ANNOTATION_CHORDSET_ATTRIBUTE);
193         if (chordSetStr == null)
194         {
195           chordSetStr = attributes.getValue(XMLConstants.ANNOTATION_CHORDSET_ATTRIBUTE_ALT);
196         }
197         StdChordSet chordSet = defaultChordSet_;
198         if (chordSetStr != null)
199         {
200           chordSet = (StdChordSet)song_.getChordSetForSerializableID(chordSetStr);
201           if (chordSet == null)
202           {
203             reportFatalError(ResourceAccess.Strings.buildString(
204               "xml_AnnotationChordSetNotFound", chordSetStr));
205           }
206         }
207         if (chordSet == null)
208         {
209           reportFatalError(STR_xml_AnnotationNoDefaultChordSet);
210         }
211         String mainStr = attributes.getValue(XMLConstants.ANNOTATION_PRIMARY_ATTRIBUTE);
212         Chord main;
213         if (mainStr != null)
214         {
215           main = notationFactory_.parseChord(mainStr);
216         }
217         else
218         {
219           main = notationFactory_.getEmptyChord();
220         }
221         String preStr = attributes.getValue(XMLConstants.ANNOTATION_PRECEDING_ATTRIBUTE);
222         Chord[] pre;
223         if (preStr != null)
224         {
225           pre = notationFactory_.parseChordArray(preStr);
226         }
227         else
228         {
229           pre = new Chord[0];
230         }
231         String postStr = attributes.getValue(XMLConstants.ANNOTATION_FOLLOWING_ATTRIBUTE);
232         Chord[] post;
233         if (postStr != null)
234         {
235           post = notationFactory_.parseChordArray(postStr);
236         }
237         else
238         {
239           post = new Chord[0];
240         }
241         StdChordAnnotation annot = new StdChordAnnotation(StdSongLine.this, chordSet,
242           main, pre, post);
243         memberList_.appendObject(annot, null);
244         return annot.new ParseHandler(getErrorHandler(), getDocumentLocator());
245       }
246       else
247       {
248         return super.localStartElement(uri, localName, qName, attributes);
249       }
250     }
251     
252     /*package*/ void localCharacters(
253       char[] chs,
254       int start,
255       int length)
256     throws
257       SAXException
258     {
259       Object member = memberList_.getPreviousObject(null);
260       StdTextString textStr;
261       if (member instanceof StdTextString)
262       {
263         textStr = (StdTextString)member;
264       }
265       else
266       {
267         textStr = new StdTextString(StdSongLine.this, "");
268         memberList_.appendObject(textStr, null);
269       }
270       textStr.setString(textStr.getString()+new String(chs, start, length), null);
271     }
272   }
273   
274   
275   //-------------------------------------------------------------------------
276   // Methods of SongLine
277   //-------------------------------------------------------------------------
278   
279   /**
280    * Get the containing song block
281    *
282    * @return SongBlock containing this line
283    */
284   public SongBlock getSongBlock()
285   {
286     return (BaseSongBlock)internalGetParent();
287   }
288   
289   
290   /**
291    * Get the indent level
292    *
293    * @return indent level
294    */
295   public int getIndentLevel()
296   {
297     return indentLevel_;
298   }
299   
300   
301   /**
302    * Get the number of members
303    *
304    * @return number of members
305    */
306   public int getMemberCount()
307   {
308     return memberList_.getCount();
309   }
310   
311   
312   /**
313    * Get the nth member
314    *
315    * @param n index
316    * @return member
317    */
318   public SongLineMember getNthMember(
319     int n)
320   {
321     return (SongLineMember)memberList_.getNthObject(n);
322   }
323   
324   
325   /**
326    * Get the next member following reference.
327    * If reference is null, returns the first member.
328    * If reference is the last member, returns null;
329    *
330    * @param reference reference SongLineMember
331    * @return next member
332    * @exception IllegalArgumentException reference is not a member
333    */
334   public SongLineMember getNextMember(
335     SongLineMember reference)
336   {
337     return (SongLineMember)memberList_.getNextObject(reference);
338   }
339   
340   
341   /**
342    * Get the previous member preceding reference.
343    * If reference is null, returns the last member.
344    * If reference is the first member, returns null;
345    *
346    * @param reference reference SongLineMember
347    * @return previous member
348    * @exception IllegalArgumentException reference is not a member
349    */
350   public SongLineMember getPreviousMember(
351     SongLineMember reference)
352   {
353     return (SongLineMember)memberList_.getPreviousObject(reference);
354   }
355   
356   
357   private class ChordSetFilter
358   extends ListHelper.ObjectFilter
359   {
360     private StdChordSet set_;
361     
362     /*package*/ ChordSetFilter(
363       ChordSet set)
364     {
365       if (set != null && !((StdSong)getSong()).containsChordSet(set))
366       {
367         throw new IllegalArgumentException("Unknown chord set");
368       }
369       set_ = (StdChordSet)set;
370     }
371     
372     protected boolean isRelevant(
373       BaseSongMember member)
374     {
375       if (member instanceof ChordAnnotation)
376       {
377         return ((ChordAnnotation)member).isInChordSet(set_);
378       }
379       else
380       {
381         return true;
382       }
383     }
384   }
385   
386   
387   /**
388    * Get the number of members in the given chord set
389    *
390    * @param set ChordSet to filter by, or null for no chords
391    * @return number of members
392    */
393   public int getMemberCount(
394     ChordSet set)
395   {
396     return memberList_.getCount(new ChordSetFilter(set));
397   }
398   
399   
400   /**
401    * Get the nth member
402    *
403    * @param n index
404    * @param set ChordSet to filter by, or null for no chords
405    * @return member
406    */
407   public SongLineMember getNthMember(
408     int n,
409     ChordSet set)
410   {
411     return (SongLineMember)memberList_.getNthObject(n, new ChordSetFilter(set));
412   }
413   
414   
415   /**
416    * Get the next member following reference.
417    * If reference is null, returns the first member.
418    * If reference is the last member, returns null;
419    *
420    * @param reference reference SongLineMember
421    * @param set ChordSet to filter by, or null for no chords
422    * @return next member
423    * @exception IllegalArgumentException reference is not a member
424    */
425   public SongLineMember getNextMember(
426     SongLineMember reference,
427     ChordSet set)
428   {
429     return (SongLineMember)memberList_.getNextObject(reference, new ChordSetFilter(set));
430   }
431   
432   
433   /**
434    * Get the previous member preceding reference.
435    * If reference is null, returns the last member.
436    * If reference is the first member, returns null;
437    *
438    * @param reference reference SongLineMember
439    * @param set ChordSet to filter by, or null for no chords
440    * @return previous member
441    * @exception IllegalArgumentException reference is not a member
442    */
443   public SongLineMember getPreviousMember(
444     SongLineMember reference,
445     ChordSet set)
446   {
447     return (SongLineMember)memberList_.getPreviousObject(reference, new ChordSetFilter(set));
448   }
449   
450   
451   /**
452    * Set the indent level
453    *
454    * @param indent new indent level
455    * @param undoListener listener to notify if an undoable edit is generated,
456    *     or null to suppress generation of undoable edits
457    */
458   public void setIndentLevel(
459     final int indent,
460     UndoableEditListener undoListener)
461   {
462     final int oldIndent = indentLevel_;
463     indentLevel_ = indent;
464     if (undoListener != null)
465     {
466       internalReportUndoableEdit(undoListener,
467         new AbstractUndoableEdit()
468         {
469           public void undo()
470           throws CannotUndoException
471           {
472             super.undo();
473             indentLevel_ = oldIndent;
474           }
475           
476           public void redo()
477           throws CannotRedoException
478           {
479             super.redo();
480             indentLevel_ = indent;
481           }
482         });
483     }
484   }
485   
486   
487   /**
488    * Add a text string at the given position.
489    *
490    * @param before insert before this member, or at the end if null
491    * @param str string value
492    * @param undoListener listener to notify if an undoable edit is generated,
493    *     or null to suppress generation of undoable edits
494    * @return added TextString
495    * @exception IllegalArgumentException before is not a member
496    * @exception NullPointerException str was null
497    */
498   public TextString insertTextStringBefore(
499     SongLineMember before,
500     String str,
501     UndoableEditListener undoListener)
502   {
503     StdTextString nstring = new StdTextString(this, str);
504     memberList_.insertObjectBefore(nstring, before, undoListener);
505     return nstring;
506   }
507   
508   
509   /**
510    * Add a text string at the given position.
511    *
512    * @param after insert after this member, or at the beginning if null
513    * @param str string value
514    * @param undoListener listener to notify if an undoable edit is generated,
515    *     or null to suppress generation of undoable edits
516    * @return added TextString
517    * @exception IllegalArgumentException after is not a member
518    * @exception NullPointerException str was null
519    */
520   public TextString insertTextStringAfter(
521     SongLineMember after,
522     String str,
523     UndoableEditListener undoListener)
524   {
525     StdTextString nstring = new StdTextString(this, str);
526     memberList_.insertObjectAfter(nstring, after, undoListener);
527     return nstring;
528   }
529   
530   
531   /**
532    * Add a comment string at the given position.
533    *
534    * @param before insert before this member, or at the end if null
535    * @param str string value
536    * @param undoListener listener to notify if an undoable edit is generated,
537    *     or null to suppress generation of undoable edits
538    * @return added CommentString
539    * @exception IllegalArgumentException before is not a member
540    * @exception NullPointerException str was null
541    */
542   public CommentString insertCommentStringBefore(
543     SongLineMember before,
544     String str,
545     UndoableEditListener undoListener)
546   {
547     StdCommentString nstring = new StdCommentString(this, str);
548     memberList_.insertObjectBefore(nstring, before, undoListener);
549     return nstring;
550   }
551   
552   
553   /**
554    * Add a comment string at the given position.
555    *
556    * @param after insert after this member, or at the beginning if null
557    * @param str string value
558    * @param undoListener listener to notify if an undoable edit is generated,
559    *     or null to suppress generation of undoable edits
560    * @return added CommentString
561    * @exception IllegalArgumentException after is not a member
562    * @exception NullPointerException str was null
563    */
564   public CommentString insertCommentStringAfter(
565     SongLineMember after,
566     String str,
567     UndoableEditListener undoListener)
568   {
569     StdCommentString nstring = new StdCommentString(this, str);
570     memberList_.insertObjectAfter(nstring, after, undoListener);
571     return nstring;
572   }
573   
574   
575   /**
576    * Add a chord annotation at the given position.
577    *
578    * @param before insert before this member, or at the end if null
579    * @param cs ChordSet for the annotation. May not be null.
580    * @param primary primary chord for the annotation. May not be null.
581    * @param preceding array of preceding chords. May be null.
582    * @param following array of following chords. May be null.
583    * @param undoListener listener to notify if an undoable edit is generated,
584    *     or null to suppress generation of undoable edits
585    * @return added ChordAnnotation
586    * @exception IllegalArgumentException before or cs is not a member
587    * @exception NullPointerException cs was null
588    */
589   public ChordAnnotation insertChordAnnotationBefore(
590     SongLineMember before,
591     ChordSet cs,
592     Chord primary,
593     Chord[] preceding,
594     Chord[] following,
595     UndoableEditListener undoListener)
596   {
597     if (!((StdSong)getSong()).containsChordSet(cs))
598     {
599       throw new IllegalArgumentException();
600     }
601     StdChordAnnotation ann = new StdChordAnnotation(this, (StdChordSet)cs, primary, preceding, following);
602     memberList_.insertObjectBefore(ann, before, undoListener);
603     return ann;
604   }
605   
606   
607   /**
608    * Add a chord annotation at the given position.
609    *
610    * @param after insert after this member, or at the beginning if null
611    * @param cs ChordSet for the annotation. May not be null.
612    * @param primary primary chord for the annotation. May not be null.
613    * @param preceding array of preceding chords. May be null.
614    * @param following array of following chords. May be null.
615    * @param undoListener listener to notify if an undoable edit is generated,
616    *     or null to suppress generation of undoable edits
617    * @return added ChordAnnotation
618    * @exception IllegalArgumentException after or cs is not a member
619    * @exception NullPointerException cs was null
620    */
621   public ChordAnnotation insertChordAnnotationAfter(
622     SongLineMember after,
623     ChordSet cs,
624     Chord primary,
625     Chord[] preceding,
626     Chord[] following,
627     UndoableEditListener undoListener)
628   {
629     if (!((StdSong)getSong()).containsChordSet(cs))
630     {
631       throw new IllegalArgumentException();
632     }
633     StdChordAnnotation ann = new StdChordAnnotation(this, (StdChordSet)cs, primary, preceding, following);
634     memberList_.insertObjectAfter(ann, after, undoListener);
635     return ann;
636   }
637   
638   
639   /**
640    * Remove the given member.
641    *
642    * @param member member to remove
643    * @param undoListener listener to notify if an undoable edit is generated,
644    *     or null to suppress generation of undoable edits
645    * @exception IllegalArgumentException member is not a member
646    * @exception NullPointerException member was null
647    */
648   public void removeMember(
649     SongLineMember member,
650     UndoableEditListener undoListener)
651   {
652     memberList_.removeObject(member, undoListener);
653   }
654 }