Source code: com/virtuosotechnologies/asaph/standardmodel/StdChordSet.java
1 /*
2 ================================================================================
3
4 FILE: StdChordSet.java
5
6 PROJECT:
7
8 Asaph
9
10 CONTENTS:
11
12 Standard implementation of ChordSet
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.event.UndoableEditListener;
47 import org.xml.sax.SAXException;
48 import org.xml.sax.Attributes;
49 import org.xml.sax.ErrorHandler;
50 import org.xml.sax.Locator;
51
52 import com.virtuosotechnologies.lib.util.StringID;
53 import com.virtuosotechnologies.lib.xml.XMLUnparser;
54
55 import com.virtuosotechnologies.asaph.model.ChordSet;
56 import com.virtuosotechnologies.asaph.model.ChordSetKey;
57 import com.virtuosotechnologies.asaph.model.SimpleString;
58 import com.virtuosotechnologies.asaph.model.notation.Note;
59 import com.virtuosotechnologies.asaph.model.notation.NotationFactory;
60
61
62 /**
63 * Standard implementation of ChordSet
64 */
65 /*package*/ class StdChordSet
66 extends BaseSongMember
67 implements
68 ChordSet
69 {
70 private StdSimpleString name_;
71 private StdSimpleString keySigType_;
72 private StdChordSetKey nativeKey_;
73 private ListHelper altKeysList_;
74 private StringID id_;
75
76
77 /*package*/ StdChordSet(
78 StdSong parent,
79 String name,
80 String keySigType,
81 Note nativeKeyNote,
82 String nativeKeyInfo,
83 StringID id)
84 {
85 super(parent);
86 name_ = new StdSimpleString(this, name);
87 keySigType_ = new StdSimpleString(this, keySigType);
88 nativeKey_ = new StdChordSetKey(this, nativeKeyNote, nativeKeyInfo);
89 altKeysList_ = new ListHelper(this);
90 id_ = id;
91 }
92
93
94 /*package*/ void unparse(
95 XMLUnparser unparser)
96 throws
97 IOException
98 {
99 unparser.startMultiLineElement(XMLConstants.CHORDSET_ELEMENT);
100 unparser.addAttribute(XMLConstants.CHORDSET_ID_ATTRIBUTE, id_.getValue());
101
102 name_.unparse(unparser, XMLConstants.CHORDSETNAME_ELEMENT);
103 keySigType_.unparse(unparser, XMLConstants.KEYTYPE_ELEMENT);
104 nativeKey_.unparse(unparser, XMLConstants.NATIVEKEY_ELEMENT);
105
106 unparser.startMultiLineElement(XMLConstants.ALTKEYLIST_ELEMENT);
107 for (StdChordSetKey altKey = (StdChordSetKey)altKeysList_.getNextObject(null);
108 altKey != null; altKey = (StdChordSetKey)altKeysList_.getNextObject(altKey))
109 {
110 altKey.unparse(unparser, XMLConstants.ALTKEY_ELEMENT);
111 }
112 unparser.endElement(XMLConstants.ALTKEYLIST_ELEMENT);
113
114 unparser.endElement(XMLConstants.CHORDSET_ELEMENT);
115 }
116
117
118 /*package*/ class ParseHandler
119 extends ParseHandlerBase
120 {
121 private NotationFactory notationFactory_;
122
123 /*package*/ ParseHandler(
124 ErrorHandler errorHandler,
125 Locator locator,
126 String localElement,
127 NotationFactory notationFactory)
128 {
129 super(errorHandler, locator, localElement);
130 notationFactory_ = notationFactory;
131 }
132
133 /*package*/ ParseHandlerBase localStartElement(
134 String uri,
135 String localName,
136 String qName,
137 Attributes attributes)
138 throws
139 SAXException
140 {
141 if (localName.equals(XMLConstants.CHORDSETNAME_ELEMENT) ||
142 localName.equals(XMLConstants.CHORDSETNAME_ELEMENT_ALT))
143 {
144 return name_.new ParseHandler(getErrorHandler(), getDocumentLocator(), localName);
145 }
146 else if (localName.equals(XMLConstants.KEYTYPE_ELEMENT))
147 {
148 return keySigType_.new ParseHandler(getErrorHandler(),
149 getDocumentLocator(), XMLConstants.KEYTYPE_ELEMENT);
150 }
151 else if (localName.equals(XMLConstants.NATIVEKEY_ELEMENT))
152 {
153 String noteStr = attributes.getValue(XMLConstants.KEY_NOTE_ATTRIBUTE);
154 if (noteStr == null)
155 {
156 reportFatalError(ResourceAccess.Strings.buildString("xml_MissingAttribute",
157 XMLConstants.KEY_NOTE_ATTRIBUTE, XMLConstants.NATIVEKEY_ELEMENT));
158 }
159 Note note = notationFactory_.parseNote(noteStr);
160 if (note == null)
161 {
162 reportFatalError(ResourceAccess.Strings.buildString(
163 "xml_MalformedNativeKeyNote", noteStr));
164 }
165 nativeKey_.setKeyNote(note, null);
166 return nativeKey_.new ParseHandler(getErrorHandler(),
167 getDocumentLocator(), XMLConstants.NATIVEKEY_ELEMENT);
168 }
169 else if (localName.equals(XMLConstants.ALTKEYLIST_ELEMENT))
170 {
171 return new AltKeyListParseHandler(getErrorHandler(), getDocumentLocator(), notationFactory_);
172 }
173 else
174 {
175 return super.localStartElement(uri, localName, qName, attributes);
176 }
177 }
178 }
179
180
181 /*package*/ class AltKeyListParseHandler
182 extends ParseHandlerBase
183 {
184 private NotationFactory notationFactory_;
185
186 /*package*/ AltKeyListParseHandler(
187 ErrorHandler errorHandler,
188 Locator locator,
189 NotationFactory notationFactory)
190 {
191 super(errorHandler, locator, XMLConstants.ALTKEYLIST_ELEMENT);
192 notationFactory_ = notationFactory;
193 }
194
195 /*package*/ ParseHandlerBase localStartElement(
196 String uri,
197 String localName,
198 String qName,
199 Attributes attributes)
200 throws
201 SAXException
202 {
203 if (localName.equals(XMLConstants.ALTKEY_ELEMENT))
204 {
205 String noteStr = attributes.getValue(XMLConstants.KEY_NOTE_ATTRIBUTE);
206 if (noteStr == null)
207 {
208 reportFatalError(ResourceAccess.Strings.buildString("xml_MissingAttribute",
209 XMLConstants.KEY_NOTE_ATTRIBUTE, XMLConstants.ALTKEY_ELEMENT));
210 }
211 Note note = notationFactory_.parseNote(noteStr);
212 if (note == null)
213 {
214 reportFatalError(ResourceAccess.Strings.buildString(
215 "xml_MalformedAltKeyNote", noteStr));
216 }
217 StdChordSetKey altKey = new StdChordSetKey(StdChordSet.this, note, "");
218 altKeysList_.appendObject(altKey, null);
219 return altKey.new ParseHandler(getErrorHandler(),
220 getDocumentLocator(), XMLConstants.ALTKEY_ELEMENT);
221 }
222 else
223 {
224 return super.localStartElement(uri, localName, qName, attributes);
225 }
226 }
227 }
228
229
230 //-------------------------------------------------------------------------
231 // Methods of ChordSet
232 //-------------------------------------------------------------------------
233
234 /**
235 * Get a SimpleString containing the name of the chord set.
236 * Every ChordSet will have a name, even if it is the empty string.
237 *
238 * @return name
239 */
240 public SimpleString getName()
241 {
242 return name_;
243 }
244
245
246 /**
247 * Get a SimpleString containing the key signature type. This string
248 * is typically the string that gets concatenated to the note to form
249 * a key signature. Often it begins with a space. Every ChordSet
250 * will have a key signature type, even if it is the empty string.
251 *
252 * @return key signature type
253 */
254 public SimpleString getKeySignatureType()
255 {
256 return keySigType_;
257 }
258
259
260 /**
261 * Get the ChordSetKey representing the native key signature.
262 *
263 * @return native key signature
264 */
265 public ChordSetKey getNativeKey()
266 {
267 return nativeKey_;
268 }
269
270
271 /**
272 * Get the number of alternate keys
273 *
274 * @return number of alternate keys
275 */
276 public int getAlternateKeyCount()
277 {
278 return altKeysList_.getCount();
279 }
280
281
282 /**
283 * Get the next alternate key following reference.
284 * If reference is null, returns the first alternate key.
285 * If reference is the last alternate key, returns null;
286 *
287 * @param reference reference ChordSetKey
288 * @return next alternate key
289 * @exception IllegalArgumentException reference is not a member
290 */
291 public ChordSetKey getNextAlternateKey(
292 ChordSetKey reference)
293 {
294 return (StdChordSetKey)altKeysList_.getNextObject(reference);
295 }
296
297
298 /**
299 * Get the previous alternate key preceding reference.
300 * If reference is null, returns the last alternate key.
301 * If reference is the first alternate key, returns null;
302 *
303 * @param reference reference ChordSetKey
304 * @return previous alternate key
305 * @exception IllegalArgumentException reference is not a member
306 */
307 public ChordSetKey getPreviousAlternateKey(
308 ChordSetKey reference)
309 {
310 return (StdChordSetKey)altKeysList_.getPreviousObject(reference);
311 }
312
313
314 /**
315 * Get a string ID that can be used to serialize references to this
316 * ChordSet. The ID is guaranteed to be unique among ChordSets within
317 * the owning Song, and will remain the same for the same ChordSet across
318 * different executions of the tool. However, two ChordSets from different
319 * Songs may have the same string ID, and the same string ID may be
320 * shared between SongBlocks, Variations and ChordSets within the same
321 * Song.
322 *
323 * @return a unique serializable String ID for this ChordSet
324 */
325 public String getSerializableID()
326 {
327 return id_.getValue();
328 }
329
330
331 /**
332 * Add a new alternate key to the chord set.
333 *
334 * @param note key note
335 * @param undoListener listener to notify if an undoable edit is generated,
336 * or null to suppress generation of undoable edits
337 * @return added alternate key
338 * @exception NullPointerException note was null
339 */
340 public ChordSetKey addAlternateKey(
341 Note note,
342 UndoableEditListener undoListener)
343 {
344 StdChordSetKey nkey = new StdChordSetKey(this, note, "");
345 altKeysList_.appendObject(nkey, undoListener);
346 return nkey;
347 }
348
349
350 /**
351 * Remove the given alternate key from the chord set.
352 *
353 * @param alternateKey ChordSetKey to remove
354 * @param undoListener listener to notify if an undoable edit is generated,
355 * or null to suppress generation of undoable edits
356 * @exception IllegalArgumentException alternateKey is not present
357 * @exception NullPointerException alternateKey was null
358 */
359 public void removeAlternateKey(
360 ChordSetKey alternateKey,
361 UndoableEditListener undoListener)
362 {
363 altKeysList_.removeObject(alternateKey, undoListener);
364 }
365 }