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

Quick Search    Search Deep

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


1   /*
2   ================================================================================
3   
4     FILE:  StdChordAnnotation.java
5     
6     PROJECT:
7     
8       Asaph
9     
10    CONTENTS:
11    
12      Standard implementation of ChordAnnotation
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.io.IOException;
46  import javax.swing.undo.AbstractUndoableEdit;
47  import javax.swing.undo.CannotUndoException;
48  import javax.swing.undo.CannotRedoException;
49  import javax.swing.event.UndoableEditListener;
50  import org.xml.sax.ErrorHandler;
51  import org.xml.sax.Locator;
52  
53  import com.virtuosotechnologies.lib.xml.XMLUnparser;
54  
55  import com.virtuosotechnologies.asaph.model.ChordAnnotation;
56  import com.virtuosotechnologies.asaph.model.SongLine;
57  import com.virtuosotechnologies.asaph.model.ChordSet;
58  import com.virtuosotechnologies.asaph.model.notation.Chord;
59  
60  
61  /**
62   * Standard implementation of ChordAnnotation
63   */
64  /*package*/ class StdChordAnnotation
65  extends BaseSongMember
66  implements
67    ChordAnnotation
68  {
69    private StdChordSet chordSet_;
70    private Chord main_;
71    private Chord[] pre_;
72    private Chord[] post_;
73    
74    
75    /*package*/ StdChordAnnotation(
76      StdSongLine parent,
77      StdChordSet chordSet,
78      Chord main,
79      Chord[] pre,
80      Chord[] post)
81    {
82      super(parent);
83      assert parent.getSongBlock().getSong() == chordSet.getSong();
84      if (main == null)
85      {
86        throw new NullPointerException();
87      }
88      chordSet_ = chordSet;
89      main_ = main;
90      if (pre == null)
91      {
92        pre_ = new Chord[0];
93      }
94      else
95      {
96        pre_ = new Chord[pre.length];
97        System.arraycopy(pre, 0, pre_, 0, pre.length);
98      }
99      if (post == null)
100     {
101       post_ = new Chord[0];
102     }
103     else
104     {
105       post_ = new Chord[post.length];
106       System.arraycopy(post, 0, post_, 0, post.length);
107     }
108   }
109   
110   
111   /*package*/ void unparse(
112     XMLUnparser unparser)
113   throws
114     IOException
115   {
116     unparser.startSingleLineElement(XMLConstants.ANNOTATION_ELEMENT);
117     if (chordSet_ != getSong().getDefaultChordSet())
118     {
119       unparser.addAttribute(XMLConstants.ANNOTATION_CHORDSET_ATTRIBUTE,
120         chordSet_.getSerializableID());
121     }
122     if (pre_.length > 0)
123     {
124       unparser.addAttribute(XMLConstants.ANNOTATION_PRECEDING_ATTRIBUTE,
125         pre_[0].getNotationFactory().unparseChordArray(pre_));
126     }
127     if (!main_.isEmpty())
128     {
129       unparser.addAttribute(XMLConstants.ANNOTATION_PRIMARY_ATTRIBUTE,
130         main_.generateString());
131     }
132     if (post_.length > 0)
133     {
134       unparser.addAttribute(XMLConstants.ANNOTATION_FOLLOWING_ATTRIBUTE,
135         post_[0].getNotationFactory().unparseChordArray(post_));
136     }
137     unparser.endElement(XMLConstants.ANNOTATION_ELEMENT);
138   }
139   
140   
141   /*package*/ class ParseHandler
142   extends ParseHandlerBase
143   {
144     /*package*/ ParseHandler(
145       ErrorHandler errorHandler,
146       Locator locator)
147     {
148       super(errorHandler, locator, XMLConstants.ANNOTATION_ELEMENT);
149     }
150   }
151   
152   
153   //-------------------------------------------------------------------------
154   // Methods of SongLineMember
155   //-------------------------------------------------------------------------
156   
157   /**
158    * Get the containing song line
159    *
160    * @return SongLine containing this member
161    */
162   public SongLine getSongLine()
163   {
164     return (SongLine)internalGetParent();
165   }
166   
167   
168   //-------------------------------------------------------------------------
169   // Methods of ChordAnnotation
170   //-------------------------------------------------------------------------
171   
172   /**
173    * Get the ChordSet relevant to this annotation. Every annotation
174    * is part of a ChordSet. Note that this method may be slow, since
175    * implementations may need to search the Song for the correct
176    * ChordSet. If all you need to do is determine whether this
177    * annotation is associated with a given ChordSet, use isInChordSet
178    * instead, which may be optimized by the implementation.
179    *
180    * @return ChordSet this annotation is part of
181    */
182   public ChordSet getChordSet()
183   {
184     return chordSet_;
185   }
186   
187   
188   /**
189    * Returns true if this annotation in the given ChordSet.
190    * Implementations of this method may be faster than
191    * getChordSet().equals(). Returns false but does not throw
192    * an exception if the given ChordSet is null, or is not a
193    * member of the Song containing this annotation
194    *
195    * @param cs ChordSet to match with
196    * @return true if this annotation is in the given ChordSet
197    */
198   public boolean isInChordSet(
199     ChordSet cs)
200   {
201     return chordSet_ == cs;
202   }
203   
204   
205   /**
206    * Get the primary chord.
207    *
208    * @return the chord
209    */
210   public Chord getPrimaryChord()
211   {
212     return main_;
213   }
214   
215   
216   /**
217    * Get the array of chords that should precede the main chord.
218    * This will return an empty array if there are no preceding chords.
219    *
220    * @return the chord array
221    */
222   public Chord[] getPrecedingChords()
223   {
224     Chord[] ret = new Chord[pre_.length];
225     System.arraycopy(pre_, 0, ret, 0, pre_.length);
226     return ret;
227   }
228   
229   
230   /**
231    * Get the array of chords that should follow the main chord.
232    * This will return an empty array if there are no following chords.
233    *
234    * @return the chord array
235    */
236   public Chord[] getFollowingChords()
237   {
238     Chord[] ret = new Chord[post_.length];
239     System.arraycopy(post_, 0, ret, 0, post_.length);
240     return ret;
241   }
242   
243   
244   /**
245    * Set the primary chord. The primary chord may not be null.
246    *
247    * @param chord the chord.
248    * @param undoListener listener to notify if an undoable edit is generated,
249    *     or null to suppress generation of undoable edits
250    */
251   public void setPrimaryChord(
252     final Chord chord,
253     UndoableEditListener undoListener)
254   {
255     if (chord == null)
256     {
257       throw new NullPointerException();
258     }
259     if (chord.equals(main_))
260     {
261       return;
262     }
263     final Chord oldChord = main_;
264     main_ = chord;
265     if (undoListener != null)
266     {
267       internalReportUndoableEdit(undoListener,
268         new AbstractUndoableEdit()
269         {
270           public void undo()
271           throws CannotUndoException
272           {
273             super.undo();
274             main_ = oldChord;
275           }
276           
277           public void redo()
278           throws CannotRedoException
279           {
280             super.redo();
281             main_ = chord;
282           }
283         });
284     }
285   }
286   
287   
288   private Chord[] analyzeNewChords(
289     Chord[] chords,
290     Chord[] oldChords)
291   {
292     final Chord[] newChords;
293     if (chords == null)
294     {
295       newChords = new Chord[0];
296     }
297     else
298     {
299       newChords = new Chord[chords.length];
300       System.arraycopy(chords, 0, newChords, 0, chords.length);
301     }
302     if (newChords.length != oldChords.length)
303     {
304       return newChords;
305     }
306     for (int i=0; i<newChords.length; ++i)
307     {
308       if (!newChords[i].equals(oldChords[i]))
309       {
310         return newChords;
311       }
312     }
313     return null;
314   }
315   
316   
317   /**
318    * Set the array of chords that should precede the main one.
319    * You may pass null or the empty array for no preceding chords.
320    *
321    * @param chords the chord array
322    * @param undoListener listener to notify if an undoable edit is generated,
323    *     or null to suppress generation of undoable edits
324    */
325   public void setPrecedingChords(
326     Chord[] chords,
327     UndoableEditListener undoListener)
328   {
329     final Chord[] newChords = analyzeNewChords(chords, pre_);
330     if (newChords == null)
331     {
332       return;
333     }
334     final Chord[] oldChords = pre_;
335     pre_ = newChords;
336     if (undoListener != null)
337     {
338       internalReportUndoableEdit(undoListener,
339         new AbstractUndoableEdit()
340         {
341           public void undo()
342           throws CannotUndoException
343           {
344             super.undo();
345             pre_ = oldChords;
346           }
347           
348           public void redo()
349           throws CannotRedoException
350           {
351             super.redo();
352             pre_ = newChords;
353           }
354         });
355     }
356   }
357   
358   
359   /**
360    * Set the array of chords that should follow the main one.
361    * You may pass null or the empty array for no following chords.
362    *
363    * @param chords the chord array
364    * @param undoListener listener to notify if an undoable edit is generated,
365    *     or null to suppress generation of undoable edits
366    */
367   public void setFollowingChords(
368     Chord[] chords,
369     UndoableEditListener undoListener)
370   {
371     final Chord[] newChords = analyzeNewChords(chords, post_);
372     if (newChords == null)
373     {
374       return;
375     }
376     final Chord[] oldChords = post_;
377     post_ = newChords;
378     if (undoListener != null)
379     {
380       internalReportUndoableEdit(undoListener,
381         new AbstractUndoableEdit()
382         {
383           public void undo()
384           throws CannotUndoException
385           {
386             super.undo();
387             post_ = oldChords;
388           }
389           
390           public void redo()
391           throws CannotRedoException
392           {
393             super.redo();
394             post_ = newChords;
395           }
396         });
397     }
398   }
399 }