lbajardsilogic@19
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
lbajardsilogic@19
|
2
|
lbajardsilogic@19
|
3 /* Sound Access
|
lbajardsilogic@19
|
4 EASAIER client application.
|
lbajardsilogic@19
|
5 Silogic 2007. Laure Bajard.
|
lbajardsilogic@19
|
6
|
lbajardsilogic@19
|
7 This program is free software; you can redistribute it and/or
|
lbajardsilogic@19
|
8 modify it under the terms of the GNU General Public License as
|
lbajardsilogic@19
|
9 published by the Free Software Foundation; either version 2 of the
|
lbajardsilogic@19
|
10 License, or (at your option) any later version. See the file
|
lbajardsilogic@19
|
11 COPYING included with this distribution for more information.
|
lbajardsilogic@19
|
12 */
|
lbajardsilogic@19
|
13
|
lbajardsilogic@19
|
14 #include <QString>
|
lbajardsilogic@19
|
15 #include <QMessageBox>
|
lbajardsilogic@19
|
16 #include <QFileDialog>
|
lbajardsilogic@19
|
17 #include <QUrl>
|
lbajardsilogic@19
|
18
|
lbajardsilogic@19
|
19 #include <iostream>
|
lbajardsilogic@19
|
20
|
lbajardsilogic@19
|
21 #include "ESFileReader.h"
|
lbajardsilogic@19
|
22
|
lbajardsilogic@19
|
23 #include "layer/Layer.h"
|
lbajardsilogic@19
|
24 #include "view/View.h"
|
lbajardsilogic@19
|
25 #include "base/PlayParameters.h"
|
lbajardsilogic@19
|
26 #include "base/PlayParameterRepository.h"
|
lbajardsilogic@19
|
27 #include "base/TempDirectory.h"
|
lbajardsilogic@19
|
28 #include "data/fileio/AudioFileReaderFactory.h"
|
lbajardsilogic@19
|
29 #include "data/model/WaveFileModel.h"
|
lbajardsilogic@19
|
30 #include "data/model/DenseThreeDimensionalModel.h"
|
lbajardsilogic@19
|
31 #include "data/model/SparseOneDimensionalModel.h"
|
lbajardsilogic@19
|
32 #include "data/model/SparseTimeValueModel.h"
|
lbajardsilogic@19
|
33 #include "data/model/NoteModel.h"
|
lbajardsilogic@19
|
34 #include "data/model/TextModel.h"
|
lbajardsilogic@19
|
35 #include "view/Pane.h"
|
lbajardsilogic@19
|
36 #include "document/Document.h"
|
lbajardsilogic@19
|
37
|
lbajardsilogic@19
|
38
|
lbajardsilogic@19
|
39 ESFileReader::ESFileReader(Document *document,
|
lbajardsilogic@19
|
40 ESFileReaderPaneCallback &callback) : QXmlDefaultHandler(),
|
lbajardsilogic@19
|
41 m_document(document),
|
lbajardsilogic@19
|
42 m_paneCallback(callback),
|
lbajardsilogic@19
|
43 m_currentPane(0),
|
lbajardsilogic@19
|
44 m_inView(false),
|
lbajardsilogic@19
|
45 m_inData(false),
|
lbajardsilogic@19
|
46 m_ok(false)
|
lbajardsilogic@19
|
47 {}
|
lbajardsilogic@19
|
48
|
lbajardsilogic@19
|
49 void
|
lbajardsilogic@19
|
50 ESFileReader::parse(const QString &xmlData)
|
lbajardsilogic@19
|
51 {
|
lbajardsilogic@19
|
52 QXmlInputSource inputSource;
|
lbajardsilogic@19
|
53 inputSource.setData(xmlData);
|
lbajardsilogic@19
|
54 parse(inputSource);
|
lbajardsilogic@19
|
55 }
|
lbajardsilogic@19
|
56
|
lbajardsilogic@19
|
57 void
|
lbajardsilogic@19
|
58 ESFileReader::parse(QXmlInputSource &inputSource)
|
lbajardsilogic@19
|
59 {
|
lbajardsilogic@19
|
60 QXmlSimpleReader reader;
|
lbajardsilogic@19
|
61 reader.setContentHandler(this);
|
lbajardsilogic@19
|
62 reader.setErrorHandler(this);
|
lbajardsilogic@19
|
63 m_ok = reader.parse(inputSource);
|
lbajardsilogic@19
|
64 }
|
lbajardsilogic@19
|
65
|
lbajardsilogic@19
|
66 bool
|
lbajardsilogic@19
|
67 ESFileReader::isOK()
|
lbajardsilogic@19
|
68 {
|
lbajardsilogic@19
|
69 return m_ok;
|
lbajardsilogic@19
|
70 }
|
lbajardsilogic@19
|
71
|
lbajardsilogic@19
|
72 ESFileReader::~ESFileReader()
|
lbajardsilogic@19
|
73 {}
|
lbajardsilogic@19
|
74
|
lbajardsilogic@19
|
75 bool
|
lbajardsilogic@19
|
76 ESFileReader::startElement(const QString &, const QString &,
|
lbajardsilogic@19
|
77 const QString &qName,
|
lbajardsilogic@19
|
78 const QXmlAttributes &attributes)
|
lbajardsilogic@19
|
79 {
|
lbajardsilogic@19
|
80 QString name = qName.toLower();
|
lbajardsilogic@19
|
81
|
lbajardsilogic@19
|
82 bool ok = false;
|
lbajardsilogic@19
|
83
|
lbajardsilogic@19
|
84 // Valid element names:
|
lbajardsilogic@19
|
85 //
|
lbajardsilogic@19
|
86 // easaiersession
|
lbajardsilogic@19
|
87 // data
|
lbajardsilogic@19
|
88 // easaierresources
|
lbajardsilogic@19
|
89 // audio
|
lbajardsilogic@19
|
90 // display
|
lbajardsilogic@19
|
91 // window
|
lbajardsilogic@19
|
92 // view
|
lbajardsilogic@19
|
93 // layer
|
lbajardsilogic@19
|
94
|
lbajardsilogic@19
|
95 if (name == "easaiersession") {
|
lbajardsilogic@19
|
96 // nothing needed
|
lbajardsilogic@19
|
97 ok = true;
|
lbajardsilogic@19
|
98
|
lbajardsilogic@19
|
99 } else if (name == "data") {
|
lbajardsilogic@19
|
100 // nothing needed
|
lbajardsilogic@19
|
101 m_inData = true;
|
lbajardsilogic@19
|
102 ok = true;
|
lbajardsilogic@19
|
103
|
lbajardsilogic@19
|
104 } else if (name == "easaierresources") {
|
lbajardsilogic@19
|
105 // nothing needed
|
lbajardsilogic@19
|
106 ok = true;
|
lbajardsilogic@19
|
107
|
lbajardsilogic@19
|
108 } else if (name == "audio") {
|
lbajardsilogic@19
|
109 QString filename = attributes.value("value");
|
lbajardsilogic@19
|
110 m_document->setAudioSourceInfoFileName(filename);
|
lbajardsilogic@19
|
111
|
lbajardsilogic@203
|
112 } else if (name == "filters") {
|
lbajardsilogic@203
|
113 // nothing needed
|
lbajardsilogic@203
|
114 ok = true;
|
lbajardsilogic@203
|
115
|
lbajardsilogic@203
|
116 } else if (name == "filter") {
|
lbajardsilogic@203
|
117 // nothing needed
|
lbajardsilogic@203
|
118 ok = readFilter(attributes);;
|
lbajardsilogic@203
|
119
|
lbajardsilogic@19
|
120 } else if (name == "display") {
|
lbajardsilogic@19
|
121 // nothing needed
|
lbajardsilogic@19
|
122 ok = true;
|
lbajardsilogic@19
|
123
|
lbajardsilogic@19
|
124 } else if (name == "window") {
|
lbajardsilogic@19
|
125 ok = readWindow(attributes);
|
lbajardsilogic@19
|
126
|
lbajardsilogic@19
|
127 } else if (name == "view") {
|
lbajardsilogic@19
|
128 m_inView = true;
|
lbajardsilogic@19
|
129 ok = readView(attributes);
|
lbajardsilogic@19
|
130
|
lbajardsilogic@19
|
131 } else if (name == "layer") {
|
lbajardsilogic@19
|
132 ok = readLayer(attributes);
|
lbajardsilogic@19
|
133
|
lbajardsilogic@19
|
134 }
|
lbajardsilogic@19
|
135
|
lbajardsilogic@19
|
136 if (!ok) {
|
lbajardsilogic@19
|
137 std::cerr << "WARNING: Easaier Session-XML: Failed to completely process element \""
|
lbajardsilogic@19
|
138 << name.toLocal8Bit().data() << "\"" << std::endl;
|
lbajardsilogic@19
|
139 }
|
lbajardsilogic@19
|
140
|
lbajardsilogic@19
|
141 return true;
|
lbajardsilogic@19
|
142 }
|
lbajardsilogic@19
|
143
|
lbajardsilogic@19
|
144 bool
|
lbajardsilogic@19
|
145 ESFileReader::characters(const QString &text)
|
lbajardsilogic@19
|
146 {
|
lbajardsilogic@19
|
147 return true;
|
lbajardsilogic@19
|
148 }
|
lbajardsilogic@19
|
149
|
lbajardsilogic@19
|
150 bool
|
lbajardsilogic@19
|
151 ESFileReader::endElement(const QString &, const QString &,
|
lbajardsilogic@19
|
152 const QString &qName)
|
lbajardsilogic@19
|
153 {
|
lbajardsilogic@19
|
154 QString name = qName.toLower();
|
lbajardsilogic@19
|
155
|
lbajardsilogic@19
|
156 if (name == "data") {
|
lbajardsilogic@19
|
157
|
lbajardsilogic@19
|
158 m_inData = false;
|
lbajardsilogic@19
|
159
|
lbajardsilogic@19
|
160 } else if (name == "view") {
|
lbajardsilogic@19
|
161 m_inView = false;
|
lbajardsilogic@19
|
162 }
|
lbajardsilogic@19
|
163
|
lbajardsilogic@19
|
164 return true;
|
lbajardsilogic@19
|
165 }
|
lbajardsilogic@19
|
166
|
lbajardsilogic@19
|
167 bool
|
lbajardsilogic@19
|
168 ESFileReader::error(const QXmlParseException &exception)
|
lbajardsilogic@19
|
169 {
|
lbajardsilogic@19
|
170 m_errorString =
|
lbajardsilogic@19
|
171 QString("ERROR: Easaier Session-XML: %1 at line %2, column %3")
|
lbajardsilogic@19
|
172 .arg(exception.message())
|
lbajardsilogic@19
|
173 .arg(exception.lineNumber())
|
lbajardsilogic@19
|
174 .arg(exception.columnNumber());
|
lbajardsilogic@19
|
175 std::cerr << m_errorString.toLocal8Bit().data() << std::endl;
|
lbajardsilogic@19
|
176 return QXmlDefaultHandler::error(exception);
|
lbajardsilogic@19
|
177 }
|
lbajardsilogic@19
|
178
|
lbajardsilogic@19
|
179 bool
|
lbajardsilogic@19
|
180 ESFileReader::fatalError(const QXmlParseException &exception)
|
lbajardsilogic@19
|
181 {
|
lbajardsilogic@19
|
182 m_errorString =
|
lbajardsilogic@19
|
183 QString("FATAL ERROR: Easaier Session-XML: %1 at line %2, column %3")
|
lbajardsilogic@19
|
184 .arg(exception.message())
|
lbajardsilogic@19
|
185 .arg(exception.lineNumber())
|
lbajardsilogic@19
|
186 .arg(exception.columnNumber());
|
lbajardsilogic@19
|
187 std::cerr << m_errorString.toLocal8Bit().data() << std::endl;
|
lbajardsilogic@19
|
188 return QXmlDefaultHandler::fatalError(exception);
|
lbajardsilogic@19
|
189 }
|
lbajardsilogic@19
|
190
|
lbajardsilogic@19
|
191
|
lbajardsilogic@19
|
192 #define READ_MANDATORY(TYPE, NAME, CONVERSION) \
|
lbajardsilogic@19
|
193 TYPE NAME = attributes.value(#NAME).trimmed().CONVERSION(&ok); \
|
lbajardsilogic@19
|
194 if (!ok) { \
|
lbajardsilogic@19
|
195 std::cerr << "WARNING: Easaier Session-XML: Missing or invalid mandatory " #TYPE " attribute \"" #NAME "\"" << std::endl; \
|
lbajardsilogic@19
|
196 return false; \
|
lbajardsilogic@19
|
197 }
|
lbajardsilogic@19
|
198
|
lbajardsilogic@19
|
199 bool
|
lbajardsilogic@19
|
200 ESFileReader::readWindow(const QXmlAttributes &attributes)
|
lbajardsilogic@19
|
201 {
|
lbajardsilogic@19
|
202 bool ok = false;
|
lbajardsilogic@19
|
203
|
lbajardsilogic@19
|
204 READ_MANDATORY(int, width, toInt);
|
lbajardsilogic@19
|
205 READ_MANDATORY(int, height, toInt);
|
lbajardsilogic@19
|
206
|
lbajardsilogic@19
|
207 m_paneCallback.setWindowSize(width, height);
|
lbajardsilogic@19
|
208 return true;
|
lbajardsilogic@19
|
209 }
|
lbajardsilogic@19
|
210
|
lbajardsilogic@19
|
211 bool
|
lbajardsilogic@19
|
212 ESFileReader::readView(const QXmlAttributes &attributes)
|
lbajardsilogic@19
|
213 {
|
lbajardsilogic@19
|
214 QString type = attributes.value("type");
|
lbajardsilogic@19
|
215 m_currentPane = 0;
|
lbajardsilogic@19
|
216
|
lbajardsilogic@19
|
217 if (type != "pane") {
|
lbajardsilogic@19
|
218 std::cerr << "WARNING: Easaier session-XML: Unexpected view type \""
|
lbajardsilogic@19
|
219 << type.toLocal8Bit().data() << "\"" << std::endl;
|
lbajardsilogic@19
|
220 return false;
|
lbajardsilogic@19
|
221 }
|
lbajardsilogic@19
|
222
|
lbajardsilogic@19
|
223 m_currentPane = m_paneCallback.addPane();
|
lbajardsilogic@19
|
224
|
lbajardsilogic@19
|
225 if (!m_currentPane) {
|
lbajardsilogic@19
|
226 std::cerr << "WARNING: Easaier session-XML: Internal error: Failed to add pane!"
|
lbajardsilogic@19
|
227 << std::endl;
|
lbajardsilogic@19
|
228 return false;
|
lbajardsilogic@19
|
229 }
|
lbajardsilogic@19
|
230
|
lbajardsilogic@19
|
231 bool ok = false;
|
lbajardsilogic@19
|
232
|
lbajardsilogic@19
|
233 View *view = m_currentPane;
|
lbajardsilogic@19
|
234
|
lbajardsilogic@19
|
235 // The view properties first
|
lbajardsilogic@19
|
236
|
lbajardsilogic@19
|
237 READ_MANDATORY(size_t, centre, toUInt);
|
lbajardsilogic@19
|
238 READ_MANDATORY(size_t, zoom, toUInt);
|
lbajardsilogic@19
|
239 READ_MANDATORY(int, followPan, toInt);
|
lbajardsilogic@19
|
240 READ_MANDATORY(int, followZoom, toInt);
|
lbajardsilogic@19
|
241 QString tracking = attributes.value("tracking");
|
lbajardsilogic@19
|
242
|
lbajardsilogic@19
|
243 // Specify the follow modes before we set the actual values
|
lbajardsilogic@19
|
244 view->setFollowGlobalPan(followPan);
|
lbajardsilogic@19
|
245 view->setFollowGlobalZoom(followZoom);
|
lbajardsilogic@19
|
246 view->setPlaybackFollow(tracking == "scroll" ? PlaybackScrollContinuous :
|
lbajardsilogic@19
|
247 tracking == "page" ? PlaybackScrollPage
|
lbajardsilogic@19
|
248 : PlaybackIgnore);
|
lbajardsilogic@19
|
249
|
lbajardsilogic@19
|
250 // Then set these values
|
lbajardsilogic@19
|
251 view->setCentreFrame(centre);
|
lbajardsilogic@19
|
252 view->setZoomLevel(zoom);
|
lbajardsilogic@19
|
253
|
lbajardsilogic@19
|
254 // And pane properties
|
lbajardsilogic@19
|
255 READ_MANDATORY(int, centreLineVisible, toInt);
|
lbajardsilogic@19
|
256 m_currentPane->setCentreLineVisible(centreLineVisible);
|
lbajardsilogic@19
|
257
|
lbajardsilogic@19
|
258 int height = attributes.value("height").toInt(&ok);
|
lbajardsilogic@19
|
259 if (ok) {
|
lbajardsilogic@19
|
260 m_currentPane->resize(m_currentPane->width(), height);
|
lbajardsilogic@19
|
261 }
|
lbajardsilogic@19
|
262
|
lbajardsilogic@19
|
263 return true;
|
lbajardsilogic@19
|
264 }
|
lbajardsilogic@19
|
265
|
lbajardsilogic@19
|
266 bool
|
lbajardsilogic@19
|
267 ESFileReader::readLayer(const QXmlAttributes &attributes)
|
lbajardsilogic@19
|
268 {
|
lbajardsilogic@19
|
269 QString type = attributes.value("type");
|
lbajardsilogic@19
|
270
|
lbajardsilogic@19
|
271 int id;
|
lbajardsilogic@19
|
272 bool ok = false;
|
lbajardsilogic@19
|
273 id = attributes.value("id").trimmed().toInt(&ok);
|
lbajardsilogic@19
|
274
|
lbajardsilogic@19
|
275 if (!ok) {
|
lbajardsilogic@19
|
276 std::cerr << "WARNING: Easaier session-XML: No layer id for layer of type \""
|
lbajardsilogic@19
|
277 << type.toLocal8Bit().data()
|
lbajardsilogic@19
|
278 << "\"" << std::endl;
|
lbajardsilogic@19
|
279 return false;
|
lbajardsilogic@19
|
280 }
|
lbajardsilogic@19
|
281
|
lbajardsilogic@19
|
282 Layer *layer = 0;
|
lbajardsilogic@19
|
283 bool isNewLayer = false;
|
lbajardsilogic@19
|
284
|
lbajardsilogic@19
|
285 // Layers are expected to be defined in layer elements in the data
|
lbajardsilogic@19
|
286 // section, and referred to in layer elements in the view
|
lbajardsilogic@19
|
287 // sections. So if we're in the data section, we expect this
|
lbajardsilogic@19
|
288 // layer not to exist already; if we're in the view section, we
|
lbajardsilogic@19
|
289 // expect it to exist.
|
lbajardsilogic@19
|
290
|
lbajardsilogic@19
|
291 if (m_inData) {
|
lbajardsilogic@19
|
292
|
lbajardsilogic@19
|
293 if (m_layers.find(id) != m_layers.end()) {
|
lbajardsilogic@19
|
294 std::cerr << "WARNING: Easaier session-XML: Ignoring duplicate layer id " << id
|
lbajardsilogic@19
|
295 << " in data section" << std::endl;
|
lbajardsilogic@19
|
296 return false;
|
lbajardsilogic@19
|
297 }
|
lbajardsilogic@19
|
298
|
lbajardsilogic@19
|
299 layer = m_layers[id] = m_document->createLayer
|
lbajardsilogic@19
|
300 (LayerFactory::getInstance()->getLayerTypeForName(type));
|
lbajardsilogic@19
|
301
|
lbajardsilogic@19
|
302 if (layer) {
|
lbajardsilogic@19
|
303 m_layers[id] = layer;
|
lbajardsilogic@19
|
304 isNewLayer = true;
|
lbajardsilogic@19
|
305 }
|
lbajardsilogic@19
|
306
|
lbajardsilogic@19
|
307 } else {
|
lbajardsilogic@19
|
308
|
lbajardsilogic@19
|
309 if (!m_currentPane) {
|
lbajardsilogic@19
|
310 std::cerr << "WARNING: Easaier session-XML: No current pane for layer " << id
|
lbajardsilogic@19
|
311 << " in view section" << std::endl;
|
lbajardsilogic@19
|
312 return false;
|
lbajardsilogic@19
|
313 }
|
lbajardsilogic@19
|
314
|
lbajardsilogic@19
|
315 if (m_layers.find(id) != m_layers.end()) {
|
lbajardsilogic@19
|
316
|
lbajardsilogic@19
|
317 layer = m_layers[id];
|
lbajardsilogic@19
|
318
|
lbajardsilogic@19
|
319 } else {
|
lbajardsilogic@19
|
320 layer = m_document->createLayer(LayerFactory::getInstance()->getLayerTypeForName(type));
|
lbajardsilogic@19
|
321
|
lbajardsilogic@19
|
322 if (layer) {
|
lbajardsilogic@19
|
323 m_layers[id] = layer;
|
lbajardsilogic@19
|
324 isNewLayer = true;
|
lbajardsilogic@19
|
325 }
|
lbajardsilogic@19
|
326 }
|
lbajardsilogic@19
|
327 }
|
lbajardsilogic@19
|
328
|
lbajardsilogic@19
|
329 if (!layer) {
|
lbajardsilogic@19
|
330 std::cerr << "WARNING: Easaier session-XML: Failed to add layer of type \""
|
lbajardsilogic@19
|
331 << type.toLocal8Bit().data()
|
lbajardsilogic@19
|
332 << "\"" << std::endl;
|
lbajardsilogic@19
|
333 return false;
|
lbajardsilogic@19
|
334 }
|
lbajardsilogic@19
|
335
|
lbajardsilogic@19
|
336 if (isNewLayer) {
|
lbajardsilogic@19
|
337
|
lbajardsilogic@19
|
338 QString name = attributes.value("name");
|
lbajardsilogic@19
|
339 layer->setObjectName(name);
|
lbajardsilogic@19
|
340
|
lbajardsilogic@19
|
341 QString modelName = attributes.value("model");
|
lbajardsilogic@19
|
342 int modelId = attributes.value("modelId").toInt();
|
lbajardsilogic@19
|
343
|
lbajardsilogic@19
|
344 layer->setModelName(modelName);
|
lbajardsilogic@19
|
345 layer->setModelId(modelId);
|
lbajardsilogic@19
|
346
|
lbajardsilogic@19
|
347 layer->setProperties(attributes);
|
lbajardsilogic@19
|
348 }
|
lbajardsilogic@19
|
349
|
lbajardsilogic@19
|
350 if (!m_inData && m_currentPane) {
|
lbajardsilogic@19
|
351 m_document->addLayerToView(m_currentPane, layer);
|
lbajardsilogic@19
|
352 }
|
lbajardsilogic@19
|
353
|
lbajardsilogic@19
|
354 return true;
|
lbajardsilogic@19
|
355 }
|
lbajardsilogic@19
|
356
|
lbajardsilogic@203
|
357 bool
|
lbajardsilogic@203
|
358 ESFileReader::readFilter(const QXmlAttributes &attributes)
|
lbajardsilogic@203
|
359 {
|
lbajardsilogic@203
|
360 QString name = attributes.value("name");
|
lbajardsilogic@203
|
361
|
lbajardsilogic@203
|
362 FilterStack *filterStack = m_document->getRealTimeFilterStack();
|
lbajardsilogic@203
|
363
|
lbajardsilogic@203
|
364 if (!filterStack)
|
lbajardsilogic@203
|
365 {
|
lbajardsilogic@203
|
366 std::cerr << "WARNING: Easaier session-XML: Failed to get filterStack \""
|
lbajardsilogic@203
|
367 << name.toLocal8Bit().data()
|
lbajardsilogic@203
|
368 << "\"" << std::endl;
|
lbajardsilogic@203
|
369 return false;
|
lbajardsilogic@203
|
370 }
|
lbajardsilogic@203
|
371
|
lbajardsilogic@203
|
372 Filter *curFilter = filterStack->findFilter(name);
|
lbajardsilogic@203
|
373
|
lbajardsilogic@203
|
374 if (!curFilter)
|
lbajardsilogic@203
|
375 {
|
lbajardsilogic@203
|
376 std::cerr << "WARNING: Easaier session-XML: Failed to get filter \""
|
lbajardsilogic@203
|
377 << name.toLocal8Bit().data()
|
lbajardsilogic@203
|
378 << "\"" << std::endl;
|
lbajardsilogic@203
|
379 return false;
|
lbajardsilogic@203
|
380 }
|
lbajardsilogic@203
|
381
|
lbajardsilogic@203
|
382 curFilter->setProperties(attributes);
|
lbajardsilogic@203
|
383
|
lbajardsilogic@203
|
384 return true;
|
lbajardsilogic@203
|
385 }
|