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
ZSettings.cpp
Go to the documentation of this file.
1 /*
2  * Zuble - A run-time system for QML/Javascript applications
3  * Copyright (C) 2015 Bob Dinitto
4  *
5  * Filename: ZSettings.cpp
6  * Created on: 5/16/2015
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 "ZSettings.h"
26 #include "ZApplication.h"
27 #include <QtQml>
28 #include <QJsonDocument>
29 //#include <QXmlQuery>
30 #include "ZxQuery.h"
31 #include "ZFileSystemWatcher.h"
32 #include "ZblApp.h" // debug
33 
34 
35 namespace Zbl
36 {
37 
39 
40 const QString ZSettings::m_ext = "zbl";
41 
42 QSettings::Format ZSettings::m_format = QSettings::InvalidFormat;
43 
44 QVariant ZSettings::m_tags;
45 
46 qint64 ZSettings::m_maxFileSize = 1024 * 1000;
47 
49 
50 ZFileSystemWatcher* ZSettings::m_watcher = nullptr;
51 
52 
53 ZSettings::ZSettings(QObject *parent) :
54  QObject(parent), m_s(nullptr), m_watching(false)
55 {
56  //zDebug() << "ZSettings::ZSettings";
57 
58  if(!m_watcher)
59  {
60  m_format = QSettings::registerFormat(m_ext, readFunc, writeFunc);
62 
63  // Because QSettings deletes/recreates files on Linux
65  }
66 
67  QMetaObject::Connection connection = connect(m_watcher,
69 
70  if(!connection)
71  zCritical() << "Settings object watcher connection failed.";
72 }
73 
75 {
76  //zDebug() << "ZSettings::~ZSettings";
77  if(m_watching)
78  setFileWatcher(false);
79 }
80 
81 
83 {
84 
85  qmlRegisterType<ZSettings>("org.zuble.qml", 1, 0, "ZSettings");
86 }
87 
88 void ZSettings::onFileChanged(const QString &path)
89 {
90  zDebug() << "SETTINGS FILE MODIFIED SIGNAL FOR THREAD:" <<
92  " PATH=" << path;
93 
94  if(path == m_s->fileName())
95  {
96  zDebug() << "EMITTING SETTINGS FILE MODIFIED! PATH=" << m_s->fileName();
97  m_s->sync();
98  emit settingsModified(path);
99  }
100  else
101  {
102  zDebug() << "NOT MODIFIED! ACTUAL PATH=" << m_s->fileName();
103  }
104 
105  zDebug() << "DUMPING FILE WATCHER PATHS: ";
106  foreach( QString path, m_watcher->files())
107  {
108  zDebug() << path;
109  }
110 
111 }
112 
114 {
116 
117  createTags();
118 }
119 
121 {
122  if(!m_tags.isNull())
123  return;
124 
125  QVariantMap map;
126 
127  map.insert("UserScope", QSettings::UserScope);
128  map.insert("SystemScope", QSettings::SystemScope);
129 
130  map.insert("NoError", QSettings::NoError);
131  map.insert("AccessError", QSettings::AccessError);
132  map.insert("FormatError", QSettings::FormatError);
133 
134  m_tags = QVariant::fromValue(map);
135 }
136 
138 {
139  return m_tags;
140 }
141 
142 QString ZSettings::getFileName() const
143 {
144  QString ret;
145 
147  validateStatus();
148 
149  if(!m_s)
150  {
151  zWarning() << "ZSettings::getFileName - WARNING: settings object not opened.";
152  }
153  else
154  {
155  ret = m_s->fileName();
156  }
157 
158  return m_s->fileName();
159  ZBL_SLOT_END_RETURN(ret, ret,
161 }
162 
163 
164 bool ZSettings::readFunc(QIODevice &device, QSettings::SettingsMap &map)
165 {
166  //zDebug() << "readFunc enetered";
167 
168  dumpMap(map);
169 
170  // device -> QByteArray
171 
172  // should we test for error conditions?
173 
174  QByteArray bytes = device.read(m_maxFileSize);
175 
176  // should we test for error conditions?
177 
178  if(bytes.isNull() || bytes.isEmpty())
179  {
180  zWarning() << "ZSettings::readFunc - can't read from settings device.";
181  return true; // TBD: should return false here?
182  //return false;
183  }
184 
185  // QByteArray -> doc
186 
187  QJsonParseError error;
188  QJsonDocument doc(QJsonDocument::fromJson(bytes, &error));
189 
190  if(doc.isNull() || error.error != QJsonParseError::NoError)
191  {
192  zCritical() << "ZSettings::readFunc - ERROR parsing JSON file: "
193  << error.errorString();
194 
195  return false;
196  }
197 
198 
199  // doc -> map
200 
201  QVariant vMap(doc.toVariant());
202 
203  map = vMap.toMap();
204 
205  // TBD: test document integrity here?
206  // should we test for error conditions?
207 
208 
209  return true;
210 }
211 
212 bool ZSettings::writeFunc(QIODevice &device, const QSettings::SettingsMap &map)
213 {
214  zDebug() << "ZSettings::writeFunc enetered";
215 
216  dumpMap(map);
217 
218  // map -> doc
219 
220  // TBD: check for valid qvariant?
221 
222  QVariant vMap(map);
223 
224  QJsonDocument doc(QJsonDocument::fromVariant(vMap));
225 
226  // doc -> QByteArray
227 
228  QByteArray bytes(doc.toJson());
229 
230  // QByteArray -> device
231 
232  qint64 status = device.write(bytes);
233 
234  if(status == -1)
235  {
236  zCritical() << "ZSettings::writeFunc - an error occurred writing to "
237  "the settings device: " << device.errorString();
238 
239  return false;
240  }
241 
242 
243  return true;
244 
245 }
246 
247 void ZSettings::dumpMap(const QSettings::SettingsMap &map)
248 {
249  QList<QString> keys;
250 
251  keys = map.keys();
252 
253  zDebug() << "ZSettings begin dumping map...";
254 
255  for(int i=0; i<keys.count(); i++)
256  {
257  QString key(keys.at(i));
258  QVariant value(map.value(key));
259 
260  zDebug() << "value type is: " << value.typeName();
261 
262  if(value.type() == QVariant::Map)
263  {
264  dumpGroup(key,value);
265 
266  }
267  else
268  {
269  zDebug() << "key=" << key << ", value=" << value.toString();
270  }
271  }
272 
273  zDebug() << "ZSettings end dumping map.";
274 
275 }
276 
277 void ZSettings::dumpGroup(const QString& groupKey, const QVariant& group)
278 {
279  zDebug() << "begin group " + groupKey;
280 
281  QVariantMap map = group.toMap();
282 
283  QList<QString> keys = map.keys();
284 
285  for(int i=0; i<map.count(); i++)
286  {
287  QString key(keys.at(i));
288  QVariant value(map.value(key));
289 
290  if(value.type() == QVariant::Map)
291  {
292  dumpGroup(key, value);
293 
294  }
295  else
296  {
297  zDebug() << "key=" << key << ", value=" << value.toString();
298  }
299  }
300  zDebug() << "end group " + groupKey;
301 
302 }
303 
305  const QString& application,
306  const QString& organization)
307 {
308  QSettings::Scope scp = QSettings::Scope(scope);
309 
310  if(m_s != nullptr)
311  {
312  zWarning() << "Programming error: object is already opened.";
313 
314  return false;
315  }
316 
317  if(scp != QSettings::UserScope && scp != QSettings::SystemScope)
318  {
319  zWarning() << "Invalid scope: " << scope
320  << " opening settings in User scope...";
321 
322  scp = QSettings::UserScope;
323  }
324 
326 
327  QString org;
328 
329  if(organization.isEmpty())
330  org = QCoreApplication::organizationName();
331  else
332  org = organization;
333 
334  QString app;
335 
336  if(application.isEmpty())
337  app = QCoreApplication::applicationName();
338  else
339  app = application;
340 
341  //zDebug() << "Opening settings file for organization: "
342  // << org << ", application: " << app;
343 
344  m_s = new QSettings(m_format, scp, org, app, this);
345 
346  QString filePath = m_s->fileName();
347 
348  ensureFileExists(filePath);
349 
350  //m_s->sync();
351 
352 #if 0
353 
355 
356  //QString filePath = m_s->fileName();
357 
358  //zDebug() << "Settings filename = " << filePath;
359 
360  if(QFile::exists(filePath))
361  {
362  //zDebug() << "settings file exists";
363  }
364  else
365  {
366  //zDebug() << "settings file DOES NOT exist";
367 
368  }
369 #endif
370 
371 
373 
374  if(!validateOpen())
375  {
376  zCritical() << "Failed to open organization: "
377  << org << ", application: " << app;
378 
379  throw ZblException("Can't open settings.");
380  }
381 
382  ZBL_SLOT_END_RETURN(true, false,
383  Z_FAC_JS, ZSettings::open, open failed)
384 }
385 
386 bool ZSettings::setFileWatcher(bool enabled)
387 {
388  validateWatcher();
389  bool ret = false;
390 
391  if(enabled && !m_watching)
392  {
393  ret = m_watcher->addPath(m_s->fileName());
394  if(ret) //TBD: report failure?
395  m_watching = true;
396  }
397  else if(!enabled && m_watching)
398  {
399  ret = m_watcher->removePath(m_s->fileName()); // TBD: report failure?
400  m_watching = false;
401  }
402  return ret;
403 }
404 
405 
406 bool ZSettings::ensureFileExists(const QString& filePath)
407 {
408  if(QFile::exists(filePath))
409  {
410  zDebug() << "Settings file exists: " << filePath;
411  return true;
412  }
413 
414  // TBD: check for and create lock file first - or block waiting for lock file!
415 
416  QFile file(filePath);
417 
418  bool status = file.open(QIODevice::WriteOnly | QIODevice::Text);
419 
420  if(!status)
421  {
422  zWarning() << "Can't open empty settings file: " << filePath
423  << " -- Error message: " << file.errorString();
424  return false;
425  }
426 
427  QString emptyJSONObject("{}");
428 
429  qint64 bytesOut = file.write(emptyJSONObject.toUtf8());
430 
431  if(bytesOut == -1)
432  {
433  zWarning() << "Can't write to empty settings file: " << filePath
434  << " -- Error message: " << file.errorString();
435  return false;
436  }
437 
438  file.flush();
439 
440  file.close();
441 
442 
443  if(QFile::exists(filePath))
444  {
445  zDebug() << "Created empty settings file: " << filePath;
446 
447  return true;
448  }
449  else
450  {
451  zDebug() << "FAILED to create empty settings file: " << filePath;
452  return false;
453  }
454 }
455 
456 
457 bool ZSettings::open(const QString& filePath)
458 {
459  if(m_s != nullptr)
460  {
461  zWarning() << "Programming error: object is already opened.";
462 
463  return false;
464  }
465 
467 
468  QString realPath(ZApplication::resolvePath(filePath, false));
469 
470  //zDebug() << "Opening settings file: " << realPath;
471 
472  if(realPath.isEmpty())
473  throw ZblException("Can't open empty settings file path.");
474 
475  m_s = new QSettings(realPath, m_format, this);
476 
477  if(!validateOpen())
478  {
479  zCritical() << "Failed to open settings file: "
480  << realPath;
481 
482  throw ZblException("Can't open settings.");
483  }
484 
485  ZBL_SLOT_END_RETURN(true, false,
486  Z_FAC_JS, ZSettings::open, open failed)
487 }
488 
489 
490 bool ZSettings::open(const SettingsBundle& settingsBundle)
491 {
492  if(!settingsBundle.m_dataPath.isEmpty())
493  return open(settingsBundle.m_dataPath);
494  else
495  return open(settingsBundle.m_scope, settingsBundle.m_application,
496  settingsBundle.m_organization);
497 }
498 
500 {
501  QString filePath = m_s->fileName();
502 
503  QSettings::Status status = m_s->status();
504 
505  if(status != QSettings::NoError)
506  {
507 
508  if(status == QSettings::AccessError)
509  zCritical() << "ERROR: Can't access settings file: " << filePath;
510  else if(status == QSettings::FormatError)
511  zCritical() << "ERROR: Settings file has invalid format: " << filePath;
512  else
513  zCritical() << "ERROR: Unknown failure type from QSettings: " << filePath;
514 
515  m_s->deleteLater();
516 
517  m_s = nullptr;
518 
519  return false;
520  }
521 
522  return true;
523 }
524 
525 bool ZSettings::containsBundle(const QString& id)
526 {
527  return m_bundles.contains(id);
528 }
529 
531  const QString& id,
532  const QString& metaPath,
533  QSettings::Scope scope,
534  const QString organization,
535  const QString application)
536 {
537  if(m_bundles.contains(id))
538  m_bundles.remove(id);
539 
540  QString org = organization;
541 
542  if(org.isEmpty())
544 
545  QString app = application;
546 
547  if(app.isEmpty())
548  app = ZApplication::getAppName();
549 
550  SettingsBundle bundle(metaPath,
551  scope,
552  org,
553  app);
554 
555  bool ret = realizeSettings(id, bundle);
556 
557  if(!ret)
558  {
559  zCritical() << "ZSettings::insertBundle can't load settings bundle id: "
560  << id;
561  }
562  else
563  {
564  m_bundles.insert(id, bundle);
565 
567  emit zApp.settingsBundleAvailable(id);
568  }
569 
570  return ret;
571 }
572 
574  const QString& id,
575  const QString& meta,
576  const QString& dataPath,
577  bool metaAtomic)
578 
579 {
580  bool ret = false;
581 
582  if(m_bundles.contains(id))
583  {
584  zDebug() << "Replacing bundle id: " << id;
585 
586  m_bundles.remove(id);
587  }
588 
590 
591  bundle.m_dataPath = ZApplication::resolvePath(dataPath, false);
592 
593  if(metaAtomic)
594  {
595  bundle.m_metaData = meta;
596  }
597  else
598  {
599  bundle.m_metaPath = meta;
600  }
601  ret = realizeSettings(id, bundle);
602 
603  if(!ret)
604  {
605  zCritical() << "ZSettings::insertBundle can't load settings bundle id: "
606  << id;
607  }
608  else
609  {
610  m_bundles.insert(id, bundle);
611 
613  emit zApp.settingsBundleAvailable(id);
614  }
615 
616  return ret;
617 }
618 
619 bool ZSettings::insertBundle(const QString& id, QVariant bundle)
620 {
621  //zDebug() << "Sorry insertBundle for Javascript not yet implemented...";
622 
623  return false;
624 }
625 
626 
627 QVariant ZSettings::getBundle(const QString& id)
628 {
629  QVariant ret;
630 
631  if(m_bundles.contains(id))
632  {
633  const SettingsBundle& bundle = m_bundles.value(id);
634 
635  QVariantMap vm;
636  vm.insert("metaPath", bundle.m_metaPath);
637  vm.insert("dataPath", bundle.m_dataPath);
638  vm.insert("application", bundle.m_application);
639  vm.insert("organization", bundle.m_organization);
640  ret = QVariant::fromValue(vm);
641  }
642  return ret;
643 }
644 
646 {
647  ZSettings* zSet = nullptr;
648 
649  try
650  {
651 
652  if(!m_bundles.contains(id))
653  {
654  zWarning() << "Invalid bundle ID: " << id;
655 
656  return zSet;
657  }
658 
659  const SettingsBundle& bundle = m_bundles.value(id);
660 
661  zSet = new ZSettings();
662 
663  if(!bundle.m_dataPath.isEmpty())
664  {
665  QString dataPath = bundle.m_dataPath;
666 
667  if(QDir::isRelativePath(dataPath))
668  dataPath = ZApplication::getDataPath() + dataPath;
669 
670  dataPath = QDir::cleanPath(dataPath);
671 
672  if(!zSet->open(dataPath))
673  throw ZblException(QString(
674  "Can't open settings data for path: %1").arg(dataPath));
675  }
676  else
677  {
678  QString org = bundle.m_organization;
679  QString app = bundle.m_application;
680  QSettings::Scope scope;
681 
682  if(org.isEmpty())
683  org = QCoreApplication::organizationName();
684 
685  if(app.isEmpty())
686  app = ZApplication::getAppName();
687 
688  if(bundle.m_scope == QSettings::SystemScope)
689  scope = QSettings::SystemScope;
690  else
691  scope = QSettings::UserScope;
692 
693  if(!zSet->open(scope, app, org))
694  {
695  throw ZblException(QString(
696  "Can't open settings data for orgainzation/app: %1/%2").arg(org).arg(app));
697  }
698 
699  }
700 
701  }
702  catch(...)
703  {
704  if(zSet != nullptr)
705  delete zSet;
706 
707  throw;
708  }
709 
710  return zSet;
711 }
712 
713 QString ZSettings::getBundleMetapath(const QString& id)
714 {
715  if(!m_bundles.contains(id))
716  throw ZblException(QString("Invalid bundle ID: %1").arg(id));
717 
718  return m_bundles.value(id).m_metaPath;
719 }
720 
721 QString ZSettings::getBundleMetadata(const QString& id)
722 {
723  if(!m_bundles.contains(id))
724  throw ZblException(QString("Invalid bundle ID: %1").arg(id));
725 
726  return m_bundles.value(id).m_metaData;
727 }
728 
729 
730 
732 {
733  QVariantMap ret;
734 
735  QStringList keys(m_bundles.keys());
736 
737  const int keyCount = keys.count();
738 
739  for(int i=0; i<keyCount; i++)
740  {
741  const QString nextKey = keys.at(i);
742  ret.insert(nextKey, getBundle(nextKey));
743  }
744 
745  return QVariant::fromValue(ret);
746 }
747 
748 
749 bool ZSettings::hasBundle(const QString& id) const
750 {
754 }
755 
756 QVariant ZSettings::bundle(const QString& id) const
757 {
759  ZBL_SLOT_END_RETURN(getBundle(id), false,
761 }
762 
763 QVariant ZSettings::allBundles() const
764 {
768 }
769 
770 bool ZSettings::mapConfigSettings(const char* configFilePath)
771 {
772 
773  // locate zblconfig file
774 
775  if(!configFilePath)
776  {
777  zWarning() << "FAILED - invalid configuration file path: NULL";
778  return false;
779  }
780 
781  //zDebug() << "Mapping configuration settings resources: "
782  // << configFilePath;
783 
784 
785  QFile cfg(configFilePath);
786 
787  if(!cfg.exists())
788  {
789  zWarning() << QString(
790  "ABORTING - Nonexistent configuration file: %1").arg(configFilePath);
791  return false;
792  }
793 
794  // create query
795 
796  QXmlQuery xq;
797 
798  QUrl url(QUrl::fromLocalFile(configFilePath));
799 
800  //zDebug() << "Setting XQuery focus to config file: " << url.path();
801 
802  // id
803  // metaPath
804  // dataPath
805  // scope
806  // org
807  // app
808 
809  static const int x_operation = 0;
810  static const int x_id = 1;
811  static const int x_metaPath = 2;
812  static const int x_dataPath = 3;
813  static const int x_scope = 3;
814  static const int x_org = 4;
815  static const int x_app = 5;
816 
817  QString query = "declare default element namespace 'http://zuble.org/schema/zuble/zblconfig'; \n"
818 
819  "declare function local:if-empty( \n"
820  "$node as node()?, $value as xs:anyAtomicType) as xs:string* \n"
821  "{ if(string($node) != '') then string($node) else $value };"
822  "declare function local:appSettings($s as element()?) as xs:string* \n"
823  "{ ('=app', \n"
824  " local:if-empty($s/@xml:id,' '), \n"
825  " local:if-empty($s/meta_path,' '), \n"
826  " local:if-empty($s/setting-data/@scope,' '), \n"
827  " local:if-empty($s/setting-data/organization,' '), \n"
828  " local:if-empty($s/setting-data/application,' ')) }; \n"
829  "declare function local:pathSettings($s as element()?) as xs:string* \n"
830  "{ ('=path', \n"
831  " local:if-empty($s/@xml:id,' '), \n"
832  " local:if-empty($s/meta_path,' '), \n"
833  " local:if-empty($s/data_path,' ')) }; \n"
834 
835  "for $bundle in /zblconfig/settings/setting_bundle \n"
836  " let $app := $bundle/setting-data/application \n"
837  " let $path := $bundle/data_path \n"
838  " return (if($path) then local:pathSettings($bundle) \n"
839  " else if($app) then local:appSettings($bundle) else '=invalid')";
840 
841  bool status = xq.setFocus(url);
842 
843  if(!status)
844  {
845  zCritical() <<
846  QString("QXmlQuery can't load configuration file: %1").arg(
847  url.path().toUtf8().constData());
848 
849  return false;
850  }
851 
852  //zDebug() << "Query=" << query;
853 
854  xq.setQuery(query);
855 
856  if(!xq.isValid())
857  {
858  zWarning() << QString("Programming ERROR: invalid XQuery: %1").arg(query.toUtf8().constData());
859 
860  return false;
861  }
862 
863  // evaluate results
864 
865  QStringList xmlResults;
866 
867  xq.evaluateTo(&xmlResults);
868 
869  const int count = xmlResults.count();
870 
871  //zDebug() << "Dumping XQuery evaluation results ++++++++++++++++++++++++++";
872 
873  //for(int x=0; x<count; x++)
874 
875  // zDebug() << xmlResults.at(x).toUtf8().constData();
876 
877  // qDebug("Evaluated to: %s", xmlResults.at(x).toUtf8().constData());
878 
879  //zDebug() << "End dumping XQuery evaluation results ++++++++++++++++++++++++++";
880 
881  for(int j=0; j<count;j++)
882  {
883  const QString op = xmlResults[j+x_operation];
884 
885  if(op == "=app")
886  {
887  //zDebug() << "found app";
888 
889  insertBundle(
890  xmlResults[j+x_id],
891  xmlResults[j+x_metaPath],
892  textToScope(xmlResults[j+x_scope]),
893  xmlResults[j+x_org],
894  xmlResults[j+x_app]);
895 
896  j+= x_app;
897  }
898  else if(op == "=path")
899  {
900  //zDebug() << "found path";
901 
902  insertBundle(
903  xmlResults[j+x_id],
904  xmlResults[j+x_metaPath],
905  rectifySettingsDataPath(xmlResults[j+x_dataPath]));
906 
907  j+= x_dataPath;
908  }
909  else if(op == "=invalid")
910  {
911  //zDebug() << "found invalid";
912  j++;
913  }
914  else
915  {
916  //zDebug() << "found badness";
917  j++;
918 
919  }
920 
921  }
922 
923 
924 
925  return true;
926 
927 
928 }
929 
930 QString ZSettings::rectifySettingsDataPath(const QString& dataPath)
931 {
932  // paths are relative to home directory, not current directory
933 
934  QString ret(QDir::cleanPath(ZApplication::resolvePath(dataPath, false)));
935 
936  if(QDir::isAbsolutePath(ret))
937  return ret;
938 
939  QDir home(QDir::home());
940 
941  return home.filePath(ret);
942 }
943 
944 
945 bool ZSettings::realizeSettings(const QString& id, const SettingsBundle& settingsBundle)
946 {
947  static const int keyIx = 0;
948  static const int valueIx = 1;
949 
950  ZxQuery settingQuery;
951 
952  QString settingsMetafilePath;
953 
954  if(settingsBundle.m_metaPath.isEmpty())
955  {
956 #if 0
957  settingsMetafilePath = "Query text: ";
958  settingsMetafilePath += settingsBundle.m_metaData.left(30);
959  settingsMetafilePath += "...";
960 
961  //zDebug() << "Initializing application settings ID: "
962  // << id << " from metadata: " << settingsMetafilePath;
963 #endif
964  settingQuery.setFocusText(settingsBundle.m_metaData);
965  }
966  else
967  {
968 
969  settingsMetafilePath = settingsBundle.m_metaPath;
970 
971  //zDebug() << "Initializing application settings ID: "
972  // << id << " from metafile: " << settingsMetafilePath;
973 
974  settingQuery.setFocusUrl(settingsMetafilePath);
975  }
976 
977  if(zThreadErr.isError())
978  {
979  zCritical() << "XQuery can't load application settings metadata file: "
980  << settingsMetafilePath;
981 
982  return false;
983  }
984 
985  static const QString query =
986  "declare default element namespace "
987  "'http://zuble.org/schema/zuble/settings'; \n"
988  " for $setting in /appsettings/settings/setting \n"
989  " let $key := concat(xs:string($setting/@group), "
990  " \"/\", xs:string($setting/@xml:id)) \n"
991  " let $value := xs:string($setting/default) \n"
992  " return (($key,$value))";
993 
994 
995  settingQuery.setQueryText(query);
996 
997  if(zThreadErr.isError())
998  {
999  zCritical() << "Zuble internal programming ERROR: settings query is invalid.";
1000  return false;
1001  }
1002 
1003  QStringList data = settingQuery.evaluateToStringList();
1004 
1005  if(zThreadErr.isError())
1006  {
1007  zCritical() << "ERROR: Can't process application settings metadata file: "
1008  << settingsMetafilePath
1009  << ", Error message = "
1010  << zThreadErr.getErrorMessage();
1011  return false;
1012  }
1013 
1014  const int count = data.size();
1015 
1016  if(count%2)
1017  {
1018  zCritical() << "WARNING: Invalid data in application settings metadata file: "
1019  << settingsMetafilePath;
1020  return false;
1021  }
1022 
1023  ZSettings zSet;
1024 
1025  if(!zSet.open(settingsBundle))
1026  {
1027  zCritical() << "WARNING: Can't open application settings data for settings bundle ID: "
1028  << id;
1029  return false;
1030  }
1031 
1032  bool needSync = false;
1033 
1034  for(int i=0; i<count; i += 2)
1035  {
1036  QString key(data.at(i+keyIx));
1037 
1038  if(!zSet.contains(key))
1039  {
1040  QString value(data.at(i+valueIx));
1041 
1042  zSet.setValue(key,value);
1043 
1044  needSync = true;
1045 
1046  //zDebug() << "Creating default application setting key: "
1047  // << key << ", value: " << value;
1048  }
1049 
1050  //zDebug() << "data[" << i << "] = " << data.at(i);
1051  }
1052 
1053  //if(needSync)
1054  // zSet.sync();
1055 
1056  //zDebug() << "Completed initializing application settings ID: "
1057  // << id << " from metafile: " << settingsMetafilePath;
1058 
1059  return true;
1060 
1061 }
1062 
1063 QString ZSettings::scopeToText(QSettings::Scope scope)
1064 {
1065  if(scope == QSettings::SystemScope)
1066  return QString("system");
1067  else if(scope == QSettings::UserScope)
1068  return QString("user");
1069  else
1070  return QString();
1071 }
1072 
1073 QSettings::Scope ZSettings::textToScope(const QString& text)
1074 {
1075  QString lc = text.toLower();
1076 
1077  if(lc == "system")
1078  return QSettings::SystemScope;
1079  else if(lc == "user")
1080  return QSettings::UserScope;
1081  else
1082  return QSettings::Scope(-1);
1083 }
1084 
1086 {
1088  validateStatus();
1089  m_s->clear();
1091 }
1092 
1094 {
1096  validateStatus();
1097  m_s->sync();
1099 }
1100 
1102 {
1104  validateStatus();
1105  ZBL_SLOT_END_RETURN(static_cast<int>(m_s->status()), -1,
1107 }
1108 
1109 void ZSettings::setValue(const QString &key, const QVariant &value)
1110 {
1112  validateStatus();
1113  QString settingName = QString("%1/%2").arg(m_s->group(), key);
1114  QVariant oldValue = m_s->value(key);
1115 
1116  if(oldValue != value)
1117  {
1118  m_s->setValue(key, value);
1119  emit updateValue(m_s->fileName(), settingName, oldValue, value);
1120  }
1122 }
1123 
1124 QVariant ZSettings::value(const QString &key, const QVariant &defaultValue) const
1125 {
1127  validateStatus();
1128  ZBL_SLOT_END_RETURN(m_s->value(key, defaultValue), QVariant(),
1129  Z_FAC_JS, ZSettings::value, value failed)
1130 }
1131 
1132 
1133 void ZSettings::remove(const QString &key)
1134 {
1136  validateStatus();
1137  m_s->remove(key);
1139 }
1140 
1141 bool ZSettings::contains(const QString &key) const
1142 {
1144  validateStatus();
1145  ZBL_SLOT_END_RETURN(m_s->contains(key), false,
1147 }
1148 
1149 void ZSettings::beginGroup(const QString &prefix)
1150 {
1152  validateStatus();
1153  m_s->beginGroup(prefix);
1155 }
1156 
1158 {
1160  validateStatus();
1161  m_s->endGroup();
1163 }
1164 
1165 QString ZSettings::group() const
1166 {
1168  validateStatus();
1169  ZBL_SLOT_END_RETURN(m_s->group(), QString(),
1170  Z_FAC_JS, ZSettings::group, group failed)
1171 }
1172 
1173 int ZSettings::beginReadArray(const QString &prefix)
1174 {
1176  validateStatus();
1177  ZBL_SLOT_END_RETURN(m_s->beginReadArray(prefix), -1,
1179 }
1180 
1181 void ZSettings::beginWriteArray(const QString &prefix, int size)
1182 {
1184  validateStatus();
1185  m_s->beginWriteArray(prefix, size);
1187 }
1188 
1190 {
1192  validateStatus();
1193  m_s->endArray();
1195 }
1196 
1198 {
1200  validateStatus();
1201  m_s->setArrayIndex(i);
1203 }
1204 
1205 QStringList ZSettings::getAllKeys() const
1206 {
1208  validateStatus();
1209  ZBL_SLOT_END_RETURN(m_s->allKeys(), QStringList(),
1211 }
1212 
1213 QStringList ZSettings::getChildKeys() const
1214 {
1216  validateStatus();
1217  ZBL_SLOT_END_RETURN(m_s->childKeys(), QStringList(),
1219 }
1220 
1221 QStringList ZSettings::getChildGroups() const
1222 {
1224  validateStatus();
1225  ZBL_SLOT_END_RETURN(m_s->childGroups(), QStringList(),
1227 }
1228 
1230 {
1232  validateStatus();
1233  ZBL_SLOT_END_RETURN(m_s->isWritable(), false,
1235 }
1236 
1238 {
1240  validateStatus();
1241  ZBL_SLOT_END_RETURN(m_s->format(), false,
1243 }
1244 
1246 {
1248  validateStatus();
1249  ZBL_SLOT_END_RETURN(m_s->scope(), false,
1251 }
1252 
1254 {
1256  validateStatus();
1257  ZBL_SLOT_END_RETURN(m_s->organizationName(), QString(),
1259 }
1260 
1262 {
1264  validateStatus();
1265  ZBL_SLOT_END_RETURN(m_s->applicationName(), QString(),
1267 }
1268 
1269 
1270 } // Zbl
static qint64 m_maxFileSize
Maximum size settings file that Zuble will try to read.
Definition: ZSettings.h:492
static QVariant getBundle(const QString &id)
Definition: ZSettings.cpp:627
int scope
Obtain.
Definition: ZSettings.h:156
QString getFileName() const
Definition: ZSettings.cpp:142
Q_INVOKABLE QVariant allBundles() const
Definition: ZSettings.cpp:763
static const QString m_ext
File extension for Zuble&#39;s custom JSON format files: ".zbl".
Definition: ZSettings.h:486
This class wraps QFileSystemWatcher and adds path reference counting.
static QString getAppName()
Obtains the name of the Zuble application.
static void zInit()
Initialize static variables.
Definition: ZSettings.cpp:113
static bool isInitialized()
true if the ZApplication object has completed initialization, false otherwise
Definition: Zblcore.cpp:140
static void registerType()
Registers ZSettings as a QML type.
Definition: ZSettings.cpp:82
virtual ~ZSettings()
Definition: ZSettings.cpp:74
Q_INVOKABLE void setValue(const QString &key, const QVariant &value)
Definition: ZSettings.cpp:1109
static ZblApp & zInstance()
Obtains a reference to the ZblApp object for the current thread.
Definition: ZblApp.cpp:96
#define zApp
Definition: ZApplication.h:37
static ZFileSystemWatcher * m_watcher
Monitors settings data files for updates from this and other applications.
Definition: ZSettings.h:505
Q_INVOKABLE QString group() const
Definition: ZSettings.cpp:1165
QStringList getChildGroups() const
Definition: ZSettings.cpp:1221
Q_INVOKABLE void clear()
Definition: ZSettings.cpp:1085
void setFocusUrl(const QString &url)
sets the XQuery focus url and calls setQuery on the encapsulated QXmlQuery object.
Definition: ZxQuery.cpp:121
#define Z_FAC_JS
Definition: zglobal.h:123
QString getOrganizationName() const
Definition: ZSettings.cpp:1253
Q_INVOKABLE void remove(const QString &key)
Definition: ZSettings.cpp:1133
Q_INVOKABLE QVariant bundle(const QString &id) const
Definition: ZSettings.cpp:756
QStringList getAllKeys() const
Definition: ZSettings.cpp:1205
static QSettings::Format m_format
QSettings custom format value assigned to Zuble for this application instance. This is the value retu...
Definition: ZSettings.h:480
Q_INVOKABLE void endGroup()
Definition: ZSettings.cpp:1157
#define ZBL_REGISTER_LOGGED_OBJECT
Definition: zglobal.h:104
Q_INVOKABLE int status() const
Definition: ZSettings.cpp:1101
bool getWritable() const
Definition: ZSettings.cpp:1229
static QString getDataPath()
Obtains the canonical path to the Zuble application&#39;s data directory.
Q_INVOKABLE bool removePath(const QString &file)
ZSettings(QObject *parent=nullptr)
Definition: ZSettings.cpp:53
static QString getOrganization()
Obtains the organization of the Zuble application.
Q_INVOKABLE bool hasBundle(const QString &id) const
Definition: ZSettings.cpp:749
static bool realizeSettings(const QString &id, const SettingsBundle &settingsBundle)
Creates the default settings values for keys in the settings metadata that don&#39;t exist in the setting...
Definition: ZSettings.cpp:945
static bool mapConfigSettings(const char *configFilePath)
Definition: ZSettings.cpp:770
QVariant getTags()
Definition: ZSettings.cpp:137
bool m_watching
True if this settings object is currently watching it&#39;s source file, false otherwise.
Definition: ZSettings.h:511
Q_INVOKABLE int beginReadArray(const QString &prefix)
Definition: ZSettings.cpp:1173
Q_INVOKABLE bool addPath(const QString &file)
Q_INVOKABLE void beginGroup(const QString &prefix)
Definition: ZSettings.cpp:1149
QMap< QString, SettingsBundle > bundleMap
Definition: ZSettings.h:87
void setRestoreDeletedFiles(bool restoreFiles)
Q_INVOKABLE bool setFileWatcher(bool enabled)
Enables or disables the file system watcher. This method must be called to enable this object to emit...
Definition: ZSettings.cpp:386
static QVariant m_tags
QVariantMap of ZSettings enumerations for use by Javascript programs.
Definition: ZSettings.h:466
static bool ensureFileExists(const QString &filePath)
Definition: ZSettings.cpp:406
bool validateOpen()
Definition: ZSettings.cpp:499
static QSettings::Scope textToScope(const QString &text)
Definition: ZSettings.cpp:1073
static void dumpMap(const QSettings::SettingsMap &map)
Definition: ZSettings.cpp:247
void setFocusText(const QString &text)
sets the XQuery focus url and calls setQuery on the encapsulated QXmlQuery object.
Definition: ZxQuery.cpp:167
static bool writeFunc(QIODevice &device, const QSettings::SettingsMap &map)
Write function for Zuble&#39;s custom settings format.
Definition: ZSettings.cpp:212
static bool containsBundle(const QString &id)
Definition: ZSettings.cpp:525
QSettings * m_s
Pointer to the encapsulated QSettings object.
Definition: ZSettings.h:472
QStringList getChildKeys() const
Definition: ZSettings.cpp:1213
static QVariant getAllBundles()
Definition: ZSettings.cpp:731
Definition: ZAndGate.cpp:6
#define ZBL_SLOT_BEGIN_TRY
Definition: zglobal.h:128
void validateStatus() const
Definition: ZSettings.h:518
void setQueryText(const QString &text)
Copies the specified text to the query text buffer and calls setQuery on the encapsulated QXmlQuery o...
Definition: ZxQuery.cpp:219
#define ZBL_DEFINE_LOGGED_OBJECT(class_name)
Definition: zglobal.h:99
Q_INVOKABLE void endArray()
Definition: ZSettings.cpp:1189
void settingsModified(const QString &path)
Sent whenever the settings file is modified by this or other programs.
static QString scopeToText(QSettings::Scope scope)
Definition: ZSettings.cpp:1063
#define zWarning()
Definition: zglobal.h:111
#define zThreadErr
where does this show up?
Definition: ZblThreadErr.h:39
void updateValue(const QString &settingPath, const QString &settingName, QVariant oldValue, QVariant newValue)
Sent whenever ZSettings values are modified by this or other ZSettings objects within this Qt/QML pro...
Q_INVOKABLE QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
Definition: ZSettings.cpp:1124
#define ZBL_SLOT_END_VOID(facility, code, error_message)
Definition: zglobal.h:134
static bool readFunc(QIODevice &device, QSettings::SettingsMap &map)
Read function for Zuble&#39;s custom settings format.
Definition: ZSettings.cpp:164
Q_INVOKABLE QStringList files() const
static bundleMap m_bundles
Maps settings bundle ID values to the associated bundle.
Definition: ZSettings.h:498
#define zDebug()
Definition: zglobal.h:113
Q_INVOKABLE QStringList evaluateToStringList()
Evaluates the current XQuery to a QStringList object and returns that object.
Definition: ZxQuery.cpp:307
static void createTags()
Definition: ZSettings.cpp:120
Wraps the QSettings class and implements a JSON-based backend for storing the settings data...
Definition: ZSettings.h:44
static QString resolvePath(const QString &path, bool includeUrlScheme=true)
Converts relative file paths into canonical file paths. Paths prefixed with prefix are mapped relativ...
static QString getBundleMetadata(const QString &id)
Definition: ZSettings.cpp:721
static QString rectifySettingsDataPath(const QString &dataPath)
Definition: ZSettings.cpp:930
int getScope() const
Definition: ZSettings.cpp:1245
Q_INVOKABLE void beginWriteArray(const QString &prefix, int size=-1)
Definition: ZSettings.cpp:1181
QString getApplicationName() const
Definition: ZSettings.cpp:1261
QSettings::Scope m_scope
Definition: ZSettings.h:84
Q_INVOKABLE QString getCurrentThreadAddress()
Returns the human-readable memory address of the current thread.
Definition: ZblApp.cpp:765
Zuble&#39;s Qt Exception Object.
Definition: ZblException.h:45
void validateWatcher() const
Definition: ZSettings.h:525
Q_INVOKABLE void sync()
Definition: ZSettings.cpp:1093
This inner class allows ZSettings to store settings bundles.
Definition: ZSettings.h:55
static ZSettings * getBundleSettings(const QString &id)
Returns the ZSettings object for the specified settings bundle ID. Caller takes ownership of the ZSet...
Definition: ZSettings.cpp:645
This class provides access to the QXMLQuery class from Javascript.
Definition: ZxQuery.h:48
static QString getBundleMetapath(const QString &id)
Definition: ZSettings.cpp:713
Q_INVOKABLE void setArrayIndex(int i)
Definition: ZSettings.cpp:1197
int getFormat() const
Definition: ZSettings.cpp:1237
static void dumpGroup(const QString &groupKey, const QVariant &group)
Definition: ZSettings.cpp:277
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
Q_INVOKABLE bool open(int scope=static_cast< int >(QSettings::UserScope), const QString &application=QString(), const QString &organization=QString())
Opens the settings object in the platform-specific configuration file location.
Definition: ZSettings.cpp:304
Q_INVOKABLE bool contains(const QString &key) const
Definition: ZSettings.cpp:1141
#define ZBL_SLOT_END_RETURN(return_success, return_failed, facility, code, error_message)
Definition: zglobal.h:141
#define zCritical()
Definition: zglobal.h:112
void onFileChanged(const QString &path)
Definition: ZSettings.cpp:88
void fileChanged(const QString &path)