Source code: com/virtuosotechnologies/asaph/standardmodel/BaseSongBlock.java
1 /*
2 ================================================================================
3
4 FILE: BaseSongBlock.java
5
6 PROJECT:
7
8 Asaph
9
10 CONTENTS:
11
12 Base class for SongBlock implementations
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 import java.io.IOException;
45 import javax.swing.undo.AbstractUndoableEdit;
46 import javax.swing.undo.CannotUndoException;
47 import javax.swing.undo.CannotRedoException;
48 import javax.swing.event.UndoableEditListener;
49 import org.xml.sax.SAXException;
50 import org.xml.sax.Attributes;
51 import org.xml.sax.ErrorHandler;
52 import org.xml.sax.Locator;
53
54 import com.virtuosotechnologies.lib.util.StringID;
55 import com.virtuosotechnologies.lib.xml.XMLUnparser;
56
57 import com.virtuosotechnologies.asaph.model.SongLine;
58 import com.virtuosotechnologies.asaph.model.SongBlock;
59 import com.virtuosotechnologies.asaph.model.notation.NotationFactory;
60
61
62 /**
63 * Base class for SongBlock implementations
64 */
65 /*package*/ abstract class BaseSongBlock
66 extends BaseSongMember
67 implements
68 SongBlock
69 {
70 private int indentLevel_;
71 private ListHelper lineList_;
72 private StringID id_;
73
74
75 /*package*/ BaseSongBlock(
76 StdSong parent,
77 StringID id,
78 int indentLevel)
79 {
80 super(parent);
81 indentLevel_ = indentLevel;
82 lineList_ = new ListHelper(this);
83 id_ = id;
84 }
85
86
87 /*package*/ void handleChordSetDeleted(
88 StdChordSet chordSet,
89 UndoableEditListener undoListener)
90 {
91 for (StdSongLine line = (StdSongLine)lineList_.getNextObject(null);
92 line != null; line = (StdSongLine)lineList_.getNextObject(line))
93 {
94 line.handleChordSetDeleted(chordSet, undoListener);
95 }
96 }
97
98
99 /*package*/ void unparse(
100 XMLUnparser unparser)
101 throws
102 IOException
103 {
104 unparser.startMultiLineElement(XMLConstants.BLOCK_ELEMENT);
105 unparser.addAttribute(XMLConstants.BLOCK_ID_ATTRIBUTE, id_.getValue());
106 if (indentLevel_ != 0)
107 {
108 unparser.addAttribute(XMLConstants.BLOCK_INDENT_ATTRIBUTE,
109 Integer.toString(indentLevel_));
110 }
111 unparseVariationAttribute(unparser);
112 for (StdSongLine line = (StdSongLine)lineList_.getNextObject(null);
113 line != null; line = (StdSongLine)lineList_.getNextObject(line))
114 {
115 line.unparse(unparser);
116 }
117 unparser.endElement(XMLConstants.BLOCK_ELEMENT);
118 }
119
120
121 /*package*/ abstract void unparseVariationAttribute(
122 XMLUnparser unparser)
123 throws
124 IOException;
125
126
127 /*package*/ class ParseHandler
128 extends ParseHandlerBase
129 {
130 private StdSong song_;
131 private NotationFactory notationFactory_;
132
133 /*package*/ ParseHandler(
134 ErrorHandler errorHandler,
135 Locator locator,
136 StdSong song,
137 NotationFactory notationFactory)
138 {
139 super(errorHandler, locator, XMLConstants.BLOCK_ELEMENT);
140 song_ = song;
141 notationFactory_ = notationFactory;
142 }
143
144 /*package*/ ParseHandlerBase localStartElement(
145 String uri,
146 String localName,
147 String qName,
148 Attributes attributes)
149 throws
150 SAXException
151 {
152 if (localName.equals(XMLConstants.LINE_ELEMENT))
153 {
154 String indentStr = attributes.getValue(XMLConstants.LINE_INDENT_ATTRIBUTE);
155 int indent = 0;
156 if (indentStr != null)
157 {
158 try
159 {
160 indent = Integer.parseInt(indentStr);
161 }
162 catch (NumberFormatException ex)
163 {
164 reportError(ResourceAccess.Strings.buildString(
165 "xml_MalformedIndent", indentStr));
166 }
167 }
168 StdSongLine line = new StdSongLine(BaseSongBlock.this, indent);
169 lineList_.appendObject(line, null);
170 return line.new ParseHandler(getErrorHandler(), getDocumentLocator(), song_,
171 notationFactory_);
172 }
173 else
174 {
175 return super.localStartElement(uri, localName, qName, attributes);
176 }
177 }
178 }
179
180
181 //-------------------------------------------------------------------------
182 // Methods of SongBlock
183 //-------------------------------------------------------------------------
184
185 /**
186 * Get the indent level
187 *
188 * @return indent level
189 */
190 public int getIndentLevel()
191 {
192 return indentLevel_;
193 }
194
195
196 /**
197 * Get the number of lines
198 *
199 * @return number of lines
200 */
201 public int getLineCount()
202 {
203 return lineList_.getCount();
204 }
205
206
207 /**
208 * Get the nth line
209 *
210 * @param n index
211 * @return line
212 */
213 public SongLine getNthLine(
214 int n)
215 {
216 return (StdSongLine)lineList_.getNthObject(n);
217 }
218
219
220 /**
221 * Get the next line following reference.
222 * If reference is null, returns the first line.
223 * If reference is the last line, returns null;
224 *
225 * @param reference reference SongLine
226 * @return next line
227 * @exception IllegalArgumentException reference is not a member
228 */
229 public SongLine getNextLine(
230 SongLine reference)
231 {
232 return (StdSongLine)lineList_.getNextObject(reference);
233 }
234
235
236 /**
237 * Get the previous line preceding reference.
238 * If reference is null, returns the last line.
239 * If reference is the first line, returns null;
240 *
241 * @param reference reference SongLine
242 * @return previous line
243 * @exception IllegalArgumentException reference is not a member
244 */
245 public SongLine getPreviousLine(
246 SongLine reference)
247 {
248 return (StdSongLine)lineList_.getPreviousObject(reference);
249 }
250
251
252 /**
253 * Get a string ID that can be used to serialize references to this
254 * SongBlock. The ID is guaranteed to be unique among SongBlocks within
255 * the owning Song, and will remain the same for the same SongBlock across
256 * different executions of the tool. However, two SongBlocks from different
257 * Songs may have the same string ID, and the same string ID may be
258 * shared between SongBlocks, Variations and ChordSets within the same
259 * Song.
260 *
261 * @return a unique serializable String ID for this SongBlock
262 */
263 public String getSerializableID()
264 {
265 return id_.getValue();
266 }
267
268
269 /**
270 * Set the indent level
271 *
272 * @param indent new indent level
273 * @param undoListener listener to notify if an undoable edit is generated,
274 * or null to suppress generation of undoable edits
275 */
276 public void setIndentLevel(
277 final int indent,
278 UndoableEditListener undoListener)
279 {
280 final int oldIndent = indentLevel_;
281 indentLevel_ = indent;
282 if (undoListener != null)
283 {
284 internalReportUndoableEdit(undoListener,
285 new AbstractUndoableEdit()
286 {
287 public void undo()
288 throws CannotUndoException
289 {
290 super.undo();
291 indentLevel_ = oldIndent;
292 }
293
294 public void redo()
295 throws CannotRedoException
296 {
297 super.redo();
298 indentLevel_ = indent;
299 }
300 });
301 }
302 }
303
304
305 /**
306 * Add a line at the given position.
307 *
308 * @param before insert before this line, or at the end if null
309 * @param undoListener listener to notify if an undoable edit is generated,
310 * or null to suppress generation of undoable edits
311 * @return added SongLine
312 * @exception IllegalArgumentException before is not a member
313 */
314 public SongLine insertLineBefore(
315 SongLine before,
316 UndoableEditListener undoListener)
317 {
318 StdSongLine nline = new StdSongLine(this);
319 lineList_.insertObjectBefore(nline, before, undoListener);
320 return nline;
321 }
322
323
324 /**
325 * Add a line at the given position.
326 *
327 * @param after insert after this line, or at the beginning if null
328 * @param undoListener listener to notify if an undoable edit is generated,
329 * or null to suppress generation of undoable edits
330 * @return added SongLine
331 * @exception IllegalArgumentException after is not a member
332 */
333 public SongLine insertLineAfter(
334 SongLine after,
335 UndoableEditListener undoListener)
336 {
337 StdSongLine nline = new StdSongLine(this);
338 lineList_.insertObjectAfter(nline, after, undoListener);
339 return nline;
340 }
341
342
343 /**
344 * Remove the given line.
345 *
346 * @param line line to remove
347 * @param undoListener listener to notify if an undoable edit is generated,
348 * or null to suppress generation of undoable edits
349 * @exception IllegalArgumentException line is not present
350 * @exception NullPointerException line was null
351 */
352 public void removeLine(
353 SongLine line,
354 UndoableEditListener undoListener)
355 {
356 lineList_.removeObject(line, undoListener);
357 }
358 }