[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$ */
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 
An abstract object characterized by properties.
Definition: klfpobj.h:59
virtual bool hasFixedTypes() const
Definition: klfpobj.h:129
virtual QByteArray typeNameFor(const QString &property) const
Corresonding type for the given property.
Definition: klfpobj.h:135
virtual QString objectKind() const =0
A string representing this object type.
virtual bool setAllProperties(const QMap< QString, QVariant > &data)
Convenience function to load a set of property values.
Definition: klfpobj.cpp:61
virtual QByteArray typeSpecificationFor(const QString &property) const
A type specification for the given property.
Definition: klfpobj.h:144
virtual QMap< QString, QVariant > allProperties() const
Convenience function to retrieve all properties.
Definition: klfpobj.cpp:51
Inherit this class to implement a custom saver for KLFAbstractPropertizedObjects.
Definition: klfdatautil.h:124
virtual QString recognizeDataFormat(const QByteArray &data) const =0
virtual bool load(const QByteArray &data, KLFAbstractPropertizedObject *obj, const QString &format)=0
static KLFAbstractPropertizedObjectSaver * findSaverFor(const QString &format)
static KLFAbstractPropertizedObjectSaver * findRecognizedFormat(const QByteArray &data, QString *format=NULL)
virtual QByteArray save(const KLFAbstractPropertizedObject *obj, const QString &format)=0
int value() const
Definition: klfpobj.h:172
bool setSpecification(const QByteArray &data)
Definition: klfpobj.h:205
void setValue(int v)
Definition: klfpobj.h:176
Base class for factories.
Definition: klffactory.h:41
A base abstract factory manager class.
Definition: klffactory.h:92
KLFFactoryBase * findFactoryFor(const QString &objType)
Definition: klffactory.cpp:52
QList< KLFFactoryBase * > registeredFactories()
Definition: klffactory.h:107
static bool isRegistered(const char *name)
Definition: klfpobj.h:905
static bool isRegistered(const char *name)
Definition: klfpobj.h:947
virtual bool setSpecification(const QByteArray &data)=0
virtual QByteArray specification() const =0
int propId
Definition: klfdatautil.cpp:96
KLFBaseFormatsPropertizedObjectSaver __klf_baseformats_pobj_saver
const char * style
Definition: klfdatautil.cpp:56
#define KLF_BRUSH_STYLE(sty)
Definition: klfdatautil.cpp:53
int brushStyle
Definition: klfdatautil.cpp:56
KLF_EXPORT QByteArray klfEscapedToData(const QByteArray &data, char escapechar)
int formatId
Definition: klfdatautil.cpp:81
const char * keyword
#define KLF_TEXT_FORMAT_PROP(p, type)
Definition: klfdatautil.cpp:93
KLF_EXPORT QDomElement klfSaveVariantListToXML(const QVariantList &vlist, QDomElement baseNode)
Lossless save of full list to XML with type information.
const char * format
Definition: klfdatautil.cpp:81
QVariant fixed_value
const char * type
Definition: klfdatautil.cpp:96
#define RX_INT
KLF_EXPORT QDomElement klfSaveVariantMapToXML(const QVariantMap &vmap, QDomElement baseNode)
Lossless save of full map to XML with type information.
#define RX_COORD_SEP
KLF_EXPORT QVariant klfLoadVariantFromText(const QByteArray &stringdata, const char *dataTypeName, const char *listOrMapDataTypeName)
KLF_EXPORT bool klfLoad(const QByteArray &data, KLFAbstractPropertizedObject *obj, const QString &format)
KLF_EXPORT QByteArray klfDataToEscaped(const QByteArray &value_ba, char escapechar)
KLF_EXPORT QByteArray klfSaveVariantToText(const QVariant &value, bool saveListAndMapsAsXML, QByteArray *savedType, QByteArray *savedListOrMapType)
KLF_EXPORT QVariantMap klfLoadVariantMapFromXML(const QDomElement &xmlNode)
Load a map saved with klfSaveVariantMapToXML()
const char * key
Definition: klfdatautil.cpp:96
#define RX_SIZE_SEP
KLF_EXPORT QVariantList klfLoadVariantListFromXML(const QDomElement &xmlNode)
Load a list saved with klfSaveVariantListToXML()
KLF_EXPORT QByteArray klfSave(const KLFAbstractPropertizedObject *obj, const QString &format)
#define KLF_TEXT_FORMAT_FORMAT(fmt)
Definition: klfdatautil.cpp:78
#define KLF_DEBUG_TIME_BLOCK(msg)
Utility to time the execution of a block.
#define klfWarning(streamableItems)
#define KLF_DEBUG_BLOCK(msg)
Utility to debug the execution of a block.
#define KLF_ASSERT_NOT_NULL(ptr, msg, failaction)
Asserting Non-NULL pointers (NON-FATAL)
#define KLF_ASSERT_CONDITION(expr, msg, failaction)
Asserting Conditions (NON-FATAL)
#define KLF_FUNC_NAME
#define klfDbg(streamableItems)
print debug stream items
Base declarations for klatexformula and some utilities.
#define klfFmtCC
Definition: klfdefs.h:61
#define KLF_EXPORT
Definition: klfdefs.h:41
const QColor & color() const
const QMatrix & matrix() const
Qt::BrushStyle style() const
const char * constData() const
bool contains(char ch) const
int indexOf(char ch, int from) const
bool isEmpty() const
bool isNull() const
QByteArray left(int len) const
QByteArray mid(int pos, int len) const
QByteArray number(int n, int base)
QByteArray & remove(int pos, int len)
QByteArray & replace(int pos, int len, const char *after)
int size() const
bool startsWith(const QByteArray &ba) const
double toDouble(bool *ok) const
int toInt(bool *ok, int base) const
long toLong(bool *ok, int base) const
qlonglong toLongLong(bool *ok, int base) const
QByteArray toLower() const
short toShort(bool *ok, int base) const
uint toUInt(bool *ok, int base) const
ulong toULong(bool *ok, int base) const
qulonglong toULongLong(bool *ok, int base) const
ushort toUShort(bool *ok, int base) const
QByteArray trimmed() const
ushort unicode() const
int alpha() const
int blue() const
int green() const
bool isValid() const
int red() const
void setAlpha(int alpha)
void setNamedColor(const QString &name)
void setVersion(int v)
QDate fromString(const QString &string, Qt::DateFormat format)
bool isValid() const
QDateTime fromString(const QString &string, Qt::DateFormat format)
bool isValid() const
QDomElement createElement(const QString &tagName)
QDomText createTextNode(const QString &value)
QByteArray toByteArray(int indent) const
QString attribute(const QString &name, const QString &defValue) const
void setAttribute(const QString &name, const QString &value)
QString text() const
QDomNode appendChild(const QDomNode &newChild)
QDomNode firstChild() const
bool isNull() const
QDomNode nextSibling() const
QString nodeName() const
NodeType nodeType() const
QDomDocument ownerDocument() const
QDomElement toElement() const
QString family() const
void setStyle(Style style)
Style style() const
int weight() const
void append(const T &value)
iterator begin()
iterator end()
bool isEmpty() const
int size() const
T takeFirst()
const Key & key() const
const T & value() const
iterator begin()
iterator end()
bool isIdentity() const
int type(const char *typeName)
int x() const
int y() const
int height() const
int left() const
int top() const
int width() const
QStringList capturedTexts() const
int indexIn(const QString &str, int offset, CaretMode caretMode) const
QString pattern() const
void setMinimal(bool minimal)
int height() const
int width() const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const
int compare(const QString &other, Qt::CaseSensitivity cs) const
QString fromLatin1(const char *str, int size)
QString fromLocal8Bit(const char *str, int size)
QString fromUtf8(const char *str, int size)
bool isEmpty() const
int length() const
QString mid(int position, int n) const
QString number(int n, int base)
QString & replace(int position, int n, QChar after)
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
int toInt(bool *ok, int base) const
QByteArray toLatin1() const
QByteArray toLocal8Bit() const
QString toUpper() const
QByteArray toUtf8() const
bool canEncode(QChar ch) const
QTextCodec * codecForLocale()
QByteArray fromUnicode(const QString &str) const
QMap< int, QVariant > properties() const
void setProperty(int propertyId, const QVariant &value)
int type() const
QTime fromString(const QString &string, Qt::DateFormat format)
bool isValid() const
QByteArray toEncoded(FormattingOptions options) const
bool isNull() const
bool isValid() const
bool toBool() const
QChar toChar() const
QList< QVariant > toList() const
QMap< QString, QVariant > toMap() const
QPoint toPoint() const
QRect toRect() const
QSize toSize() const
QString toString() const
QStringList toStringList() const
QUrl toUrl() const
Type type() const
const char * typeName() const
T value() const

Generated by doxygen 1.9.1