OSDN Git Service

98e37c06bb9cfa8a4f1ca6c4a803de1caa857f7e
[kde/kde-extraapps.git] / kvkbd / src / themeloader.cpp
1 /*
2  * <one line to give the library's name and an idea of what it does.>
3  * Copyright (C) 2014  Todor <email>
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  *
18  */
19
20 #include "themeloader.h"
21
22 #include <QMessageBox>
23 #include <QString>
24 #include <QFile>
25 #include <QtXml/qdom.h>
26 #include <QFileInfo>
27 #include <QDir>
28 #include <QMenu>
29
30 #include <KUniqueApplication>
31 #include <KStandardDirs>
32 #include <KAction>
33 #include <KIcon>
34 #include <KToggleAction>
35
36 #include <iostream>
37 using namespace std;
38
39
40 int defaultWidth = 25;
41 int defaultHeight = 25;
42
43 #define DEFAULT_CSS ":/theme/standart.css"
44
45 ThemeLoader::ThemeLoader(QWidget *parent) : QObject(parent)
46 {
47
48 }
49
50 ThemeLoader::~ThemeLoader()
51 {
52
53 }
54 void ThemeLoader::loadTheme(QString& themeName)
55 {
56     bool loading = true;
57     while (loading) {
58         int ret = this->loadLayout(themeName, ":/theme/");
59
60         if (ret == 0) {
61             break;
62         }
63         //bail out
64         else {
65             if (QString::compare(themeName, "standart")==0) {
66                 loading = false;
67                 kapp->quit();
68             }
69             else {
70                 themeName="standart";
71             }
72         }
73     }
74 }
75 void ThemeLoader::loadColorFile(const QString& fileName)
76 {
77     QFile themeFile;
78
79     themeFile.setFileName(fileName);
80
81     if (!themeFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
82
83         QMessageBox::information(0, "Error", QString("Unable to open css file: %1").arg(themeFile.fileName()));
84         return;
85     }
86
87     ((QWidget*)parent())->setStyleSheet(themeFile.readAll());
88     ((QWidget*)parent())->setProperty("colors", fileName);
89     themeFile.close();
90     
91     ((QWidget*)parent())->repaint();
92     
93     emit colorStyleChanged();
94     
95     
96 }
97 void ThemeLoader::loadColorStyle()
98 {
99
100     QAction *action = (QAction*)QObject::sender();
101    
102     QFileInfo info(action->data().toString());
103     
104     this->loadColorFile(info.absoluteFilePath());
105
106 }
107 void ThemeLoader::findColorStyles(QMenu *colors, const QString& configSelectedStyle)
108 {
109     KStandardDirs kdirs;
110     QStringList dirs = kdirs.findDirs("data", "kvkbd");
111
112     QActionGroup *color_group = new QActionGroup(colors);
113     color_group->setExclusive(true);
114
115
116     QAction *item = new QAction(colors);
117     item->setCheckable(true);
118     item->setText("standart");
119     item->setData(":/theme/standart.css");
120     colors->addAction(item);
121     color_group->addAction(item);
122     
123     
124
125
126
127     colors->setTitle("Color Style");
128     colors->setIcon(KIcon("preferences-desktop-color"));
129     QListIterator<QString> itr(dirs);
130     while (itr.hasNext()) {
131         QString data_path = itr.next() + "colors";
132
133         QFileInfo info(data_path);
134         if (info.isDir() && info.isReadable()) {
135             QDir colors_dir(info.absoluteFilePath(), "*.css");
136             QFileInfoList list = colors_dir.entryInfoList();
137
138             QListIterator<QFileInfo> itr(list);
139             while (itr.hasNext()) {
140                 QFileInfo fileInfo = itr.next();
141                 //std::cout << qPrintable(QString("%1 %2").arg(fileInfo.size(), 10)
142                 //                                  .arg(fileInfo.fileName()));
143                 //std::cout << std::endl;
144
145                 QAction *item = new QAction(this);
146                 item->setCheckable(true);
147
148                 item->setText(fileInfo.baseName());
149                 item->setData(fileInfo.absoluteFilePath());
150                 colors->addAction(item);
151                 color_group->addAction(item);
152
153
154             }
155
156         }
157
158     }
159
160     QString selectedStyle = configSelectedStyle;
161     if (selectedStyle.length()<1) {
162         selectedStyle = DEFAULT_CSS;
163     }
164     QAction *selectedAction = 0;
165     
166     QListIterator<QAction*> itrActions(color_group->actions());
167     while (itrActions.hasNext()) {
168         QAction *item = itrActions.next();
169         
170         if (item->data().toString() == selectedStyle) {
171             item->setChecked(true);
172             selectedAction = item;
173         }
174       
175         
176         connect(item, SIGNAL(triggered(bool)), this, SLOT(loadColorStyle()));
177     }
178     
179     if (selectedAction) {
180       selectedAction->trigger();
181     }
182
183 }
184
185
186 int ThemeLoader::loadLayout(const QString& themeName, const QString& path)
187 {
188
189 //     const KArchiveDirectory * KArchive::directory    (               )        const
190
191
192     QFile themeFile;
193
194
195
196     QDomDocument doc;
197
198     themeFile.setFileName(QString(path + "%1.xml").arg(themeName));
199
200     if (!themeFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
201         QMessageBox::information(0, "Error", QString("Unable to open theme xml file: %1").arg(themeFile.fileName()));
202         return -1;
203     }
204     if (!doc.setContent(&themeFile)) {
205         QMessageBox::information(0, "Error", QString("Unable to parse theme xml file: %1").arg(themeFile.fileName()));
206         return -2;
207     }
208     themeFile.close();
209
210
211     QDomElement docElem = doc.documentElement();
212
213     QDomNodeList wList = docElem.elementsByTagName("buttonWidth");
214     QDomNode wNode = wList.at(0);
215
216     //read default button width
217     defaultWidth = wNode.attributes().namedItem("width").toAttr().value().toInt();
218
219     QDomNodeList nList = (wNode.toElement()).elementsByTagName("item");
220     for (int a=0; a<nList.count(); a++) {
221         QDomNode node = nList.at(a);
222         int width = node.attributes().namedItem("width").toAttr().value().toInt();
223         QString hintName = node.attributes().namedItem("name").toAttr().value();
224         widthMap.insert(hintName, width);
225         //cout  << "widths[" << qPrintable(hintName) << "]=>"<< width << endl;
226     }
227
228     wList = docElem.elementsByTagName("buttonHeight");
229     wNode = wList.at(0);
230     nList = (wNode.toElement()).elementsByTagName("item");
231     for (int a=0; a<nList.count(); a++) {
232         QDomNode node = nList.at(a);
233         int height = node.attributes().namedItem("height").toAttr().value().toInt();
234         QString hintName = node.attributes().namedItem("name").toAttr().value();
235         heightMap.insert(hintName, height);
236         //cout  << "heights[" << qPrintable(hintName) << "]=>"<< height << endl;
237     }
238
239
240     wList = docElem.elementsByTagName("spacingHints");
241     wNode = wList.at(0);
242     nList = (wNode.toElement()).elementsByTagName("item");
243     for (int a=0; a<nList.count(); a++) {
244         QDomNode node = nList.at(a);
245         int width = node.attributes().namedItem("width").toAttr().value().toInt();
246         QString hintName = node.attributes().namedItem("name").toAttr().value();
247         spacingMap.insert(hintName, width);
248         //cout  << "spacing[" << qPrintable(hintName) << "]=>"<< width << endl;
249     }
250
251
252     wList = docElem.elementsByTagName("part");
253     wNode = wList.at(0);
254
255     //insert main part to widget
256     QString partName = wNode.attributes().namedItem("name").toAttr().value();
257
258     MainWidget *part = new MainWidget((QWidget*)parent());
259     part->setProperty("part", "main");
260
261
262     loadKeys(part, wNode);
263
264     wList = wNode.childNodes();
265
266     for (int a=0; a<wList.size(); a++) {
267
268         QDomNode wNode = wList.at(a);
269         if (wNode.toElement().tagName() == "extension") {
270             MainWidget *widget1 = new MainWidget((QWidget*)parent());
271             widget1->setProperty("part", "extension");
272             loadKeys(widget1, wNode);
273             break;
274         }
275     }
276
277
278
279     return 0;
280 }
281 bool ThemeLoader::applyProperty(VButton *btn, const QString& attributeName, QDomNamedNodeMap *attributes, QVariant defaultValue)
282 {
283     bool ret = false;
284
285     QString attributeValue = attributes->namedItem(attributeName).toAttr().value();
286     if (attributeValue.length()>0) {
287         btn->setProperty(qPrintable(attributeName), attributeValue);
288         ret = true;
289     }
290     else {
291         if (defaultValue.toString().length()>0) {
292             btn->setProperty(qPrintable(attributeName), defaultValue);
293             ret = true;
294         }
295     }
296     return ret;
297 }
298 void ThemeLoader::loadKeys(MainWidget *vPart, const QDomNode& wNode)
299 {
300     int max_sx = 0;
301     int max_sy = 0;
302
303     int sx = 0;
304     int sy = 0;
305     int rowMarginLeft = 0;
306     int rowSpacingY = 0;
307     int rowSpacingX = 0;
308
309     int total_cols = 0;
310     int total_rows = 0;
311
312     QDomNodeList nList = wNode.childNodes();
313
314     //(wNode.toElement()).elementsByTagName("row");
315
316     for (int a=0; a<nList.size(); a++) {
317
318         QDomNode wNode = nList.at(a);
319         if (wNode.toElement().tagName() != "row") continue;
320
321         total_rows++;
322
323         int rowHeight = defaultHeight;
324
325         int row_buttons = 0;
326
327
328         QDomNodeList key_list = wNode.childNodes();
329
330         QString rowHeightHint = wNode.attributes().namedItem("height").toAttr().value();
331         if (heightMap.contains(rowHeightHint)) {
332             rowHeight = heightMap.value(rowHeightHint);
333         }
334
335
336         for (int b=0; b<key_list.count(); b++) {
337             QDomNode node = key_list.at(b);
338             QDomNamedNodeMap attributes = node.attributes();
339
340             if (node.toElement().tagName()== "key") {
341
342                 VButton *btn = new VButton(vPart);
343                 row_buttons++;
344                 //width
345
346                 int buttonWidth = defaultWidth;
347                 int buttonHeight = defaultHeight;
348
349                 QString widthHint = attributes.namedItem("width").toAttr().value();
350                 if (widthMap.contains(widthHint)) {
351                     buttonWidth = widthMap.value(widthHint);
352                 }
353
354                 QString heightHint = attributes.namedItem("height").toAttr().value();
355                 if (heightMap.contains(heightHint)) {
356                     buttonHeight = heightMap.value(heightHint);
357                 }
358
359                 //name
360                 QString button_name = attributes.namedItem("name").toAttr().value();
361                 if (button_name.length()>0) {
362                     btn->setObjectName(button_name);
363                 }
364
365
366                 if (applyProperty(btn, "label", &attributes)) {
367                     btn->setText(btn->property("label").toString());
368                 }
369
370
371                 applyProperty(btn, "group_label", &attributes);
372
373                 applyProperty(btn, "group_toggle", &attributes);
374
375                 applyProperty(btn, "group_name", &attributes);
376
377                 applyProperty(btn, "colorGroup", &attributes, "normal");
378
379                 applyProperty(btn, "tooltip", &attributes);
380
381                 QString modifier = attributes.namedItem("modifier").toAttr().value();
382                 if (modifier.toInt()>0) {
383                     btn->setProperty("modifier", true);
384                     btn->setCheckable(true);
385                 }
386
387                 unsigned int key_code = attributes.namedItem("code").toAttr().value().toInt();
388                 if (key_code>0) {
389                     btn->setKeyCode(key_code);
390                 }
391
392                 if (applyProperty(btn, "action", &attributes)) {
393                     btn->setProperty("action", btn->property("action").toString());
394
395                 }
396
397                 
398                 int is_checkable = attributes.namedItem("checkable").toAttr().value().toInt();
399                 if (is_checkable>0) {
400                     btn->setCheckable(true);
401                     btn->setChecked(false);
402                 }
403
404                 btn->move(sx,sy);
405                 btn->resize(buttonWidth, buttonHeight);
406                 btn->storeSize();
407
408 //              btn->setNode(node);
409                 // cout  << "ColorGroup: " << qPrintable(colorGroup) << endl;
410
411                 sx+=buttonWidth+rowSpacingX;
412
413                 emit buttonLoaded(btn);
414             }
415             else if (node.toElement().tagName()=="spacing") {
416
417                 QString widthHint = attributes.namedItem("width").toAttr().value();
418                 QString heightHint = attributes.namedItem("height").toAttr().value();
419
420
421                 if (spacingMap.contains(widthHint)) {
422                     int spacingWidth = spacingMap.value(widthHint);
423
424                     sx+=spacingWidth;
425
426
427                 }
428                 if (heightMap.contains(heightHint)) {
429                     int spacingHeight = heightMap.value(heightHint);
430
431                     if (spacingHeight>rowHeight) rowHeight = spacingHeight;
432
433                 }
434
435             }
436
437             //cout << "X=>"<<sx<<" | Y=>"<<sy<<endl;
438             //
439         }//row
440
441         if (sx>max_sx)max_sx = sx;
442
443         sy+=(rowHeight+rowSpacingY);
444         sx=0+rowMarginLeft;
445
446         if (row_buttons>total_cols)total_cols=row_buttons;
447
448     }
449     if (sy>max_sy) max_sy = sy;
450
451     vPart->setBaseSize(max_sx, max_sy);
452
453     emit partLoaded(vPart, total_rows, total_cols);
454     
455
456
457 }
458
459 #include "moc_themeloader.cpp"