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
ZScopedMap.cpp
Go to the documentation of this file.
1 /*
2  * Zuble - A run-time system for QML/Javascript applications
3  * Copyright (C) 2016 Bob Dinitto
4  *
5  * Filename: ZScopedMap.cpp
6  * Created on: 06-Oct-2017
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 "ZScopedMap.h"
26 #include <QtQml>
27 #include <QStringBuilder>
28 
29 namespace Zbl
30 {
31 
33 
34 ZScopedMap::ZScopedMap(QObject *parent) :
35  QObject(parent), m_outerScope(0)
36 {
37 }
38 
40 {
42 
43  qmlRegisterType<ZScopedMap>("org.zuble.qml", 1, 0, "ZScopedMap");
44 }
45 
47 {
48  // TBD: hook up connections & notify listeners
49 
50  ZScopedMap* outer = qobject_cast<ZScopedMap*>(outerScope);
51 
52  if(!outer)
53  {
54  zWarning() << "ZScopedMap programming error - outerScope must be a ZScopedMap object.";
55 
56  return;
57  }
58 
59  if(m_outerScope)
60  {
61  disconnect(m_outerScope, SIGNAL(reset()), this, SIGNAL(reset()));
62  }
63 
64  m_outerScope = outer;
65 
66  connect(m_outerScope, SIGNAL(reset()), this, SIGNAL(reset()));
67 
68 }
69 
71 {
72  return m_outerScope;
73 }
74 
75 void ZScopedMap::loadJSON(const QString& jsonString)
76 {
77 
78  if(jsonString.isEmpty())
79  return;
80 
81  if(!m_JSON.isEmpty())
82  {
83  zWarning() << "loadJSON failed! - JSON initializer string has already been set.";
84 
85  return;
86  }
87 
88  QJsonParseError er;
89 
90  QJsonDocument doc = QJsonDocument::fromJson(jsonString.toUtf8(), &er);
91 
92  if(er.error != QJsonParseError::NoError)
93  {
94  zWarning() << "loadJSON parse error: " << er.errorString();
95  zWarning() << "JSON failed: " << jsonString;
96 
97  return;
98  }
99 
100  if(!doc.isObject())
101  {
102  zWarning() << "loadJSON format error: " <<
103  "JSON initializer should be a JSON object of key/value pairs.";
104  zWarning() << "JSON failed: " << jsonString;
105  }
106 
107  QJsonObject ob = doc.object();
108 
109  QJsonObject::const_iterator i = ob.begin();
110 
111  QVariantMap tempMap;
112 
113  for(;i != ob.end(); i++)
114  {
115  QString key = i.key();
116  QJsonValue value = *i;
117 
118  QVariant qValue(value.toVariant());
119 
120 
121  if(isValidType(value))
122  tempMap.insert(key, qValue);
123  }
124 
125  m_JSON = jsonString;
126 
127  m_map = tempMap;
128 }
129 
130 QString ZScopedMap::toJSON() const
131 {
132  zDebug() << "Getting JSON string from scoped map.";
133 
134  QJsonDocument jdoc = QJsonDocument::fromVariant(m_map);
135 
136  QString json = jdoc.toJson();
137 
138  zDebug() << "JSON property string = " << json;
139 
140  return json;
141 }
142 
144 {
145  return m_JSON;
146 }
147 
148 
150 {
151  return m_map.size();
152 }
153 
154 bool ZScopedMap::has(const QString& key) const
155 {
156  if(m_map.contains(key))
157  return true;
158  else if(m_outerScope)
159  return m_outerScope->has(key);
160 }
161 
162 QVariant ZScopedMap::get(const QString& key) const
163 {
164  if(m_map.contains(key))
165  return m_map.value(key);
166  else if(m_outerScope)
167  return m_outerScope->get(key);
168  else
169  return QVariant();
170 }
171 
172 void ZScopedMap::set(const QString& key, const QJsonValue &value)
173 {
174  if(!isValidType(value))
175  return;
176 
177  QVariant qValue = value.toVariant();
178 
179  setValue(m_map, key, qValue, true);
180 }
181 
182 bool ZScopedMap::setValue(QVariantMap& map, const QString& key, QVariant value, bool emitSignal)
183 {
184  if(map.contains(key))
185  {
186  QVariant old = m_map.value(key);
187 
188  if(old.type() == value.type() && old == value)
189  return true;
190  }
191 
192  zDebug() << "Modifying scoped map - key: " << key << ", value: " << value;
193 
194  map.insert(key, value);
195 
196  if(emitSignal)
197  emit itemChanged(key, value);
198 
199  return true;
200 }
201 
202 bool ZScopedMap::remove(const QString& key)
203 {
204  return m_map.remove(key) ? true : false;
205 }
206 
207 QVariantList ZScopedMap::keys() const
208 {
209  // TBD: bug! need to call outer scope here - we should collect the set of
210  // all keys for all enclosing scopes, eliminating duplicates.
211 
212 
213  QList<QString> k = m_map.keys();
214 
215  const int count = k.count();
216 
217  QVariantList vk;
218 
219  for(int i=0; i<count; i++)
220  {
221  qDebug() << "mapkey = " << k.at(i);
222 
223  vk.append(QVariant(k.at(i)));
224  }
225 
226  for(int i = 0; i<vk.count(); i++)
227  qDebug() << "variant key = " << vk.at(i);
228 
229  return vk;
230 }
231 
233 {
234  m_map.clear();
235 }
236 
237 bool ZScopedMap::isValidType(const QJsonValue& value)
238 {
239  switch(value.type())
240  {
241  case QJsonValue::Bool:
242  case QJsonValue::Double:
243  case QJsonValue::String:
244  return true;
245  }
246 
247  zWarning() << "Value type error: " <<
248  "type must be either number, boolean or string.";
249  zWarning() << "Failed value: " << value.toString();
250  //zWarning() << "Failed type: " <<
251 
252  return false;
253 }
254 
255 bool ZScopedMap::isValidType(const QVariant& value)
256 {
257  switch(value.type())
258  {
259  case QMetaType::Bool:
260  case QMetaType::Double:
261  case QMetaType::Int:
262  case QMetaType::UInt:
263  case QMetaType::LongLong:
264  case QMetaType::ULongLong:
265  case QMetaType::QString:
266  return true;
267  }
268 
269  zWarning() << "Value type error: " <<
270  "type must be either number, boolean or string.";
271  zWarning() << "Failed value: " << value.toString();
272  //zWarning() << "Failed type: " <<
273 
274  return false;
275 }
276 
277 bool ZScopedMap::setMap(QVariantMap map)
278 {
279  // update is transactional: all or nothing
280 
281  QVariantMap tempMap;
282 
283  QVariantMap::const_iterator i = map.begin();
284 
285  for(;i != map.end(); i++)
286  {
287  QVariant nextValue(i.value());
288 
289  if(!isValidType(nextValue))
290  return false;
291 
292  if(!setValue(tempMap, i.key(), i.value()), false)
293  return false;
294  }
295 
296  if(tempMap.isEmpty())
297  return false;
298 
299  i = tempMap.begin();
300 
301  for(;i != tempMap.end(); i++)
302  m_map.insert(i.key(), i.value());
303 
304  emit mapChanged(tempMap);
305 
306  return true;
307  }
308 
309 bool ZScopedMap::setScopedMap(QObject* map)
310 {
311  ZScopedMap* scoped = qobject_cast<ZScopedMap*>(map);
312 
313  if(!scoped)
314  {
315  zWarning() << "setMap invalid parameter type: object must be of type "
316  "ZScopedMap or QVariantMap (javascript native object)";
317  return false;
318  }
319 
320  return setMap(scoped->m_map);
321 }
322 
324 {
325  zDebug() << "Emitting ZScopedMap::reset signal";
326 
327  emit reset();
328 }
329 
330 
331 
332 
333 
334 } // Zbl
bool isValidType(const QJsonValue &value)
Test if a value has a type that can be stored in the scope.
Definition: ZScopedMap.cpp:237
QVariantMap m_map
A dictionary of scoped objects.
Definition: ZScopedMap.h:284
QObject outerScope
The number of items in the map.
Definition: ZScopedMap.h:60
#define ZBL_REGISTER_LOGGED_OBJECT
Definition: zglobal.h:104
int getSize() const
Obtain number of items in the map.
Definition: ZScopedMap.cpp:149
bool setMap(QVariantMap map)
Inserts a set of key/value pairs into the map. Existing values are overwritten.
Definition: ZScopedMap.cpp:277
Definition: ZAndGate.cpp:6
ZBL_DECLARE_LOGGED_OBJECT QString getInitializer() const
Return the JSON string used to initialize this object.
Definition: ZScopedMap.cpp:143
bool setScopedMap(QObject *map)
Inserts a set of key/value pairs into the map. Existing values are overwritten.
Definition: ZScopedMap.cpp:309
Q_INVOKABLE QVariantList keys() const
Obtain the key names in the map.
Definition: ZScopedMap.cpp:207
#define ZBL_DEFINE_LOGGED_OBJECT(class_name)
Definition: zglobal.h:99
void set(const QString &key, const QJsonValue &value)
Sets the specified key in the map to the specified value. Existing values are overwritten.
Definition: ZScopedMap.cpp:172
#define zWarning()
Definition: zglobal.h:111
ZScopedMap * m_outerScope
The scope enclosing this scope, or null if this is outermost scope.
Definition: ZScopedMap.h:278
QObject * getOuterScope()
Get the enclosing scope. May be null if this is outermost scope.
Definition: ZScopedMap.cpp:70
Q_INVOKABLE bool has(const QString &key) const
Returns true if the map contains the specified key.
Definition: ZScopedMap.cpp:154
#define zDebug()
Definition: zglobal.h:113
bool setValue(QVariantMap &map, const QString &key, QVariant value, bool emitSignal=false)
Sets the specified key in the map to the specified value. Existing values are overwritten.
Definition: ZScopedMap.cpp:182
void loadJSON(const QString &jsonString)
Parses the supplied JSON string and writes the contained key/value pairs to the map.
Definition: ZScopedMap.cpp:75
Q_INVOKABLE void invalidate()
Issue a scopeChanged signal. All clients should query their values.
Definition: ZScopedMap.cpp:323
QString m_JSON
JSON string used to initialize this scope.
Definition: ZScopedMap.h:290
void clear()
Remove all key/value pairs from the map.
Definition: ZScopedMap.cpp:232
void itemChanged(const QString key, QVariant value)
void mapChanged(QVariantMap newValues)
A hierarchical map object for creating scopes.
Definition: ZScopedMap.h:36
Q_INVOKABLE QString toJSON() const
Obtain a JSON string representation of the map.
Definition: ZScopedMap.cpp:130
Q_INVOKABLE QVariant get(const QString &key) const
Returns the value associated with a specified key in the map.
Definition: ZScopedMap.cpp:162
static void registerType()
Register ZMailbox as a QML type.
Definition: ZScopedMap.cpp:39
bool remove(const QString &key)
Removes the specified key from the map.
Definition: ZScopedMap.cpp:202
void setOuterScope(QObject *outerScope)
Set the enclosing scope to which unresolved name lookups will be forwarded.
Definition: ZScopedMap.cpp:46