BuildmLearn Toolkit  2.0.4
BuildmLearn Toolkit is an easy-to-use program that helps users make mobile apps without any knowledge of application development.
 All Classes Functions Enumerations Groups Pages
application.cpp
1 /*
2  Copyright (c) 2012, BuildmLearn Contributors listed at http://buildmlearn.org/people/
3  All rights reserved.
4 
5  Redistribution and use in source and binary forms, with or without
6  modification, are permitted provided that the following conditions are met:
7 
8  * Redistributions of source code must retain the above copyright notice, this
9  list of conditions and the following disclaimer.
10 
11  * Redistributions in binary form must reproduce the above copyright notice,
12  this list of conditions and the following disclaimer in the documentation
13  and/or other materials provided with the distribution.
14 
15  * Neither the name of the BuildmLearn nor the names of its
16  contributors may be used to endorse or promote products derived from
17  this software without specific prior written permission.
18 
19  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30 
31 #include "miscellaneous/application.h"
32 
33 #include "miscellaneous/systemfactory.h"
34 #include "miscellaneous/skinfactory.h"
35 #include "network-web/networkfactory.h"
36 #include "gui/systemtrayicon.h"
37 #include "gui/formmain.h"
38 #include "core/templatefactory.h"
39 
40 #include <QMutex>
41 #include <QFuture>
42 #include <QFutureWatcher>
43 
44 #if QT_VERSION >= 0x050000
45 #include <QtConcurrent/QtConcurrentRun>
46 #else
47 #include <QtConcurrentRun>
48 #endif
49 
50 
51 Application::Application(int &argc, char **argv)
52  : QApplication(argc, argv),
53  m_externalApplicationChecked(false),
54  m_closeLock(new QMutex()),
55  m_availableActions(QList<QAction*>()),
56  m_settings(NULL),
57  m_skinFactory(NULL),
58  m_trayIcon(NULL),
59  m_templateManager(NULL),
60  m_closing(false) {
61  connect(this, SIGNAL(aboutToQuit()), this, SLOT(onAboutToQuit()));
62  connect(this, SIGNAL(commitDataRequest(QSessionManager&)), this, SLOT(onCommitData(QSessionManager&)));
63  connect(this, SIGNAL(saveStateRequest(QSessionManager&)), this, SLOT(onSaveState(QSessionManager&)));
64 }
65 
66 Application::~Application() {
67  delete m_closeLock;
68 }
69 
72 }
73 
75  if (m_skinFactory == NULL) {
76  m_skinFactory = new SkinFactory(this);
77  }
78 
79  return m_skinFactory;
80 }
81 
82 void Application::setZipUtilityPath(const QString& zip_path) {
83  settings()->setValue(APP_CFG_GEN, "zip_path", zip_path);
84 }
85 
86 void Application::setSignApkUtilityPath(const QString& signapk_path) {
87  settings()->value(APP_CFG_GEN, "signapk_path", signapk_path);
88 }
89 
90 int Application::checkJava(const QString &new_path) {
91  QString java_path = new_path.isEmpty() ? javaInterpreterPath() : new_path;
92 
93  if (java_path.isEmpty()) {
94  return EXIT_STATUS_NOT_STARTED;
95  }
96  else {
97  QProcess process;
98 
99  process.setReadChannelMode(QProcess::MergedChannels);
100  process.start(QDir::toNativeSeparators(java_path), QStringList() << "-version");
101  process.waitForFinished(-1);
102 
103  return process.exitCode();
104  }
105 }
106 
107 int Application::checkSignApk(const QString &new_path, const QString &java_path) {
108  QString real_java_path = java_path.isEmpty() ? javaInterpreterPath() : java_path;
109  QString signapk_path = new_path.isEmpty() ? signApkUtlityPath() : new_path;
110 
111  if (signapk_path.isEmpty()) {
112  return EXIT_STATUS_NOT_STARTED;
113  }
114  else {
115  QProcess process;
116 
117  process.setReadChannelMode(QProcess::MergedChannels);
118  process.start(QDir::toNativeSeparators(real_java_path),
119  QStringList() << "-jar" << QDir::toNativeSeparators(signapk_path));
120  process.waitForFinished(-1);
121 
122  return process.exitCode();
123  }
124 }
125 
126 int Application::checkZip(const QString &new_path) {
127  QString zip_path = new_path.isEmpty() ? zipUtilityPath() : new_path;
128 
129  if (zip_path.isEmpty()) {
130  return EXIT_STATUS_NOT_STARTED;
131  }
132  else {
133  QProcess process;
134 
135  process.setReadChannelMode(QProcess::MergedChannels);
136  process.start(QDir::toNativeSeparators(zip_path), QStringList() << "--version");
137  process.waitForFinished(-1);
138 
139  return process.exitCode();
140  }
141 }
142 
143 void Application::recheckExternalApplications(bool emit_signals) {
144  int java_ready = checkJava();
145  int zip_ready = checkZip();
146  int signapk_ready = checkSignApk();
147 
148  if (signapk_ready != EXIT_STATUS_SIGNAPK_NORMAL ||
149  java_ready != EXIT_STATUS_JAVA_NORMAL ||
150  zip_ready != EXIT_STATUS_ZIP_NORMAL) {
151  m_externalApplicationsStatus = QString();
152 
153  if (signapk_ready != EXIT_STATUS_SIGNAPK_NORMAL) {
154  m_externalApplicationsStatus += qApp->interpretSignApk(signapk_ready) + '\n';
155  }
156 
157  if (java_ready != EXIT_STATUS_JAVA_NORMAL) {
158  m_externalApplicationsStatus += qApp->interpretJava(java_ready) + '\n';
159  }
160 
161  if (zip_ready != EXIT_STATUS_ZIP_NORMAL) {
162  m_externalApplicationsStatus += qApp->interpretZip(zip_ready) + '\n';
163  }
164 
165  m_externalApplicationsStatus.chop(1);
166  m_externalApplicationsReady = false;
167  }
168  else {
169  m_externalApplicationsReady = true;
170  }
171 
172  m_externalApplicationChecked = true;
173 
174  if (emit_signals) {
176  }
177 }
178 
179 QString Application::interpretJava(int return_code) {
180  switch (return_code) {
181  case EXIT_STATUS_NOT_STARTED:
182  return tr("JAVA was not found at given location.");
183 
184  case EXIT_STATUS_CRASH:
185  return tr("JAVA found but is crashy.");
186 
187  case EXIT_STATUS_JAVA_NORMAL:
188  return tr("JAVA found and probably working.");
189 
190  default:
191  return tr("JAVA returned uknown code.");
192  }
193 }
194 
195 QString Application::interpretZip(int return_code) {
196  switch (return_code) {
197  case EXIT_STATUS_NOT_STARTED:
198  return tr("ZIP was not found at given location.");
199 
200  case EXIT_STATUS_CRASH:
201  return tr("ZIP found but is crashy.");
202 
203  case EXIT_STATUS_ZIP_NORMAL:
204  return tr("ZIP found and probably working.");
205 
206  default:
207  return tr("ZIP returned uknown code.");
208  }
209 }
210 
211 QString Application::interpretSignApk(int return_code) {
212  switch (return_code) {
213  case EXIT_STATUS_NOT_STARTED:
214  return tr("SIGNAPK was not found because JAVA was not found.");
215 
216  case EXIT_STATUS_CRASH:
217  return tr("SIGNAPK found but is crashy.");
218 
219  case EXIT_STATUS_SIGNAPK_NOT_FOUND:
220  return tr("SIGNAPK not found.");
221 
222  case EXIT_STATUS_SIGNAPK_NORMAL:
223  return tr("SIGNAPK found and probably working.");
224 
225  case EXIT_STATUS_SIGNAPK_WORKING:
226  return tr("SIGNAPK found and but there is high risk it is invalid.");
227 
228  default:
229  return tr("SIGNAPK returned uknown code.");
230  }
231 }
232 
233 QList<QAction*> Application::availableActions() {
234  if (m_mainForm == NULL) {
235  return QList<QAction*>();
236  }
237  else {
238  if (m_availableActions.isEmpty()) {
239  m_availableActions = m_mainForm->allActions();
240  }
241 
242  return m_availableActions;
243  }
244 }
245 
247  if (m_trayIcon == NULL) {
248  m_trayIcon = new SystemTrayIcon(APP_ICON_PATH, m_mainForm);
249  m_trayIcon->setToolTip(APP_LONG_NAME);
250  }
251 
252  return m_trayIcon;
253 }
254 
256  if (m_templateManager == NULL) {
257  m_templateManager = new TemplateFactory(this);
258  }
259 
260  return m_templateManager;
261 }
262 
263 void Application::handleBackgroundUpdatesCheck() {
264  QFutureWatcher<UpdateCheck> *future_watcher = static_cast<QFutureWatcher<UpdateCheck>*>(sender());
265  UpdateCheck updates = future_watcher->result();
266 
267  switch (updates.second) {
268  case QNetworkReply::NoError:
269  if (updates.first.m_availableVersion > APP_VERSION) {
271  trayIcon()->showMessage(tr("Update available"),
272  tr("New application update is available."),
273  QSystemTrayIcon::Information,
274  TRAY_ICON_BUBBLE_TIMEOUT,
275  qApp->mainForm(),
276  SLOT(showUpdatesAfterBubbleClick()));
277  }
278  }
279  else {
281  trayIcon()->showMessage(tr("No updates available"),
282  tr("No new updates are available."),
283  QSystemTrayIcon::Information);
284  }
285  }
286 
287  break;
288 
289  default:
291  trayIcon()->showMessage(tr("Update check error"),
292  tr("Could not check for updates: %1.").arg(NetworkFactory::networkErrorText(updates.second)),
293  QSystemTrayIcon::Warning);
294  }
295 
296  break;
297  }
298 }
299 
301  return m_closing;
302 }
303 
304 bool Application::externalApplicationChecked() const {
305  return m_externalApplicationChecked;
306 }
307 
308 QString Application::externalApplicationsStatus() const {
309  return m_externalApplicationsStatus;
310 }
311 
312 bool Application::externalApplicationsReady() const {
313  return m_externalApplicationsReady;
314 }
315 
317  if (!settings()->value(APP_CFG_GEN,
318  "check_for_updates_startup",
319  true).toBool()) {
320  qDebug("Checking for updates after application startup is not allowed.");
321  }
322  else {
323  qDebug("Checking for updates after application has started.");
324 
325  QFutureWatcher<UpdateCheck> *watcher_for_future = new QFutureWatcher<UpdateCheck>(this);
326 
327  connect(watcher_for_future, SIGNAL(finished()), this, SLOT(handleBackgroundUpdatesCheck()));
328  watcher_for_future->setFuture(QtConcurrent::run(this, &Application::checkForUpdates));
329  }
330 }
331 
332 void Application::onAboutToQuit() {
333  qDebug("Quitting the application.");
334  qDebug("Cleaning up resources and saving application state.");
335 
336  if (closeLock()->tryLock(CLOSE_LOCK_TIMEOUT)) {
337  // Application obtained permission to close
338  // in a safety way.
339  qDebug("Close lock was obtained safely.");
340 
341  templateManager()->quit();
342 
343  // We locked the lock to exit peacefully, unlock it to avoid warnings.
344  closeLock()->unlock();
345  }
346  else {
347  // Request for write lock timed-out. This means
348  // that some critical action can be processed right now.
349  qDebug("Close lock timed-out.");
350  }
351 }
352 
353 void Application::onCommitData(QSessionManager &manager) {
354  qDebug("OS asked application to commit its data.");
355 
356  m_closing = true;
357 
358  manager.setRestartHint(QSessionManager::RestartNever);
359  manager.release();
360 }
361 
362 void Application::onSaveState(QSessionManager &manager) {
363  qDebug("OS asked application to save its state.");
364 
365  manager.setRestartHint(QSessionManager::RestartNever);
366  manager.release();
367 }
int checkZip(const QString &new_path=QString())
Tests if binary in new_path is correct ZIP executable.
bool isClosing() const
Application closing indication.
Main features for skinning.
Definition: skinfactory.h:59
Settings * settings()
Access to application-wide settings.
Definition: application.h:80
QString javaInterpreterPath()
Access to path to "java" interpreter.
Definition: application.h:126
void showMessage(const QString &title, const QString &message, MessageIcon icon=Information, int milliseconds_timeout_hint=TRAY_ICON_BUBBLE_TIMEOUT, QObject *click_target=NULL, const char *click_slot=NULL)
Displays new balloon tip with message.
void checkForUpdatesOnBackground()
Schedules check for updates.
void setSignApkUtilityPath(const QString &signapk_path)
Sets new path to "signapk".
Definition: application.cpp:86
void setValue(const QString &section, const QString &key, const QVariant &value)
Sets new value into settings.
Definition: settings.h:74
static QPair< UpdateInfo, QNetworkReply::NetworkError > checkForUpdates()
Tries to synchronously download list with new updates.
int checkJava(const QString &new_path=QString())
Tests if binary in new_path is correct JAVA executable.
Definition: application.cpp:90
static QString networkErrorText(QNetworkReply::NetworkError error_code)
Gets human readable text for given network error.
UpdateCheck checkForUpdates()
Tries to download list with new updates.
Definition: application.cpp:70
The top-level manager of templates.
QMutex * closeLock() const
Access to application-wide close lock.
Definition: application.h:92
TemplateFactory * templateManager()
Access to template high level manager.
static bool isSystemTrayAvailable()
Indicates whether tray icon is supported.
QList< QAction * > availableActions()
Access to all application-wide useable actions.
void quit()
Quits running actions of template manager.
SkinFactory * skinFactory()
Access to application-wide skin facilities.
Definition: application.cpp:74
void externalApplicationsRechecked()
Emitted if external applications are rechecked which happens usually if path to some of external appl...
SystemTrayIcon * trayIcon()
Access to application tray icon.
Application-wide tray icon.
QVariant value(const QString &section, const QString &key, const QVariant &default_value=QVariant())
Getter/setter for settings values.
Definition: settings.h:64
QList< QAction * > allActions()
Access to all actions provided by this window.
Definition: formmain.cpp:130
QString zipUtilityPath()
Access to "zip" utility path.
Definition: application.h:102
Application(int &argc, char **argv)
Constructor.
Definition: application.cpp:51
void setZipUtilityPath(const QString &zip_path)
Sets new path to "zip".
Definition: application.cpp:82
int checkSignApk(const QString &new_path=QString(), const QString &java_path=QString())
Tests if binary in new_path is correct SIGNAPK executable.
QString signApkUtlityPath()
Access to path to "signapk" utility.
Definition: application.h:114