WARNING: USE THIS SOFTWARE AT YOUR OWN RISK! THIS IS EXPERIMENTAL SOFTWARE NOT INTENDED FOR PRODUCTION USE! Zuble is currently an early stage prototype. As such Zuble is minimally tested and inherently unstable. It is provided for experimental, development, and demonstration purposes only. Zuble QML Types   |  Zuble C++ Classes   |  Zuble Overview
Zuble  0.1
Zuble Framework C++/QML extension API
ZApplication.cpp
Go to the documentation of this file.
1 /*
2  * Zuble - A run-time system for QML/Javascript applications
3  * Copyright (C) 2013, 2014 Bob Dinitto
4  *
5  * ZApplication.cpp
6  *
7  * Created on: Feb 3, 2013
8  * Author: Bob Dinitto bob@ninzo.com
9  *
10  * Zuble is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23  *
24 */
25 
26 #include <QDebug>
27 #include <QSettings>
28 #include <QMetaProperty>
29 #include <QApplication>
30 #include <QXmlQuery>
31 #include <QXmlResultItems>
32 #include "ZApplication.h"
33 #include "ZblException.h"
34 #include "ZblThreadErr.h"
35 #include "ZblLogManager.h"
36 #include "ZSettings.h"
37 #include "ZblApp.h"
38 
39 //#include "ZFile.h"
40 #include <QDir>
41 
42 namespace Zbl
43 {
44 
46 
47 ZTextFeed ZApplication::m_status;
48 
49 QList<ZblApp*> ZApplication::m_zappObjects;
50 
51 const QString ZApplication::m_defaultOrganization = "zubleapp";
52 
54 
55 //const QString ZApplication::m_queryProlog =
56 //"declare namespace zset = \"http://zuble.org/schema/zuble/settings\"; ";
57 
58 const QString ZApplication::m_appPathPrefix = "zbl://";
59 
60 const QString ZApplication::m_homePathPrefix = "home://";
61 
62 const QString ZApplication::m_dataPathPrefix = "data://";
63 
64 const QString ZApplication::m_fileUrlPrefix = "file://";
65 
66 const QString ZApplication::m_resourcePathPrefix = "qrc://";
67 
68 const QString ZApplication::m_settingMetadataFileName = "zblsettings.xml";
69 
70 const QString ZApplication::m_settingMetadataInitName = "zblinitset.xml";
71 
72 const QString ZApplication::m_defaultSettingsID = "default";
73 
75 
76 "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
77 "<appsettings\n"
78 "xmlns=\"http://zuble.org/schema/zuble/settings\"\n"
79 "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
80 "xsi:schemaLocation=\"http://zuble.org/schema/zuble/settings zublesettings01.xsd\">\n"
81 "<organization>zuble.org</organization>\n"
82 "<name>Zuble</name>\n"
83 "<setgroups>\n"
84 " <setgroup xml:id=\"zuble\">\n"
85 " <name>Zuble Settings</name>\n"
86 " </setgroup>\n"
87 "</setgroups>\n"
88 "<settings>\n"
89 " <setting xml:id=\"enable-zuble-logging\" group=\"zuble\">\n"
90 " <name>Enable Zuble Logging</name> "
91 " <type>bool</type>\n"
92 " <default>true</default>\n"
93 " <status>\n"
94 " <state value=\"false\">Disabled</state>\n"
95 " <state value=\"true\">Enabled</state>\n"
96 " </status>\n"
97 " <desc>Redirects Qt log messages to Zuble's log manager.</desc>\n"
98 " </setting>\n"
99 " <setting xml:id=\"log-profile-path\" group=\"zuble\">\n"
100 " <name>Log Profile</name>\n"
101 " <type>string</type>\n"
102 " <default>data://log-profiles/default-log-profile.json</default>\n"
103 " <desc>The log profile controls the Zuble application's current logging behavior.</desc>\n"
104 " </setting>\n"
105 " <setting xml:id=\"sync-log-profile\" group=\"zuble\">\n"
106 " <name>Sync Log Profile To Settings</name> "
107 " <type>bool</type>\n"
108 " <default>true</default>\n"
109 " <status>\n"
110 " <state value=\"false\">Disabled</state>\n"
111 " <state value=\"true\">Enabled</state>\n"
112 " </status>\n"
113 " <desc>Current log settings will be synchronized with the log profile.</desc>\n"
114 " </setting>\n"
115 " <setting xml:id=\"log-output-dir\" group=\"zuble\">\n"
116 " <name>Log Output Directory</name>\n"
117 " <type>string</type>\n"
118 " <default>data://log</default>\n"
119 " <desc>Directory where log files will be saved.</desc>\n"
120 " </setting>\n"
121 "</settings>\n"
122 "</appsettings>\n";
123 
124 ZApplication::ZApplication(QObject * parent)
125  : QObject(parent)
126 
127 {
129 
130  zDebug() << "ZApplication::ZApplication";
131 
132 }
133 
135 {
136 
137  zDebug() << "ZApplication::zInit";
138 
139 
140  //QString dataPath(resolvePath(m_dataPathPrefix));
141 
142  //QDir dataDir(QDir::home());
143 
145 
146 }
147 
149 {
150  //static const QString settingMetadataFileName = "zblsettings.xml";
151 
152  // locate XML settings metadata - look in Zuble application dir,
153  // or else use default settings.
154 
155  QString settingSrcPath = getRootPath();
156  settingSrcPath += m_settingMetadataFileName;
157 
158  //bool queryOK = false;
159  bool usingDefault = false;
160 
161  if(!QFile::exists(settingSrcPath))
162  {
163  zDebug() << "Can't find app settings metadata file: " << settingSrcPath;
164 
165  usingDefault = true;
166 
167  QString initSettingsMetaPath(m_dataPathPrefix + m_settingMetadataInitName);
168  initSettingsMetaPath = resolvePath(initSettingsMetaPath, false);
169 
170  QFile initMetafile(initSettingsMetaPath);
171 
172  if(!initMetafile.exists())
173  {
174  zDebug() << "Creating default app settings metadata file...";
175 
176  const QString dataPath(getDataPath());
177 
178  QDir dataDir(dataPath);
179 
180  if(!dataDir.exists())
181  {
182  zDebug() << "Creating Zuble data directory: " << dataDir.path();
183 
184  if(!dataDir.mkpath(dataPath))
185  {
186  zCritical() << "Can't create Zuble data directory";
187 
188  zCritical() << "ABORTING settings initialization!";
189 
190  return false;
191  }
192  }
193 
194  bool fileOK = initMetafile.open(QIODevice::WriteOnly);
195 
196  if(!fileOK)
197  {
198  zDebug() << "Can't initialize settings metafile: "
199  << initSettingsMetaPath
200  << " error message = "
201  << initMetafile.errorString();
202 
203  zCritical() << "ABORTING settings initialization!";
204 
205  return false;
206  }
207  else
208  {
209  qint64 bytesWritten =
210  initMetafile.write(m_defaultZubleAppSettings.toUtf8());
211 
212  if(bytesWritten == -1)
213  {
214  zDebug() << "Can't initialize settings metafile: "
215  << initSettingsMetaPath
216  << " error message = "
217  << initMetafile.errorString();
218 
219  zCritical() << "ABORTING settings initialization!";
220 
221  return false;
222 
223  }
224 
225  initMetafile.close();
226  }
227  }
228 
229  zDebug() << "Using default settings metafile: "
230  << initSettingsMetaPath;
231 
232  settingSrcPath = initSettingsMetaPath;
233  }
234  else
235  {
236  zDebug() << "Using application settings metafile: " << settingSrcPath;
237  }
238 
239 
240  return ZSettings::insertBundle(m_defaultSettingsID, settingSrcPath);
241 
242 }
243 
245 {
246  return m_status;
247 }
248 
249 
251  const QString& prefix,
252  const QString& root,
253  const QString& path,
254  bool includeUrlScheme)
255 {
256  if(path.length() < prefix.length())
257  {
258  return path;
259  }
260  else if(path.startsWith(prefix))
261  {
262  if(includeUrlScheme)
263  {
264  if(hasPathScheme(root))
265  return root + path.mid(prefix.length());
266  else
267  return m_fileUrlPrefix + root + path.mid(prefix.length());
268  }
269  else
270  {
271  return root + path.mid(prefix.length());
272  }
273  }
274  else
275  {
276  return path;
277  }
278 }
279 
280 QString ZApplication::resolvePath( const QString& path,
281  bool includeUrlScheme)
282 {
283  QString ret = path;
284 
285  if(ret.length() < 4)
286  return ret;
287 
288  if(!hasPathScheme(path) && includeUrlScheme)
289  {
290  ret = m_fileUrlPrefix + path;
291  }
292  else if(path.startsWith(m_appPathPrefix))
293  {
295  getRootPath(),
296  path,
297  includeUrlScheme);
298  }
299  else if(path.startsWith(m_homePathPrefix))
300  {
301  QString homePath(QDir::homePath() + "/");
302 
304  homePath,
305  path,
306  includeUrlScheme);
307  }
308  else if(path.startsWith(m_dataPathPrefix))
309  {
311  getDataPath(),
312  path,
313  includeUrlScheme);
314  }
315  else if(path.startsWith(m_resourcePathPrefix))
316  {
318  ":",
319  path,
320  false);
321  }
322 
323 
324  return ret;
325 }
326 
327 QString ZApplication::getPathScheme(const QString& path)
328 {
329  QString ret;
330 
331  const int ixC = path.indexOf(':');
332 
333  if(ixC == -1)
334  return ret;
335 
336  const int ixS = path.indexOf('/');
337 
338  if(ixS != ixC+1)
339  return ret;
340 
341  ret = path.left(ixS+1);
342 
343  return ret;
344 }
345 
346 QString ZApplication::removePathScheme(const QString& path)
347 {
348  QString ret;
349 
350  const int ixC = path.indexOf(':');
351 
352  if(ixC == -1)
353  return ret;
354 
355  const int ixS = path.indexOf('/');
356 
357  if(ixS != ixC+1)
358  return ret;
359 
360  const int pathSize = path.length() - ixS - 1;
361 
362  if(pathSize > 0)
363  ret = path.right(pathSize);
364 
365  return ret;
366 }
367 
368 bool ZApplication::hasPathScheme(const QString& path)
369 {
370  const int ixC = path.indexOf(':');
371 
372  if(ixC == -1)
373  return false;
374 
375  const int ixS = path.indexOf('/');
376 
377  if(ixS != ixC+1)
378  return false;
379 
380  return true;
381 }
382 
383 
385 {
386 #if 0
387  QString orgName = QCoreApplication::organizationName();
388 
389  if(orgName.isEmpty())
390  {
391  return QDir::homePath() + "/."
392  + m_defaultOrganization + "/"
393  + getAppName() + "/";
394 
395  }
396  else
397  {
398  return QDir::homePath() + "/."
399  + orgName + "/"
400  + getAppName() + "/";
401  }
402 #endif
403  return QDir::homePath() + "/."
404  + getOrganization() + "/"
405  + getAppName() + "/";
406 
407 }
408 
410 {
411  QVariant path(qApp->property("org_zuble_appRootPath"));
412 
413  if(path.isValid())
414  return path.toString();
415  else
416  return QString("%1/").arg(QCoreApplication::applicationDirPath());
417 }
418 
420 {
421  QVariant path(qApp->property("org_zuble_appMainQmlPath"));
422 
423  if(path.isValid())
424  return path.toString();
425  else
426  return QString("%1/%2").arg(getRootPath()).arg("main.qml");
427 }
428 
429 
431 {
432  QVariant name(qApp->property("org_zuble_appName"));
433 
434  if(name.isValid())
435  return name.toString();
436  else
437  return QString(qApp->applicationName());
438 }
439 
441 {
442  QString orgName = QCoreApplication::organizationName();
443 
444  if(!orgName.isEmpty())
445  return orgName;
446  else
447  return m_defaultOrganization;
448 }
449 
450 QVariant ZApplication::getAppData(int tag)
451 {
452  QVariant retValue;
453 
454  switch(tag)
455  {
456  case appDirPath:
457  retValue = QCoreApplication::applicationDirPath();
458  break;
459  case appFilePath:
460  retValue = QCoreApplication::applicationFilePath();
461  break;
462  case appName:
463  retValue = QCoreApplication::applicationName();
464  break;
465  case appPid:
466  retValue = QCoreApplication::applicationPid();
467  break;
468  case appVersion:
469  retValue = QCoreApplication::applicationVersion();
470  break;
471  case appArguments:
472  retValue = QCoreApplication::arguments();
473  break;
474  case appLibraryPath:
475  retValue = QCoreApplication::libraryPaths();
476  break;
477 
478  default:
479 
480  zThreadErr.raiseError("ZApplication::getAppData - invalid data key: " + tag);
481  }
482 
483  return retValue;
484 
485 }
486 
487 QString ZApplication::getObjectThreadAddress(QObject* object)
488 {
489  char threadID[50];
491  if(!object)
492  {
493  sprintf(threadID, "<null object>");
494  }
495  else
496  {
497  QThread* pThread = object->thread();
498  sprintf(threadID, "%p", pThread);
499  }
500  ZBL_SLOT_END_RETURN(QString(threadID), QString("<Thread ID Error>"),
502 }
503 
505 {
506  char threadID[50];
508  QThread* pThread = QThread::currentThread();
509  sprintf(threadID, "%p", pThread);
510  ZBL_SLOT_END_RETURN(QString(threadID), QString("<Thread ID Error>"),
512 }
513 
514 void ZApplication::debugObjectThreadAddress(const char* label, QObject* obj)
515 {
516  qDebug() << label << " OBJECT THREAD: " << getObjectThreadAddress(obj);
517 }
518 
520 {
521  qDebug() << label << " CURRENT THREAD: " << getCurrentThreadAddress();
522 }
523 
524 void ZApplication::debugGuiThreadAddress(const char* label)
525 {
526  qDebug() << label << " GUI THREAD: " << getObjectThreadAddress(qApp);
527 }
528 
529 void ZApplication::debugCompareThreadAddress(const char* label, QObject* obj)
530 {
532 
533  debugObjectThreadAddress(label, obj);
534 
535  debugGuiThreadAddress(label);
536 }
537 
539 {
540  if(inObjectThread(this))
541  {
542  if(!m_zappObjects.contains(appObject))
543  {
544  m_zappObjects.append(appObject);
545 
546  //connect(this, &ZApplication::settingsBundleAvailable,
547  // appObject, &ZblApp::settingsBundleAvailable);
548  }
549 
550  }
551  else
552  {
553  QMetaObject::invokeMethod(this,"addThreadApp",
554  Qt::QueuedConnection,
555  Q_ARG(ZblApp*, appObject));
556  }
557 
558 }
559 
561 {
562  if(inObjectThread(this))
563  {
564  int ix = m_zappObjects.indexOf(appObject);
565 
566  if(ix != -1)
567  {
568  //disconnect(this, &ZApplication::settingsBundleAvailable,
569  // appObject, &ZblApp::settingsBundleAvailable);
570 
571  m_zappObjects.removeAt(ix);
572  }
573 
574  }
575  else
576  {
577  QMetaObject::invokeMethod(this,"removeThreadApp",
578  Qt::BlockingQueuedConnection,
579  Q_ARG(ZblApp*, appObject));
580  }
581 
582 }
583 
584 
585 } // Zbl
static const QString m_settingMetadataInitName
Name of default settings metadata file in user&#39;s home directory, created if no metadata file found in...
Definition: ZApplication.h:423
static const QString m_defaultSettingsID
The Zuble application settings application name.
Definition: ZApplication.h:403
static ZTextFeed m_status
The main application status text feed.
Definition: ZApplication.h:383
static QString getAppName()
Obtains the name of the Zuble application.
static QString getPathScheme(const QString &path)
Obtains the scheme part of a URL path.
static void debugCompareThreadAddress(const char *label, QObject *obj)
Sends both current thread address and object&#39;s thread address to qDebug.
static const QString m_settingMetadataFileName
Name of default settings metadata file in Zuble application directory.
Definition: ZApplication.h:416
#define Z_FAC_JS
Definition: zglobal.h:123
void removeThreadApp(ZblApp *appObject)
Removes the specified ZblApp object from the list of running thread applications. ...
This class provides a means of directing a text stream to listeners.
Definition: ZTextFeed.h:50
static const QString m_fileUrlPrefix
URL scheme used to specify local file location: "file://".
Definition: ZApplication.h:358
#define ZBL_REGISTER_LOGGED_OBJECT
Definition: zglobal.h:104
static const QString m_dataPathPrefix
URL scheme used to specify user&#39;s Zuble data directory location: "data://".
Definition: ZApplication.h:352
static QString getDataPath()
Obtains the canonical path to the Zuble application&#39;s data directory.
static QString getOrganization()
Obtains the organization of the Zuble application.
static const QString m_defaultApplication
The Zuble application default application name.
Definition: ZApplication.h:397
static const QString m_appPathPrefix
URL scheme used to specify Zuble app directory location: "zbl://".
Definition: ZApplication.h:340
static const QString m_resourcePathPrefix
URL scheme used to specify Qt binary resource location: "qrc://".
Definition: ZApplication.h:364
static const QString m_defaultOrganization
The Zuble application default organization name, "zuble".
Definition: ZApplication.h:391
static QString getMainQmlPath()
Obtains the canonical path to the Zuble application&#39;s main QML file.
static const QString m_homePathPrefix
URL scheme used to specify user&#39;s home directory location: "home://".
Definition: ZApplication.h:346
static const QString m_defaultZubleAppSettings
Settings metadata to use when no other settings data can be found.
Definition: ZApplication.h:409
static void debugCurrentThreadAddress(const char *label)
Sends current thread address to qDebug.
Q_INVOKABLE QVariant getAppData(int tag)
Obtains application object data for background threads.
void addThreadApp(ZblApp *appObject)
Adds the specified ZblApp object to the list of running thread applications.
Definition: ZAndGate.cpp:6
#define ZBL_SLOT_BEGIN_TRY
Definition: zglobal.h:128
#define ZBL_DEFINE_LOGGED_OBJECT(class_name)
Definition: zglobal.h:99
#define zThreadErr
where does this show up?
Definition: ZblThreadErr.h:39
bool initDefaultApplicationSettings()
Checks the Zuble application directory for a settings metafile and uses it if found. Otherwise checks for a default settings metafile, creates a default metafile if that doesn&#39;t exist, and uses the default metafile instead.
ZTextFeed & zStatus()
Obtains Zuble&#39;s main status text feed. Output text sent to this feed is broadcast to all Zuble status...
The primary QML API to the Zuble plugin library. Zuble applications access this object through the ja...
Definition: ZblApp.h:81
#define zDebug()
Definition: zglobal.h:113
static QString getObjectThreadAddress(QObject *object)
Returns the human-readable memory address of the specified object&#39;s thread.
static QString resolvePath(const QString &path, bool includeUrlScheme=true)
Converts relative file paths into canonical file paths. Paths prefixed with prefix are mapped relativ...
bool inObjectThread(const QObject &object)
Definition: zglobal.h:173
Zuble&#39;s Singleton Application Object.
Definition: ZApplication.h:54
ZApplication(QObject *parent=nullptr)
Don&#39;t construct this. Use zInit and zInstance instead.
static QString getCurrentThreadAddress()
Returns the human-readable memory address of the current thread.
static void debugObjectThreadAddress(const char *label, QObject *obj)
Sends object&#39;s thread address to qDebug.
static QString getRootPath()
Obtains the canonical path to the Zuble application&#39;s root directory.
bool zInit()
Initializes the application settings from information in the Zuble application&#39;s settings metadata fi...
static QList< ZblApp * > m_zappObjects
Definition: ZApplication.h:369
static bool insertBundle(const QString &id, const QString &metaPath, QSettings::Scope scope=QSettings::UserScope, const QString organization=QString(), const QString application=QString())
Adds the specified settings bundle to the settings repository.
Definition: ZSettings.cpp:530
static void debugGuiThreadAddress(const char *label)
Sends QApplication&#39;s thread address to qDebug.
#define ZBL_SLOT_END_RETURN(return_success, return_failed, facility, code, error_message)
Definition: zglobal.h:141
#define zCritical()
Definition: zglobal.h:112
static bool hasPathScheme(const QString &path)
Determines if a URL contains a scheme.
static QString removePathScheme(const QString &path)
Removes the scheme part from a URL path.