Diffstat (limited to 'noncore/apps/tableviewer/db/xmlsource.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r-- | noncore/apps/tableviewer/db/xmlsource.cpp | 295 |
1 files changed, 295 insertions, 0 deletions
diff --git a/noncore/apps/tableviewer/db/xmlsource.cpp b/noncore/apps/tableviewer/db/xmlsource.cpp new file mode 100644 index 0000000..7418a85 --- a/dev/null +++ b/noncore/apps/tableviewer/db/xmlsource.cpp | |||
@@ -0,0 +1,295 @@ | |||
1 | /********************************************************************** | ||
2 | ** Copyright (C) 2000 Trolltech AS. All rights reserved. | ||
3 | ** | ||
4 | ** This file is part of Qtopia Environment. | ||
5 | ** | ||
6 | ** This file may be distributed and/or modified under the terms of the | ||
7 | ** GNU General Public License version 2 as published by the Free Software | ||
8 | ** Foundation and appearing in the file LICENSE.GPL included in the | ||
9 | ** packaging of this file. | ||
10 | ** | ||
11 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE | ||
12 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
13 | ** | ||
14 | ** See http://www.trolltech.com/gpl/ for GPL licensing information. | ||
15 | ** | ||
16 | ** Contact info@trolltech.com if any conditions of this licensing are | ||
17 | ** not clear to you. | ||
18 | ** | ||
19 | **********************************************************************/ | ||
20 | #include "xmlsource.h" | ||
21 | #include <qdict.h> | ||
22 | #include <stdlib.h> | ||
23 | #include <qtextstream.h> | ||
24 | |||
25 | |||
26 | DBXml::DBXml(DBStore *d) | ||
27 | { | ||
28 | dstore = d; | ||
29 | } | ||
30 | |||
31 | QString DBXml::type() | ||
32 | { | ||
33 | return "xml"; | ||
34 | } | ||
35 | |||
36 | bool DBXml::openSource(QIODevice *inDev) | ||
37 | { | ||
38 | bool ok; | ||
39 | |||
40 | DBXmlHandler h(dstore); | ||
41 | |||
42 | QTextStream tsIn(inDev); | ||
43 | QXmlInputSource source(tsIn); | ||
44 | QXmlSimpleReader reader; | ||
45 | reader.setContentHandler(&h); | ||
46 | reader.setErrorHandler(&h); | ||
47 | ok = reader.parse(source); | ||
48 | |||
49 | return ok; | ||
50 | } | ||
51 | |||
52 | bool DBXml::saveSource(QIODevice *outDev) | ||
53 | { | ||
54 | int i; | ||
55 | DataElem *elem; | ||
56 | KeyList *k; | ||
57 | |||
58 | QTextStream outstream(outDev); | ||
59 | |||
60 | outstream << "<database name=\"" << dstore->getName() << "\">" << endl; | ||
61 | outstream << "<header>" << endl; | ||
62 | |||
63 | k = dstore->getKeys(); | ||
64 | KeyListIterator it(*k); | ||
65 | while(it.current()) { | ||
66 | if (!it.current()->delFlag()) { | ||
67 | outstream << "<key name=\"KEYID" << it.currentKey() << "\" "; | ||
68 | outstream << "type=\"" | ||
69 | << TVVariant::typeToName(it.current()->type()) | ||
70 | << "\">"; | ||
71 | outstream << it.current()->name() << "</key>" << endl; | ||
72 | } | ||
73 | ++it; | ||
74 | } | ||
75 | |||
76 | outstream << "</header>" << endl; | ||
77 | |||
78 | dstore->first(); | ||
79 | |||
80 | do { | ||
81 | elem = dstore->getCurrentData(); | ||
82 | if (!elem) | ||
83 | break; | ||
84 | outstream << "<record>" << endl; | ||
85 | it.toFirst(); | ||
86 | while (it.current()) { | ||
87 | i = it.currentKey(); | ||
88 | if (elem->hasValidValue(i)) { | ||
89 | outstream << "<KEYID" << i << ">"; | ||
90 | if (dstore->getKeyType(i) == TVVariant::Date) { | ||
91 | // dates in files are different from displayed dates | ||
92 | QDate date = elem->getField(i).toDate(); | ||
93 | outstream << date.day() << "/" | ||
94 | << date.month() << "/" | ||
95 | << date.year(); | ||
96 | } else { | ||
97 | outstream << elem->toQString(i); | ||
98 | } | ||
99 | outstream << "</KEYID" << i << ">" << endl; | ||
100 | } | ||
101 | ++it; | ||
102 | } | ||
103 | outstream << "</record>" << endl; | ||
104 | } while(dstore->next()); | ||
105 | |||
106 | outstream << "</database>" << endl; | ||
107 | return TRUE; | ||
108 | } | ||
109 | |||
110 | DBXml::~DBXml() {} | ||
111 | |||
112 | /*! | ||
113 | \class DBXmlHandler | ||
114 | \brief An Xml parser for flat tables. | ||
115 | |||
116 | An xml parser for parsing the files used by the table viewer application. | ||
117 | |||
118 | The format of the xml files can be found at the front of the file | ||
119 | dataparser.h | ||
120 | */ | ||
121 | |||
122 | /*! | ||
123 | Constructs a new DBXmlHandler, and sets that the table should be | ||
124 | constructed in the DBStore pointed to by ds. | ||
125 | */ | ||
126 | DBXmlHandler::DBXmlHandler(DBStore *ds) | ||
127 | { | ||
128 | data_store = ds; | ||
129 | current_keyrep = 0; | ||
130 | } | ||
131 | |||
132 | /*! | ||
133 | Destroys the DBXmlHandler | ||
134 | */ | ||
135 | DBXmlHandler::~DBXmlHandler() | ||
136 | { | ||
137 | } | ||
138 | |||
139 | QString DBXmlHandler::errorProtocol() | ||
140 | { | ||
141 | qWarning("Error reading file"); | ||
142 | return errorProt; | ||
143 | } | ||
144 | |||
145 | bool DBXmlHandler::startDocument() | ||
146 | { | ||
147 | errorProt = ""; | ||
148 | state = StateInit; | ||
149 | return TRUE; | ||
150 | } | ||
151 | |||
152 | bool DBXmlHandler::startElement(const QString&, const QString&, | ||
153 | const QString& qName, const QXmlAttributes& atts) | ||
154 | { | ||
155 | if (state == StateInit && qName == "database") { | ||
156 | // First thing it expects is a <document name="..."> tag | ||
157 | state = StateDocument; | ||
158 | data_store->setName(atts.value("name")); | ||
159 | return TRUE; | ||
160 | } | ||
161 | if (state == StateDocument && qName == "header") { | ||
162 | state = StateHeader; | ||
163 | if (current_keyrep) delete current_keyrep; | ||
164 | current_keyrep = new KeyList(); | ||
165 | return TRUE; | ||
166 | } | ||
167 | if (state == StateHeader && qName == "key") { | ||
168 | /* Ok, adding a new key to our KeyList TODO */ | ||
169 | state = StateKey; | ||
170 | last_key_type = TVVariant::String; | ||
171 | key = atts.value("name"); | ||
172 | if (key.isEmpty()) { | ||
173 | qWarning("empty key name"); | ||
174 | return FALSE; | ||
175 | } | ||
176 | if(!atts.value("type").isEmpty()) | ||
177 | last_key_type = TVVariant::nameToType(atts.value("type")); | ||
178 | return TRUE; | ||
179 | } | ||
180 | if (state == StateDocument && qName == "record") { | ||
181 | state = StateRecord; | ||
182 | current_data = new DataElem(data_store); | ||
183 | // Now expecting a <record> tag | ||
184 | return TRUE; | ||
185 | } | ||
186 | if (state == StateRecord) { | ||
187 | state = StateField; | ||
188 | /* the qName is the name of a key */ | ||
189 | if (!keyIndexList[qName]) { | ||
190 | /* invalid key, we failed */ | ||
191 | qWarning("Invalid key in record"); | ||
192 | return FALSE; | ||
193 | } | ||
194 | keyIndex = *keyIndexList[qName]; | ||
195 | return TRUE; | ||
196 | } | ||
197 | qWarning("Unable to determine tag type"); | ||
198 | return FALSE; | ||
199 | } | ||
200 | |||
201 | bool DBXmlHandler::endElement(const QString&, const QString&, | ||
202 | const QString& qName) | ||
203 | { | ||
204 | switch(state) { | ||
205 | case StateField: | ||
206 | // TODO checks 'could' be done of the popped value | ||
207 | state = StateRecord; | ||
208 | break; | ||
209 | case StateKey: | ||
210 | // TODO checks 'could' be done of the popped value | ||
211 | state = StateHeader; | ||
212 | break; | ||
213 | case StateHeader: | ||
214 | data_store->setKeys(current_keyrep); | ||
215 | state = StateDocument; | ||
216 | break; | ||
217 | case StateRecord: | ||
218 | data_store->addItem(current_data); | ||
219 | state = StateDocument; | ||
220 | break; | ||
221 | case StateDocument: | ||
222 | // we are done... | ||
223 | break; | ||
224 | default: | ||
225 | // should only get a 'endElement' from one of the above states. | ||
226 | qWarning("Invalid end tag"); | ||
227 | return FALSE; | ||
228 | break; | ||
229 | } | ||
230 | return TRUE; | ||
231 | } | ||
232 | |||
233 | bool DBXmlHandler::characters(const QString& ch) | ||
234 | { | ||
235 | // this is where the 'between tag' stuff happens. | ||
236 | // e.g. the stuff between tags. | ||
237 | QString ch_simplified = ch.simplifyWhiteSpace(); | ||
238 | |||
239 | if (ch_simplified.isEmpty()) | ||
240 | return TRUE; | ||
241 | |||
242 | if (state == StateKey) { | ||
243 | int *tmp_val = new int; | ||
244 | /* We just grabbed the display name of a key */ | ||
245 | *tmp_val = current_keyrep->addKey(ch_simplified, last_key_type); | ||
246 | keyIndexList.insert(key, tmp_val); | ||
247 | return TRUE; | ||
248 | } | ||
249 | if (state == StateField) { | ||
250 | /* Ok, need to add data here */ | ||
251 | current_data->setField(keyIndex, ch_simplified); | ||
252 | return TRUE; | ||
253 | } | ||
254 | |||
255 | qWarning("Junk characters found... ignored"); | ||
256 | return TRUE; | ||
257 | } | ||
258 | |||
259 | QString DBXmlHandler::errorString() | ||
260 | { | ||
261 | return "the document is not in the expected file format"; | ||
262 | } | ||
263 | |||
264 | bool DBXmlHandler::warning(const QXmlParseException& exception) | ||
265 | { | ||
266 | errorProt += QString("warning parsing error: %1 in line %2, column %3\n" ) | ||
267 | .arg(exception.message()) | ||
268 | .arg(exception.lineNumber()) | ||
269 | .arg(exception.columnNumber()); | ||
270 | |||
271 | qWarning(errorProt); | ||
272 | return QXmlDefaultHandler::fatalError(exception); | ||
273 | } | ||
274 | |||
275 | bool DBXmlHandler::error(const QXmlParseException& exception) | ||
276 | { | ||
277 | errorProt += QString("error parsing error: %1 in line %2, column %3\n" ) | ||
278 | .arg(exception.message()) | ||
279 | .arg(exception.lineNumber()) | ||
280 | .arg(exception.columnNumber()); | ||
281 | |||
282 | qWarning(errorProt); | ||
283 | return QXmlDefaultHandler::fatalError(exception); | ||
284 | } | ||
285 | |||
286 | bool DBXmlHandler::fatalError(const QXmlParseException& exception) | ||
287 | { | ||
288 | errorProt += QString("fatal parsing error: %1 in line %2, column %3\n" ) | ||
289 | .arg(exception.message()) | ||
290 | .arg(exception.lineNumber()) | ||
291 | .arg(exception.columnNumber()); | ||
292 | |||
293 | qWarning(errorProt); | ||
294 | return QXmlDefaultHandler::fatalError(exception); | ||
295 | } | ||