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
main.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 * Filename: main.cpp
6 * Created on: 11/9/2014
7 * Author: Bob Dinitto
8 *
9 * Zuble is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 *
23 */
24 
25 #include <QtWidgets/QApplication>
26 #include <QQmlEngine>
27 #include <QQmlContext>
28 #include <QDir>
29 #include <QXmlSchema>
31 
32 #include <QDebug>
33 #include <QPluginLoader>
34 #include <QQmlExtensionPlugin>
35 #include <QJsonObject>
36 #include <QJsonValue>
37 #include <QJsonArray>
38 #include <QJsonDocument>
39 #include <QObject>
40 #include <QProcessEnvironment>
41 //#include "Zblcore.h"
42 #include "ZResourceEdifyIF.h"
43 
44 void showAppStructureMessage(const char* appName);
45 bool validateXMLDoc(const QString& schemaUrl, const QString& docUrl);
46 void dumpPathList(const QStringList& list);
47 void dumpResourceSpace(QString path);
48 
49 bool loadZubleConfiguration(const QString& configFilePath);
50 
51 void dumpJsonObject(QJsonObject jsonObject);
52 void dumpJsonValue(const QString& key, QJsonValue& jsonValue);
53 void dumpJsonArray(QJsonArray jsonArray);
54 void dumpEnv(const char* name);
55 QString getEnv(const char* name);
56 void addPath(const QString& prefix, const QString& path, QStringList& pathList);
57 void addImportPath(const QString& prefix, const QString& path, QQmlEngine* engine);
58 
59 static int versionMajor = 0;
60 static int versionMinor = 1;
61 static int versionPatch = 0;
62 static QString versionBuild = "prototype-91";
63 
64 
65 int main(int argc, char *argv[])
66 {
67  qDebug("starting...");
68 
69  dumpResourceSpace(":/");
70 
71  dumpEnv("HOME");
72  dumpEnv("LD_LIBRARY_PATH");
73  dumpEnv("SNAP");
74  dumpEnv("SNAP_ARCH");
75  dumpEnv("SNAP_DATA");
76  dumpEnv("SNAP_LIBRARY_PATH");
77  dumpEnv("SNAP_NAME");
78  dumpEnv("SNAP_REVISION");
79  dumpEnv("SNAP_USER_DATA");
80  dumpEnv("SNAP_VERSION");
81  dumpEnv("TMPDIR");
82 
83  QApplication* app = new QApplication(argc, argv);
84 
85  qDebug("library paths: ");
86 
87  dumpPathList(QCoreApplication::libraryPaths());
88 
89  //qDebug("Added library path: %s", pluginPath.toUtf8().constData());
90 
91 
93 
94  //QObject::connect(&libraryviewer, SIGNAL(statusChanged(QQuickView::Status)),
95  // app, SLOT(onViewStatusChanged(QQuickView::Status)));
96 
97 
98  QQmlEngine* engine = viewer.engine();
99 
100  bool snapApp = true;
101 
102  QString zAppDirPath ;
103 
104  QString installPrefix(getEnv("SNAP"));
105  if(installPrefix.isEmpty())
106  {
107  installPrefix = QCoreApplication::applicationDirPath();
108  installPrefix += "/../";
109  installPrefix = QDir::cleanPath(installPrefix);
110  zAppDirPath = installPrefix + "/apps";
111 
112  snapApp = false;
113  }
114  else
115  {
116  installPrefix += "/opt/zbl";
117  zAppDirPath = installPrefix + "/apps";
118  }
119  qDebug("Install prefix: %s", installPrefix.toUtf8().constData());
120  qDebug("Zuble app directory: %s", zAppDirPath.toUtf8().constData());
121 
122  QStringList libPaths;
123 
124  if(snapApp)
125  libPaths = QCoreApplication::libraryPaths();
126 
127 
128  addPath(installPrefix, "/lib", libPaths);
129  addPath("",".", libPaths);
130 
131  QCoreApplication::setLibraryPaths(libPaths);
132  engine->setPluginPathList(libPaths);
133 
134  engine->addImportPath("qrc:/"); // exposes /org/zuble/qml/qmldir to QML
135 
136  addImportPath(installPrefix, "/lib", engine); // exposes Zuble plugins to QML
137 
138  qDebug("Dumping library paths...");
139  libPaths = QCoreApplication::libraryPaths();
140  dumpPathList(libPaths);
141 
142  qDebug("Dumping plugin paths...");
143  libPaths = engine->pluginPathList();
144  dumpPathList(libPaths);
145  int retvalue = -1;
146 
147  try
148  {
149  QUrl sourceUrl; // ultimate location of main.qml file
150  QString zblmainPath("qrc:/org/zuble/qml/frames/zblmain.qml"); // zbl hosted main qml file
151  QString title("I Am Zuble");
152  bool zblHostedApp = true;
153 
154  QString zAppName;
155 
156  // get the specific directory for this application
157 
158  QString zAppMainQmlFilePath;
159 
160  if(argc < 2 )
161  {
162  // no args so run stand-alone zbl app
163 
164  sourceUrl.setUrl(zblmainPath);
165  zAppDirPath += "/zbl/";
166  zAppName = "zbl";
167  }
168  else
169  {
170  const char* arg1 = argv[1];
171 
172  if(arg1[0] == '-')
173  {
174  // first arg is option flag so run stand-alone zbl app
175 
176  sourceUrl.setUrl(zblmainPath);
177  zAppDirPath += "/zbl/";
178  zAppName = "zbl";
179  }
180  else
181  {
182  // first arg is zuble app name so run named app
183 
184  zAppDirPath += "/";
185  zAppDirPath += arg1;
186  zAppName = arg1;
187 
188  QFileInfo appDirInfo(zAppDirPath);
189 
190  if(!appDirInfo.exists())
191  {
192  // app directory is missing!
193 
194  qCritical("ERROR: Zuble application directory doesn't exist: %s",
195  zAppDirPath.toUtf8().constData());
196 
198 
199  qFatal("Zuble aborting...!");
200 
201  }
202  else if(!appDirInfo.isDir())
203  {
204  // specified app should be a subdirectory of zuble apps directory!
205 
206  qCritical("ERROR: Specified Zuble application is not a directory type file: %s",
207  zAppDirPath.toUtf8().constData());
208 
210 
211  qFatal("Zuble aborting...!");
212  }
213 
214  zAppDirPath += "/";
215 
216  zAppMainQmlFilePath = zAppDirPath;
217  zAppMainQmlFilePath += "main.qml";
218 
219  if(QFile::exists(zAppMainQmlFilePath))
220  {
221  // main.qml file exists so run named app stand-alone
222 
223  sourceUrl.setUrl(zAppMainQmlFilePath);
224  zblHostedApp = false;
225  }
226  else
227  {
228  // no main.qml file so run named app in zbl
229 
230  sourceUrl.setUrl(zblmainPath);
231  title = "Zuble: ";
232  title += zAppName;
233  }
234  }
235  }
236 
237  engine->addImportPath(zAppDirPath);
238 
239 #if 0
240  //TBD: XML validation too slow for normal program startup,
241  // use MD5 checksum stored in application settings to determine
242  // when this should be performed.
243  if(zblHostedApp)
244  {
245  QString zAppConfigFilePath(zAppDirPath);
246  zAppConfigFilePath += "zblconfig.xml";
247 
248  bool bValidConfig = validateXMLDoc(
249  "qrc:///schema/zblconfig.xsd",
250  zAppConfigFilePath);
251 
252  if(!bValidConfig)
253  qDebug("Invalid zblconfig.xml file!");
254  }
255 #endif
256 
257  // initialize the application settings
258 
259  QCoreApplication::setOrganizationName("zuble"); // org name
260  QCoreApplication::setOrganizationDomain("zuble.org"); // org domain
261  QCoreApplication::setApplicationName(zAppName); // app name
262 
263  // exposes application directory to QML
264 
265  qApp->setProperty("org_zuble_appName",
266  QVariant(zAppName));
267 
268  qApp->setProperty("org_zuble_appRootPath",
269  QVariant(zAppDirPath));
270 
271  if(zAppMainQmlFilePath.isEmpty())
272  qApp->setProperty("org_zuble_appMainQmlPath",
273  QVariant(zblmainPath));
274  else
275  qApp->setProperty("org_zuble_appMainQmlPath",
276  QVariant(zAppMainQmlFilePath));
277 
278  // set Zuble identity properties
279 
280 
281  qApp->setProperty("org_zuble_host_name",
282  QVariant("zbl"));
283 
284  qApp->setProperty("org_zuble_host_versionMajor",
285  QVariant(versionMajor));
286 
287  qApp->setProperty("org_zuble_host_versionMinor",
288  QVariant(versionMinor));
289 
290  qApp->setProperty("org_zuble_host_versionPatch",
291  QVariant(versionPatch));
292 
293  qApp->setProperty("org_zuble_host_versionBuild",
294  QVariant(versionBuild));
295 
296  QVariant appRootPath(qApp->property("org_zuble_appRootPath"));
297 
298  qDebug("Root path property on QApplication = %s",
299  appRootPath.toString().toUtf8().constData());
300 
301  qDebug("Dumping import paths...");
302 
303  QStringList importPathList = engine->importPathList();
304 
305  dumpPathList(importPathList);
306 
307  if(zblHostedApp)
308  {
309  QString zAppConfigFilePath(zAppDirPath);
310  zAppConfigFilePath += "zblconfig.xml";
311 
312  loadZubleConfiguration(zAppConfigFilePath);
313 
314  // debug
315 
316  qDebug("Dumping resource space...");
317 
318  dumpResourceSpace(":/org/zuble/qml");
319 
320  qDebug("End dumping resource space...");
321  }
322 
323  viewer.setTitle(title);
324  viewer.setSource(sourceUrl);
325  viewer.showExpanded();
326 
327  retvalue = qApp->exec();
328 
329  //delete qApp;
330  }
331  catch(...)
332  {
333  qDebug("Zuble QML exception caught...!");
334 
335  retvalue = -1;
336 
337  }
338  qDebug("ending...");
339 
340  return retvalue;
341 }
342 
343 
344 
345 bool loadZubleConfiguration(const QString& configFilePath)
346 {
347 
348  // if(hasArg("-zl"))
349  // logging = "on";
350  //
351  // registerConfigSettingsBundles
352  // if(logprofile)
353  // use it;
354  // else
355  // use default log profile;
356 
357  qDebug("Loading Zuble core plugin resources...");
358 
359  bool status = false;
360 
361  static const QString corePluginName = "libzblcore";
362 
363  QPluginLoader loader;
364 
365  loader.setFileName(corePluginName);
366 
367  if(!loader.load())
368  {
369  qWarning() << "Zuble failed to load core plugin: " << loader.errorString();
370  return status;
371  }
372 
373  Zbl::ZResourceEdifyIF* plugin =
374  qobject_cast<Zbl::ZResourceEdifyIF*>(loader.instance());
375 
376 
377  if(!plugin)
378  {
379  qWarning() << "Zuble core ERROR, core plugin doesn't implement ZResourceEdifyIF";
380 
381  return status;
382  }
383 
384  status = plugin->mapPluginResources(corePluginName.toUtf8(), true);
385 
386  if(!status)
387  {
388  qWarning() << "Zuble FAILED to locate and register core binary "
389  "resource files.";
390 
391  return status;
392  }
393 
394  qDebug("Loading application resources...");
395 
396 
397  status = plugin->mapConfigResources(configFilePath.toUtf8());
398 
399  if(!status)
400  {
401  qWarning() << "Zuble FAILED to locate and register application's "
402  "binary resource files.";
403 
404  return status;
405  }
406 
407  qDebug("Done loading application resources.");
408 
409  qDebug("Mapping application settings bundles.");
410 
411  status = plugin->mapConfigSettings(configFilePath.toUtf8());
412 
413  if(!status)
414  {
415  qWarning() << "Zuble FAILED to map applicaiton settings bundles.";
416  }
417 
418  qDebug("Done mapping application settings bundles.");
419 
420 
421  return status;
422 
423 }
424 
425 void dumpJsonObject(QJsonObject jsonObject)
426 {
427  QJsonDocument doc(jsonObject);
428 
429  QByteArray ba = doc.toJson();
430 
431  qDebug("%s", ba.constData());
432 
433  return;
434 
435 }
436 
437 void dumpJsonValue(const QString& key, QJsonValue& jsonValue)
438 {
439  QString stringValue;
440  QJsonArray emptyArray;
441 
442  switch(jsonValue.type())
443  {
444 
445  case QJsonValue::Null:
446  stringValue = "null";
447  break;
448  case QJsonValue::Bool:
449  if(jsonValue.toBool())
450  stringValue = "true";
451  else
452  stringValue = "false";
453  break;
454  case QJsonValue::Double:
455  stringValue = QString::number(jsonValue.toDouble());
456  break;
457  case QJsonValue::String:
458  stringValue = jsonValue.toString();
459  break;
460  case QJsonValue::Array:
461  dumpJsonArray(jsonValue.toArray(emptyArray));
462  return;
463  case QJsonValue::Object:
464  dumpJsonObject(jsonValue.toObject());
465  return;
466  case QJsonValue::Undefined:
467  stringValue = "undefined";
468  break;
469  };
470 
471  qDebug("METADATA %s=%s",
472  key.toUtf8().constData(),
473  stringValue.toUtf8().constData());
474 
475 }
476 
477 void dumpJsonArray(QJsonArray jsonArray)
478 {
479  qDebug("[");
480 
481  QString emptyKey;
482 
483  QJsonArray::const_iterator it(jsonArray.constBegin());
484 
485  while(it != jsonArray.constEnd())
486  {
487  QJsonValue jVal = *it;
488  dumpJsonValue(emptyKey, jVal);
489  it++;
490  }
491  qDebug("]");
492 
493 }
494 
495 
496 
497 void showAppStructureMessage(const char* appName)
498 {
499  qCritical("ERROR: Zuble application should be a subdirectory named \"%s\" "
500  "within the zuble apps directory, containing "
501  "either a main.qml or zblconfig.xml file.", appName);
502 }
503 
504 bool validateXMLDoc(const QString& schemaUrl, const QString& docUrl)
505 {
506  QUrl schemaURL(schemaUrl);
507  QXmlSchema schema;
508  QUrl docURL(docUrl);
509 
510  bool status = schema.load(schemaURL);
511 
512  return status;
513 
514 }
515 
516 void dumpPathList(const QStringList& list)
517 {
518  const int len = list.length();
519 
520  for(int i=0; i < len; i++)
521  {
522  qDebug("path: %s", list.at(i).toUtf8().constData() );
523  }
524 
525 }
526 
527 void dumpResourceSpace(QString path)
528 {
529  QDir dir(path);
530 
531  QStringList list = dir.entryList(QStringList());
532 
533  int count = list.count();
534 
535  for(int i=0; i<count; i++)
536  {
537  qDebug("resource: %s", list.at(i).toUtf8().data());
538  }
539 }
540 
541 void dumpEnv(const char* name)
542 {
543  char* value;
544 
545  value = getenv(name);
546 
547  if(value)
548  qDebug("env %s=%s", name, value);
549  else
550  qDebug("env %s=", name);
551 
552 }
553 
554 QString getEnv(const char* name)
555 {
556  char* value;
557 
558  value = getenv(name);
559 
560  if(value)
561  return QString(value);
562  else
563  return QString();
564 }
565 
566 void addPath(const QString& prefix, const QString& path, QStringList& pathList)
567 {
568  QString tempPath("%1%2");
569  tempPath = tempPath.arg(prefix).arg(path);
570 
571  qDebug("Adding path: %s", tempPath.toUtf8().constData());
572 
573  pathList.append(tempPath);
574 }
575 
576 void addImportPath(const QString& prefix, const QString& path, QQmlEngine* engine)
577 {
578  QString tempPath("%1%2");
579  tempPath = tempPath.arg(prefix).arg(path);
580 
581  qDebug("Adding import path: %s", tempPath.toUtf8().constData());
582 
583  engine->addImportPath(tempPath);
584 }
QString getEnv(const char *name)
Definition: main.cpp:554
void dumpJsonValue(const QString &key, QJsonValue &jsonValue)
Definition: main.cpp:437
bool validateXMLDoc(const QString &schemaUrl, const QString &docUrl)
Definition: main.cpp:504
void addImportPath(const QString &prefix, const QString &path, QQmlEngine *engine)
Definition: main.cpp:576
void dumpResourceSpace(QString path)
Definition: main.cpp:527
void dumpEnv(const char *name)
Definition: main.cpp:541
static QString versionBuild
Definition: main.cpp:62
virtual bool mapPluginResources(const char *fileName, bool qmlRegister)=0
void addPath(const QString &prefix, const QString &path, QStringList &pathList)
Definition: main.cpp:566
static int versionMinor
Definition: main.cpp:60
void dumpJsonArray(QJsonArray jsonArray)
Definition: main.cpp:477
void dumpJsonObject(QJsonObject jsonObject)
Definition: main.cpp:425
void showAppStructureMessage(const char *appName)
Definition: main.cpp:497
static int versionMajor
Definition: main.cpp:59
bool loadZubleConfiguration(const QString &configFilePath)
Definition: main.cpp:345
void dumpPathList(const QStringList &list)
Definition: main.cpp:516
virtual bool mapConfigResources(const char *configFilePath)=0
int main(int argc, char *argv[])
Definition: main.cpp:65
virtual bool mapConfigSettings(const char *fileName)=0
This interface allows Qt applications to access Zuble&#39;s platform-independent binary resource manageme...
static int versionPatch
Definition: main.cpp:61