skin: make menu key button
[sdk/emulator/qemu.git] / tizen / src / ui / xmllayoutparser.cpp
1 /*
2  * Qt UI
3  *
4  * Copyright (C) 2014 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact:
7  * GiWoong Kim <giwoong.kim@samsung.com>
8  * SeokYeon Hwang <syeon.hwang@samsung.com>
9  * Sangho Park <sangho.p@samsung.com>
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
24  * MA 02110-1301, USA.
25  *
26  * Contributors:
27  * - S-Core Co., Ltd
28  *
29  */
30
31 #include "config-host.h"
32
33 #include "xmllayoutparser.h"
34 #include "xmllayoutkeyword.h"
35 #include "skinpainter.h"
36 #include "layout/keycodetype.h"
37 #include "controller/generalpurposecon.h"
38 #include "resource/ui_strings.h"
39
40 #define LOG_LINE_HEAD_CHAR "> "
41 #define LOG_INDENTATION_SIZE 2
42 #define QDEBUG_INDENT(x) qDebug().nospace() << qPrintable(getIndenting(x))
43 #define QWARN_INDENT(x) qWarning().nospace() << qPrintable(getIndenting(x))
44
45 /* Qt QLayout has a minimum size */
46 #define QT_LAYOUT_MINIMUM (73)
47
48 XmlLayoutParser::XmlLayoutParser(const QString &path, UiInformation *uiInfo)
49 {
50     this->xmlPath = path;
51     this->uiInfo = uiInfo;
52
53     menuItems.insert(SEPARATOR_MENU_KEYWORD, MenuItemType::separator);
54     menuItems.insert(ADVANCED_MENU_KEYWORD, MenuItemType::advancedItem);
55     menuItems.insert(INFO_MENU_KEYWORD, MenuItemType::infoItem);
56     menuItems.insert(ONTOP_MENU_KEYWORD, MenuItemType::onTopItem);
57     menuItems.insert(MOVE_MENU_KEYWORD, MenuItemType::moveItem);
58     menuItems.insert(SWITCH_MENU_KEYWORD, MenuItemType::switchItem);
59     menuItems.insert(SCALE_MENU_KEYWORD, MenuItemType::scaleItem);
60     menuItems.insert(CONTROLLER_MENU_KEYWORD, MenuItemType::controllerItem);
61     menuItems.insert(HOSTKBD_MENU_KEYWORD, MenuItemType::hostKeyboardItem);
62     menuItems.insert(SHELL_MENU_KEYWORD, MenuItemType::shellItem);
63     menuItems.insert(ECP_MENU_KEYWORD, MenuItemType::controlPanelItem);
64     menuItems.insert(SCREENSHOT_MENU_KEYWORD, MenuItemType::screenShotItem);
65     menuItems.insert(ABOUT_MENU_KEYWORD, MenuItemType::aboutItem);
66     menuItems.insert(SYSTEM_RESET_MENU_KEYWORD, MenuItemType::systemResetItem);
67     menuItems.insert(FORCECLOSE_MENU_KEYWORD, MenuItemType::forceCloseItem);
68     menuItems.insert(CLOSE_MENU_KEYWORD, MenuItemType::closeItem);
69 }
70
71 QString XmlLayoutParser::getIndenting(int depth) {
72     QString indenting = LOG_LINE_HEAD_CHAR;
73
74     if (depth > 0) {
75         while (depth--) {
76             for (int i = 0; i < LOG_INDENTATION_SIZE; i++) {
77                 indenting.append(QChar::Space);
78             }
79         }
80     }
81
82     return indenting;
83 }
84
85 QColor XmlLayoutParser::parseColor(QXmlStreamReader &xml, const int depth)
86 {
87     int red = 0, green = 0, blue = 0;
88
89     if (xml.name() == COLOR_KEYWORD &&
90         xml.tokenType() == QXmlStreamReader::StartElement) {
91         QXmlStreamAttributes attributes = xml.attributes();
92
93         if (attributes.hasAttribute(COLOR_RED_ATTR_KEYWORD)) {
94             red = attributes.value(COLOR_RED_ATTR_KEYWORD).toString().toInt();
95         }
96         if (attributes.hasAttribute(COLOR_GREEN_ATTR_KEYWORD)) {
97             green = attributes.value(COLOR_GREEN_ATTR_KEYWORD).toString().toInt();
98         }
99         if (attributes.hasAttribute(COLOR_BLUE_ATTR_KEYWORD)) {
100             blue = attributes.value(COLOR_BLUE_ATTR_KEYWORD).toString().toUInt();
101         }
102     }
103
104     return QColor(red, green, blue, 255);
105 }
106
107 HoverType XmlLayoutParser::parseHover(QXmlStreamReader &xml, const int depth)
108 {
109     QColor color(255, 255, 255);
110     bool fill = false;
111
112     QDEBUG_INDENT(depth) << HOVER_KEYWORD << " {";
113
114     fill = xml.attributes().value(HOVER_FILL_ATTR_KEYWORD).compare("true") == 0;
115     QDEBUG_INDENT(depth + 1) << HOVER_FILL_ATTR_KEYWORD << ": " << fill;
116
117     QXmlStreamReader::TokenType token = xml.readNext();
118
119     while (xml.atEnd() == false && (xml.name() == HOVER_KEYWORD &&
120         token == QXmlStreamReader::EndElement) == false) /* ~ </hover> */
121     {
122         if (token == QXmlStreamReader::StartElement) {
123             if (xml.name() == COLOR_KEYWORD) {
124                 /* color */
125                 color = parseColor(xml, depth + 1);
126                 QDEBUG_INDENT(depth + 1) << COLOR_KEYWORD << ": " << color.name();
127             } else {
128                 QWARN_INDENT(depth + 1) << "undefined element: " << xml.name();
129             }
130         }
131
132         token = xml.readNext();
133     }
134
135     QDEBUG_INDENT(depth) << "}";
136
137     return HoverType(color, fill);
138 }
139
140 QRect XmlLayoutParser::parseRegion(QXmlStreamReader &xml, const int depth)
141 {
142     int left = 0, top = 0;
143     unsigned int width = 0, height = 0;
144
145     if (xml.name() == REGION_KEYWORD &&
146         xml.tokenType() == QXmlStreamReader::StartElement) {
147         QXmlStreamAttributes attributes = xml.attributes();
148
149         if (attributes.hasAttribute(REGION_LEFT_ATTR_KEYWORD)) {
150             left = attributes.value(REGION_LEFT_ATTR_KEYWORD).toString().toInt();
151         }
152         if (attributes.hasAttribute(REGION_TOP_ATTR_KEYWORD)) {
153             top = attributes.value(REGION_TOP_ATTR_KEYWORD).toString().toInt();
154         }
155         if (attributes.hasAttribute(REGION_WIDTH_ATTR_KEYWORD)) {
156             width = attributes.value(REGION_WIDTH_ATTR_KEYWORD).toString().toUInt();
157         }
158         if (attributes.hasAttribute(REGION_HEIGHT_ATTR_KEYWORD)) {
159             height = attributes.value(REGION_HEIGHT_ATTR_KEYWORD).toString().toUInt();
160         }
161     }
162
163     return QRect(left, top, width, height);
164 }
165
166 DisplayType *XmlLayoutParser::parseDisplay(QXmlStreamReader &xml, const int depth)
167 {
168     QRect displayRect(0, 0, 0, 0);
169     int angle = 0;
170     QPixmap maskImage;
171
172     QDEBUG_INDENT(depth) << DISPLAY_KEYWORD << " {";
173
174     QXmlStreamReader::TokenType token = xml.readNext();
175
176     while (xml.atEnd() == false && (xml.name() == DISPLAY_KEYWORD &&
177         token == QXmlStreamReader::EndElement) == false) /* ~ </display> */
178     {
179         if (token == QXmlStreamReader::StartElement) {
180             if (xml.name() == REGION_KEYWORD) {
181                 /* region */
182                 displayRect = parseRegion(xml, depth + 1);
183                 QDEBUG_INDENT(depth + 1) <<
184                     "(" << displayRect.x() <<  "," << displayRect.y() << " " <<
185                     displayRect.width() << "x" << displayRect.height() << ")";
186             } else if (xml.name() == ANGLE_KEYWORD) {
187                 /* angle */
188                 angle = xml.readElementText().toInt();
189             } else if (xml.name() == MASK_IMG_KEYWORD) {
190                 /* display mask */
191                 QString maskImageFileName = xml.readElementText();
192                 QDEBUG_INDENT(depth + 1) <<
193                     MASK_IMG_KEYWORD << ": " << maskImageFileName;
194
195                 if (maskImage.load(
196                     xmlPath + QDir::separator() + maskImageFileName) == false) {
197                     QWARN_INDENT(depth + 1) << "failed to load mask image";
198                 }
199             } else {
200                 QWARN_INDENT(depth + 1) << "undefined element: " << xml.name();
201             }
202         }
203
204         token = xml.readNext();
205     }
206
207     QDEBUG_INDENT(depth) << "}";
208
209     return new DisplayType(displayRect, angle, maskImage);
210 }
211
212 KeycodeType XmlLayoutParser::parseKeycode(QXmlStreamReader &xml, const int depth)
213 {
214     int longPress = -1, shortPress = 0;
215
216     /* attribute */
217     longPress = xml.attributes().value(KEYCODE_LONGPRESS_ATTR_KEYWORD).toString().toInt();
218
219     shortPress = xml.readElementText().toInt();
220
221     return KeycodeType(shortPress, longPress);
222 }
223
224 HardwareKey *XmlLayoutParser::parseKey(QXmlStreamReader &xml, const int depth)
225 {
226     QRect keyRegion;
227     KeycodeType keycodeType;
228     QString keyTooptip;
229     QKeySequence keySequence;
230
231     /* attribute */
232     QString keyName = xml.attributes().value(NAME_ATTR_KEYWORD).toString();
233
234     QXmlStreamReader::TokenType token = xml.readNext();
235
236     while (xml.atEnd() == false && (xml.name() == KEY_KEYWORD &&
237         token == QXmlStreamReader::EndElement) == false) /* ~ </key> */
238     {
239         if (token == QXmlStreamReader::StartElement) {
240             if (xml.name() == REGION_KEYWORD) {
241                 /* region */
242                 keyRegion = parseRegion(xml, depth + 1);
243             } else if (xml.name() == KEYCODE_KEYWORD) {
244                 /* keycode */
245                 keycodeType = parseKeycode(xml, depth + 1);
246             } else if (xml.name() == TOOLTIP_KEYWORD) {
247                 /* tooltip */
248                 keyTooptip = xml.readElementText();
249             } else if (xml.name() == SHORTCUT_KEYWORD) {
250                 /* shortcut */
251                 keySequence = parseShortcut(xml, depth + 1);
252             } else {
253                 QWARN_INDENT(depth + 1) << "undefined element: " << xml.name();
254             }
255         }
256
257         token = xml.readNext();
258     }
259
260     return new HardwareKey(keyName, keycodeType, keyRegion, keyTooptip, keySequence);
261 }
262
263 int XmlLayoutParser::parseKeyList(QXmlStreamReader &xml,
264     const int depth, QList<HardwareKey *> &list)
265 {
266     HardwareKey *hwKey = NULL;
267
268     QXmlStreamReader::TokenType token = xml.readNext();
269
270     while (xml.atEnd() == false && (xml.name() == KEYLIST_KEYWORD &&
271         token == QXmlStreamReader::EndElement) == false) /* ~ </keyList> */
272     {
273         if (token == QXmlStreamReader::StartElement) {
274             if (xml.name() == KEY_KEYWORD) {
275                 hwKey = parseKey(xml, depth + 1);
276                 if (hwKey != NULL) {
277                     list.append(hwKey);
278                 }
279             } else {
280                 QWARN_INDENT(depth + 1) << "undefined element: " << xml.name();
281             }
282         }
283
284         token = xml.readNext();
285     }
286
287     return list.count();
288 }
289
290 MainForm *XmlLayoutParser::parseMainForm(QXmlStreamReader &xml, const int depth)
291 {
292     /* attribute */
293     QString formName = xml.attributes().value(NAME_ATTR_KEYWORD).toString();
294     MainForm *form = new MainForm(formName);
295
296     qDebug(LOG_LINE_HEAD_CHAR);
297     QDEBUG_INDENT(depth) << form->getName() << " {";
298
299     QXmlStreamReader::TokenType token = xml.readNext();
300
301     while (xml.atEnd() == false && (xml.name() == FORM_KEYWORD &&
302         token == QXmlStreamReader::EndElement) == false) /* ~ </form> */
303     {
304         if (token == QXmlStreamReader::StartElement) {
305             if (xml.name() == DISPLAY_KEYWORD) {
306                 /* display */
307                 form->setDpyType(parseDisplay(xml, depth + 1));
308             } else if (xml.name() == NORMAL_IMG_KEYWORD) {
309                 /* normal image */
310                 QString normalImageFileName = xml.readElementText();
311                 QDEBUG_INDENT(depth + 1) <<
312                     NORMAL_IMG_KEYWORD << ": " << normalImageFileName;
313
314                 if (form->skinImg[LayoutForm::normal].load(
315                     xmlPath + QDir::separator() + normalImageFileName) == false) {
316                     QWARN_INDENT(depth + 1) << "failed to load normal image";
317                 }
318             } else if (xml.name() == PRESSED_IMG_KEYWORD) {
319                 /* key pressed image */
320                 QString pressedImageFileName = xml.readElementText();
321                 QDEBUG_INDENT(depth + 1) <<
322                     PRESSED_IMG_KEYWORD << ": " << pressedImageFileName;
323
324                 if (form->skinImg[LayoutForm::pressed].load(
325                     xmlPath + QDir::separator() + pressedImageFileName) == false) {
326                     QWARN_INDENT(depth + 1) << "failed to load pressed image";
327                 }
328             }  else if (xml.name() == ROTARY_IMG_KEYWORD) {
329                 /* rotary image */
330                 QString rotaryImageFileName = xml.readElementText();
331                 QDEBUG_INDENT(depth + 1) <<
332                     ROTARY_IMG_KEYWORD << ": " << rotaryImageFileName;
333
334                 form->setRotaryImage(new QPixmap(
335                     xmlPath + QDir::separator() + rotaryImageFileName));
336                 if (form->getRotaryImage()->isNull() == true) {
337                     QWARN_INDENT(depth + 1) << "failed to load rotary image";
338                 }
339             } else if (xml.name() == KEYLIST_KEYWORD) {
340                 /* HW keys */
341                 const int cnt = parseKeyList(xml, depth + 1, form->getKeyList());
342                 QDEBUG_INDENT(depth + 1) << KEYLIST_KEYWORD << ": " << cnt;
343             } else if (xml.name() == HOVER_KEYWORD) {
344                 /* hover */
345                 form->setHoverType(parseHover(xml, depth + 1));
346             } else {
347                 QWARN_INDENT(depth + 1) << "undefined element: " << xml.name();
348             }
349         }
350
351         token = xml.readNext();
352     }
353
354     QDEBUG_INDENT(depth) << "}";
355
356     return form;
357 }
358
359 int XmlLayoutParser::parseMainFormList(QXmlStreamReader &xml,
360     const int depth, QList<MainForm *> &list)
361 {
362     MainForm *form = NULL;
363
364     QDEBUG_INDENT(depth) << FORMLIST_KEYWORD << " {";
365
366     QXmlStreamReader::TokenType token = xml.readNext();
367
368     while (xml.atEnd() == false && (xml.name() == FORMLIST_KEYWORD &&
369         token == QXmlStreamReader::EndElement) == false) /* ~ </formList> */
370     {
371         if (token == QXmlStreamReader::StartElement) {
372             if (xml.name() == FORM_KEYWORD) {
373                 form = parseMainForm(xml, depth + 1);
374                 if (form != NULL) {
375                     /* image validation */
376                     if (form->skinImg[LayoutForm::normal].size() == QSize(0, 0)) {
377                         QDEBUG_INDENT(depth + 1) << "(general purpose skin type)";
378
379                         SkinPainter painter("main-skin",
380                             uiInfo->getResolution(), form->getDpyType()->getAngle(),
381                             QPoint(30, 16), uiInfo->getVMColor());
382                         form->setGeneralPurpose(true);
383
384                         form->skinImg[LayoutForm::normal] = painter.getSkinImage();
385                         form->getDpyType()->setRect(painter.getCenteralRect());
386                     }
387
388                     list.append(form);
389                 }
390             } else {
391                 QWARN_INDENT(depth + 1) << "undefined element: " << xml.name();
392             }
393         }
394
395         token = xml.readNext();
396     }
397
398     QDEBUG_INDENT(depth) << "}";
399
400     return list.count();
401 }
402
403 /* menu */
404 int XmlLayoutParser::parseFactorList(QXmlStreamReader &xml,
405     const int depth, QMap<int, QString> &map, int *defaultFactor)
406 {
407     QString defaultValue = xml.attributes().value(DEFAULT_ATTR_KEYWORD).toString();
408     *defaultFactor = defaultValue.toInt();
409
410     QXmlStreamReader::TokenType token = xml.readNext();
411
412     while (xml.atEnd() == false && (xml.name() == FACTORLIST_KEYWORD &&
413         token == QXmlStreamReader::EndElement) == false) /* ~ </factorList> */
414     {
415         if (token == QXmlStreamReader::StartElement) {
416             if (xml.name() == FACTOR_KEYWORD) {
417                 QString value = xml.attributes().value(NAME_ATTR_KEYWORD).toString();
418                 map.insert(xml.readElementText().toInt(), value);
419             } else {
420                 QWARN_INDENT(depth + 1) << "undefined element: " << xml.name();
421             }
422         }
423
424         token = xml.readNext();
425     }
426
427     return map.count();
428 }
429
430 QKeySequence XmlLayoutParser::parseShortcut(QXmlStreamReader &xml, const int depth)
431 {
432     QString keyString = xml.readElementText();
433
434 #ifdef CONFIG_DARWIN
435     /* QKeySequence Note: On Mac OS X, references to "Ctrl", Qt::CTRL, Qt::Control and
436      * Qt::ControlModifier correspond to the Command keys on the Macintosh keyboard,
437      * and references to "Meta", Qt::META, Qt::Meta and Qt::MetaModifier correspond to
438      * the Control keys. Developers on Mac OS X can use the same shortcut descriptions
439      * across all platforms, and their applications will automatically work as expected
440      * on Mac OS X. */
441
442     /* According to Qt note, "Ctrl" will be treated as command key. This is not what we
443      * want. To be recognized as control key on MacOS, XML Parser should replace "Ctrl"
444      * with "Meta" text. */
445
446     keyString.replace(XML_QT_CTRLKEY_STRING, XML_QT_METAKEY_STRING);
447 #endif
448
449     return QKeySequence::fromString(keyString);
450 }
451
452 int XmlLayoutParser::parseShortcuts(QXmlStreamReader &xml,
453     const int depth, QMap<QString, QKeySequence> &map)
454 {
455     QString key = xml.attributes().value(PROP_ATTR_KEYWORD).toString();
456     map.insert(key, parseShortcut(xml, depth + 1));
457
458     return map.count();
459 }
460
461 AdvancedMenuItem *XmlLayoutParser::parseAdvancedMenuItem(
462     QXmlStreamReader &xml, const int depth)
463 {
464     /* attribute */
465     QString menuName = xml.attributes().value(NAME_ATTR_KEYWORD).toString();
466     AdvancedMenuItem *item = new AdvancedMenuItem(menuName);
467
468     QDEBUG_INDENT(depth) << ADVANCED_MENU_KEYWORD << " {";
469
470     QXmlStreamReader::TokenType token = xml.readNext();
471
472     while (xml.atEnd() == false && (xml.name() == ADVANCED_MENU_KEYWORD &&
473         token == QXmlStreamReader::EndElement) == false) /* ~ </advancedItem> */
474     {
475         if (token == QXmlStreamReader::StartElement) {
476             if (xml.name() == SHORTCUT_KEYWORD) {
477                 parseShortcuts(xml, depth + 1, item->getShortcuts());
478             } else if (xml.name() == MENULIST_KEYWORD) {
479                 const int cnt = parseMenuList(xml, depth + 1, item->getMenuList());
480                 QDEBUG_INDENT(depth + 1) << MENULIST_KEYWORD << ": " << cnt;
481             } else {
482                 QWARN_INDENT(depth + 1) << "undefined element: " << xml.name();
483             }
484         }
485
486         token = xml.readNext();
487     }
488
489     QDEBUG_INDENT(depth) << "}";
490
491     return item;
492 }
493
494 ScaleMenuItem *XmlLayoutParser::parseScaleMenuItem(
495     QXmlStreamReader &xml, const int depth)
496 {
497     /* attribute */
498     QString menuName = xml.attributes().value(NAME_ATTR_KEYWORD).toString();
499     ScaleMenuItem *item = new ScaleMenuItem(menuName);
500
501     QDEBUG_INDENT(depth) << SCALE_MENU_KEYWORD << " {";
502
503     QXmlStreamReader::TokenType token = xml.readNext();
504
505     while (xml.atEnd() == false && (xml.name() == SCALE_MENU_KEYWORD &&
506         token == QXmlStreamReader::EndElement) == false) /* ~ </scaleItem> */
507     {
508         if (token == QXmlStreamReader::StartElement) {
509             if (xml.name() == SHORTCUT_KEYWORD) {
510                 parseShortcuts(xml, depth + 1, item->getShortcuts());
511             } else if (xml.name() == FACTORLIST_KEYWORD) {
512                 int defaultFactor = 0;
513                 const int cnt = parseFactorList(xml, depth + 1,
514                     item->getFactorMap(), &defaultFactor);
515                 QDEBUG_INDENT(depth + 1) << FACTORLIST_KEYWORD << ": " << cnt;
516
517                 item->setDefaultScaleFactor(defaultFactor);
518             } else {
519                 QWARN_INDENT(depth + 1) << "undefined element: " << xml.name();
520             }
521         }
522
523         token = xml.readNext();
524     }
525
526     QDEBUG_INDENT(depth) << "}";
527
528     return item;
529 }
530
531 MenuItem *XmlLayoutParser::parseGeneralMenuItem(
532     QXmlStreamReader &xml, const int depth, int menuType)
533 {
534     QString itemKeyword = xml.name().toString();
535
536     /* attribute */
537     QString menuName = xml.attributes().value(NAME_ATTR_KEYWORD).toString();
538     MenuItem *item = new MenuItem(menuType, menuName);
539
540     QString shortcut;
541     QXmlStreamReader::TokenType token = xml.readNext();
542
543     while (xml.atEnd() == false && (xml.name().compare(itemKeyword) == 0 &&
544         token == QXmlStreamReader::EndElement) == false) /* ~ </xxItem> */
545     {
546         if (token == QXmlStreamReader::StartElement) {
547             if (xml.name() == SHORTCUT_KEYWORD) {
548                 parseShortcuts(xml, depth + 1, item->getShortcuts());
549             } else {
550                 QWARN_INDENT(depth + 1) << "undefined element: " << xml.name();
551             }
552         }
553
554         token = xml.readNext();
555     }
556
557     return item;
558 }
559
560 int XmlLayoutParser::parseMenuList(QXmlStreamReader &xml,
561     const int depth, QList<MenuItem *> &list)
562 {
563     MenuItem *item = NULL;
564
565     qDebug(LOG_LINE_HEAD_CHAR);
566     QDEBUG_INDENT(depth) << MENULIST_KEYWORD << " {";
567
568     QXmlStreamReader::TokenType token = xml.readNext();
569     QString tokenName = xml.name().toString();
570
571     while (xml.atEnd() == false && (tokenName == MENULIST_KEYWORD &&
572         token == QXmlStreamReader::EndElement) == false) /* ~ </menuList> */
573     {
574         if (token == QXmlStreamReader::StartElement) {
575             const int menuType = menuItems.value(tokenName, -1);
576
577             switch(menuType) {
578             case MenuItemType::separator:
579                 // separator
580                 item = new MenuItem(menuType, NULL);
581                 break;
582             case MenuItemType::advancedItem:
583                 // Advanced
584                 item = dynamic_cast<MenuItem *>(
585                     parseAdvancedMenuItem(xml, depth + 1));
586                 break;
587             case MenuItemType::scaleItem:
588                 // Scale
589                 item = dynamic_cast<MenuItem *>(
590                     parseScaleMenuItem(xml, depth + 1));
591                 break;
592             case MenuItemType::infoItem:
593             case MenuItemType::onTopItem:
594             case MenuItemType::moveItem:
595             case MenuItemType::switchItem:
596             case MenuItemType::controllerItem:
597             case MenuItemType::hostKeyboardItem:
598             case MenuItemType::shellItem:
599             case MenuItemType::controlPanelItem:
600             case MenuItemType::screenShotItem:
601             case MenuItemType::aboutItem:
602             case MenuItemType::systemResetItem:
603             case MenuItemType::forceCloseItem:
604                 /* fall through */
605             case MenuItemType::closeItem:
606                 item = parseGeneralMenuItem(xml, depth + 1, menuType);
607                 break;
608             default:
609                 QWARN_INDENT(depth + 1) << "undefined element: " << tokenName;
610                 item = NULL;
611                 break;
612             }
613
614             if (item != NULL) {
615                 list.append(item);
616             }
617         }
618
619         token = xml.readNext();
620         tokenName = xml.name().toString();
621     }
622
623     QDEBUG_INDENT(depth) << "}";
624
625     return list.count();
626 }
627
628 QString XmlLayoutParser::parseEmulatorUI(QXmlStreamReader &xml)
629 {
630     QString layoutVersion = GENERIC_TEXT_UNDEFINED;
631     const int depth = 0;
632
633     qDebug(LOG_LINE_HEAD_CHAR);
634     QDEBUG_INDENT(depth) << EMULATOR_UI_KEYWORD << " {";
635
636     QXmlStreamReader::TokenType token = QXmlStreamReader::NoToken;
637
638     while (xml.atEnd() == false && xml.hasError() == false) {
639         token = xml.readNext();
640
641         /* If token is just StartDocument, go to next. */
642         if (token == QXmlStreamReader::StartDocument) {
643             continue;
644         }
645
646         if (token == QXmlStreamReader::StartElement) {
647             if (xml.name() == EMULATOR_UI_KEYWORD) {
648                 continue;
649             }
650
651             if (xml.name() == LAYOUTVER_KEYWORD) {
652                 layoutVersion = xml.readElementText();
653                 continue;
654             } else if (xml.name() == FORMLIST_KEYWORD) {
655                 /* forms */
656                 const int cnt = parseMainFormList(xml,
657                     depth + 1, uiInfo->getMainFormList());
658                 QDEBUG_INDENT(depth + 1) << FORMLIST_KEYWORD << ": " << cnt;
659             } else if (xml.name() == MENULIST_KEYWORD) {
660                 /* menus */
661                 const int cnt = parseMenuList(xml,
662                     depth + 1, uiInfo->getMenuList());
663                 QDEBUG_INDENT(depth + 1) << MENULIST_KEYWORD << ": " << cnt;
664             } else {
665                 QWARN_INDENT(depth + 1) << "undefined element: " << xml.name();
666             }
667         }
668     }
669
670     QDEBUG_INDENT(depth) << "}";
671
672     if (xml.hasError() == true) {
673         printError(xml.error());
674     }
675
676     return layoutVersion;
677 }
678
679 /* controller */
680 ControllerForm *XmlLayoutParser::parseControllerForm(
681     QXmlStreamReader &xml, const int depth)
682 {
683     /* attribute */
684     QString formName = xml.attributes().value(NAME_ATTR_KEYWORD).toString();
685     ControllerForm *form = new ControllerForm(
686         formName.isEmpty() ? xmlPath.section(QDir::separator(), -1) : formName);
687
688     QDEBUG_INDENT(depth) << form->getName() << " {";
689
690     QXmlStreamReader::TokenType token = xml.readNext();
691
692     while (xml.atEnd() == false && (xml.name() == FORM_KEYWORD &&
693         token == QXmlStreamReader::EndElement) == false) /* ~ </form> */
694     {
695         if (token == QXmlStreamReader::StartElement) {
696             if (xml.name() == NORMAL_IMG_KEYWORD) {
697                 /* normal image */
698                 QString normalImageFileName = xml.readElementText();
699                 QDEBUG_INDENT(depth + 1) <<
700                     NORMAL_IMG_KEYWORD << ": " <<  normalImageFileName;
701
702                 if (form->skinImg[LayoutForm::normal].load(
703                     xmlPath + QDir::separator() + normalImageFileName) == false) {
704                     QWARN_INDENT(depth + 1) << "failed to load normal image";
705                 }
706             } else if (xml.name() == PRESSED_IMG_KEYWORD) {
707                 /* key pressed image */
708                 QString pressedImageFileName = xml.readElementText();
709                 QDEBUG_INDENT(depth + 1) <<
710                     PRESSED_IMG_KEYWORD << ": " << pressedImageFileName;
711
712                 if (form->skinImg[LayoutForm::pressed].load(
713                     xmlPath + QDir::separator() + pressedImageFileName) == false) {
714                     QWARN_INDENT(depth + 1) << "failed to load pressed image";
715                 }
716             } else if (xml.name() == KEYLIST_KEYWORD) {
717                 /* HW keys */
718                 const int cnt = parseKeyList(xml, depth + 1, form->getKeyList());
719                 QDEBUG_INDENT(depth + 1) << KEYLIST_KEYWORD << ": " << cnt;
720             } else if (xml.name() == HOVER_KEYWORD) {
721                 /* hover */
722                 form->setHoverType(parseHover(xml, depth + 1));
723             } else if (xml.name() == FORM_KEYWORD) {
724                 /* sub form */
725                 QWARN_INDENT(depth + 1) << "undefined element: " << xml.name();
726                 ControllerForm *subform = parseControllerForm(xml, depth + 1);
727                 if (subform != NULL) {
728                     form->getSubFormList().append(subform);
729                 }
730             } else {
731                 QWARN_INDENT(depth + 1) << "undefined element: " << xml.name();
732             }
733         }
734
735         token = xml.readNext();
736     }
737
738     QDEBUG_INDENT(depth) << "}";
739
740     return form;
741 }
742
743 QString XmlLayoutParser::parseControllerUI(QXmlStreamReader &xml)
744 {
745     QString layoutVersion = GENERIC_TEXT_UNDEFINED;
746     const int depth = 0;
747
748     qDebug(LOG_LINE_HEAD_CHAR);
749     QDEBUG_INDENT(depth) << CONTROLLER_UI_KEYWORD << " {";
750
751     ControllerForm *form = NULL;
752     QXmlStreamReader::TokenType token = QXmlStreamReader::NoToken;
753
754     while (xml.atEnd() == false && xml.hasError() == false) {
755         token = xml.readNext();
756
757         /* If token is just StartDocument, go to next. */
758         if (token == QXmlStreamReader::StartDocument) {
759             continue;
760         }
761
762         if (token == QXmlStreamReader::StartElement) {
763             if (xml.name() == CONTROLLER_UI_KEYWORD) {
764                 continue;
765             }
766
767             if (xml.name() == LAYOUTVER_KEYWORD) {
768                 layoutVersion = xml.readElementText();
769                 continue;
770             } else if (xml.name() == FORM_KEYWORD) {
771                 form = parseControllerForm(xml, depth + 1);
772                 if (form != NULL) {
773                     /* image validation */
774                     if (form->skinImg[LayoutForm::normal].size() == QSize(0, 0)) {
775                         QDEBUG_INDENT(depth + 1) << "(general purpose con type)";
776                         makeGeneralCon(form);
777                     }
778
779                     uiInfo->getConFormList().append(form);
780                 }
781             } else {
782                 QWARN_INDENT(depth + 1) << "undefined element: " << xml.name();
783             }
784         }
785     }
786
787     QDEBUG_INDENT(depth) << "}";
788
789     if (xml.hasError() == true) {
790         printError(xml.error());
791     }
792
793     return layoutVersion;
794 }
795
796 void XmlLayoutParser::makeGeneralCon(ControllerForm *form)
797 {
798     int keyCount = form->getKeyList().count();
799
800     int width = GPC_KEYBUTTON_WIDTH + GPC_KEYBUTTON_HSPACING;
801     int height = GPC_HEAD_SPACING;
802     height += (GPC_KEYBUTTON_HEIGHT * keyCount) +
803                 (GPC_KEYBUTTON_VSPACING * (keyCount - 1));
804
805     // add sub form
806     QList<Separator *> sList;
807     QPen pen(QColor(205, 205, 205), 1, Qt::SolidLine);
808     for (int i = 0; i < form->getSubFormList().count(); i++) {
809         // for separator
810         Separator *s = new Separator();
811         s->pen = pen;
812         s->hOffset = height + GPC_KEYBUTTON_VSPACING / 2;
813         sList.append(s);
814
815         ControllerForm *subForm = form->getSubFormList().at(i);
816         keyCount = subForm->getKeyList().count();
817
818         height += (GPC_KEYBUTTON_HEIGHT * keyCount) +
819                 (GPC_KEYBUTTON_VSPACING * keyCount);
820     }
821
822     height += GPC_TAIL_SPACING;
823
824     SkinPainter painter(QSize(width, qMax(height, QT_LAYOUT_MINIMUM - 20)), 0, sList);
825
826     form->skinImg[LayoutForm::normal] = painter.getSkinImage();
827     form->setCenteralRect(painter.getCenteralRect());
828     form->setGeneralPurpose(true);
829 }
830
831 void XmlLayoutParser::printError(QXmlStreamReader::Error err)
832 {
833     switch (err) {
834     case QXmlStreamReader::NoError:
835         /* do nothing */
836         break;
837     case QXmlStreamReader::UnexpectedElementError:
838         qCritical("The parser encountered an element that was different to those it expected.");
839         break;
840     case QXmlStreamReader::CustomError:
841         qCritical("A custom error has been raised with raiseError().");
842         break;
843     case QXmlStreamReader::NotWellFormedError:
844         qCritical("The parser internally raised an error due to the read XML not being well-formed.");
845         break;
846     case QXmlStreamReader::PrematureEndOfDocumentError:
847         qCritical("The input stream ended before a well-formed XML document was parsed.");
848         break;
849     default:
850         qCritical("Unexpected error type was returned.");
851         break;
852     }
853 }