1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the demonstration applications of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:BSD$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** BSD License Usage
18** Alternatively, you may use this file under the terms of the BSD license
19** as follows:
20**
21** "Redistribution and use in source and binary forms, with or without
22** modification, are permitted provided that the following conditions are
23** met:
24** * Redistributions of source code must retain the above copyright
25** notice, this list of conditions and the following disclaimer.
26** * Redistributions in binary form must reproduce the above copyright
27** notice, this list of conditions and the following disclaimer in
28** the documentation and/or other materials provided with the
29** distribution.
30** * Neither the name of The Qt Company Ltd nor the names of its
31** contributors may be used to endorse or promote products derived
32** from this software without specific prior written permission.
33**
34**
35** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
46**
47** $QT_END_LICENSE$
48**
49****************************************************************************/
50
51#include <QScreen>
52#include <QXmlStreamReader>
53
54#include "fluidlauncher.h"
55
56#define DEFAULT_INPUT_TIMEOUT 10000
57#define SIZING_FACTOR_HEIGHT 6/10
58#define SIZING_FACTOR_WIDTH 6/10
59
60FluidLauncher::FluidLauncher(QStringList* args)
61{
62 pictureFlowWidget = new PictureFlow();
63 slideShowWidget = new SlideShow();
64 inputTimer = new QTimer();
65
66 addWidget(w: pictureFlowWidget);
67 addWidget(w: slideShowWidget);
68 setCurrentWidget(pictureFlowWidget);
69 pictureFlowWidget->setFocus();
70
71 QRect screen_size = QGuiApplication::primaryScreen()->geometry();
72
73 QObject::connect(sender: pictureFlowWidget, SIGNAL(itemActivated(int)), receiver: this, SLOT(launchApplication(int)));
74 QObject::connect(sender: pictureFlowWidget, SIGNAL(inputReceived()), receiver: this, SLOT(resetInputTimeout()));
75 QObject::connect(sender: slideShowWidget, SIGNAL(inputReceived()), receiver: this, SLOT(switchToLauncher()));
76 QObject::connect(sender: inputTimer, SIGNAL(timeout()), receiver: this, SLOT(inputTimedout()));
77
78 inputTimer->setSingleShot(true);
79 inputTimer->setInterval(DEFAULT_INPUT_TIMEOUT);
80
81 const int h = screen_size.height() * SIZING_FACTOR_HEIGHT;
82 const int w = screen_size.width() * SIZING_FACTOR_WIDTH;
83 const int hh = qMin(a: h, b: w);
84 const int ww = hh / 3 * 2;
85 pictureFlowWidget->setSlideSize(QSize(ww, hh));
86
87 bool success;
88 int configIndex = args->indexOf(t: "-config");
89 if ( (configIndex != -1) && (configIndex != args->count()-1) )
90 success = loadConfig(configPath: args->at(i: configIndex+1));
91 else
92 success = loadConfig(configPath: ":/fluidlauncher/config.xml");
93
94 if (success) {
95 populatePictureFlow();
96
97 showFullScreen();
98 inputTimer->start();
99 } else {
100 pictureFlowWidget->setAttribute(Qt::WA_DeleteOnClose, on: true);
101 pictureFlowWidget->close();
102 }
103
104}
105
106FluidLauncher::~FluidLauncher()
107{
108 delete pictureFlowWidget;
109 delete slideShowWidget;
110}
111
112bool FluidLauncher::loadConfig(QString configPath)
113{
114 QFile xmlFile(configPath);
115
116 if (!xmlFile.exists() || (xmlFile.error() != QFile::NoError)) {
117 qDebug() << "ERROR: Unable to open config file " << configPath;
118 return false;
119 }
120
121 slideShowWidget->clearImages();
122
123 xmlFile.open(flags: QIODevice::ReadOnly);
124 QXmlStreamReader reader(&xmlFile);
125 while (!reader.atEnd()) {
126 reader.readNext();
127
128 if (reader.isStartElement()) {
129 if (reader.name() == "demos")
130 parseDemos(reader);
131 else if(reader.name() == "slideshow")
132 parseSlideshow(reader);
133 }
134 }
135
136 if (reader.hasError()) {
137 qDebug() << QString("Error parsing %1 on line %2 column %3: \n%4")
138 .arg(a: configPath)
139 .arg(a: reader.lineNumber())
140 .arg(a: reader.columnNumber())
141 .arg(a: reader.errorString());
142 }
143
144 // Append an exit Item
145 DemoApplication* exitItem = new DemoApplication(QString(), QLatin1String("Exit Embedded Demo"), QString(), QStringList());
146 demoList.append(t: exitItem);
147
148 return true;
149}
150
151
152void FluidLauncher::parseDemos(QXmlStreamReader& reader)
153{
154 while (!reader.atEnd()) {
155 reader.readNext();
156 if (reader.isStartElement() && reader.name() == "example") {
157 QXmlStreamAttributes attrs = reader.attributes();
158 QStringRef filename = attrs.value(qualifiedName: "filename");
159 if (!filename.isEmpty()) {
160 QStringRef name = attrs.value(qualifiedName: "name");
161 QStringRef image = attrs.value(qualifiedName: "image");
162 QStringRef args = attrs.value(qualifiedName: "args");
163
164 DemoApplication* newDemo = new DemoApplication(
165 filename.toString(),
166 name.isEmpty() ? "Unnamed Demo" : name.toString(),
167 image.toString(),
168 args.toString().split(sep: " "));
169 demoList.append(t: newDemo);
170 }
171 } else if(reader.isEndElement() && reader.name() == "demos") {
172 return;
173 }
174 }
175}
176
177void FluidLauncher::parseSlideshow(QXmlStreamReader& reader)
178{
179 QXmlStreamAttributes attrs = reader.attributes();
180
181 QStringRef timeout = attrs.value(qualifiedName: "timeout");
182 bool valid;
183 if (!timeout.isEmpty()) {
184 int t = timeout.toString().toInt(ok: &valid);
185 if (valid)
186 inputTimer->setInterval(t);
187 }
188
189 QStringRef interval = attrs.value(qualifiedName: "interval");
190 if (!interval.isEmpty()) {
191 int i = interval.toString().toInt(ok: &valid);
192 if (valid)
193 slideShowWidget->setSlideInterval(i);
194 }
195
196 while (!reader.atEnd()) {
197 reader.readNext();
198 if (reader.isStartElement()) {
199 QXmlStreamAttributes attrs = reader.attributes();
200 if (reader.name() == "imagedir") {
201 QStringRef dir = attrs.value(qualifiedName: "dir");
202 slideShowWidget->addImageDir(dirName: dir.toString());
203 } else if(reader.name() == "image") {
204 QStringRef image = attrs.value(qualifiedName: "image");
205 slideShowWidget->addImage(filename: image.toString());
206 }
207 } else if(reader.isEndElement() && reader.name() == "slideshow") {
208 return;
209 }
210 }
211
212}
213
214void FluidLauncher::populatePictureFlow()
215{
216 pictureFlowWidget->setSlideCount(demoList.count());
217
218 for (int i=demoList.count()-1; i>=0; --i) {
219 const QImage image = demoList[i]->getImage();
220 if (!image.isNull())
221 pictureFlowWidget->setSlide(index: i, image);
222 pictureFlowWidget->setSlideCaption(index: i, caption: demoList[i]->getCaption());
223 }
224
225 pictureFlowWidget->setCurrentSlide(demoList.count()/2);
226}
227
228
229void FluidLauncher::launchApplication(int index)
230{
231 // NOTE: Clearing the caches will free up more memory for the demo but will cause
232 // a delay upon returning, as items are reloaded.
233 //pictureFlowWidget->clearCaches();
234
235 if (index == demoList.size() -1) {
236 qApp->quit();
237 return;
238 }
239
240 inputTimer->stop();
241
242 QObject::connect(sender: demoList[index], SIGNAL(demoFinished()), receiver: this, SLOT(demoFinished()));
243
244 demoList[index]->launch();
245}
246
247
248void FluidLauncher::switchToLauncher()
249{
250 slideShowWidget->stopShow();
251 inputTimer->start();
252 setCurrentWidget(pictureFlowWidget);
253}
254
255
256void FluidLauncher::resetInputTimeout()
257{
258 if (inputTimer->isActive())
259 inputTimer->start();
260}
261
262void FluidLauncher::inputTimedout()
263{
264 switchToSlideshow();
265}
266
267
268void FluidLauncher::switchToSlideshow()
269{
270 inputTimer->stop();
271 slideShowWidget->startShow();
272 setCurrentWidget(slideShowWidget);
273}
274
275void FluidLauncher::demoFinished()
276{
277 setCurrentWidget(pictureFlowWidget);
278 inputTimer->start();
279
280 // Bring the Fluidlauncher to the foreground to allow selecting another demo
281 raise();
282 activateWindow();
283}
284
285void FluidLauncher::changeEvent(QEvent* event)
286{
287 if (event->type() == QEvent::ActivationChange) {
288 if (isActiveWindow()) {
289 if(currentWidget() == pictureFlowWidget) {
290 resetInputTimeout();
291 } else {
292 slideShowWidget->startShow();
293 }
294 } else {
295 inputTimer->stop();
296 slideShowWidget->stopShow();
297 }
298 }
299 QStackedWidget::changeEvent(event);
300}
301

source code of qtsvg/examples/svg/embedded/fluidlauncher/fluidlauncher.cpp