00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <stdlib.h>
00025
00026 #include <qglobal.h>
00027 #include <QByteArray>
00028 #include <QString>
00029 #include <QDebug>
00030 #include <QFile>
00031 #include <QDir>
00032 #include <QLibraryInfo>
00033 #include <QUrl>
00034 #include <QMessageBox>
00035 #include <QTextCodec>
00036 #include <QDateTime>
00037 #include <QRect>
00038 #include <QIcon>
00039 #include <QColor>
00040 #include <QBrush>
00041 #include <QPushButton>
00042 #include <QApplication>
00043 #include <QDesktopWidget>
00044 #include <QDomDocument>
00045 #include <QTextFormat>
00046
00047 #include "klfutil.h"
00048 #include "klfstyle.h"
00049
00050
00051
00052 KLF_EXPORT bool klfEnsureDir(const QString& dir)
00053 {
00054 if ( ! QDir(dir).exists() ) {
00055 bool r = QDir("/").mkpath(dir);
00056 if ( ! r ) {
00057 qWarning("Can't create local directory %s!", qPrintable(dir));
00058 return false;
00059 }
00060
00061 r = QFile::setPermissions(dir, QFile::ReadOwner|QFile::WriteOwner|QFile::ExeOwner|
00062 QFile::ReadUser|QFile::WriteUser|QFile::ExeUser);
00063 if ( ! r ) {
00064 qWarning("Can't set permissions to local config directory `%s' !", qPrintable(dir));
00065 return false;
00066 }
00067 }
00068 return true;
00069 }
00070
00071
00072
00073 static QMap<QString,QString> klf_url_query_items_map(const QUrl& url,
00074 const QStringList& interestQueryItems)
00075 {
00076 QList<QPair<QString,QString> > qitems = url.queryItems();
00077 QMap<QString,QString> map;
00078 int k;
00079 for (k = 0; k < qitems.size(); ++k) {
00080 const QPair<QString,QString>& p = qitems[k];
00081 if (interestQueryItems.isEmpty() || interestQueryItems.contains(p.first))
00082 map[p.first] = p.second;
00083 }
00084 return map;
00085 }
00086
00087
00088
00089 KLF_EXPORT uint klfUrlCompare(const QUrl& url1, const QUrl& url2, uint interestFlags,
00090 const QStringList& interestQueryItems)
00091 {
00092 KLF_DEBUG_BLOCK(KLF_FUNC_NAME);
00093 klfDbg( ": 1="<<url1<<"; 2="<<url2<<"; interestflags="<<interestFlags<<"; int.q.i="
00094 <<interestQueryItems ) ;
00095 uint compareflags = 0x00;
00096
00097 Qt::CaseSensitivity queryItemValsCS = Qt::CaseSensitive;
00098 if (interestFlags & klfUrlCompareFlagIgnoreQueryItemValueCase)
00099 queryItemValsCS = Qt::CaseInsensitive;
00100
00101 QMap<QString,QString> qitems_map1;
00102 QMap<QString,QString> qitems_map2;
00103
00104 QUrl u1 = url1;
00105 QUrl u2 = url2;
00106 u1.setQueryItems(QList<QPair<QString,QString> >());
00107 u2.setQueryItems(QList<QPair<QString,QString> >());
00108
00109 klfDbg( " after q-i-stripping: u1="<<u1<<"; u2="<<u2 ) ;
00110
00111 if (interestFlags &
00112 (KlfUrlCompareEqual|KlfUrlCompareLessSpecific|KlfUrlCompareMoreSpecific)) {
00113
00114 qitems_map1 = klf_url_query_items_map(url1, interestQueryItems);
00115 qitems_map2 = klf_url_query_items_map(url2, interestQueryItems);
00116 }
00117
00118 if (interestFlags & KlfUrlCompareEqual) {
00119
00120 if (u1 == u2 && qitems_map1 == qitems_map2)
00121 compareflags |= KlfUrlCompareEqual;
00122 }
00123
00124 if (interestFlags & KlfUrlCompareLessSpecific) {
00125
00126 if (u1 == u2) {
00127 bool ok = klfMapIsIncludedIn(qitems_map1, qitems_map2, queryItemValsCS);
00128 if (ok)
00129 compareflags |= KlfUrlCompareLessSpecific;
00130 }
00131 }
00132 if (interestFlags & KlfUrlCompareMoreSpecific) {
00133
00134 if (u1 == u2) {
00135 bool ok = klfMapIsIncludedIn(qitems_map2, qitems_map1, queryItemValsCS);
00136 if (ok)
00137 compareflags |= KlfUrlCompareMoreSpecific;
00138 }
00139 }
00140
00141 if (interestFlags & KlfUrlCompareBaseEqual) {
00142 if (u1 == u2)
00143 compareflags |= KlfUrlCompareBaseEqual;
00144 }
00145
00146 klfDbg( "... and the result is compareflags="<<compareflags ) ;
00147 return compareflags;
00148 }
00149
00150
00151
00152
00153
00154
00155
00156 KLF_EXPORT bool klfMatch(const QVariant& testForHitCandidateValue, const QVariant& queryValue,
00157 Qt::MatchFlags flags, const QString& queryStringCache )
00158 {
00159
00160
00161
00162
00163
00164
00165 uint matchType = flags & 0x0F;
00166 Qt::CaseSensitivity cs = (flags & Qt::MatchCaseSensitive)
00167 ? Qt::CaseSensitive
00168 : Qt::CaseInsensitive;
00169
00170 const QVariant& v = testForHitCandidateValue;
00171
00172
00173 if (matchType == Qt::MatchExactly)
00174 return (queryValue == v);
00175
00176
00177 QString text = !queryStringCache.isNull() ? queryStringCache : queryValue.toString();
00178 QString t = v.toString();
00179 switch (matchType) {
00180 case Qt::MatchRegExp:
00181 return (QRegExp(text, cs).exactMatch(t));
00182 case Qt::MatchWildcard:
00183 return (QRegExp(text, cs, QRegExp::Wildcard).exactMatch(t));
00184 case Qt::MatchStartsWith:
00185 return (t.startsWith(text, cs));
00186 case Qt::MatchEndsWith:
00187 return (t.endsWith(text, cs));
00188 case Qt::MatchFixedString:
00189 return (QString::compare(t, text, cs) == 0);
00190 case Qt::MatchContains:
00191 default:
00192 return (t.contains(text, cs));
00193 }
00194 }
00195
00196
00197
00198
00199
00200
00201 static inline bool klf_is_hex_char(char c)
00202 {
00203 return ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F');
00204 }
00205
00206
00207
00208 #define KLF_BRUSH_STYLE(sty) \
00209 { Qt::sty##Pattern, #sty }
00210
00211 static struct { int brushStyle; const char *style; } klf_brush_styles[] = {
00212 { Qt::NoBrush, "NoBrush" },
00213 { Qt::SolidPattern, "" },
00214 { Qt::SolidPattern, "Solid" },
00215 KLF_BRUSH_STYLE(Dense1),
00216 KLF_BRUSH_STYLE(Dense2),
00217 KLF_BRUSH_STYLE(Dense3),
00218 KLF_BRUSH_STYLE(Dense4),
00219 KLF_BRUSH_STYLE(Dense5),
00220 KLF_BRUSH_STYLE(Dense6),
00221 KLF_BRUSH_STYLE(Dense7),
00222 KLF_BRUSH_STYLE(Hor),
00223 KLF_BRUSH_STYLE(Ver),
00224 KLF_BRUSH_STYLE(Cross),
00225 KLF_BRUSH_STYLE(BDiag),
00226 KLF_BRUSH_STYLE(FDiag),
00227 KLF_BRUSH_STYLE(DiagCross),
00228 { -1, NULL }
00229 };
00230
00231
00232
00233 #define KLF_TEXT_FORMAT_FORMAT(fmt) \
00234 { QTextFormat::fmt##Format, #fmt "Format" }
00235
00236 static struct { int formatId; const char *format; } klf_text_format_formats[] = {
00237 KLF_TEXT_FORMAT_FORMAT(Invalid),
00238 KLF_TEXT_FORMAT_FORMAT(Block),
00239 KLF_TEXT_FORMAT_FORMAT(Char),
00240 KLF_TEXT_FORMAT_FORMAT(List),
00241 KLF_TEXT_FORMAT_FORMAT(Table),
00242 KLF_TEXT_FORMAT_FORMAT(Frame),
00243 KLF_TEXT_FORMAT_FORMAT(User),
00244 { -100, NULL }
00245 };
00246
00247
00248 #define KLF_TEXT_FORMAT_PROP(p, type) \
00249 { QTextFormat::p, #p, #type }
00250
00251 static struct { int propId; const char *key; const char *type; } klf_text_format_props[] = {
00252 KLF_TEXT_FORMAT_PROP(ForegroundBrush, QBrush),
00253 KLF_TEXT_FORMAT_PROP(BackgroundBrush, QBrush),
00254 KLF_TEXT_FORMAT_PROP(FontFamily, QString),
00255 KLF_TEXT_FORMAT_PROP(FontPointSize, int),
00256 KLF_TEXT_FORMAT_PROP(FontWeight, int),
00257 KLF_TEXT_FORMAT_PROP(FontItalic, bool),
00258 KLF_TEXT_FORMAT_PROP(TextUnderlineStyle, int),
00259
00260 { QTextFormat::ForegroundBrush, "FG", "QBrush" },
00261 { QTextFormat::BackgroundBrush, "BG", "QBrush" },
00262
00263 { -1, NULL, NULL }
00264 };
00265
00266 static struct { const char * keyword; int propId; QVariant fixed_value; } klf_text_format_keywords[] = {
00267 { "NORMALWEIGHT", QTextFormat::FontWeight, QVariant(QFont::Normal) },
00268 { "BOLD", QTextFormat::FontWeight, QVariant(QFont::Bold) },
00269 { "NORMALSTYLE", QTextFormat::FontItalic, QVariant(false) },
00270 { "ITALIC", QTextFormat::FontItalic, QVariant(true) },
00271
00272 { NULL, -1, QVariant() }
00273 };
00274
00275
00276
00277
00278 KLF_EXPORT QByteArray klfDataToEscaped(const QByteArray& value_ba)
00279 {
00280 qDebug("klfDataToEscaped: len=%d, data=`%s'", value_ba.size(), value_ba.constData());
00281 QByteArray data;
00282 int k;
00283 for (k = 0; k < value_ba.size(); ++k) {
00284
00285 if (value_ba[k] >= 32 && value_ba[k] <= 126 && value_ba[k] != '\\') {
00286
00287 data += value_ba[k];
00288 } else if (value_ba[k] == '\\') {
00289 data += "\\\\";
00290 } else {
00291 data += QString("\\x%1").arg((uint)(uchar)value_ba[k], 2, 16, QChar('0')).toAscii();
00292 }
00293 }
00294 return data;
00295 }
00296
00297 KLF_EXPORT QByteArray klfEscapedToData(const QByteArray& data)
00298 {
00299 bool convertOk;
00300 int k;
00301 QByteArray value_ba;
00302 k = 0;
00303 while (k < data.size()) {
00304 if (data[k] != '\\') {
00305 value_ba += data[k];
00306 ++k;
00307 continue;
00308 }
00309 if (data[k] == '\\' && k+1 >= data.size()) {
00310 value_ba += '\\';
00311 ++k;
00312 continue;
00313 }
00314
00315 if (data[k+1] != 'x') {
00316
00317 value_ba += data[k+1];
00318 k += 2;
00319 continue;
00320 }
00321
00322 if (k+3 >= data.size() || !klf_is_hex_char(data[k+2]) || !klf_is_hex_char(data[k+3])) {
00323
00324 value_ba += data[k];
00325 ++k;
00326 continue;
00327 }
00328
00329 uchar cval = data.mid(k+2, 2).toUInt(&convertOk, 16);
00330 value_ba += (char)cval;
00331 k += 4;
00332 }
00333 return value_ba;
00334 }
00335
00336
00337 static QByteArray encaps_list(const QList<QByteArray>& list)
00338 {
00339 QByteArray data = "[";
00340 for (int k = 0; k < list.size(); ++k) {
00341 QByteArray d = list[k];
00342 d.replace("\\", "\\\\");
00343 d.replace(";", "\\;");
00344 d.replace("[", "\\[");
00345 d.replace("]", "\\]");
00346 data += d;
00347 if (k < list.size()-1)
00348 data += ";";
00349 }
00350 data += "]";
00351 return data;
00352 }
00353
00354
00355 static QByteArray encaps_map(const QList<QPair<QByteArray,QByteArray> >& sections, bool ignore_empty_values = false)
00356 {
00357 QByteArray data;
00358 data = "{";
00359 bool first_item = true;
00360 int k;
00361 for (k = 0; k < sections.size(); ++k) {
00362 if (!first_item) {
00363 data += ";";
00364 }
00365 first_item = false;
00366 QByteArray key = sections[k].first;
00367 QByteArray val = sections[k].second;
00368
00369 key.replace("\\", "\\\\");
00370 key.replace(";", "\\;");
00371 key.replace("=", "\\=");
00372 val.replace("\\", "\\\\");
00373 val.replace(";", "\\;");
00374 if (val.isEmpty() && ignore_empty_values)
00375 data += key;
00376 else
00377 data += key + "=" + val;
00378 }
00379 data += "}";
00380 return data;
00381 }
00382
00383
00384 static QList<QByteArray> decaps_list(const QByteArray& ba_data)
00385 {
00386 klfDbg("decaps_list, data="<<ba_data);
00387 QByteArray data = ba_data.trimmed();
00388 if (data[0] != '[')
00389 return QList<QByteArray>();
00390
00391 QList<QByteArray> sections;
00392 QByteArray chunk;
00393
00394
00395 int k = 1;
00396 while (k < data.size()) {
00397 if (data[k] == ';') {
00398
00399 sections.append(chunk);
00400
00401 chunk = QByteArray();
00402 ++k;
00403 }
00404 if (data[k] == '\\') {
00405 if (k+1 < data.size()) {
00406 chunk += data[k+1];
00407 k += 2;
00408 } else {
00409 chunk += data[k];
00410 ++k;
00411 }
00412 continue;
00413 }
00414 if (data[k] == ']') {
00415
00416
00417 if (!chunk.isEmpty())
00418 sections.append(chunk);
00419 chunk = "";
00420 break;
00421 }
00422
00423 chunk += data[k];
00424 ++k;
00425 }
00426 if (!chunk.isEmpty()) {
00427
00428 sections.append(chunk);
00429 }
00430
00431 klfDbg("sections="<<sections);
00432
00433 return sections;
00434 }
00435
00436 static QList<QPair<QByteArray,QByteArray> > decaps_map(const QByteArray& ba_data, bool allow_empty_values = false)
00437 {
00438 QByteArray data = ba_data.trimmed();
00439 if (data[0] != '{')
00440 return QList<QPair<QByteArray,QByteArray> >();
00441 if ( !data.contains('}') )
00442 data += '}';
00443
00444 QList<QPair<QByteArray, QByteArray> > sections;
00445 QByteArray chunkkey;
00446 QByteArray chunkvalue;
00447 QByteArray *curChunk = &chunkkey;
00448
00449
00450 int k = 1;
00451 while (k < data.size()) {
00452 if (data[k] == ';') {
00453
00454 if (!allow_empty_values && curChunk == &chunkkey)
00455 qWarning()<<KLF_FUNC_NAME<<": no '=' in pair at pos "<<k<<" in string: "<<data<<"";
00456 sections << QPair<QByteArray,QByteArray>(chunkkey, chunkvalue);
00457
00458 chunkkey = QByteArray();
00459 chunkvalue = QByteArray();
00460 curChunk = &chunkkey;
00461 ++k;
00462 }
00463 if (data[k] == '\\') {
00464 if (k+1 < data.size()) {
00465 *curChunk += data[k+1];
00466 k += 2;
00467 } else {
00468 *curChunk += data[k];
00469 ++k;
00470 }
00471 continue;
00472 }
00473 if (curChunk == &chunkkey && data[k] == '=') {
00474
00475 curChunk = &chunkvalue;
00476 ++k;
00477 continue;
00478 }
00479 if (data[k] == '}') {
00480
00481
00482 if (!allow_empty_values && curChunk == &chunkkey)
00483 qWarning()<<"klfLoadVariantFromText: no '=' in pair at pos "<<k<<" in string: "<<data<<"";
00484 sections << QPair<QByteArray,QByteArray>(chunkkey, chunkvalue);
00485 break;
00486 }
00487
00488 *curChunk += data[k];
00489 ++k;
00490 }
00491 return sections;
00492 }
00493
00494
00495
00496
00497 static QDomElement make_xml_wrapper(const QString& rootname)
00498 {
00499 QDomDocument xmldoc(rootname);
00500 QDomElement root = xmldoc.createElement(rootname);
00501 xmldoc.appendChild(root);
00502 return root;
00503 }
00504
00505 static QDomElement parse_xml_wrapper(const QByteArray& xmldata, const QString& shouldBeRootName)
00506 {
00507 QDomDocument xmldoc(shouldBeRootName);
00508 bool result = xmldoc.setContent(xmldata);
00509 KLF_ASSERT_CONDITION(result, "Failed to read wrapper XML for klfLoadVariantFromText()",
00510 return QDomElement() ) ;
00511
00512 QDomElement el = xmldoc.documentElement();
00513 KLF_ASSERT_CONDITION( el.nodeName() == shouldBeRootName,
00514 "Wrong XML root node in wrapper for klfLoadVariantFromText(): "
00515 <<el.nodeName() , ) ;
00516 return el;
00517 }
00518
00519 KLF_EXPORT QByteArray klfSaveVariantToText(const QVariant& value, bool saveListAndMapsAsXML)
00520 {
00521 QTextCodec *tc = QTextCodec::codecForLocale();
00522
00523 QString s;
00524 QByteArray data;
00525 int k;
00526
00527 if (!value.isValid() || value.isNull())
00528 return QByteArray();
00529
00530
00531 switch (value.type()) {
00532 case QMetaType::Bool:
00533 data = value.toBool() ? "true" : "false";
00534 break;
00535 case QMetaType::Int:
00536 case QMetaType::UInt:
00537 case QMetaType::Short:
00538 case QMetaType::UShort:
00539 case QMetaType::Long:
00540 case QMetaType::ULong:
00541 case QMetaType::LongLong:
00542 case QMetaType::ULongLong:
00543 case QMetaType::Double:
00544 data = value.toString().toLocal8Bit();
00545 break;
00546 case QMetaType::Char:
00547 {
00548 char c = value.value<char>();
00549 if (c >= 32 && c <= 126 && c != '\\')
00550 data = QByteArray(1, c);
00551 else if (c == '\\')
00552 data = "\\\\";
00553 else
00554 data = "\\" + QString::number(c, 16).toUpper().toAscii();
00555 }
00556 case QMetaType::QChar:
00557 {
00558 QChar c = value.toChar();
00559 if (tc->canEncode(c) && c != '\\')
00560 data = tc->fromUnicode(QString(c));
00561 else if (c == '\\')
00562 data = "\\\\";
00563 else
00564 data = "\\" + QString::number(c.unicode(), 16).toUpper().toAscii();
00565 break;
00566 }
00567 case QMetaType::QString:
00568 {
00569 s = value.toString();
00570 if (tc->canEncode(s)) {
00571
00572 data = tc->fromUnicode(s.replace("\\", "\\\\"));
00573 } else {
00574
00575 data = QByteArray("");
00576 for (k = 0; k < s.length(); ++k) {
00577 if (tc->canEncode(s[k]))
00578 data += tc->fromUnicode(s.mid(k,1));
00579 else
00580 data += QString("\\x%1").arg((uint)s[k].unicode(), 4, 16, QChar('0')).toAscii();
00581 }
00582 }
00583 break;
00584 }
00585 case QMetaType::QStringList:
00586 {
00587 const QStringList list = value.toStringList();
00588 QList<QByteArray> sections;
00589 int k;
00590 for (k = 0; k < list.size(); ++k) {
00591 sections.append(klfDataToEscaped(list[k].toUtf8()));
00592 }
00593 data = encaps_list(sections);
00594 break;
00595 }
00596 case QMetaType::QUrl:
00597 data = value.toUrl().toEncoded(); break;
00598 case QMetaType::QByteArray:
00599 {
00600 data = klfDataToEscaped(value.value<QByteArray>());
00601 break;
00602 }
00603 case QMetaType::QDate:
00604 data = value.value<QDate>().toString(Qt::SystemLocaleShortDate).toLocal8Bit(); break;
00605 case QMetaType::QTime:
00606 data = value.value<QTime>().toString(Qt::SystemLocaleShortDate).toLocal8Bit(); break;
00607 case QMetaType::QDateTime:
00608 data = value.value<QDateTime>().toString(Qt::SystemLocaleShortDate).toLocal8Bit(); break;
00609 case QMetaType::QSize:
00610 { QSize sz = value.toSize();
00611 data = QString("(%1 %2)").arg(sz.width()).arg(sz.height()).toAscii();
00612 break;
00613 }
00614 case QMetaType::QPoint:
00615 { QPoint pt = value.toPoint();
00616 data = QString("(%1 %2)").arg(pt.x()).arg(pt.y()).toAscii();
00617 break;
00618 }
00619 case QMetaType::QRect:
00620 { QRect r = value.toRect();
00621 data = QString("(%1 %2 %3x%4)").arg(r.left()).arg(r.top()).arg(r.width()).arg(r.height()).toAscii();
00622 break;
00623 }
00624 case QMetaType::QColor:
00625 { QColor c = value.value<QColor>();
00626 klfDbg("Saving color "<<c<<": alpha="<<c.alpha()) ;
00627 if (c.alpha() == 255)
00628 data = QString("(%1 %2 %3)").arg(c.red()).arg(c.green()).arg(c.blue()).toAscii();
00629 else
00630 data = QString("(%1 %2 %3 %4)").arg(c.red()).arg(c.green()).arg(c.blue()).arg(c.alpha()).toAscii();
00631 break;
00632 }
00633 case QMetaType::QFont:
00634 { QFont f = value.value<QFont>();
00635 data = "'" + f.family().toLocal8Bit() + "'";
00636 switch (f.weight()) {
00637 case QFont::Light: data += " Light"; break;
00638 case QFont::Normal: break;
00639 case QFont::DemiBold: data += " DemiBold"; break;
00640 case QFont::Bold: data += " Bold"; break;
00641 case QFont::Black: data += " Black"; break;
00642 default: data += QString(" Wgt=%1").arg(f.weight()); break;
00643 }
00644 switch (f.style()) {
00645 case QFont::StyleNormal: break;
00646 case QFont::StyleItalic: data += " Italic"; break;
00647 case QFont::StyleOblique: data += " Oblique"; break;
00648 default: break;
00649 }
00650
00651 data += " " + QString::number(QFontInfo(f).pointSize()).toAscii();
00652 break;
00653 }
00654 case QMetaType::QBrush:
00655 { QBrush b = value.value<QBrush>();
00656 if (!b.matrix().isIdentity())
00657 break;
00658 int bstyle = b.style();
00659
00660 int k;
00661 bool found_style = false;
00662 for (k = 0; klf_brush_styles[k].brushStyle >= 0 && klf_brush_styles[k].style != NULL; ++k) {
00663 if (klf_brush_styles[k].brushStyle == bstyle) {
00664 found_style = true;
00665 break;
00666 }
00667 }
00668 if (!found_style) {
00669
00670 break;
00671 }
00672
00673 data = "(";
00674 data += klf_brush_styles[k].style;
00675 if (strlen(klf_brush_styles[k].style))
00676 data += " ";
00677 QColor c = b.color();
00678 data += QString("%1 %2 %3 %4").arg(c.red()).arg(c.green()).arg(c.blue()).arg(c.alpha());
00679 data += ")";
00680 break;
00681 }
00682 case QMetaType::QTextFormat:
00683 {
00684 QTextFormat tf = value.value<QTextFormat>();
00685 const QMap<int,QVariant> props = tf.properties();
00686
00687 QList<QPair<QByteArray,QByteArray> > sections;
00688
00689
00690 int k;
00691 for (k = 0; klf_text_format_formats[k].format != NULL; ++k)
00692 if (klf_text_format_formats[k].formatId == tf.type())
00693 break;
00694 if (klf_text_format_formats[k].format == NULL) {
00695
00696
00697 data = QByteArray();
00698 break;
00699 }
00700
00701 sections << QPair<QByteArray,QByteArray>(klf_text_format_formats[k].format, QByteArray());
00702
00703 QMap<int,QVariant>::const_iterator it;
00704 for (it = props.begin(); it != props.end(); ++it) {
00705 int propId = it.key();
00706 QVariant propValue = it.value();
00707
00708
00709
00710 for (k = 0; klf_text_format_keywords[k].keyword != NULL; ++k)
00711 if (klf_text_format_keywords[k].propId == propId &&
00712 klf_text_format_keywords[k].fixed_value == propValue)
00713 break;
00714 const char *kw = klf_text_format_keywords[k].keyword;
00715 if (kw != NULL) {
00716
00717 QByteArray key = kw;
00718 sections << QPair<QByteArray,QByteArray>(kw, QByteArray());
00719 continue;
00720 }
00721
00722
00723 for (k = 0; klf_text_format_props[k].key != NULL; ++k)
00724 if (klf_text_format_props[k].propId == propId)
00725 break;
00726 if (klf_text_format_props[k].key != NULL) {
00727
00728 if ( !strcmp(klf_text_format_props[k].type, propValue.typeName()) ) {
00729
00730 QByteArray key = klf_text_format_props[k].key;
00731 QByteArray value = klfSaveVariantToText(propValue, true);
00732 sections << QPair<QByteArray,QByteArray>(key, value);
00733 continue;
00734 } else {
00735 qWarning()<<KLF_FUNC_NAME<<": QTextFormat property "<<klf_text_format_props[k].key
00736 <<" 's type is `"<<propValue.typeName()<<"' which is not the known type: "
00737 <<klf_text_format_props[k].type;
00738 }
00739 }
00740
00741
00742 QByteArray key = QString::number(propId).toLatin1();
00743 QByteArray value;
00744 value = QByteArray("[")+propValue.typeName()+"]"+klfSaveVariantToText(propValue, true);
00745 }
00746 data = encaps_map(sections, true);
00747 break;
00748 }
00749 case QMetaType::QVariantList:
00750 {
00751 const QList<QVariant>& list = value.toList();
00752 if (saveListAndMapsAsXML) {
00753 QDomElement el = make_xml_wrapper("variant-list");
00754 el = klfSaveVariantListToXML(list, el);
00755 data = el.ownerDocument().toByteArray(0);
00756 } else {
00757 QList<QByteArray> sections;
00758 for (k = 0; k < list.size(); ++k) {
00759 sections << klfSaveVariantToText(list[k]);
00760 }
00761 data = encaps_list(sections);
00762 }
00763 break;
00764 }
00765 case QMetaType::QVariantMap:
00766 {
00767 const QMap<QString,QVariant>& map = value.toMap();
00768 if (saveListAndMapsAsXML) {
00769 QDomElement el = make_xml_wrapper("variant-map");
00770 el = klfSaveVariantMapToXML(map, el);
00771 data = el.ownerDocument().toByteArray(0);
00772 } else {
00773 QList<QPair<QByteArray, QByteArray> > sections;
00774 for (QMap<QString,QVariant>::const_iterator it = map.begin(); it != map.end(); ++it) {
00775 QByteArray k = klfSaveVariantToText(QVariant(it.key()));
00776 QByteArray v = klfSaveVariantToText(it.value());
00777 sections << QPair<QByteArray,QByteArray>(k, v);
00778 }
00779 data = encaps_map(sections);
00780 }
00781 break;
00782 }
00783 default:
00784 break;
00785 };
00786
00787
00788
00789 QByteArray typeName = value.typeName();
00790
00791 if (typeName == "KLFStyle") {
00792 KLFStyle style = value.value<KLFStyle>();
00793 QVariantMap map;
00794 map["name"] = klfSaveVariantToText(style.name);
00795 map["fg_color"] = klfSaveVariantToText(QColor(style.fg_color));
00796 map["bg_color"] = klfSaveVariantToText(QColor(style.bg_color));
00797 map["mathmode"] = klfSaveVariantToText(style.mathmode);
00798 map["preamble"] = klfSaveVariantToText(style.preamble);
00799 map["dpi"] = klfSaveVariantToText(QVariant::fromValue(style.dpi));
00800
00801
00802 return klfSaveVariantToText(map);
00803 }
00804
00805
00806
00807 if (data.startsWith("[QVariant]") || data.startsWith("\\"))
00808 data = "\\"+data;
00809
00810
00811
00812
00813 if (data.isNull()) {
00814 QByteArray vdata;
00815 {
00816 QDataStream stream(&vdata, QIODevice::WriteOnly);
00817 stream << value;
00818 }
00819 QByteArray vdata_esc = klfDataToEscaped(vdata);
00820 qDebug("\tVariant value is %s, len=%d", vdata.constData(), vdata.size());
00821 data = QByteArray("[QVariant]");
00822 data += vdata_esc;
00823 }
00824
00825 klfDbg( "klfSaveVariantToText("<<value<<"): saved data (len="<<data.size()<<") : "<<data ) ;
00826 return data;
00827 }
00828
00829
00830
00831
00832 KLF_EXPORT QVariant klfLoadVariantFromText(const QByteArray& stringdata, const char * dataTypeName,
00833 const char *listOrMapDataTypeName)
00834 {
00835 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
00836
00837
00838
00839 #define RX_INT "-?\\d+"
00840 #define RX_COORD_SEP "\\s*(?:[,;]|\\s)\\s*" // note: non-capturing parenthesis
00841 #define RX_SIZE_SEP "\\s*(?:[,;x]|\\s)\\s*" // note: non-capturing parenthesis
00842
00843
00844 QRegExp v2rx("^\\(?\\s*(" RX_INT ")" RX_COORD_SEP "(" RX_INT ")\\s*\\)?");
00845 static const int V2RX_X = 1, V2RX_Y = 2;
00846
00847
00848 QRegExp szrx("^\\(?\\s*(" RX_INT ")" RX_SIZE_SEP "(" RX_INT ")\\s*\\)?");
00849 static const int SZRX_W = 1, SZRX_H = 2;
00850
00851
00852 QRegExp rectrx("^\\(?\\s*(" RX_INT ")" RX_COORD_SEP "(" RX_INT ")"
00853
00854 "(?:" RX_COORD_SEP "|\\s*([+])\\s*)"
00855
00856 "(" RX_INT ")(?:"RX_COORD_SEP"|\\s*([x])\\s*)(" RX_INT ")\\s*\\)?");
00857 static const int RECTRX_X1 = 1, RECTRX_Y1 = 2, RECTRX_MIDDLESEP_PLUS = 3,
00858 RECTRX_X2orW = 4, RECTRX_LASTSEP_X = 5, RECTRX_Y2orH = 6;
00859
00860
00861 QRegExp colrx("^(?:rgba?)?\\(?\\s*(\\d+)" RX_COORD_SEP "(\\d+)" RX_COORD_SEP "(\\d+)"
00862
00863 "(" RX_COORD_SEP "(\\d+))?\\s*\\)?", Qt::CaseInsensitive);
00864 static const int COLRX_R = 1, COLRX_G = 2, COLRX_B = 3, COLRX_MAYBE_ALPHA = 4, COLRX_A = 5;
00865
00866
00867 QRegExp brushrx("^(?:q?brush)?\\(?\\s*(?:([A-Za-z_]\\w*)" RX_COORD_SEP ")?(\\d+)" RX_COORD_SEP "(\\d+)"
00868
00869 RX_COORD_SEP "(\\d+)" "("RX_COORD_SEP "(\\d+))?" "\\s*\\)?", Qt::CaseInsensitive);
00870 static const int BRUSHRX_STYLE = 1, BRUSHRX_R = 2, BRUSHRX_G = 3, BRUSHRX_B = 4, BRUSHRX_A = 6;
00871
00872
00873 QRegExp fontrx("^([\"']?)\\s*(.+)\\s*\\1"
00874
00875 "(\\s+(Light|Normal|DemiBold|Bold|Black|Wgt\\s*=\\s*(\\d+)))?"
00876
00877 "(\\s+(Normal|Italic|Oblique))?(\\s+(\\d+))?$");
00878 fontrx.setMinimal(true);
00879 static const int FONTRX_FAMILY = 2, FONTRX_WEIGHT_TEXT = 4, FONTRX_WEIGHT_VALUE = 5,
00880 FONTRX_STYLE_TEXT = 7, FONTRX_POINTSIZE = 9;
00881
00882
00883
00884
00885 QByteArray data = stringdata;
00886
00887 QVariant value;
00888 if (data.startsWith("[QVariant]")) {
00889 QByteArray vdata_esc = data.mid(strlen("[QVariant]"));
00890 QByteArray vdata = klfEscapedToData(vdata_esc);
00891 klfDbg( "\tAbout to read raw variant from datastr="<<vdata_esc<<", ie. from data len="<<vdata.size() ) ;
00892 QDataStream stream(vdata);
00893 stream >> value;
00894 return value;
00895 }
00896 if (data.startsWith("\\"))
00897 data = data.mid(1);
00898
00899 klfDbg( "Will start loading a `"<<dataTypeName<<"' from data (len="<<data.size()<<") : "<<data ) ;
00900
00901
00902 int type = QVariant::nameToType(dataTypeName);
00903 bool convertOk = false;
00904 int k;
00905 switch (type) {
00906 case QMetaType::Bool:
00907 {
00908 QByteArray lowerdata = data.trimmed().toLower();
00909 QChar c = QChar(lowerdata[0]);
00910
00911 return QVariant::fromValue<bool>(c == 't' || c == 'y' || c == '1' || lowerdata == "on");
00912 }
00913 case QMetaType::Int:
00914 {
00915 int i = data.toInt(&convertOk);
00916 if (convertOk)
00917 return QVariant::fromValue<int>(i);
00918 break;
00919 }
00920 case QMetaType::UInt:
00921 {
00922 uint i = data.toUInt(&convertOk);
00923 if (convertOk)
00924 return QVariant::fromValue<uint>(i);
00925 break;
00926 }
00927 case QMetaType::Short:
00928 {
00929 short i = data.toShort(&convertOk);
00930 if (convertOk)
00931 return QVariant::fromValue<short>(i);
00932 break;
00933 }
00934 case QMetaType::UShort:
00935 {
00936 ushort i = data.toUShort(&convertOk);
00937 if (convertOk)
00938 return QVariant::fromValue<ushort>(i);
00939 break;
00940 }
00941 case QMetaType::Long:
00942 {
00943 long i = data.toLong(&convertOk);
00944 if (convertOk)
00945 return QVariant::fromValue<long>(i);
00946 break;
00947 }
00948 case QMetaType::ULong:
00949 {
00950 ulong i = data.toULong(&convertOk);
00951 if (convertOk)
00952 return QVariant::fromValue<ulong>(i);
00953 break;
00954 }
00955 case QMetaType::LongLong:
00956 {
00957 qlonglong i = data.toLongLong(&convertOk);
00958 if (convertOk)
00959 return QVariant::fromValue<qlonglong>(i);
00960 break;
00961 }
00962 case QMetaType::ULongLong:
00963 {
00964 qulonglong i = data.toULongLong(&convertOk);
00965 if (convertOk)
00966 return QVariant::fromValue<qulonglong>(i);
00967 break;
00968 }
00969 case QMetaType::Double:
00970 {
00971 double val = data.toDouble(&convertOk);
00972 if (convertOk)
00973 return QVariant::fromValue<double>(val);
00974 break;
00975 }
00976 case QMetaType::Char:
00977 {
00978 if (data[0] == '\\') {
00979 if (data.size() < 2)
00980 break;
00981 if (data[1] == '\\')
00982 return QVariant::fromValue<char>('\\');
00983 if (data.size() < 3)
00984 break;
00985 uint c = data.mid(1).toUInt(&convertOk, 16);
00986 if (!convertOk)
00987 break;
00988 convertOk = false;
00989 if (c > 255)
00990 break;
00991 return QVariant::fromValue<char>( (char)c );
00992 }
00993 return QVariant::fromValue<char>( (char)data[0] );
00994 }
00995 case QMetaType::QChar:
00996 {
00997 if (data[0] == '\\') {
00998 if (data.size() < 2)
00999 break;
01000 if (data[1] == '\\')
01001 return QVariant::fromValue<QChar>(QChar('\\'));
01002 if (data.size() < 3)
01003 break;
01004 uint c = data.mid(1).toUInt(&convertOk, 16);
01005 if (!convertOk)
01006 break;
01007 convertOk = false;
01008 if (c > 255)
01009 break;
01010 return QVariant::fromValue<QChar>( QChar(c) );
01011 }
01012 return QVariant::fromValue<QChar>( QChar(data[0]) );
01013 }
01014 case QMetaType::QString:
01015 {
01016 QString s;
01017 QByteArray chunk;
01018 k = 0;
01019 while (k < data.size()) {
01020 if (data[k] != '\\') {
01021 chunk += data[k];
01022 ++k;
01023 continue;
01024 }
01025 if (data[k] == '\\' && k+1 >= data.size()) {
01026 chunk += '\\';
01027 ++k;
01028 continue;
01029 }
01030
01031 if (data[k+1] != 'x') {
01032
01033 chunk += data[k+1];
01034 k += 2;
01035 continue;
01036 }
01037
01038 int nlen = -1;
01039 if (k+5 < data.size() && klf_is_hex_char(data[k+2]) && klf_is_hex_char(data[k+3])
01040 && klf_is_hex_char(data[k+4]) && klf_is_hex_char(data[k+5]))
01041 nlen = 4;
01042 if (k+3 < data.size() && klf_is_hex_char(data[k+2]) && klf_is_hex_char(data[k+3]))
01043 nlen = 2;
01044 if (nlen < 0) {
01045
01046 chunk += data[k];
01047 ++k;
01048 continue;
01049 }
01050
01051 ushort cval = data.mid(k+2, nlen).toUShort(&convertOk, 16);
01052 QChar ch(cval);
01053
01054 s += QString::fromLocal8Bit(chunk) + ch;
01055
01056 chunk = QByteArray();
01057
01058
01059 k += 2 + nlen;
01060 }
01061
01062 s += QString::fromLocal8Bit(chunk);
01063 return QVariant::fromValue<QString>(s);
01064 }
01065 case QMetaType::QStringList:
01066 {
01067 QList<QByteArray> sections = decaps_list(data);
01068
01069
01070 QStringList list;
01071 for (k = 0; k < sections.size(); ++k) {
01072 list << QString::fromUtf8(klfEscapedToData(sections[k]));
01073 }
01074
01075 return QVariant::fromValue<QStringList>(list);
01076 }
01077 case QMetaType::QUrl:
01078 return QVariant::fromValue<QUrl>(QUrl(QString::fromLocal8Bit(data), QUrl::TolerantMode));
01079 case QMetaType::QByteArray:
01080 {
01081 QByteArray value_ba = klfEscapedToData(data);
01082 return QVariant::fromValue<QByteArray>(value_ba);
01083 }
01084 case QMetaType::QDate:
01085 {
01086 QString s = QString::fromLocal8Bit(data);
01087 QDate date = QDate::fromString(s, Qt::SystemLocaleShortDate);
01088 if (!date.isValid()) date = QDate::fromString(s, Qt::ISODate);
01089 if (!date.isValid()) date = QDate::fromString(s, Qt::SystemLocaleLongDate);
01090 if (!date.isValid()) date = QDate::fromString(s, Qt::DefaultLocaleShortDate);
01091 if (!date.isValid()) date = QDate::fromString(s, Qt::TextDate);
01092 if (!date.isValid()) date = QDate::fromString(s, "dd-MM-yyyy");
01093 if (!date.isValid()) date = QDate::fromString(s, "dd.MM.yyyy");
01094 if (!date.isValid()) date = QDate::fromString(s, "dd MM yyyy");
01095 if (!date.isValid()) date = QDate::fromString(s, "yyyy-MM-dd");
01096 if (!date.isValid()) date = QDate::fromString(s, "yyyy.MM.dd");
01097 if (!date.isValid()) date = QDate::fromString(s, "yyyy MM dd");
01098 if (!date.isValid()) date = QDate::fromString(s, "yyyyMMdd");
01099 if (!date.isValid())
01100 break;
01101 return QVariant::fromValue<QDate>(date);
01102 }
01103 case QMetaType::QTime:
01104 {
01105 QString s = QString::fromLocal8Bit(data);
01106 QTime time = QTime::fromString(s, Qt::SystemLocaleShortDate);
01107 if (!time.isValid()) time = QTime::fromString(s, Qt::ISODate);
01108 if (!time.isValid()) time = QTime::fromString(s, Qt::SystemLocaleLongDate);
01109 if (!time.isValid()) time = QTime::fromString(s, Qt::DefaultLocaleShortDate);
01110 if (!time.isValid()) time = QTime::fromString(s, Qt::TextDate);
01111 if (!time.isValid()) time = QTime::fromString(s, "hh:mm:ss.z");
01112 if (!time.isValid()) time = QTime::fromString(s, "hh:mm:ss");
01113 if (!time.isValid()) time = QTime::fromString(s, "hh:mm:ss AP");
01114 if (!time.isValid()) time = QTime::fromString(s, "hh.mm.ss");
01115 if (!time.isValid()) time = QTime::fromString(s, "hh.mm.ss AP");
01116 if (!time.isValid()) time = QTime::fromString(s, "hh mm ss");
01117 if (!time.isValid()) time = QTime::fromString(s, "hh mm ss AP");
01118 if (!time.isValid()) time = QTime::fromString(s, "hhmmss");
01119 if (!time.isValid())
01120 break;
01121 return QVariant::fromValue<QTime>(time);
01122 }
01123 case QMetaType::QDateTime:
01124 {
01125 QString s = QString::fromLocal8Bit(data);
01126 QDateTime dt = QDateTime::fromString(s, Qt::SystemLocaleShortDate);
01127 if (!dt.isValid()) dt = QDateTime::fromString(s, Qt::ISODate);
01128 if (!dt.isValid()) dt = QDateTime::fromString(s, Qt::SystemLocaleLongDate);
01129 if (!dt.isValid()) dt = QDateTime::fromString(s, Qt::DefaultLocaleShortDate);
01130 if (!dt.isValid()) dt = QDateTime::fromString(s, Qt::TextDate);
01131 if (!dt.isValid()) dt = QDateTime::fromString(s, "dd-MM-yyyy hh:mm:ss");
01132 if (!dt.isValid()) dt = QDateTime::fromString(s, "dd-MM-yyyy hh.mm.ss");
01133 if (!dt.isValid()) dt = QDateTime::fromString(s, "dd.MM.yyyy hh:mm:ss");
01134 if (!dt.isValid()) dt = QDateTime::fromString(s, "dd.MM.yyyy hh.mm.ss");
01135 if (!dt.isValid()) dt = QDateTime::fromString(s, "dd MM yyyy hh mm ss");
01136 if (!dt.isValid()) dt = QDateTime::fromString(s, "yyyy-MM-dd hh:mm:ss");
01137 if (!dt.isValid()) dt = QDateTime::fromString(s, "yyyy-MM-dd hh.mm.ss");
01138 if (!dt.isValid()) dt = QDateTime::fromString(s, "yyyy.MM.dd hh:mm:ss");
01139 if (!dt.isValid()) dt = QDateTime::fromString(s, "yyyy.MM.dd hh.mm.ss");
01140 if (!dt.isValid()) dt = QDateTime::fromString(s, "yyyy MM dd hh mm ss");
01141 if (!dt.isValid()) dt = QDateTime::fromString(s, "yyyyMMddhhmmss");
01142 if (!dt.isValid())
01143 break;
01144 return QVariant::fromValue<QDateTime>(dt);
01145 }
01146 case QMetaType::QSize:
01147 {
01148 QString s = QString::fromLocal8Bit(data.trimmed());
01149 if (szrx.indexIn(s) < 0)
01150 break;
01151 QStringList vals = szrx.capturedTexts();
01152 return QVariant::fromValue<QSize>(QSize(vals[SZRX_W].toInt(), vals[SZRX_H].toInt()));
01153 }
01154 case QMetaType::QPoint:
01155 {
01156 QString s = QString::fromLocal8Bit(data.trimmed());
01157 if (v2rx.indexIn(s) < 0)
01158 break;
01159 QStringList vals = v2rx.capturedTexts();
01160 return QVariant::fromValue<QPoint>(QPoint(vals[V2RX_X].toInt(), vals[V2RX_Y].toInt()));
01161 }
01162 case QMetaType::QRect:
01163 {
01164 QString s = QString::fromLocal8Bit(data.trimmed());
01165 if (rectrx.indexIn(s) < 0)
01166 break;
01167 QStringList vals = rectrx.capturedTexts();
01168 if (vals[RECTRX_MIDDLESEP_PLUS] == "+" || vals[RECTRX_LASTSEP_X] == "x") {
01169 return QVariant::fromValue<QRect>(QRect( QPoint(vals[RECTRX_X1].toInt(), vals[RECTRX_Y1].toInt()),
01170 QSize(vals[RECTRX_X2orW].toInt(), vals[RECTRX_Y2orH].toInt()) ));
01171 }
01172 return QVariant::fromValue<QRect>(QRect( QPoint(vals[RECTRX_X1].toInt(), vals[RECTRX_Y1].toInt()),
01173 QPoint(vals[RECTRX_X2orW].toInt(), vals[RECTRX_Y2orH].toInt()) ));
01174 }
01175 case QMetaType::QColor:
01176 {
01177 QString colstr = QString::fromLocal8Bit(data.trimmed());
01178
01179 if (colrx.indexIn(colstr) < 0) {
01180 klfDbg("color "<<colstr<<" does not match regexp="<<colrx.pattern()<<", trying named...") ;
01181
01182 QColor color; color.setNamedColor(colstr);
01183
01184 if (color.isValid())
01185 return color;
01186 break;
01187 }
01188
01189 QStringList vals = colrx.capturedTexts();
01190 QColor color = QColor(vals[COLRX_R].toInt(), vals[COLRX_G].toInt(), vals[COLRX_B].toInt(), 255);
01191 if (!vals[COLRX_MAYBE_ALPHA].isEmpty())
01192 color.setAlpha(vals[COLRX_A].toInt());
01193 return QVariant::fromValue<QColor>(color);
01194 }
01195 case QMetaType::QFont:
01196 {
01197 if (fontrx.indexIn(QString::fromLocal8Bit(data.trimmed())) < 0) {
01198 klfDbg("malformed font: "<<data);
01199 break;
01200 }
01201 QStringList vals = fontrx.capturedTexts();
01202 klfDbg("parsing font: data="<<data<<"; captured texts are: "<<vals );
01203
01204 QString family = vals[FONTRX_FAMILY].trimmed();
01205 QString weighttxt = vals[FONTRX_WEIGHT_TEXT];
01206 QString weightval = vals[FONTRX_WEIGHT_VALUE];
01207 QString styletxt = vals[FONTRX_STYLE_TEXT];
01208 QString ptsval = vals[FONTRX_POINTSIZE];
01209
01210 int weight = QFont::Normal;
01211 if (weighttxt == "Light") weight = QFont::Light;
01212 else if (weighttxt == "Normal") weight = QFont::Normal;
01213 else if (weighttxt == "DemiBold") weight = QFont::DemiBold;
01214 else if (weighttxt == "Bold") weight = QFont::Bold;
01215 else if (weighttxt == "Black") weight = QFont::Black;
01216 else if (weighttxt.startsWith("Wgt")) weight = weightval.toInt();
01217
01218
01219 QFont::Style style = QFont::StyleNormal;
01220 if (styletxt == "Normal") style = QFont::StyleNormal;
01221 else if (styletxt == "Italic") style = QFont::StyleItalic;
01222 else if (styletxt == "Oblique") style = QFont::StyleOblique;
01223
01224 int pt = -1;
01225 if (!ptsval.isEmpty())
01226 pt = ptsval.toInt();
01227
01228 QFont font(family, pt, weight);
01229 font.setStyle(style);
01230 return QVariant::fromValue<QFont>(font);
01231 }
01232 case QMetaType::QBrush:
01233 {
01234 if (brushrx.indexIn(QString::fromLocal8Bit(data.trimmed())) < 0) {
01235 klfDbg("malformed brush text: "<<data) ;
01236 break;
01237 }
01238 QStringList vals = brushrx.capturedTexts();
01239 QString style = vals[BRUSHRX_STYLE];
01240
01241 int k;
01242 bool style_found = false;
01243 for (k = 0; klf_brush_styles[k].brushStyle >= 0 && klf_brush_styles[k].style != NULL; ++k) {
01244 if (klf_brush_styles[k].style == style) {
01245 style_found = true;
01246 break;
01247 }
01248 }
01249 if (!style_found) {
01250 klfDbg("Can't find style"<<style<<" in brush style list!");
01251 break;
01252 }
01253 int qbrush_style = klf_brush_styles[k].brushStyle;
01254
01255 QColor c = QColor(vals[BRUSHRX_R].toInt(), vals[BRUSHRX_G].toInt(),
01256 vals[BRUSHRX_B].toInt());
01257 if (!vals[BRUSHRX_A].isEmpty())
01258 c.setAlpha(vals[BRUSHRX_A].toInt());
01259 return QBrush(c, static_cast<Qt::BrushStyle>(qbrush_style));
01260 }
01261 case QMetaType::QTextFormat:
01262 {
01263 int k;
01264 QList<QPair<QByteArray,QByteArray> > sections = decaps_map(data, true);
01265 if (sections.isEmpty()) {
01266 klfDbg("Invalid QTextFormat data.") ;
01267 break;
01268 }
01269 QPair<QByteArray,QByteArray> firstSection = sections.takeFirst();
01270 QString fmttype = QString::fromLatin1(firstSection.first);
01271
01272 for (k = 0; klf_text_format_formats[k].format != NULL; ++k)
01273 if (QString::compare(fmttype, QLatin1String(klf_text_format_formats[k].format),
01274 Qt::CaseInsensitive) == 0)
01275 break;
01276 if (klf_text_format_formats[k].format == NULL) {
01277 klfDbg("QTextFormat: Invalid format type: "<<fmttype) ;
01278 break;
01279 }
01280 int qtextformat_type = klf_text_format_formats[k].formatId;
01281
01282
01283 QTextFormat textformat(qtextformat_type);
01284 QList<QPair<QByteArray,QByteArray> >::const_iterator it;
01285 for (it = sections.begin(); it != sections.end(); ++it) {
01286 QByteArray key = (*it).first.trimmed();
01287 QByteArray value = (*it).second;
01288 klfDbg("QTextFormat: considering property pair key="<<key<<"; value="<<value) ;
01289
01290 for (k = 0; klf_text_format_keywords[k].keyword != NULL; ++k)
01291 if (QString::compare(QLatin1String(klf_text_format_keywords[k].keyword),
01292 key, Qt::CaseInsensitive) == 0)
01293 break;
01294 if (klf_text_format_keywords[k].keyword != NULL) {
01295
01296 klfDbg("QTextFormat: is keyword, propId="<<klf_text_format_keywords[k].propId<<", fixed_value="
01297 <<klf_text_format_keywords[k].fixed_value) ;
01298 textformat.setProperty(klf_text_format_keywords[k].propId,
01299 klf_text_format_keywords[k].fixed_value);
01300 continue;
01301 }
01302
01303 for (k = 0; klf_text_format_props[k].key != NULL; ++k)
01304 if (QString::compare(QLatin1String(klf_text_format_props[k].key),
01305 key, Qt::CaseInsensitive) == 0)
01306 break;
01307 if (klf_text_format_props[k].key != NULL) {
01308 klfDbg("QTextFormat: is known property of type "<<klf_text_format_props[k].type) ;
01309
01310 QVariant vval = klfLoadVariantFromText(value, klf_text_format_props[k].type, "XML");
01311 textformat.setProperty(klf_text_format_props[k].propId, vval);
01312 continue;
01313 }
01314
01315
01316 bool tointok = true;
01317 int propid = key.toInt(&tointok);
01318 if (!tointok) {
01319 qWarning()<<KLF_FUNC_NAME<<": QTextFormat bad format for general property key=value pair; "
01320 <<"key is not a numerical property ID, nor is it a known property name.";
01321 }
01322
01323 klfDbg("QTextFormat: property is not a known one. propid="<<propid) ;
01324
01325
01326 while (value.size() && QChar(value[0]).isSpace())
01327 value.remove(0, 1);
01328 int i;
01329 if (value.isEmpty() || !value.startsWith("[") || ((i = value.indexOf(']')) == -1)) {
01330 qWarning().nospace()<<KLF_FUNC_NAME<<": QTextFormat bad format for general property, value does "
01331 <<"not begin with \"[type-name]\".";
01332 continue;
01333 }
01334 QByteArray typenm = value.mid(1, i-1);
01335 QByteArray valuedata = value.mid(i+1);
01336 QVariant vval = klfLoadVariantFromText(valuedata, typenm);
01337 klfDbg("setting generalized property "<<propid<<" to value "<<vval) ;
01338 textformat.setProperty(propid, vval);
01339 }
01340 return textformat;
01341 }
01342 case QMetaType::QVariantList:
01343 {
01344 if (listOrMapDataTypeName == QLatin1String("XML")) {
01345 QDomElement el = parse_xml_wrapper(data, "variant-list");
01346 return klfLoadVariantListFromXML(el);
01347 } else {
01348 QList<QByteArray> sections = decaps_list(data);
01349
01350
01351 QVariantList list;
01352 for (k = 0; k < sections.size(); ++k) {
01353 QVariant val = klfLoadVariantFromText(sections[k], listOrMapDataTypeName);
01354 list << val;
01355 }
01356
01357 return QVariant::fromValue<QVariantList>(list);
01358 }
01359 }
01360 case QMetaType::QVariantMap:
01361 {
01362 if (listOrMapDataTypeName == QLatin1String("XML")) {
01363 QDomElement el = parse_xml_wrapper(data, "variant-map");
01364 return klfLoadVariantMapFromXML(el);
01365 } else {
01366 const QList<QPair<QByteArray,QByteArray> > sections = decaps_map(data);
01367 QVariantMap vmap;
01368 QList<QPair<QByteArray,QByteArray> >::const_iterator it;
01369 for (it = sections.begin(); it != sections.end(); ++it) {
01370 QString key = klfLoadVariantFromText((*it).first, "QString").toString();
01371 QVariant value = klfLoadVariantFromText((*it).second, listOrMapDataTypeName);
01372 vmap[key] = value;
01373 }
01374 return QVariant::fromValue<QVariantMap>(vmap);
01375 }
01376 }
01377 default:
01378 break;
01379 }
01380
01381 QByteArray tname = dataTypeName;
01382 if (tname == "KLFStyle") {
01383 KLFStyle style;
01384 QVariantMap map = klfLoadVariantFromText(data, "QByteArray").toMap();
01385 style.name = klfLoadVariantFromText(map["name"].toByteArray(), "QString").toString();
01386 style.fg_color =
01387 klfLoadVariantFromText(map["fg_color"].toByteArray(), "QColor").value<QColor>().rgba();
01388 style.bg_color =
01389 klfLoadVariantFromText(map["bg_color"].toByteArray(), "QColor").value<QColor>().rgba();
01390 style.mathmode = klfLoadVariantFromText(map["mathmode"].toByteArray(), "QString").toString();
01391 style.preamble = klfLoadVariantFromText(map["preamble"].toByteArray(), "QString").toString();
01392 style.dpi = klfLoadVariantFromText(map["dpi"].toByteArray(), "int").toInt();
01393 return QVariant::fromValue<KLFStyle>(style);
01394 }
01395
01396 qWarning("klfLoadVariantFromText: Can't load a %s from %s !", dataTypeName, stringdata.constData());
01397 return QVariant();
01398 }
01399
01400
01401
01402
01403
01404
01405
01406
01407
01408
01409
01410 KLF_EXPORT QDomElement klfSaveVariantMapToXML(const QVariantMap& vmap, QDomElement baseNode)
01411 {
01412 QDomDocument doc = baseNode.ownerDocument();
01413
01414 for (QVariantMap::const_iterator it = vmap.begin(); it != vmap.end(); ++it) {
01415 QString key = it.key();
01416 QVariant value = it.value();
01417
01418 QDomElement pairNode = doc.createElement("pair");
01419
01420 QDomElement keyNode = doc.createElement("key");
01421 QDomText keyText = doc.createTextNode(key);
01422 keyNode.appendChild(keyText);
01423 pairNode.appendChild(keyNode);
01424
01425 QDomElement vdataNode = doc.createElement("value");
01426 QString vtype = QLatin1String(value.typeName());
01427 vdataNode.setAttribute(QLatin1String("type"), vtype);
01428 if (vtype == "QVariantMap") {
01429 vdataNode = klfSaveVariantMapToXML(value.toMap(), vdataNode);
01430 } else if (vtype == "QVariantList") {
01431 vdataNode = klfSaveVariantListToXML(value.toList(), vdataNode);
01432 } else {
01433 QDomText vdataText = doc.createTextNode(QString::fromLocal8Bit(klfSaveVariantToText(value)));
01434 vdataNode.appendChild(vdataText);
01435 }
01436 pairNode.appendChild(vdataNode);
01437
01438 baseNode.appendChild(pairNode);
01439 }
01440 return baseNode;
01441 }
01442
01443 KLF_EXPORT QVariantMap klfLoadVariantMapFromXML(const QDomElement& xmlNode)
01444 {
01445 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
01446
01447 QVariantMap vmap;
01448
01449 QDomNode n;
01450 for (n = xmlNode.firstChild(); ! n.isNull(); n = n.nextSibling()) {
01451 QDomElement e = n.toElement();
01452 if ( e.isNull() || n.nodeType() != QDomNode::ElementNode )
01453 continue;
01454 if ( e.nodeName() != "pair" ) {
01455 qWarning("%s: ignoring unexpected tag `%s'!\n", KLF_FUNC_NAME, qPrintable(e.nodeName()));
01456 continue;
01457 }
01458
01459 QString key;
01460 QByteArray valuetype;
01461 QByteArray valuedata;
01462 QDomElement valueNode;
01463 QDomNode nn;
01464 for (nn = e.firstChild(); ! nn.isNull(); nn = nn.nextSibling()) {
01465 klfDbg("inside <pair>: read node "<<nn.nodeName()) ;
01466 QDomElement ee = nn.toElement();
01467 if ( ee.isNull() || nn.nodeType() != QDomNode::ElementNode )
01468 continue;
01469 if ( ee.nodeName() == "key" ) {
01470 key = ee.text();
01471 continue;
01472 }
01473 if ( ee.nodeName() == "value" ) {
01474
01475 valueNode = ee;
01476 valuedata = ee.text().toLocal8Bit();
01477 valuetype = ee.attribute("type").toLatin1();
01478 continue;
01479 }
01480 qWarning("%s: ignoring unexpected tag `%s' in <pair>!\n", KLF_FUNC_NAME,
01481 qPrintable(ee.nodeName()));
01482 }
01483 QVariant value;
01484 if (valuetype == "QVariantMap") {
01485 value = QVariant::fromValue<QVariantMap>(klfLoadVariantMapFromXML(valueNode));
01486 } else if (valuetype == "QVariantList") {
01487 value = QVariant::fromValue<QVariantList>(klfLoadVariantListFromXML(valueNode));
01488 } else {
01489 value = klfLoadVariantFromText(valuedata, valuetype.constData());
01490 }
01491
01492 vmap[key] = value;
01493 }
01494 return vmap;
01495 }
01496
01497
01498 KLF_EXPORT QDomElement klfSaveVariantListToXML(const QVariantList& vlist, QDomElement baseNode)
01499 {
01500 QDomDocument doc = baseNode.ownerDocument();
01501
01502 for (QVariantList::const_iterator it = vlist.begin(); it != vlist.end(); ++it) {
01503 QVariant value = *it;
01504
01505 QDomElement elNode = doc.createElement(QLatin1String("item"));
01506 QString vtype = QString::fromLatin1(value.typeName());
01507
01508 elNode.setAttribute(QLatin1String("type"), vtype);
01509 if (vtype == "QVariantMap") {
01510 elNode = klfSaveVariantMapToXML(value.toMap(), elNode);
01511 } else if (vtype == "QVariantList") {
01512 elNode = klfSaveVariantListToXML(value.toList(), elNode);
01513 } else {
01514 QDomText vdataText = doc.createTextNode(QString::fromLocal8Bit(klfSaveVariantToText(value)));
01515 elNode.appendChild(vdataText);
01516 }
01517
01518
01519 baseNode.appendChild(elNode);
01520 }
01521
01522 return baseNode;
01523 }
01524
01525 KLF_EXPORT QVariantList klfLoadVariantListFromXML(const QDomElement& xmlNode)
01526 {
01527 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
01528
01529 QVariantList vlist;
01530
01531 QDomNode n;
01532 for (n = xmlNode.firstChild(); ! n.isNull(); n = n.nextSibling()) {
01533 QDomElement e = n.toElement();
01534 if ( e.isNull() || n.nodeType() != QDomNode::ElementNode )
01535 continue;
01536 if ( e.nodeName() != QLatin1String("item") ) {
01537 qWarning("%s: ignoring unexpected tag `%s'!\n", KLF_FUNC_NAME, qPrintable(e.nodeName()));
01538 continue;
01539 }
01540
01541 QString vtype = e.attribute(QLatin1String("type"));
01542
01543 QVariant value;
01544 if (vtype == QLatin1String("QVariantMap")) {
01545 value = QVariant::fromValue<QVariantMap>(klfLoadVariantMapFromXML(e));
01546 } else if (vtype == QLatin1String("QVariantList")) {
01547 value = QVariant::fromValue<QVariantList>(klfLoadVariantListFromXML(e));
01548 } else {
01549 value = klfLoadVariantFromText(e.text().toLocal8Bit(), vtype.toLatin1().constData());
01550 }
01551
01552
01553 vlist << value;
01554 }
01555 return vlist;
01556 }
01557
01558
01559
01560
01561 KLF_EXPORT QString klfPrefixedPath(const QString& path, const QString& reference)
01562 {
01563 klfDbg("path="<<path<<"; reference="<<reference) ;
01564 if (QFileInfo(path).isAbsolute())
01565 return path;
01566
01567 QString ref = reference;
01568 if (ref.isEmpty())
01569 ref = QCoreApplication::applicationDirPath();
01570
01571 klfDbg("reference is "<<ref) ;
01572
01573
01574 if (!ref.endsWith("/"))
01575 ref += "/";
01576
01577 return KLF_DEBUG_TEE( ref + path );
01578 }
01579
01580
01581
01582
01583 KLF_EXPORT QString klfUrlLocalFilePath(const QUrl& url)
01584 {
01585 #ifdef Q_OS_WIN32
01586 QString p = url.path();
01587 if (p.startsWith("/"))
01588 p = p.mid(1);
01589 return p;
01590 #else
01591 return url.path();
01592 #endif
01593 }