[KLF Backend][KLF Tools][KLF Home]
KLatexFormula Project
klfdatautil.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * file klfdatautil.h
3  * This file is part of the KLatexFormula Project.
4  * Copyright (C) 2011 by Philippe Faist
5  * philippe.faist at bluewin.ch
6  * *
7  * This program is free software; you can redistribute it and/or modify *
8  * it under the terms of the GNU General Public License as published by *
9  * the Free Software Foundation; either version 2 of the License, or *
10  * (at your option) any later version. *
11  * *
12  * This program is distributed in the hope that it will be useful, *
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15  * GNU General Public License for more details. *
16  * *
17  * You should have received a copy of the GNU General Public License *
18  * along with this program; if not, write to the *
19  * Free Software Foundation, Inc., *
20  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
21  ***************************************************************************/
22 /* $Id: klfdatautil.cpp 994 2017-01-10 01:09:40Z phfaist $ */
23 
24 #include <qglobal.h>
25 #include <QObject>
26 #include <QByteArray>
27 #include <QString>
28 #include <QUrl>
29 #include <QTextCodec>
30 #include <QDateTime>
31 #include <QRect>
32 #include <QIcon>
33 #include <QColor>
34 #include <QBrush>
35 #include <QDomDocument>
36 #include <QTextFormat>
37 
38 #include "klfdefs.h"
39 #include "klfpobj.h"
40 #include "klfutil.h"
41 #include "klfdatautil.h"
42 
43 #include "klfdatautil_p.h"
44 
45 
46 static inline bool klf_is_hex_char(char c)
47 {
48  return ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F');
49 }
50 
51 
52 
53 #define KLF_BRUSH_STYLE(sty) \
54  { Qt::sty##Pattern, #sty }
55 
56 static struct { int brushStyle; const char *style; } klf_brush_styles[] = {
57  { Qt::NoBrush, "NoBrush" },
58  { Qt::SolidPattern, "" },
59  { Qt::SolidPattern, "Solid" },
60  KLF_BRUSH_STYLE(Dense1),
61  KLF_BRUSH_STYLE(Dense2),
62  KLF_BRUSH_STYLE(Dense3),
63  KLF_BRUSH_STYLE(Dense4),
64  KLF_BRUSH_STYLE(Dense5),
65  KLF_BRUSH_STYLE(Dense6),
66  KLF_BRUSH_STYLE(Dense7),
67  KLF_BRUSH_STYLE(Hor),
68  KLF_BRUSH_STYLE(Ver),
69  KLF_BRUSH_STYLE(Cross),
70  KLF_BRUSH_STYLE(BDiag),
71  KLF_BRUSH_STYLE(FDiag),
72  KLF_BRUSH_STYLE(DiagCross),
73  { -1, NULL }
74 };
75 
76 
77 
78 #define KLF_TEXT_FORMAT_FORMAT(fmt) \
79  { QTextFormat::fmt##Format, #fmt "Format" }
80 
81 static struct { int formatId; const char *format; } klf_text_format_formats[] = {
82  KLF_TEXT_FORMAT_FORMAT(Invalid),
89  { -100, NULL }
90 };
91 
92 
93 #define KLF_TEXT_FORMAT_PROP(p, type) \
94  { QTextFormat::p, #p, #type }
95 
96 static struct { int propId; const char *key; const char *type; } klf_text_format_props[] = {
97  KLF_TEXT_FORMAT_PROP(ForegroundBrush, QBrush),
98  KLF_TEXT_FORMAT_PROP(BackgroundBrush, QBrush),
99  KLF_TEXT_FORMAT_PROP(FontFamily, QString),
100  KLF_TEXT_FORMAT_PROP(FontPointSize, int),
101  KLF_TEXT_FORMAT_PROP(FontWeight, int),
102  KLF_TEXT_FORMAT_PROP(FontItalic, bool),
103  KLF_TEXT_FORMAT_PROP(TextUnderlineStyle, int),
104  // add more keys for short-hands
105  { QTextFormat::ForegroundBrush, "FG", "QBrush" },
106  { QTextFormat::BackgroundBrush, "BG", "QBrush" },
107 
108  { -1, NULL, NULL }
109 };
110 
111 static struct { const char * keyword; int propId; QVariant fixed_value; } klf_text_format_keywords[] = {
112  { "NORMALWEIGHT", QTextFormat::FontWeight, QVariant(QFont::Normal) },
113  { "BOLD", QTextFormat::FontWeight, QVariant(QFont::Bold) },
114  { "NORMALSTYLE", QTextFormat::FontItalic, QVariant(false) },
115  { "ITALIC", QTextFormat::FontItalic, QVariant(true) },
116 
117  { NULL, -1, QVariant() }
118 };
119 
120 
121 
122 
123 KLF_EXPORT QByteArray klfDataToEscaped(const QByteArray& value_ba, char escapechar)
124 {
126 
127  klfDbg("len="<<value_ba.size()<<" , data=`"<<value_ba<<"' escapechar="<<klfFmtCC("'\\x%02X'", (int)escapechar));
128 
129  QByteArray data;
130  int k;
131  for (k = 0; k < value_ba.size(); ++k) {
132  // qDebug("\tdata[%d] = %x = %c", k, (uchar)value_ba[k], value_ba[k]);
133  if (value_ba[k] >= 32 && value_ba[k] <= 126 && value_ba[k] != escapechar) {
134  // ascii-ok values, not backslash
135  data += value_ba[k];
136  } else if (value_ba[k] == escapechar) {
137  // double the escape char
138  data += escapechar;
139  data += escapechar;
140  } else {
141  data += escapechar;
142  data += QString("x%1").arg((uint)(uchar)value_ba[k], 2, 16, QChar('0')).toLatin1();
143  }
144  }
145  return data;
146 }
147 
148 KLF_EXPORT QByteArray klfEscapedToData(const QByteArray& data, char escapechar)
149 {
151  klfDbg("data=`"<<data<<"', escapechar="<<klfFmtCC("'\\x%02X'", (int)escapechar));
152 
153  bool convertOk;
154  int k;
155  QByteArray value_ba;
156  k = 0;
157  while (k < data.size()) {
158  if (data[k] != escapechar) {
159  value_ba += data[k];
160  ++k;
161  continue;
162  }
163  // we have an escapechar
164  if (data[k] == escapechar && k+1 >= data.size()) {
165  value_ba += escapechar; // backslash at end of data
166  ++k;
167  continue;
168  }
169  // not at end of data
170  if (data[k+1] != 'x') {
171  // backslash followed by something else than 'x', so see if it is a standard escape sequence (e.g. '\n'),
172  // or add that escaped 'something else'
173  if (data[k+1] == 'n')
174  value_ba += '\n';
175  if (data[k+1] == '0')
176  value_ba += '\0';
177  if (data[k+1] == 't')
178  value_ba += '\t';
179  if (data[k+1] == 'a')
180  value_ba += '\a';
181  if (data[k+1] == 'b')
182  value_ba += '\b';
183  if (data[k+1] == 'f')
184  value_ba += '\f';
185  if (data[k+1] == 'r')
186  value_ba += '\r';
187  if (data[k+1] == 'v')
188  value_ba += '\v';
189  else
190  value_ba += data[k+1];
191  k += 2; // had to skip the backslash
192  continue;
193  }
194  // pos k points on '\\', pos k+1 points on 'x'
195  if (k+3 >= data.size() || !klf_is_hex_char(data[k+2]) || !klf_is_hex_char(data[k+3])) {
196  // ignore invalid escape sequence
197  klfDbg("ignoring invalid escape sequence `"<<data.mid(k,4)<<"'") ;
198  value_ba += data[k];
199  ++k;
200  continue;
201  }
202  // decode this char
203  uchar cval = data.mid(k+2, 2).toUInt(&convertOk, 16);
204  value_ba += (char)cval;
205  k += 4; // advance of backslash + 'x' + 2 digits
206  }
207  return value_ba;
208 }
209 
210 
211 static QByteArray encaps_list(const QList<QByteArray>& list)
212 {
213  QByteArray data = "[";
214  for (int k = 0; k < list.size(); ++k) {
215  QByteArray d = list[k];
216  d.replace("\\", "\\\\");
217  d.replace(";", "\\;");
218  d.replace("[", "\\[");
219  d.replace("]", "\\]");
220  data += d;
221  if (k < list.size()-1)
222  data += ";";
223  }
224  data += "]";
225  return data;
226 }
227 
228 // if 'ignore_empty_values' is TRUE, then the '=' sign is omitted with the value in a section is empty.
229 static QByteArray encaps_map(const QList<QPair<QByteArray,QByteArray> >& sections, bool ignore_empty_values = false)
230 {
231  QByteArray data;
232  data = "{";
233  bool first_item = true;
234  int k;
235  for (k = 0; k < sections.size(); ++k) {
236  if (!first_item) {
237  data += ";";
238  }
239  first_item = false;
240  QByteArray key = sections[k].first;
241  QByteArray val = sections[k].second;
242  // prepare the pair key=value
243  key.replace("\\", "\\\\");
244  key.replace(";", "\\;");
245  key.replace("=", "\\=");
246  val.replace("\\", "\\\\");
247  val.replace(";", "\\;");
248  if (val.isEmpty() && ignore_empty_values)
249  data += key;
250  else
251  data += key + "=" + val;
252  }
253  data += "}";
254  return data;
255 }
256 
257 
258 static QList<QByteArray> decaps_list(const QByteArray& ba_data)
259 {
260  klfDbg("decaps_list, data="<<ba_data);
261  QByteArray data = ba_data.trimmed();
262  if (data[0] != '[')
263  return QList<QByteArray>();
264 
265  QList<QByteArray> sections;
266  QByteArray chunk;
267  // first, split data. take into account escaped chars.
268  // k=1 to skip '['
269  int k = 1;
270  while (k < data.size()) {
271  if (data[k] == ';') { // element separator
272  // flush chunk as a new section
273  sections.append(chunk);
274  // and start a new section
275  chunk = QByteArray();
276  ++k;
277  }
278  if (data[k] == '\\') {
279  if (k+1 < data.size()) { // there exists a next char
280  chunk += data[k+1];
281  k += 2;
282  } else {
283  chunk += data[k];
284  ++k;
285  }
286  continue;
287  }
288  if (data[k] == ']') {
289  // end of list marker.
290  // flush last chunk into sections, and break.
291  if (!chunk.isEmpty())
292  sections.append(chunk);
293  chunk = "";
294  break;
295  }
296  // regular char, populate current chunk.
297  chunk += data[k];
298  ++k;
299  }
300  if (!chunk.isEmpty()) {
301  // missing ']' at end, tolerate this by adding the unfinished chunk to sections
302  sections.append(chunk);
303  }
304 
305  klfDbg("sections="<<sections);
306 
307  return sections;
308 }
309 
310 static QList<QPair<QByteArray,QByteArray> > decaps_map(const QByteArray& ba_data, bool allow_empty_values = false)
311 {
312  QByteArray data = ba_data.trimmed();
313  if (data[0] != '{')
315  if ( !data.contains('}') )
316  data += '}';
317 
319  QByteArray chunkkey;
320  QByteArray chunkvalue;
321  QByteArray *curChunk = &chunkkey;
322  // first, split data. take into account escaped chars.
323  // k=1 to skip '{'
324  int k = 1;
325  while (k < data.size()) {
326  if (data[k] == ';') { // separator for next pair
327  // flush chunk as a new section
328  if (!allow_empty_values && curChunk == &chunkkey)
329  qWarning()<<KLF_FUNC_NAME<<": no '=' in pair at pos "<<k<<" in string: "<<data<<"";
330  sections << QPair<QByteArray,QByteArray>(chunkkey, chunkvalue);
331  // and start a new section
332  chunkkey = QByteArray();
333  chunkvalue = QByteArray();
334  curChunk = &chunkkey;
335  ++k;
336  }
337  if (data[k] == '\\') {
338  if (k+1 < data.size()) { // there exists a next char
339  *curChunk += data[k+1];
340  k += 2;
341  } else {
342  *curChunk += data[k];
343  ++k;
344  }
345  continue;
346  }
347  if (curChunk == &chunkkey && data[k] == '=') {
348  // currently reading key, switch to reading value
349  curChunk = &chunkvalue;
350  ++k;
351  continue;
352  }
353  if (data[k] == '}') {
354  // end of list marker.
355  // flush last chunk into sections, and break.
356  if (!allow_empty_values && curChunk == &chunkkey)
357  qWarning()<<"klfLoadVariantFromText: no '=' in pair at pos "<<k<<" in string: "<<data<<"";
358  sections << QPair<QByteArray,QByteArray>(chunkkey, chunkvalue);
359  break;
360  }
361  // regular char, populate current chunk.
362  *curChunk += data[k];
363  ++k;
364  }
365  return sections;
366 }
367 
368 
369 
370 // returns root node. get the document with root.ownerDocument()
371 static QDomElement make_xml_wrapper(const QString& rootname)
372 {
373  QDomDocument xmldoc(rootname);
374  QDomElement root = xmldoc.createElement(rootname);
375  xmldoc.appendChild(root);
376  return root;
377 }
378 
379 static QDomElement parse_xml_wrapper(const QByteArray& xmldata, const QString& shouldBeRootName)
380 {
381  QDomDocument xmldoc(shouldBeRootName);
382  bool result = xmldoc.setContent(xmldata);
383  KLF_ASSERT_CONDITION(result, "Failed to read wrapper XML for klfLoadVariantFromText()",
384  return QDomElement() ) ;
385 
386  QDomElement el = xmldoc.documentElement();
387  KLF_ASSERT_CONDITION( el.nodeName() == shouldBeRootName,
388  "Wrong XML root node in wrapper for klfLoadVariantFromText(): "
389  <<el.nodeName() , ; ) ;
390  return el;
391 }
392 
393 KLF_EXPORT QByteArray klfSaveVariantToText(const QVariant& value, bool saveListAndMapsAsXML, QByteArray *savedType,
394  QByteArray *savedListOrMapType)
395 {
397 
398  QString s;
399  QByteArray data;
400  int k;
401 
402  if (!value.isValid() || value.isNull()) {
403  klfDbg("saving null variant.");
404  if (savedType != NULL)
405  *savedType = QByteArray();
406  return QByteArray();
407  }
408 
409  // values of value.type() are QMetaType::Type enum entries. See qt's doc.
410  switch ((int)value.type()) {
411  case QMetaType::Bool:
412  data = value.toBool() ? "true" : "false";
413  break;
414  case QMetaType::Int:
415  case QMetaType::UInt:
416  case QMetaType::Short:
417  case QMetaType::UShort:
418  case QMetaType::Long:
419  case QMetaType::ULong:
420  case QMetaType::LongLong:
421  case QMetaType::ULongLong:
422  case QMetaType::Double:
423  data = value.toString().toLocal8Bit();
424  break;
425  case QMetaType::Char:
426  {
427  char c = value.value<char>();
428  if (c >= 32 && c <= 126 && c != '\\') {
429  data = QByteArray(1, c);
430  } else if (c == '\\') {
431  data = "\\\\";
432  } else {
433  data = "\\" + QString::number(c, 16).toUpper().toLatin1();
434  }
435  break;
436  }
437  case QMetaType::QChar:
438  {
439  QChar c = value.toChar();
440  if (tc->canEncode(c) && c != '\\') {
441  data = tc->fromUnicode(QString(c));
442  } else if (c == '\\') {
443  data = "\\\\";
444  } else {
445  data = "\\" + QString::number(c.unicode(), 16).toUpper().toLatin1();
446  }
447  break;
448  }
449  case QMetaType::QString:
450  {
451  s = value.toString();
452  if (tc->canEncode(s)) {
453  // replace any `\' by `\\' (ie. escape backslashes)
454  data = tc->fromUnicode(s.replace("\\", "\\\\"));
455  } else {
456  // encode char by char, escaping as needed
457  data = QByteArray("");
458  for (k = 0; k < s.length(); ++k) {
459  if (tc->canEncode(s[k])) {
460  data += tc->fromUnicode(s.mid(k,1));
461  } else {
462  data += QString("\\x%1").arg((uint)s[k].unicode(), 4, 16, QChar('0')).toLatin1();
463  }
464  }
465  }
466  break;
467  }
468  case QMetaType::QStringList:
469  {
470  const QStringList list = value.toStringList();
471  QList<QByteArray> sections;
472  int k;
473  for (k = 0; k < list.size(); ++k) {
474  sections.append(klfDataToEscaped(list[k].toUtf8()));
475  }
476  data = encaps_list(sections);
477  break;
478  }
479  case QMetaType::QUrl:
480  data = value.toUrl().toEncoded(); break;
481  case QMetaType::QByteArray:
482  {
483  data = klfDataToEscaped(value.value<QByteArray>());
484  break;
485  }
486  case QMetaType::QDate:
487  data = value.value<QDate>().toString(Qt::SystemLocaleShortDate).toLocal8Bit(); break;
488  case QMetaType::QTime:
489  data = value.value<QTime>().toString(Qt::SystemLocaleShortDate).toLocal8Bit(); break;
490  case QMetaType::QDateTime:
491  data = value.value<QDateTime>().toString(Qt::SystemLocaleShortDate).toLocal8Bit(); break;
492  case QMetaType::QSize:
493  { QSize sz = value.toSize();
494  data = QString("(%1 %2)").arg(sz.width()).arg(sz.height()).toLatin1();
495  break;
496  }
497  case QMetaType::QPoint:
498  { QPoint pt = value.toPoint();
499  data = QString("(%1 %2)").arg(pt.x()).arg(pt.y()).toLatin1();
500  break;
501  }
502  case QMetaType::QRect:
503  { QRect r = value.toRect();
504  data = QString("(%1 %2 %3x%4)").arg(r.left()).arg(r.top()).arg(r.width()).arg(r.height()).toLatin1();
505  break;
506  }
507  case QMetaType::QColor:
508  { QColor c = value.value<QColor>();
509  klfDbg("Saving color "<<c<<": alpha="<<c.alpha()) ;
510  if (c.alpha() == 255)
511  data = QString("(%1 %2 %3)").arg(c.red()).arg(c.green()).arg(c.blue()).toLatin1();
512  else
513  data = QString("(%1 %2 %3 %4)").arg(c.red()).arg(c.green()).arg(c.blue()).arg(c.alpha()).toLatin1();
514  break;
515  }
516  case QMetaType::QFont:
517  { QFont f = value.value<QFont>();
518  data = "'" + f.family().toLocal8Bit() + "'";
519  switch (f.weight()) {
520  case QFont::Light: data += " Light"; break;
521  case QFont::Normal: break; //data += " Normal"; break;
522  case QFont::DemiBold: data += " DemiBold"; break;
523  case QFont::Bold: data += " Bold"; break;
524  case QFont::Black: data += " Black"; break;
525  default: data += QString(" Wgt=%1").arg(f.weight()); break;
526  }
527  switch (f.style()) {
528  case QFont::StyleNormal: break; //data += " Normal"; break;
529  case QFont::StyleItalic: data += " Italic"; break;
530  case QFont::StyleOblique: data += " Oblique"; break;
531  default: break;
532  }
533  // QFontInfo is preferred, if f was set with a pixelSize().
534  data += " " + QString::number(QFontInfo(f).pointSize()).toLatin1();
535  break;
536  }
537  case QMetaType::QBrush:
538  { QBrush b = value.value<QBrush>();
539  if (!b.matrix().isIdentity())
540  break; // forget about saving complex brushes here
541  int bstyle = b.style();
542  // find index in our brush style enum
543  int k;
544  bool found_style = false;
545  for (k = 0; klf_brush_styles[k].brushStyle >= 0 && klf_brush_styles[k].style != NULL; ++k) {
546  if (klf_brush_styles[k].brushStyle == bstyle) {
547  found_style = true;
548  break;
549  }
550  }
551  if (!found_style) {
552  // didn't find this style, this is a complex brush. Need to save it via a datastream.
553  break;
554  }
555  // found brush style. This is a simple brush with just a style and a color.
556  data = "(";
557  data += klf_brush_styles[k].style;
558  if (strlen(klf_brush_styles[k].style))
559  data += " ";
560  QColor c = b.color();
561  data += QString("%1 %2 %3 %4").arg(c.red()).arg(c.green()).arg(c.blue()).arg(c.alpha());
562  data += ")";
563  break;
564  }
565  case QMetaType::QTextFormat:
566  {
567  QTextFormat tf = value.value<QTextFormat>();
568  const QMap<int,QVariant> props = tf.properties();
569 
571 
572  // first find the QTextFormat type.
573  int k;
574  for (k = 0; klf_text_format_formats[k].format != NULL; ++k)
575  if (klf_text_format_formats[k].formatId == tf.type())
576  break;
577  if (klf_text_format_formats[k].format == NULL) {
578  // didn't find format, something is bound to go wrong, so fall back
579  // on Qt's datastream saving.
580  data = QByteArray();
581  break;
582  }
583  // found format. This will be the first (value-less) section.
584  sections << QPair<QByteArray,QByteArray>(klf_text_format_formats[k].format, QByteArray());
585 
587  for (it = props.begin(); it != props.end(); ++it) {
588  int propId = it.key();
589  QVariant propValue = it.value();
590  // Add data for this property.
591 
592  // first look to see if a keyword is already known to be available
593  for (k = 0; klf_text_format_keywords[k].keyword != NULL; ++k)
594  if (klf_text_format_keywords[k].propId == propId &&
595  klf_text_format_keywords[k].fixed_value == propValue)
596  break;
597  const char *kw = klf_text_format_keywords[k].keyword;
598  if (kw != NULL) {
599  // found a keyword for this property-value pair
600  QByteArray key = kw;
601  sections << QPair<QByteArray,QByteArray>(kw, QByteArray());
602  continue;
603  }
604 
605  // now look to see if we can name the property
606  for (k = 0; klf_text_format_props[k].key != NULL; ++k)
607  if (klf_text_format_props[k].propId == propId)
608  break;
609  if (klf_text_format_props[k].key != NULL) {
610  // make sure the variant has the advertised type
611  if ( !strcmp(klf_text_format_props[k].type, propValue.typeName()) ) {
612  // found the property in our list of common properties
613  QByteArray key = klf_text_format_props[k].key;
614  QByteArray value = klfSaveVariantToText(propValue, true); // resort to XML for lists/maps...
615  sections << QPair<QByteArray,QByteArray>(key, value);
616  continue;
617  } else {
618  qWarning()<<KLF_FUNC_NAME<<": QTextFormat property "<<klf_text_format_props[k].key
619  <<" 's type is `"<<propValue.typeName()<<"' which is not the known type: "
620  <<klf_text_format_props[k].type;
621  }
622  }
623 
624  // this property is unknown to us. store it as we can.
626  QByteArray value;
627  value = QByteArray("[")+propValue.typeName()+"]"+klfSaveVariantToText(propValue, true);
628  }
629  data = encaps_map(sections, true);
630  break;
631  }
632  case QMetaType::QVariantList:
633  {
634  klfDbg("Saving list!") ;
635  const QList<QVariant>& list = value.toList();
636  if (saveListAndMapsAsXML) {
637  QDomElement el = make_xml_wrapper("variant-list");
638  el = klfSaveVariantListToXML(list, el);
639  data = el.ownerDocument().toByteArray(-1);
640  } else {
641  QList<QByteArray> sections;
642  QByteArray innertype;
643  for (k = 0; k < list.size(); ++k) {
644  if (k == 0)
645  innertype = list[k].typeName();
646  if (innertype != list[k].typeName()) {
647  klfWarning("saving list: not all inner QVariants have same type. Found a "<<innertype
648  <<" along with a "<<list[k].typeName());
649  }
650  sections << klfSaveVariantToText(list[k]);
651  }
652  if (savedListOrMapType != NULL)
653  *savedListOrMapType = innertype;
654  data = encaps_list(sections);
655  }
656  break;
657  }
658  case QMetaType::QVariantMap:
659  {
660  klfDbg("Saving Map!") ;
661  const QMap<QString,QVariant>& map = value.toMap();
662  if (saveListAndMapsAsXML) {
663  QDomElement el = make_xml_wrapper("variant-map");
664  klfDbg("map="<<map) ;
665  el = klfSaveVariantMapToXML(map, el);
666  data = el.ownerDocument().toByteArray(-1);
667  klfDbg("saved XML: data="<<data) ;
668  } else {
670  QByteArray innertype, thistype;
671  bool firstround = true;
672  for (QMap<QString,QVariant>::const_iterator it = map.begin(); it != map.end(); ++it) {
674  QByteArray v = klfSaveVariantToText(it.value());
675  thistype = it.value().typeName();
676  if (firstround) {
677  innertype = thistype;
678  firstround = false;
679  }
680  if (innertype != thistype) {
681  klfWarning("saving map: not all inner QVariants have same type. Found a "<<innertype
682  <<" along with a "<<thistype);
683  }
684  sections << QPair<QByteArray,QByteArray>(k, v);
685  }
686  if (savedListOrMapType != NULL)
687  *savedListOrMapType = innertype;
688  data = encaps_map(sections);
689  }
690  break;
691  }
692  default:
693  break;
694  };
695 
696  // -- some other types --
697 
698  QByteArray typeName = value.typeName();
699 
700  QByteArray typeSpec = QByteArray();
702  KLFSpecifyableType * t =
703  const_cast<KLFSpecifyableType*>(static_cast<const KLFSpecifyableType*>(value.data()));
704 
705  typeSpec = t->specification();
706  if (savedType != NULL) {
707  *savedType = typeName + "/" + typeSpec;
708  }
709  } else {
710  if (savedType != NULL)
711  *savedType = typeName;
712  }
713 
714  if (typeName == "KLFEnumType") {
715  // just save the integer value!
716  KLFEnumType e = value.value<KLFEnumType>();
717  data = QByteArray::number(e.value());
718  }
719 
720  if (KLFPObjRegisteredType::isRegistered(typeName)) {
722  const_cast<KLFAbstractPropertizedObject*>(static_cast<const KLFAbstractPropertizedObject*>(value.data()));
723 
724  bool hasfixedtypes = obj->hasFixedTypes();
725 
726  QVariantMap props = obj->allProperties();
727  if (!hasfixedtypes) {
728  return klfSaveVariantToText(props, true); // save all with XML
729  }
730  // if we have fixed types, convert them all to text (this is human-readable)
731  QVariantMap propstexts;
732  for (QVariantMap::const_iterator it = props.begin(); it != props.end(); ++it) {
733  propstexts[it.key()] = klfSaveVariantToText(it.value(), true); // in case of list/map values, use XML
734  klfDbg("Saving property "<<it.key()<<" to text, value = "<<propstexts[it.key()]) ;
735  }
736  props = propstexts;
737  return klfSaveVariantToText(props, false); // save all with XML
738  // NOTE: WE HAVE USED 'return', not 'data = ', because this call to klfSaveVariantToText() is
739  // already "finalizing"
740  }
741 
742  // protect data from some special sequences
743 
744  if (data.startsWith("[QVariant]") || data.startsWith("\\")) { // protect this special sequence
745  data = "\\"+data;
746  }
747 
748  // and provide a default encoding scheme in case no one up to now was able to
749  // format the data (this format is only machine-readable ...)
750 
751  if (data.isNull()) {
752  QByteArray vdata;
753  {
754  QDataStream stream(&vdata, QIODevice::WriteOnly);
755  stream.setVersion(QDataStream::Qt_4_4);
756  stream << value;
757  }
758  QByteArray vdata_esc = klfDataToEscaped(vdata);
759  qDebug("\tVariant value is %s, len=%d", vdata.constData(), vdata.size());
760  data = QByteArray("[QVariant]");
761  data += vdata_esc;
762  }
763 
764  klfDbg( "klfSaveVariantToText("<<value<<"): saved data (len="<<data.size()<<") : "<<data ) ;
765  return data;
766 }
767 
768 
769 
770 
771 KLF_EXPORT QVariant klfLoadVariantFromText(const QByteArray& stringdata, const char * dataTypeName,
772  const char *listOrMapDataTypeName)
773 {
775 
776  // SOME REGULAR EXPRESSIONS
777 
778 #define RX_INT "-?\\d+"
779 #define RX_COORD_SEP "\\s*(?:[,;]|\\s)\\s*" // note: non-capturing parenthesis
780 #define RX_SIZE_SEP "\\s*(?:[,;x]|\\s)\\s*" // note: non-capturing parenthesis
781 
782  // 1 2
783  QRegExp v2rx("^\\(?\\s*(" RX_INT ")" RX_COORD_SEP "(" RX_INT ")\\s*\\)?");
784  static const int V2RX_X = 1, V2RX_Y = 2;
785 
786  // 1 2
787  QRegExp szrx("^\\(?\\s*(" RX_INT ")" RX_SIZE_SEP "(" RX_INT ")\\s*\\)?");
788  static const int SZRX_W = 1, SZRX_H = 2;
789 
790  // 1 2
791  QRegExp rectrx("^\\(?\\s*(" RX_INT ")" RX_COORD_SEP "(" RX_INT ")"
792  // 3
793  "(?:" RX_COORD_SEP "|\\s*([+])\\s*)"
794  //4 5 6
795  "(" RX_INT ")(?:" RX_COORD_SEP "|\\s*([x])\\s*)(" RX_INT ")\\s*\\)?");
796  static const int RECTRX_X1 = 1, RECTRX_Y1 = 2, RECTRX_MIDDLESEP_PLUS = 3,
797  RECTRX_X2orW = 4, RECTRX_LASTSEP_X = 5, RECTRX_Y2orH = 6;
798 
799  // 1 2 3
800  QRegExp colrx("^(?:rgba?)?\\(?\\s*(\\d+)" RX_COORD_SEP "(\\d+)" RX_COORD_SEP "(\\d+)"
801  //4 5
802  "(" RX_COORD_SEP "(\\d+))?\\s*\\)?", Qt::CaseInsensitive);
803  static const int COLRX_R = 1, COLRX_G = 2, COLRX_B = 3, COLRX_MAYBE_ALPHA = 4, COLRX_A = 5;
804 
805  // 1 2 3
806  QRegExp brushrx("^(?:q?brush)?\\(?\\s*(?:([A-Za-z_]\\w*)" RX_COORD_SEP ")?(\\d+)" RX_COORD_SEP "(\\d+)"
807  // 4 5 6
808  RX_COORD_SEP "(\\d+)" "(" RX_COORD_SEP "(\\d+))?" "\\s*\\)?", Qt::CaseInsensitive);
809  static const int BRUSHRX_STYLE = 1, BRUSHRX_R = 2, BRUSHRX_G = 3, BRUSHRX_B = 4, BRUSHRX_A = 6;
810 
811  // 1 2
812  QRegExp fontrx("^([\"']?)\\s*(.+)\\s*\\1"
813  //3 4 5
814  "(\\s+(Light|Normal|DemiBold|Bold|Black|Wgt\\s*=\\s*(\\d+)))?"
815  //6 7 8 9
816  "(\\s+(Normal|Italic|Oblique))?(\\s+(\\d+))?$");
817  fontrx.setMinimal(true); // don't match Light|Normal|DemiBold|... etc as part of font name
818  static const int FONTRX_FAMILY = 2, FONTRX_WEIGHT_TEXT = 4, FONTRX_WEIGHT_VALUE = 5,
819  FONTRX_STYLE_TEXT = 7, FONTRX_POINTSIZE = 9;
820 
821 
822  // START DECODING TEXT
823 
824  QByteArray data = stringdata; // might need slight modifications before parsing
825 
826  // first check: if the type string is empty, we're loading a Null variant...
827  if (dataTypeName == NULL || *dataTypeName == 0) {
828  klfDbg("loading null variant.");
829  return QVariant();
830  }
831 
832  QVariant value;
833  if (data.startsWith("[QVariant]")) {
834  QByteArray vdata_esc = data.mid(strlen("[QVariant]"));
835  QByteArray vdata = klfEscapedToData(vdata_esc);
836  klfDbg( "\tAbout to read raw variant from datastr="<<vdata_esc<<", ie. from data len="<<vdata.size() ) ;
837  QDataStream stream(vdata);
838  stream.setVersion(QDataStream::Qt_4_4);
839  stream >> value;
840  return value;
841  }
842  if (data.startsWith("\\"))
843  data = data.mid(1);
844 
845  klfDbg( "Will start loading a `"<<dataTypeName<<"' from data (len="<<data.size()<<") : "<<data ) ;
846 
847 
848  QByteArray tname = dataTypeName;
849 
850  int idslash;
851  QByteArray tspecification = QByteArray();
852  if ((idslash = tname.indexOf('/')) >= 0) {
853  tspecification = tname.mid(idslash+1); // extract the specification ...
854  tname = tname.left(idslash); // ... and truncate the type name at the slash.
855  klfDbg("tspecification="<<tspecification<<", tname="<<tname) ;
856  }
857 
858  // now, start reading.
859  int type = QMetaType::type(tname);
860  klfDbg("Type is "<<type) ;
861  bool convertOk = false; // in case we break; somewhere, it's (by default) because of failed convertion.
862  int k;
863  switch (type) {
864  case QMetaType::Bool:
865  {
866  klfDbg("bool!") ;
867  QByteArray lowerdata = data.trimmed().toLower();
868  QChar c = QChar(lowerdata[0]);
869  // true, yes, on, 1
870  return QVariant::fromValue<bool>(c == 't' || c == 'y' || c == '1' || lowerdata == "on");
871  }
872  case QMetaType::Int:
873  {
874  klfDbg("int!") ;
875  int i = data.toInt(&convertOk);
876  if (convertOk)
877  return QVariant::fromValue<int>(i);
878  break;
879  }
880  case QMetaType::UInt:
881  {
882  klfDbg("uint!") ;
883  uint i = data.toUInt(&convertOk);
884  if (convertOk)
885  return QVariant::fromValue<uint>(i);
886  break;
887  }
888  case QMetaType::Short:
889  {
890  klfDbg("short!") ;
891  short i = data.toShort(&convertOk);
892  if (convertOk)
893  return QVariant::fromValue<short>(i);
894  break;
895  }
896  case QMetaType::UShort:
897  {
898  klfDbg("ushort!") ;
899  ushort i = data.toUShort(&convertOk);
900  if (convertOk)
901  return QVariant::fromValue<ushort>(i);
902  break;
903  }
904  case QMetaType::Long:
905  {
906  klfDbg("long!") ;
907  long i = data.toLong(&convertOk);
908  if (convertOk)
909  return QVariant::fromValue<long>(i);
910  break;
911  }
912  case QMetaType::ULong:
913  {
914  klfDbg("ulong!") ;
915  ulong i = data.toULong(&convertOk);
916  if (convertOk)
917  return QVariant::fromValue<ulong>(i);
918  break;
919  }
920  case QMetaType::LongLong:
921  {
922  klfDbg("longlong!") ;
923  qlonglong i = data.toLongLong(&convertOk);
924  if (convertOk)
925  return QVariant::fromValue<qlonglong>(i);
926  break;
927  }
928  case QMetaType::ULongLong:
929  {
930  klfDbg("ulonglong!") ;
931  qulonglong i = data.toULongLong(&convertOk);
932  if (convertOk)
933  return QVariant::fromValue<qulonglong>(i);
934  break;
935  }
936  case QMetaType::Double:
937  {
938  klfDbg("double!") ;
939  double val = data.toDouble(&convertOk);
940  if (convertOk)
941  return QVariant::fromValue<double>(val);
942  break;
943  }
944  case QMetaType::Char:
945  {
946  klfDbg("char!") ;
947  if (data[0] == '\\') {
948  if (data.size() < 2)
949  break;
950  if (data[1] == '\\')
951  return QVariant::fromValue<char>('\\');
952  if (data.size() < 3)
953  break;
954  uint c = data.mid(1).toUInt(&convertOk, 16);
955  if (!convertOk)
956  break;
957  convertOk = false; // reset by default convertOk to false
958  if (c > 255)
959  break;
960  return QVariant::fromValue<char>( (char)c );
961  }
962  return QVariant::fromValue<char>( (char)data[0] );
963  }
964  case QMetaType::QChar:
965  {
966  klfDbg("QChar!") ;
967  if (data[0] == '\\') {
968  if (data.size() < 2)
969  break;
970  if (data[1] == '\\')
971  return QVariant::fromValue<QChar>(QChar('\\'));
972  if (data.size() < 3)
973  break;
974  uint c = data.mid(1).toUInt(&convertOk, 16);
975  if (!convertOk)
976  break;
977  convertOk = false; // reset by default convertOk to false
978  if (c > 255)
979  break;
980  return QVariant::fromValue<QChar>( QChar(c) );
981  }
982  return QVariant::fromValue<QChar>( QChar(data[0]) );
983  }
984  case QMetaType::QString:
985  {
986  klfDbg("qstring!") ;
987  QString s;
988  QByteArray chunk;
989  k = 0;
990  while (k < data.size()) {
991  if (data[k] != '\\') {
992  chunk += data[k];
993  ++k;
994  continue;
995  }
996  if (data[k] == '\\' && k+1 >= data.size()) {
997  chunk += '\\'; // backslash at end of data
998  ++k;
999  continue;
1000  }
1001  // not at end of data
1002  if (data[k+1] != 'x') {
1003  // backslash followed by something else than 'x', add that escaped 'something else'
1004  chunk += data[k+1];
1005  k += 2; // had to skip the backslash
1006  continue;
1007  }
1008  // pos k points on '\\', pos k+1 points on 'x'
1009  int nlen = -1;
1010  if (k+5 < data.size() && klf_is_hex_char(data[k+2]) && klf_is_hex_char(data[k+3])
1011  && klf_is_hex_char(data[k+4]) && klf_is_hex_char(data[k+5])) {
1012  nlen = 4; // 4-digit Unicode char
1013  }
1014  if (k+3 < data.size() && klf_is_hex_char(data[k+2]) && klf_is_hex_char(data[k+3])) {
1015  nlen = 2; // 2 last digits of 4-digit unicode char
1016  }
1017  if (nlen < 0) {
1018  // bad format, ignore the escape sequence.
1019  chunk += data[k];
1020  ++k;
1021  continue;
1022  }
1023  // decode this char
1024  ushort cval = data.mid(k+2, nlen).toUShort(&convertOk, 16);
1025  QChar ch(cval);
1026  // dump chunk into string, and add this char
1027  s += QString::fromLocal8Bit(chunk) + ch;
1028  // reset chunk
1029  chunk = QByteArray();
1030  // and advance the corresponding number of characters, point on fresh one
1031  // advance of what we read: backslash+'x' (=2) + number of digits
1032  k += 2 + nlen;
1033  }
1034  // dump remaining chunk
1035  s += QString::fromLocal8Bit(chunk);
1036  return QVariant::fromValue<QString>(s);
1037  }
1038  case QMetaType::QStringList:
1039  {
1040  klfDbg("qstringlist!") ;
1041  QList<QByteArray> sections = decaps_list(data);
1042 
1043  // now we separated into bytearray sections. now read those into values.
1044  QStringList list;
1045  for (k = 0; k < sections.size(); ++k) {
1046  list << QString::fromUtf8(klfEscapedToData(sections[k]));
1047  }
1048 
1049  return QVariant::fromValue<QStringList>(list);
1050  }
1051  case QMetaType::QUrl:
1052  {
1053  klfDbg("url!") ;
1054  return QVariant::fromValue<QUrl>(QUrl(QString::fromLocal8Bit(data), QUrl::TolerantMode));
1055  }
1056  case QMetaType::QByteArray:
1057  {
1058  klfDbg("qbytearray!") ;
1059  QByteArray value_ba = klfEscapedToData(data);
1060  return QVariant::fromValue<QByteArray>(value_ba);
1061  }
1062  case QMetaType::QDate:
1063  {
1064  klfDbg("qdate!") ;
1065  QString s = QString::fromLocal8Bit(data);
1066  QDate date = QDate::fromString(s, Qt::SystemLocaleShortDate);
1067  if (!date.isValid()) date = QDate::fromString(s, Qt::ISODate);
1068  if (!date.isValid()) date = QDate::fromString(s, Qt::SystemLocaleLongDate);
1069  if (!date.isValid()) date = QDate::fromString(s, Qt::DefaultLocaleShortDate);
1070  if (!date.isValid()) date = QDate::fromString(s, Qt::TextDate);
1071  if (!date.isValid()) date = QDate::fromString(s, "dd-MM-yyyy");
1072  if (!date.isValid()) date = QDate::fromString(s, "dd.MM.yyyy");
1073  if (!date.isValid()) date = QDate::fromString(s, "dd MM yyyy");
1074  if (!date.isValid()) date = QDate::fromString(s, "yyyy-MM-dd");
1075  if (!date.isValid()) date = QDate::fromString(s, "yyyy.MM.dd");
1076  if (!date.isValid()) date = QDate::fromString(s, "yyyy MM dd");
1077  if (!date.isValid()) date = QDate::fromString(s, "yyyyMMdd");
1078  if (!date.isValid())
1079  break;
1080  return QVariant::fromValue<QDate>(date);
1081  }
1082  case QMetaType::QTime:
1083  {
1084  klfDbg("qtime!") ;
1085  QString s = QString::fromLocal8Bit(data);
1086  QTime time = QTime::fromString(s, Qt::SystemLocaleShortDate);
1087  if (!time.isValid()) time = QTime::fromString(s, Qt::ISODate);
1088  if (!time.isValid()) time = QTime::fromString(s, Qt::SystemLocaleLongDate);
1089  if (!time.isValid()) time = QTime::fromString(s, Qt::DefaultLocaleShortDate);
1090  if (!time.isValid()) time = QTime::fromString(s, Qt::TextDate);
1091  if (!time.isValid()) time = QTime::fromString(s, "hh:mm:ss.z");
1092  if (!time.isValid()) time = QTime::fromString(s, "hh:mm:ss");
1093  if (!time.isValid()) time = QTime::fromString(s, "hh:mm:ss AP");
1094  if (!time.isValid()) time = QTime::fromString(s, "hh.mm.ss");
1095  if (!time.isValid()) time = QTime::fromString(s, "hh.mm.ss AP");
1096  if (!time.isValid()) time = QTime::fromString(s, "hh mm ss");
1097  if (!time.isValid()) time = QTime::fromString(s, "hh mm ss AP");
1098  if (!time.isValid()) time = QTime::fromString(s, "hhmmss");
1099  if (!time.isValid())
1100  break;
1101  return QVariant::fromValue<QTime>(time);
1102  }
1103  case QMetaType::QDateTime:
1104  {
1105  klfDbg("qdatetime!") ;
1106  QString s = QString::fromLocal8Bit(data);
1107  QDateTime dt = QDateTime::fromString(s, Qt::SystemLocaleShortDate);
1108  if (!dt.isValid()) dt = QDateTime::fromString(s, Qt::ISODate);
1109  if (!dt.isValid()) dt = QDateTime::fromString(s, Qt::SystemLocaleLongDate);
1110  if (!dt.isValid()) dt = QDateTime::fromString(s, Qt::DefaultLocaleShortDate);
1111  if (!dt.isValid()) dt = QDateTime::fromString(s, Qt::TextDate);
1112  if (!dt.isValid()) dt = QDateTime::fromString(s, "dd-MM-yyyy hh:mm:ss");
1113  if (!dt.isValid()) dt = QDateTime::fromString(s, "dd-MM-yyyy hh.mm.ss");
1114  if (!dt.isValid()) dt = QDateTime::fromString(s, "dd.MM.yyyy hh:mm:ss");
1115  if (!dt.isValid()) dt = QDateTime::fromString(s, "dd.MM.yyyy hh.mm.ss");
1116  if (!dt.isValid()) dt = QDateTime::fromString(s, "dd MM yyyy hh mm ss");
1117  if (!dt.isValid()) dt = QDateTime::fromString(s, "yyyy-MM-dd hh:mm:ss");
1118  if (!dt.isValid()) dt = QDateTime::fromString(s, "yyyy-MM-dd hh.mm.ss");
1119  if (!dt.isValid()) dt = QDateTime::fromString(s, "yyyy.MM.dd hh:mm:ss");
1120  if (!dt.isValid()) dt = QDateTime::fromString(s, "yyyy.MM.dd hh.mm.ss");
1121  if (!dt.isValid()) dt = QDateTime::fromString(s, "yyyy MM dd hh mm ss");
1122  if (!dt.isValid()) dt = QDateTime::fromString(s, "yyyyMMddhhmmss");
1123  if (!dt.isValid())
1124  break;
1125  return QVariant::fromValue<QDateTime>(dt);
1126  }
1127  case QMetaType::QSize:
1128  {
1129  klfDbg("qsize!") ;
1131  if (szrx.indexIn(s) < 0)
1132  break;
1133  QStringList vals = szrx.capturedTexts();
1134  return QVariant::fromValue<QSize>(QSize(vals[SZRX_W].toInt(), vals[SZRX_H].toInt()));
1135  }
1136  case QMetaType::QPoint:
1137  {
1138  klfDbg("qpoint!") ;
1140  if (v2rx.indexIn(s) < 0)
1141  break;
1142  QStringList vals = v2rx.capturedTexts();
1143  return QVariant::fromValue<QPoint>(QPoint(vals[V2RX_X].toInt(), vals[V2RX_Y].toInt()));
1144  }
1145  case QMetaType::QRect:
1146  {
1147  klfDbg("qrect!") ;
1149  if (rectrx.indexIn(s) < 0)
1150  break;
1151  QStringList vals = rectrx.capturedTexts();
1152  if (vals[RECTRX_MIDDLESEP_PLUS] == "+" || vals[RECTRX_LASTSEP_X] == "x") {
1153  return QVariant::fromValue<QRect>(QRect( QPoint(vals[RECTRX_X1].toInt(), vals[RECTRX_Y1].toInt()),
1154  QSize(vals[RECTRX_X2orW].toInt(), vals[RECTRX_Y2orH].toInt()) ));
1155  }
1156  return QVariant::fromValue<QRect>(QRect( QPoint(vals[RECTRX_X1].toInt(), vals[RECTRX_Y1].toInt()),
1157  QPoint(vals[RECTRX_X2orW].toInt(), vals[RECTRX_Y2orH].toInt()) ));
1158  }
1159  case QMetaType::QColor:
1160  {
1161  klfDbg("qcolor!") ;
1162  QString colstr = QString::fromLocal8Bit(data.trimmed());
1163  // try our regexp
1164  if (colrx.indexIn(colstr) < 0) {
1165  klfDbg("color "<<colstr<<" does not match regexp="<<colrx.pattern()<<", trying named...") ;
1166  // try a named color
1167  QColor color; color.setNamedColor(colstr);
1168  // if we got a valid color, yepee
1169  if (color.isValid())
1170  return color;
1171  break;
1172  }
1173  // our regexp matched
1174  QStringList vals = colrx.capturedTexts();
1175  QColor color = QColor(vals[COLRX_R].toInt(), vals[COLRX_G].toInt(), vals[COLRX_B].toInt(), 255);
1176  if (!vals[COLRX_MAYBE_ALPHA].isEmpty())
1177  color.setAlpha(vals[COLRX_A].toInt());
1178  return QVariant::fromValue<QColor>(color);
1179  }
1180  case QMetaType::QFont:
1181  {
1182  klfDbg("qfont!") ;
1183  if (fontrx.indexIn(QString::fromLocal8Bit(data.trimmed())) < 0) {
1184  klfDbg("malformed font: "<<data);
1185  break;
1186  }
1187  QStringList vals = fontrx.capturedTexts();
1188  klfDbg("parsing font: data="<<data<<"; captured texts are: "<<vals );
1189 
1190  QString family = vals[FONTRX_FAMILY].trimmed();
1191  QString weighttxt = vals[FONTRX_WEIGHT_TEXT];
1192  QString weightval = vals[FONTRX_WEIGHT_VALUE];
1193  QString styletxt = vals[FONTRX_STYLE_TEXT];
1194  QString ptsval = vals[FONTRX_POINTSIZE];
1195 
1196  int weight = QFont::Normal;
1197  if (weighttxt == "Light") weight = QFont::Light;
1198  else if (weighttxt == "Normal") weight = QFont::Normal;
1199  else if (weighttxt == "DemiBold") weight = QFont::DemiBold;
1200  else if (weighttxt == "Bold") weight = QFont::Bold;
1201  else if (weighttxt == "Black") weight = QFont::Black;
1202  else if (weighttxt.startsWith("Wgt")) weight = weightval.toInt();
1203 
1204 
1205  QFont::Style style = QFont::StyleNormal;
1206  if (styletxt == "Normal") style = QFont::StyleNormal;
1207  else if (styletxt == "Italic") style = QFont::StyleItalic;
1208  else if (styletxt == "Oblique") style = QFont::StyleOblique;
1209 
1210  int pt = -1;
1211  if (!ptsval.isEmpty())
1212  pt = ptsval.toInt();
1213 
1214  QFont font(family, pt, weight);
1215  font.setStyle(style);
1216  return QVariant::fromValue<QFont>(font);
1217  }
1218  case QMetaType::QBrush:
1219  {
1220  klfDbg("qbrush!") ;
1221  if (brushrx.indexIn(QString::fromLocal8Bit(data.trimmed())) < 0) {
1222  klfDbg("malformed brush text: "<<data) ;
1223  break;
1224  }
1225  QStringList vals = brushrx.capturedTexts();
1226  QString style = vals[BRUSHRX_STYLE];
1227  // find brush style
1228  int k;
1229  bool style_found = false;
1230  for (k = 0; klf_brush_styles[k].brushStyle >= 0 && klf_brush_styles[k].style != NULL; ++k) {
1231  if (klf_brush_styles[k].style == style) {
1232  style_found = true;
1233  break;
1234  }
1235  }
1236  if (!style_found) {
1237  klfDbg("Can't find style"<<style<<" in brush style list!");
1238  break;
1239  }
1240  int qbrush_style = klf_brush_styles[k].brushStyle;
1241  // read the color and construct QBrush.
1242  QColor c = QColor(vals[BRUSHRX_R].toInt(), vals[BRUSHRX_G].toInt(),
1243  vals[BRUSHRX_B].toInt());
1244  if (!vals[BRUSHRX_A].isEmpty())
1245  c.setAlpha(vals[BRUSHRX_A].toInt());
1246  return QBrush(c, static_cast<Qt::BrushStyle>(qbrush_style));
1247  }
1248  case QMetaType::QTextFormat:
1249  {
1250  klfDbg("qtextformat!") ;
1251  int k;
1252  QList<QPair<QByteArray,QByteArray> > sections = decaps_map(data, true);
1253  if (sections.isEmpty()) {
1254  klfDbg("Invalid QTextFormat data.") ;
1255  break;
1256  }
1257  QPair<QByteArray,QByteArray> firstSection = sections.takeFirst();
1258  QString fmttype = QString::fromLatin1(firstSection.first);
1259  // find the format in our list
1260  for (k = 0; klf_text_format_formats[k].format != NULL; ++k)
1261  if (QString::compare(fmttype, QLatin1String(klf_text_format_formats[k].format),
1262  Qt::CaseInsensitive) == 0)
1263  break;
1264  if (klf_text_format_formats[k].format == NULL) {
1265  klfDbg("QTextFormat: Invalid format type: "<<fmttype) ;
1266  break;
1267  }
1268  int qtextformat_type = klf_text_format_formats[k].formatId;
1269 
1270  // now decode the list of properties
1271  QTextFormat textformat(qtextformat_type);
1272  QList<QPair<QByteArray,QByteArray> >::const_iterator it;
1273  for (it = sections.begin(); it != sections.end(); ++it) {
1274  QByteArray key = (*it).first.trimmed();
1275  QByteArray value = (*it).second;
1276  klfDbg("QTextFormat: considering property pair key="<<key<<"; value="<<value) ;
1277  // see if the key is a keyword
1278  for (k = 0; klf_text_format_keywords[k].keyword != NULL; ++k)
1279  if (QString::compare(QLatin1String(klf_text_format_keywords[k].keyword),
1280  key, Qt::CaseInsensitive) == 0)
1281  break;
1282  if (klf_text_format_keywords[k].keyword != NULL) {
1283  // this is a keyword.
1284  klfDbg("QTextFormat: is keyword, propId="<<klf_text_format_keywords[k].propId<<", fixed_value="
1285  <<klf_text_format_keywords[k].fixed_value) ;
1286  textformat.setProperty(klf_text_format_keywords[k].propId,
1287  klf_text_format_keywords[k].fixed_value);
1288  continue;
1289  }
1290  // see if the key is a known property name
1291  for (k = 0; klf_text_format_props[k].key != NULL; ++k)
1292  if (QString::compare(QLatin1String(klf_text_format_props[k].key),
1293  key, Qt::CaseInsensitive) == 0)
1294  break;
1295  if (klf_text_format_props[k].key != NULL) {
1296  klfDbg("QTextFormat: is known property of type "<<klf_text_format_props[k].type) ;
1297  // load property propId, of type type
1298  QVariant vval = klfLoadVariantFromText(value, klf_text_format_props[k].type, "XML");
1299  textformat.setProperty(klf_text_format_props[k].propId, vval);
1300  continue;
1301  }
1302  // load generally-saved qvariant property
1303 
1304  bool tointok = true;
1305  int propid = key.toInt(&tointok);
1306  if (!tointok) {
1307  qWarning()<<KLF_FUNC_NAME<<": QTextFormat bad format for general property key=value pair; "
1308  <<"key is not a numerical property ID, nor is it a known property name.";
1309  }
1310 
1311  klfDbg("QTextFormat: property is not a known one. propid="<<propid) ;
1312 
1313  // trim space beginning of string
1314  while (value.size() && QChar(value[0]).isSpace())
1315  value.remove(0, 1);
1316  int i;
1317  if (value.isEmpty() || !value.startsWith("[") || ((i = value.indexOf(']')) == -1)) {
1318  qWarning().nospace()<<KLF_FUNC_NAME<<": QTextFormat bad format for general property, value does "
1319  <<"not begin with \"[type-name]\".";
1320  continue;
1321  }
1322  QByteArray typenm = value.mid(1, i-1);
1323  QByteArray valuedata = value.mid(i+1);
1324  QVariant vval = klfLoadVariantFromText(valuedata, typenm);
1325  klfDbg("setting generalized property "<<propid<<" to value "<<vval) ;
1326  textformat.setProperty(propid, vval);
1327  }
1328  return textformat;
1329  }
1330  case QMetaType::QVariantList:
1331  {
1332  klfDbg("qvariantlist!") ;
1333  if (listOrMapDataTypeName == QLatin1String("XML")) {
1334  QDomElement el = parse_xml_wrapper(data, "variant-list");
1335  return klfLoadVariantListFromXML(el);
1336  } else {
1337  QList<QByteArray> sections = decaps_list(data);
1338 
1339  // now we separated into bytearray sections. now read those into values.
1340  QVariantList list;
1341  for (k = 0; k < sections.size(); ++k) {
1342  QVariant val = klfLoadVariantFromText(sections[k], listOrMapDataTypeName);
1343  list << val;
1344  }
1345 
1346  return QVariant::fromValue<QVariantList>(list);
1347  }
1348  }
1349  case QMetaType::QVariantMap:
1350  {
1351  klfDbg("qvariantmap!") ;
1352  if (listOrMapDataTypeName == QLatin1String("XML")) {
1353  QDomElement el = parse_xml_wrapper(data, "variant-map");
1354  return klfLoadVariantMapFromXML(el);
1355  } else {
1356  const QList<QPair<QByteArray,QByteArray> > sections = decaps_map(data);
1357  QVariantMap vmap;
1358  QList<QPair<QByteArray,QByteArray> >::const_iterator it;
1359  for (it = sections.begin(); it != sections.end(); ++it) {
1360  QString key = klfLoadVariantFromText((*it).first, "QString").toString();
1361  QVariant value = klfLoadVariantFromText((*it).second, listOrMapDataTypeName);
1362  vmap[key] = value;
1363  }
1364  return QVariant::fromValue<QVariantMap>(vmap);
1365  }
1366  }
1367  default:
1368  break;
1369  }
1370 
1371  if (tname == "KLFEnumType") {
1372  // just load the integer value!
1373  KLFEnumType e;
1374  e.setSpecification(tspecification);
1375  e.setValue(data.toInt());
1376  return QVariant::fromValue<KLFEnumType>(e);
1377  }
1378 
1379  klfDbg("other type or failed to load the good type!") ;
1380 
1381  // maybe load a propertized object.
1383  // construct a default such wanted object of requried type
1384  QVariant value(QMetaType::type(dataTypeName), (const void*)NULL);
1386  const_cast<KLFAbstractPropertizedObject*>(static_cast<const KLFAbstractPropertizedObject*>(value.data()));
1387 
1388  if (tspecification.size()) {
1389  KLFSpecifyableType * st =
1390  const_cast<KLFSpecifyableType*>(static_cast<const KLFSpecifyableType*>(value.data()));
1391  st->setSpecification(tspecification);
1392  }
1393 
1394  bool hasfixedtypes = obj->hasFixedTypes();
1395 
1396  klfDbg("loading an abstr.prop.obj: "<<obj) ;
1397  klfDbg("obj is of type "<<obj->objectKind()<<", fixedtypes="<<hasfixedtypes) ;
1398 
1399  QVariantMap props = klfLoadVariantFromText(data, "QVariantMap", hasfixedtypes ? "QByteArray" : "XML").toMap();
1400  if (!hasfixedtypes) {
1401  obj->setAllProperties(props); // the properties are all as required
1402  return value;
1403  }
1404  // if we have fixed types, convert them all back from text (this is human-readable)
1405  QVariantMap propsconverted;
1406  for (QVariantMap::const_iterator it = props.begin(); it != props.end(); ++it) {
1407  QByteArray tn = obj->typeNameFor(it.key());
1408  // add type specification if needed
1409  QByteArray ts = obj->typeSpecificationFor(it.key());
1410  if (ts.size())
1411  tn += "/"+ts;
1412  propsconverted[it.key()] = klfLoadVariantFromText(it.value().toByteArray(), tn,
1413  "XML"); // in case of list/map values, we have used XML
1414  klfDbg("Loading property "<<it.key()<<" from saved text, value = "<<propsconverted[it.key()]) ;
1415  }
1416  props = propsconverted;
1417  obj->setAllProperties(props);
1418  return value;
1419  }
1420 
1421  qWarning("klfLoadVariantFromText: Can't load a %s from %s !", dataTypeName, stringdata.constData());
1422  return QVariant();
1423 }
1424 
1425 
1426 
1427 
1428 
1429 // ----------------------------------------------------
1430 
1431 
1432 
1433 
1434 
1435 KLF_EXPORT QDomElement klfSaveVariantMapToXML(const QVariantMap& vmap, QDomElement baseNode)
1436 {
1438 
1439  QDomDocument doc = baseNode.ownerDocument();
1440 
1441  for (QVariantMap::const_iterator it = vmap.begin(); it != vmap.end(); ++it) {
1442  QString key = it.key();
1443  QVariant value = it.value();
1444 
1445  QDomElement pairNode = doc.createElement("pair");
1446  // * key
1447  QDomElement keyNode = doc.createElement("key");
1448  QDomText keyText = doc.createTextNode(key);
1449  keyNode.appendChild(keyText);
1450  pairNode.appendChild(keyNode);
1451  // * value data
1452  QDomElement vdataNode = doc.createElement("value");
1453  QString vtype = QLatin1String(value.typeName());
1454  if (vtype == "QVariantMap") {
1455  vdataNode.setAttribute(QLatin1String("type"), vtype);
1456  vdataNode = klfSaveVariantMapToXML(value.toMap(), vdataNode);
1457  } else if (vtype == "QVariantList") {
1458  vdataNode.setAttribute(QLatin1String("type"), vtype);
1459  vdataNode = klfSaveVariantListToXML(value.toList(), vdataNode);
1460  } else {
1461  QByteArray savedvtype;
1462  QDomText vdataText = doc.createTextNode(QString::fromLocal8Bit(klfSaveVariantToText(value, false, &savedvtype)));
1463  vdataNode.appendChild(vdataText);
1464  vdataNode.setAttribute(QLatin1String("type"), QString::fromUtf8(savedvtype));
1465  }
1466  pairNode.appendChild(vdataNode);
1467  // now append this pair to our list
1468  baseNode.appendChild(pairNode);
1469  }
1470  return baseNode;
1471 }
1472 
1474 {
1476 
1477  QVariantMap vmap;
1478 
1479  QDomNode n;
1480  for (n = xmlNode.firstChild(); ! n.isNull(); n = n.nextSibling()) {
1481  QDomElement e = n.toElement(); // try to convert the node to an element.
1482  if ( e.isNull() || n.nodeType() != QDomNode::ElementNode )
1483  continue;
1484  if ( e.nodeName() != "pair" ) {
1485  klfWarning("Ignoring unexpected tag "<<e.nodeName()) ;
1486  continue;
1487  }
1488  // read this pair
1489  QString key;
1490  QByteArray valuetype;
1491  QByteArray valuedata;
1492  QDomElement valueNode;
1493  QDomNode nn;
1494  for (nn = e.firstChild(); ! nn.isNull(); nn = nn.nextSibling()) {
1495  klfDbg("inside <pair>: read node "<<nn.nodeName()) ;
1496  QDomElement ee = nn.toElement();
1497  if ( ee.isNull() || nn.nodeType() != QDomNode::ElementNode )
1498  continue;
1499  if ( ee.nodeName() == "key" ) {
1500  key = ee.text();
1501  continue;
1502  }
1503  if ( ee.nodeName() == "value" ) {
1504  // "local 8-bit" because klfLoadVariantFromText() assumes local 8-bit encoding
1505  valueNode = ee;
1506  valuedata = ee.text().toLocal8Bit();
1507  valuetype = ee.attribute("type").toUtf8();
1508  continue;
1509  }
1510  klfWarning("Ignoring unexpected tag "<<ee.nodeName()<<" in <pair>!") ;
1511  }
1512  QVariant value;
1513  if (valuetype == "QVariantMap") {
1514  value = QVariant::fromValue<QVariantMap>(klfLoadVariantMapFromXML(valueNode));
1515  } else if (valuetype == "QVariantList") {
1516  value = QVariant::fromValue<QVariantList>(klfLoadVariantListFromXML(valueNode));
1517  } else {
1518  value = klfLoadVariantFromText(valuedata, valuetype.constData());
1519  }
1520  // set this value in our variant map
1521  vmap[key] = value;
1522  }
1523  return vmap;
1524 }
1525 
1526 
1527 KLF_EXPORT QDomElement klfSaveVariantListToXML(const QVariantList& vlist, QDomElement baseNode)
1528 {
1529  QDomDocument doc = baseNode.ownerDocument();
1530 
1531  for (QVariantList::const_iterator it = vlist.begin(); it != vlist.end(); ++it) {
1532  QVariant value = *it;
1533 
1534  QDomElement elNode = doc.createElement(QLatin1String("item"));
1535  QString vtype = QString::fromLatin1(value.typeName()); // "Latin1" encoding by convention
1536  // because type names do not have any special chars
1537  if (vtype == "QVariantMap") {
1538  elNode.setAttribute(QLatin1String("type"), vtype);
1539  elNode = klfSaveVariantMapToXML(value.toMap(), elNode);
1540  } else if (vtype == "QVariantList") {
1541  elNode.setAttribute(QLatin1String("type"), vtype);
1542  elNode = klfSaveVariantListToXML(value.toList(), elNode);
1543  } else {
1544  QByteArray savedvtype;
1545  QDomText vdataText = doc.createTextNode(QString::fromLocal8Bit(klfSaveVariantToText(value, false, &savedvtype)));
1546  elNode.appendChild(vdataText);
1547  elNode.setAttribute(QLatin1String("type"), QString::fromUtf8(savedvtype));
1548  }
1549  // now append this pair to our list
1550  //klfDbg( "... appending node!" ) ;
1551  baseNode.appendChild(elNode);
1552  }
1553 
1554  return baseNode;
1555 }
1556 
1558 {
1560 
1561  QVariantList vlist;
1562 
1563  QDomNode n;
1564  for (n = xmlNode.firstChild(); ! n.isNull(); n = n.nextSibling()) {
1565  QDomElement e = n.toElement(); // try to convert the node to an element.
1566  if ( e.isNull() || n.nodeType() != QDomNode::ElementNode )
1567  continue;
1568  if ( e.nodeName() != QLatin1String("item") ) {
1569  qWarning("%s: ignoring unexpected tag `%s'!\n", KLF_FUNC_NAME, qPrintable(e.nodeName()));
1570  continue;
1571  }
1572 
1573  QString vtype = e.attribute(QLatin1String("type"));
1574 
1575  QVariant value;
1576  if (vtype == QLatin1String("QVariantMap")) {
1577  value = QVariant::fromValue<QVariantMap>(klfLoadVariantMapFromXML(e));
1578  } else if (vtype == QLatin1String("QVariantList")) {
1579  value = QVariant::fromValue<QVariantList>(klfLoadVariantListFromXML(e));
1580  } else {
1581  value = klfLoadVariantFromText(e.text().toLocal8Bit(), vtype.toLatin1().constData());
1582  }
1583 
1584  // set this value in our variant map
1585  vlist << value;
1586  }
1587  return vlist;
1588 }
1589 
1590 
1591 
1592 // --------------------------------------------------
1593 
1594 
1596  : KLFFactoryBase(&pFactoryManager)
1597 {
1598 }
1600 {
1601 }
1602 
1603 // static
1604 KLFFactoryManager KLFAbstractPropertizedObjectSaver::pFactoryManager;
1605 
1606 // static
1609 {
1610  QList<KLFFactoryBase*> allFactories = pFactoryManager.registeredFactories();
1611  QString s;
1612  foreach (KLFFactoryBase * ff, allFactories) {
1614  if ((s = f->recognizeDataFormat(data)).size() != 0) {
1615  // recognized format
1616  if (format != NULL)
1617  *format = s;
1618  return f;
1619  }
1620  }
1621  // failed to recognize format
1622  if (format != NULL)
1623  *format = QString();
1624  return NULL;
1625 }
1626 
1627 // static
1630 {
1631  return dynamic_cast<KLFAbstractPropertizedObjectSaver*>(pFactoryManager.findFactoryFor(format));
1632 }
1633 
1634 // this is not a class member
1635 KLFBaseFormatsPropertizedObjectSaver __klf_baseformats_pobj_saver; // this will automatically register it...
1636 
1637 
1639 {
1643  KLF_ASSERT_NOT_NULL(saver, "Can't find object saver for format="<<format<<" !", return QByteArray(); ) ;
1644  return saver->save(obj, format);
1645 }
1646 
1648 {
1651  QString f = format;
1652  if (f.isEmpty()) { // need to recognize format
1654  KLF_ASSERT_CONDITION(!f.isEmpty(), "Can't recognize data format!", return false; ) ;
1655  } else {
1657  }
1658  KLF_ASSERT_NOT_NULL(saver, "Can't find object saver for format="<<f<<" !", return false; ) ;
1659  return saver->load(data, obj, f);
1660 }
1661 
1662 
QUrl toUrl() const
virtual QString objectKind() const =0
A string representing this object type.
#define RX_SIZE_SEP
QByteArray fromUnicode(const QString &str) const
static bool isRegistered(const char *name)
Definition: klfpobj.h:905
static KLFAbstractPropertizedObjectSaver * findRecognizedFormat(const QByteArray &data, QString *format=NULL)
uint toUInt(bool *ok, int base) const
QString toUpper() const
int width() const
KLF_EXPORT QByteArray klfSaveVariantToText(const QVariant &value, bool saveListAndMapsAsXML, QByteArray *savedType, QByteArray *savedListOrMapType)
static bool isRegistered(const char *name)
Definition: klfpobj.h:947
void setProperty(int propertyId, const QVariant &value)
int toInt(bool *ok, int base) const
KLF_EXPORT QByteArray klfSave(const KLFAbstractPropertizedObject *obj, const QString &format)
const char * style
Definition: klfdatautil.cpp:56
QDomNode appendChild(const QDomNode &newChild)
short toShort(bool *ok, int base) const
QByteArray toLower() const
QByteArray trimmed() const
double toDouble(bool *ok) const
virtual QString recognizeDataFormat(const QByteArray &data) const =0
Qt::BrushStyle style() const
QString attribute(const QString &name, const QString &defValue) const
KLF_EXPORT QVariantList klfLoadVariantListFromXML(const QDomElement &xmlNode)
Load a list saved with klfSaveVariantListToXML()
void setMinimal(bool minimal)
KLF_EXPORT QDomElement klfSaveVariantMapToXML(const QVariantMap &vmap, QDomElement baseNode)
Lossless save of full map to XML with type information.
int weight() const
QList< QVariant > toList() const
Base declarations for klatexformula and some utilities.
ushort toUShort(bool *ok, int base) const
bool isNull() const
const char * type
Definition: klfdatautil.cpp:96
#define RX_INT
bool isEmpty() const
bool isValid() const
bool startsWith(const QByteArray &ba) const
#define klfDbg(streamableItems)
print debug stream items
T value() const
#define KLF_DEBUG_BLOCK(msg)
Utility to debug the execution of a block.
void setAlpha(int alpha)
int height() const
QTime fromString(const QString &string, Qt::DateFormat format)
QDomElement documentElement() const
void setValue(int v)
Definition: klfpobj.h:176
int value() const
Definition: klfpobj.h:172
NodeType nodeType() const
long toLong(bool *ok, int base) const
void setNamedColor(const QString &name)
static KLFAbstractPropertizedObjectSaver * findSaverFor(const QString &format)
KLF_EXPORT QByteArray klfEscapedToData(const QByteArray &data, char escapechar)
int type(const char *typeName)
virtual QMap< QString, QVariant > allProperties() const
Convenience function to retrieve all properties.
Definition: klfpobj.cpp:51
int brushStyle
Definition: klfdatautil.cpp:56
QTextCodec * codecForLocale()
Base class for factories.
Definition: klffactory.h:40
int x() const
int y() const
int size() const
#define KLF_ASSERT_NOT_NULL(ptr, msg, failaction)
Asserting Non-NULL pointers (NON-FATAL)
QDomNode nextSibling() const
QVariant fixed_value
const QColor & color() const
#define KLF_TEXT_FORMAT_PROP(p, type)
Definition: klfdatautil.cpp:93
QDomElement toElement() const
int indexIn(const QString &str, int offset, CaretMode caretMode) const
QDate fromString(const QString &string, Qt::DateFormat format)
An abstract object characterized by properties.
Definition: klfpobj.h:58
int indexOf(char ch, int from) const
QString number(int n, int base)
QString fromLocal8Bit(const char *str, int size)
virtual QByteArray typeNameFor(const QString &property) const
Corresonding type for the given property.
Definition: klfpobj.h:135
void append(const T &value)
QString fromUtf8(const char *str, int size)
bool isSpace() const
void setStyle(Style style)
QDomDocument ownerDocument() const
QString text() const
bool isNull() const
#define KLF_EXPORT
Definition: klfdefs.h:41
#define RX_COORD_SEP
int top() const
int red() const
#define klfWarning(streamableItems)
QStringList capturedTexts() const
void setAttribute(const QString &name, const QString &value)
int left() const
QMap< int, QVariant > properties() const
int toInt(bool *ok, int base) const
KLF_EXPORT QDomElement klfSaveVariantListToXML(const QVariantList &vlist, QDomElement baseNode)
Lossless save of full list to XML with type information.
bool isEmpty() const
QString nodeName() const
bool isEmpty() const
const char * constData() const
QByteArray number(int n, int base)
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
A base abstract factory manager class.
Definition: klffactory.h:91
QByteArray & replace(int pos, int len, const char *after)
bool isValid() const
const char * format
Definition: klfdatautil.cpp:81
iterator end()
const char * key
Definition: klfdatautil.cpp:96
QByteArray mid(int pos, int len) const
int alpha() const
#define KLF_DEBUG_TIME_BLOCK(msg)
Utility to time the execution of a block.
iterator begin()
void setVersion(int v)
#define klfFmtCC
Definition: klfdefs.h:61
QSize toSize() const
ushort unicode() const
QDomText createTextNode(const QString &value)
int green() const
iterator end()
QByteArray toLocal8Bit() const
#define KLF_FUNC_NAME
bool isIdentity() const
virtual bool load(const QByteArray &data, KLFAbstractPropertizedObject *obj, const QString &format)=0
QDateTime fromString(const QString &string, Qt::DateFormat format)
qlonglong toLongLong(bool *ok, int base) const
bool isNull() const
bool isValid() const
const QMatrix & matrix() const
virtual QByteArray save(const KLFAbstractPropertizedObject *obj, const QString &format)=0
QString & replace(int position, int n, QChar after)
int blue() const
QByteArray left(int len) const
KLFFactoryBase * findFactoryFor(const QString &objType)
Definition: klffactory.cpp:52
KLF_EXPORT bool klfLoad(const QByteArray &data, KLFAbstractPropertizedObject *obj, const QString &format)
QDomNode firstChild() const
QByteArray toLatin1() const
int width() const
QMap< QString, QVariant > toMap() const
QString mid(int position, int n) const
virtual bool setSpecification(const QByteArray &data)=0
QStringList toStringList() const
#define KLF_BRUSH_STYLE(sty)
Definition: klfdatautil.cpp:53
T takeFirst()
int formatId
Definition: klfdatautil.cpp:81
QString family() const
QList< KLFFactoryBase * > registeredFactories()
Definition: klffactory.h:107
#define KLF_TEXT_FORMAT_FORMAT(fmt)
Definition: klfdatautil.cpp:78
const char * typeName() const
int height() const
QString pattern() const
bool contains(char ch) const
KLFBaseFormatsPropertizedObjectSaver __klf_baseformats_pobj_saver
int length() const
bool canEncode(QChar ch) const
bool toBool() const
QString fromLatin1(const char *str, int size)
bool isValid() const
QPoint toPoint() const
qulonglong toULongLong(bool *ok, int base) const
ulong toULong(bool *ok, int base) const
KLF_EXPORT QByteArray klfDataToEscaped(const QByteArray &value_ba, char escapechar)
bool setSpecification(const QByteArray &data)
Definition: klfpobj.h:205
virtual bool setAllProperties(const QMap< QString, QVariant > &data)
Convenience function to load a set of property values.
Definition: klfpobj.cpp:61
virtual bool hasFixedTypes() const
Definition: klfpobj.h:129
QRect toRect() const
#define KLF_ASSERT_CONDITION(expr, msg, failaction)
Asserting Conditions (NON-FATAL)
QDomElement createElement(const QString &tagName)
Type type() const
KLF_EXPORT QVariant klfLoadVariantFromText(const QByteArray &stringdata, const char *dataTypeName, const char *listOrMapDataTypeName)
int size() const
KLF_EXPORT QVariantMap klfLoadVariantMapFromXML(const QDomElement &xmlNode)
Load a map saved with klfSaveVariantMapToXML()
int compare(const QString &other, Qt::CaseSensitivity cs) const
virtual QByteArray specification() const =0
Inherit this class to implement a custom saver for KLFAbstractPropertizedObjects. ...
Definition: klfdatautil.h:123
QByteArray & remove(int pos, int len)
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const
QString toString() const
int propId
Definition: klfdatautil.cpp:96
const char * keyword
virtual QByteArray typeSpecificationFor(const QString &property) const
A type specification for the given property.
Definition: klfpobj.h:144
iterator begin()
QChar toChar() const
QByteArray toEncoded(FormattingOptions options) const
QByteArray toByteArray(int indent) const
Style style() const
bool setContent(const QByteArray &data, bool namespaceProcessing, QString *errorMsg, int *errorLine, int *errorColumn)
int type() const

Generated by doxygen 1.8.13