Theme Editor: Fixed bug in parser handling empty lines and made ParseTreeModel handle...
[kugel-rb.git] / utils / themeeditor / parsetreenode.cpp
blobd3a1a71c9319c3d04cada65fb8bbf307919f10b9
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2010 Robert Bieber
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "symbols.h"
23 #include "tag_table.h"
25 #include "parsetreenode.h"
26 #include "parsetreemodel.h"
28 int ParseTreeNode::openConditionals = 0;
30 /* Root element constructor */
31 ParseTreeNode::ParseTreeNode(struct skin_element* data)
32 : parent(0), element(0), param(0), children()
34 while(data)
36 children.append(new ParseTreeNode(data, this));
37 data = data->next;
41 /* Normal element constructor */
42 ParseTreeNode::ParseTreeNode(struct skin_element* data, ParseTreeNode* parent)
43 : parent(parent), element(data), param(0), children()
45 switch(element->type)
48 case TAG:
49 for(int i = 0; i < element->params_count; i++)
51 if(element->params[i].type == skin_tag_parameter::CODE)
52 children.append(new ParseTreeNode(element->params[i].data.code,
53 this));
54 else
55 children.append(new ParseTreeNode(&element->params[i], this));
57 break;
59 case CONDITIONAL:
60 for(int i = 0; i < element->params_count; i++)
61 children.append(new ParseTreeNode(&data->params[i], this));
62 for(int i = 0; i < element->children_count; i++)
63 children.append(new ParseTreeNode(data->children[i], this));
64 break;
66 case SUBLINES:
67 for(int i = 0; i < element->children_count; i++)
69 children.append(new ParseTreeNode(data->children[i], this));
71 break;
73 case VIEWPORT:
74 for(int i = 0; i < element->params_count; i++)
75 children.append(new ParseTreeNode(&data->params[i], this));
76 /* Deliberate fall-through here */
78 case LINE:
79 for(int i = 0; i < data->children_count; i++)
81 for(struct skin_element* current = data->children[i]; current;
82 current = current->next)
84 children.append(new ParseTreeNode(current, this));
87 break;
89 default:
90 break;
94 /* Parameter constructor */
95 ParseTreeNode::ParseTreeNode(skin_tag_parameter *data, ParseTreeNode *parent)
96 : parent(parent), element(0), param(data), children()
101 QString ParseTreeNode::genCode() const
103 QString buffer = "";
105 if(element)
107 switch(element->type)
110 case VIEWPORT:
111 /* Generating the Viewport tag, if necessary */
112 if(element->tag)
114 buffer.append(TAGSYM);
115 buffer.append(element->tag->name);
116 buffer.append(ARGLISTOPENSYM);
117 for(int i = 0; i < element->params_count; i++)
119 buffer.append(children[i]->genCode());
120 if(i != element->params_count - 1)
121 buffer.append(ARGLISTSEPERATESYM);
123 buffer.append(ARGLISTCLOSESYM);
124 buffer.append('\n');
127 for(int i = element->params_count; i < children.count(); i++)
128 buffer.append(children[i]->genCode());
129 break;
131 case LINE:
132 for(int i = 0; i < children.count(); i++)
134 buffer.append(children[i]->genCode());
136 if(openConditionals == 0
137 && !(parent && parent->element->type == SUBLINES))
139 buffer.append('\n');
141 break;
143 case SUBLINES:
144 for(int i = 0; i < children.count(); i++)
146 buffer.append(children[i]->genCode());
147 if(i != children.count() - 1)
148 buffer.append(MULTILINESYM);
150 if(openConditionals == 0)
151 buffer.append('\n');
152 break;
154 case CONDITIONAL:
155 openConditionals++;
157 /* Inserting the tag part */
158 buffer.append(TAGSYM);
159 buffer.append(CONDITIONSYM);
160 buffer.append(element->tag->name);
161 if(element->params_count > 0)
163 buffer.append(ARGLISTOPENSYM);
164 for(int i = 0; i < element->params_count; i++)
166 buffer.append(children[i]->genCode());
167 if( i != element->params_count - 1)
168 buffer.append(ARGLISTSEPERATESYM);
169 buffer.append(ARGLISTCLOSESYM);
173 /* Inserting the sublines */
174 buffer.append(ENUMLISTOPENSYM);
175 for(int i = element->params_count; i < children.count(); i++)
177 buffer.append(children[i]->genCode());
178 if(i != children.count() - 1)
179 buffer.append(ENUMLISTSEPERATESYM);
181 buffer.append(ENUMLISTCLOSESYM);
182 openConditionals--;
183 break;
185 case TAG:
186 buffer.append(TAGSYM);
187 buffer.append(element->tag->name);
189 if(element->params_count > 0)
191 /* Rendering parameters if there are any */
192 buffer.append(ARGLISTOPENSYM);
193 for(int i = 0; i < children.count(); i++)
195 buffer.append(children[i]->genCode());
196 if(i != children.count() - 1)
197 buffer.append(ARGLISTSEPERATESYM);
199 buffer.append(ARGLISTCLOSESYM);
201 break;
203 case TEXT:
204 for(char* cursor = (char*)element->data; *cursor; cursor++)
206 if(find_escape_character(*cursor))
207 buffer.append(TAGSYM);
208 buffer.append(*cursor);
210 break;
212 case COMMENT:
213 buffer.append(COMMENTSYM);
214 buffer.append((char*)element->data);
215 buffer.append('\n');
216 break;
219 else if(param)
221 switch(param->type)
223 case skin_tag_parameter::STRING:
224 for(char* cursor = param->data.text; *cursor; cursor++)
226 if(find_escape_character(*cursor))
227 buffer.append(TAGSYM);
228 buffer.append(*cursor);
230 break;
232 case skin_tag_parameter::NUMERIC:
233 buffer.append(QString::number(param->data.numeric, 10));
234 break;
236 case skin_tag_parameter::DEFAULT:
237 buffer.append(DEFAULTSYM);
238 break;
240 case skin_tag_parameter::CODE:
241 buffer.append(QObject::tr("This doesn't belong here"));
242 break;
246 else
248 for(int i = 0; i < children.count(); i++)
249 buffer.append(children[i]->genCode());
252 return buffer;
255 /* A more or less random hashing algorithm */
256 int ParseTreeNode::genHash() const
258 int hash = 0;
259 char *text;
261 if(element)
263 hash += element->type;
264 switch(element->type)
266 case VIEWPORT:
267 case LINE:
268 case SUBLINES:
269 case CONDITIONAL:
270 hash += element->children_count;
271 break;
273 case TAG:
274 for(unsigned int i = 0; i < strlen(element->tag->name); i++)
275 hash += element->tag->name[i];
276 break;
278 case COMMENT:
279 case TEXT:
280 text = (char*)element->data;
281 for(unsigned int i = 0; i < strlen(text); i++)
283 if(i % 2)
284 hash += text[i] % element->type;
285 else
286 hash += text[i] % element->type * 2;
288 break;
293 if(param)
295 hash += param->type;
296 switch(param->type)
298 case skin_tag_parameter::DEFAULT:
299 case skin_tag_parameter::CODE:
300 break;
302 case skin_tag_parameter::NUMERIC:
303 hash += param->data.numeric * (param->data.numeric / 4);
304 break;
306 case skin_tag_parameter::STRING:
307 for(unsigned int i = 0; i < strlen(param->data.text); i++)
309 if(i % 2)
310 hash += param->data.text[i] * 2;
311 else
312 hash += param->data.text[i];
314 break;
318 for(int i = 0; i < children.count(); i++)
320 hash += children[i]->genHash();
323 return hash;
326 ParseTreeNode* ParseTreeNode::child(int row)
328 if(row < 0 || row >= children.count())
329 return 0;
331 return children[row];
334 int ParseTreeNode::numChildren() const
336 return children.count();
340 QVariant ParseTreeNode::data(int column) const
342 switch(column)
344 case ParseTreeModel::typeColumn:
345 if(element)
347 switch(element->type)
349 case VIEWPORT:
350 return QObject::tr("Viewport");
352 case LINE:
353 return QObject::tr("Logical Line");
355 case SUBLINES:
356 return QObject::tr("Alternator");
358 case COMMENT:
359 return QObject::tr("Comment");
361 case CONDITIONAL:
362 return QObject::tr("Conditional Tag");
364 case TAG:
365 return QObject::tr("Tag");
367 case TEXT:
368 return QObject::tr("Plaintext");
371 else if(param)
373 switch(param->type)
375 case skin_tag_parameter::STRING:
376 return QObject::tr("String");
378 case skin_tag_parameter::NUMERIC:
379 return QObject::tr("Number");
381 case skin_tag_parameter::DEFAULT:
382 return QObject::tr("Default Argument");
384 case skin_tag_parameter::CODE:
385 return QObject::tr("This doesn't belong here");
388 else
390 return QObject::tr("Root");
393 break;
395 case ParseTreeModel::valueColumn:
396 if(element)
398 switch(element->type)
400 case VIEWPORT:
401 case LINE:
402 case SUBLINES:
403 return QString();
405 case CONDITIONAL:
406 return QString(element->tag->name);
408 case TEXT:
409 case COMMENT:
410 return QString((char*)element->data);
412 case TAG:
413 return QString(element->tag->name);
416 else if(param)
418 switch(param->type)
420 case skin_tag_parameter::DEFAULT:
421 return QObject::tr("-");
423 case skin_tag_parameter::STRING:
424 return QString(param->data.text);
426 case skin_tag_parameter::NUMERIC:
427 return QString::number(param->data.numeric, 10);
429 case skin_tag_parameter::CODE:
430 return QObject::tr("Seriously, something's wrong here");
433 else
435 return QString();
437 break;
439 case ParseTreeModel::lineColumn:
440 if(element)
441 return QString::number(element->line, 10);
442 else
443 return QString();
444 break;
447 return QVariant();
451 int ParseTreeNode::getRow() const
453 if(!parent)
454 return -1;
456 return parent->children.indexOf(const_cast<ParseTreeNode*>(this));
459 ParseTreeNode* ParseTreeNode::getParent() const
461 return parent;
464 ParseTreeNode::~ParseTreeNode()
466 for(int i = 0; i < children.count(); i++)
467 delete children[i];