[KLF Application][KLF Tools][KLF Backend][KLF Home]
KLatexFormula Project

src/klflib.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   file klflib.cpp
00003  *   This file is part of the KLatexFormula Project.
00004  *   Copyright (C) 2010 by Philippe Faist
00005  *   philippe.faist at bluewin.ch
00006  *                                                                         *
00007  *   This program is free software; you can redistribute it and/or modify  *
00008  *   it under the terms of the GNU General Public License as published by  *
00009  *   the Free Software Foundation; either version 2 of the License, or     *
00010  *   (at your option) any later version.                                   *
00011  *                                                                         *
00012  *   This program is distributed in the hope that it will be useful,       *
00013  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00014  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00015  *   GNU General Public License for more details.                          *
00016  *                                                                         *
00017  *   You should have received a copy of the GNU General Public License     *
00018  *   along with this program; if not, write to the                         *
00019  *   Free Software Foundation, Inc.,                                       *
00020  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
00021  ***************************************************************************/
00022 /* $Id: klflib.cpp 581 2010-12-02 23:09:05Z philippe $ */
00023 
00024 #include <QDebug>
00025 #include <QString>
00026 #include <QBuffer>
00027 #include <QByteArray>
00028 #include <QDataStream>
00029 #include <QColor>
00030 #include <QMimeData>
00031 
00032 #include <klfutil.h>
00033 #include "klflib_p.h"
00034 #include "klflib.h"
00035 
00036 
00037 
00038 
00039 // issue a warning if no default sub-resource is set
00040 #define KLFLIBRESOURCEENGINE_WARN_NO_DEFAULT_SUBRESOURCE(func)          \
00041   if ((pFeatureFlags & FeatureSubResources) && pDefaultSubResource.isNull()) { \
00042     qWarning("KLFLibResourceEngine::" func "(id): sub-resources are supported feature but" \
00043              " no default sub-resource is specified!"); }               \
00044 
00045 
00046 
00047 // ----------------------
00048 
00049 
00050 KLFLibEntry::KLFLibEntry(const QString& latex, const QDateTime& dt, const QImage& preview,
00051                          const QSize& previewsize, const QString& category, const QString& tags,
00052                          const KLFStyle& style)
00053   : KLFPropertizedObject("KLFLibEntry")
00054 {
00055   initRegisteredProperties();
00056   setLatex(latex);
00057   setDateTime(dt);
00058   setPreview(preview);
00059   setPreviewSize(previewsize);
00060   setCategory(category);
00061   setTags(tags);
00062   setStyle(style);
00063 }
00064 KLFLibEntry::KLFLibEntry(const QString& latex, const QDateTime& dt, const QImage& preview,
00065                          const KLFStyle& style)
00066   : KLFPropertizedObject("KLFLibEntry")
00067 {
00068   initRegisteredProperties();
00069   QString latexonly = stripCategoryTagsFromLatex(latex);
00070   QString category = categoryFromLatex(latex);
00071   QString tags = tagsFromLatex(latex);
00072   QSize previewsize = preview.size();
00073   setLatex(latexonly);
00074   setDateTime(dt);
00075   setPreview(preview);
00076   setPreviewSize(previewsize);
00077   setCategory(category);
00078   setTags(tags);
00079   setStyle(style);
00080 }
00081 KLFLibEntry::KLFLibEntry(const KLFLibEntry& copy)
00082   : KLFPropertizedObject("KLFLibEntry")
00083 {
00084   initRegisteredProperties();
00085   setAllProperties(copy.allProperties());
00086 }
00087 KLFLibEntry::~KLFLibEntry()
00088 {
00089 }
00090 
00091 
00092 int KLFLibEntry::setEntryProperty(const QString& propName, const QVariant& value)
00093 {
00094   int propId = propertyIdForName(propName);
00095   if (propId < 0) {
00096     // register the property
00097     propId = registerProperty(propName);
00098     if (propId < 0)
00099       return -1;
00100   }
00101   // and set the property
00102   setProperty(propId, value);
00103   return propId;
00104 }
00105 
00106 // private, static
00107 void KLFLibEntry::initRegisteredProperties()
00108 {
00109   KLF_FUNC_SINGLE_RUN ;
00110   
00111   registerBuiltInProperty(Latex, "Latex");
00112   registerBuiltInProperty(DateTime, "DateTime");
00113   registerBuiltInProperty(Preview, "Preview");
00114   registerBuiltInProperty(PreviewSize, "PreviewSize");
00115   registerBuiltInProperty(Category, "Category");
00116   registerBuiltInProperty(Tags, "Tags");
00117   registerBuiltInProperty(Style, "Style");
00118 }
00119 
00120 
00121 // static
00122 QString KLFLibEntry::categoryFromLatex(const QString& latex)
00123 {
00124   QString s = latex.section('\n', 0, 0, QString::SectionSkipEmpty);
00125   if (s[0] == '%' && s[1] == ':') {
00126     return s.mid(2).trimmed();
00127   }
00128   return QString::null;
00129 }
00130 // static
00131 QString KLFLibEntry::tagsFromLatex(const QString& latex)
00132 {
00133   QString s = latex.section('\n', 0, 0, QString::SectionSkipEmpty);
00134   if (s[0] == '%' && s[1] == ':') {
00135     // category is s.mid(2);
00136     s = latex.section('\n', 1, 1, QString::SectionSkipEmpty);
00137   }
00138   if (s[0] == '%') {
00139     return s.mid(1).trimmed();
00140   }
00141   return QString::null;
00142 }
00143 
00144 // static
00145 QString KLFLibEntry::stripCategoryTagsFromLatex(const QString& latex)
00146 {
00147   int k = 0;
00148   while (k < latex.length() && latex[k].isSpace())
00149     ++k;
00150   if (k == latex.length()) return "";
00151   if (latex[k] == '%') {
00152     ++k;
00153     if (k == latex.length()) return "";
00154     //strip category and/or tag:
00155     if (latex[k] == ':') {
00156       // strip category
00157       while (k < latex.length() && latex[k] != '\n')
00158         ++k;
00159       ++k;
00160       if (k >= latex.length()) return "";
00161       if (latex[k] != '%') {
00162         // there isn't any tags, just category; return rest of string
00163         return latex.mid(k);
00164       }
00165       ++k;
00166       if (k >= latex.length()) return "";
00167     }
00168     // strip tag:
00169     while (k < latex.length() && latex[k] != '\n')
00170       ++k;
00171     ++k;
00172     if (k >= latex.length()) return "";
00173   }
00174   // k is the beginnnig of the latex string
00175   return latex.mid(k);
00176 }
00177 
00178 // static
00179 QString KLFLibEntry::latexAddCategoryTagsComment(const QString& latex, const QString& category,
00180                                                  const QString& tags)
00181 {
00182   QString s;
00183 
00184   if (!category.isEmpty())
00185     s = "%: "+category+"\n";
00186 
00187   if (!tags.isEmpty())
00188     s += "% "+tags+"\n";
00189 
00190   s += latex;
00191   return s;
00192 }
00193 
00194 // static
00195 QString KLFLibEntry::normalizeCategoryPath(const QString& categoryPath)
00196 {
00197   QString c = categoryPath.trimmed().split('/', QString::SkipEmptyParts).join("/");
00198   if (c.endsWith("/"))
00199     c.chop(1);
00200   return c;
00201 }
00202 
00203 
00204 
00205 // ------------------------------------------------------------
00206 
00207 
00208 
00209 KLFLibEntrySorter::KLFLibEntrySorter(int propId, Qt::SortOrder order)
00210   : pCloneOf(NULL), pPropId(propId), pOrder(order)
00211 {
00212 }
00213 KLFLibEntrySorter::KLFLibEntrySorter(const KLFLibEntrySorter *clone)
00214   : pCloneOf(clone), pPropId(clone->pPropId), pOrder(clone->pOrder)
00215 {
00216 }
00217 
00218 KLFLibEntrySorter::~KLFLibEntrySorter()
00219 {
00220 }
00221 
00222 void KLFLibEntrySorter::setPropId(int propId)
00223 {
00224   if (pCloneOf != NULL) {
00225     qWarning()<<"Attempt to setPropId() in entry sorter that is a clone of "<<pCloneOf;
00226     return;
00227   }
00228   pPropId = propId;
00229 }
00230 void KLFLibEntrySorter::setOrder(Qt::SortOrder order)
00231 {
00232   if (pCloneOf != NULL) {
00233     qWarning()<<"Attempt to setOrder() in entry sorter that is a clone of "<<pCloneOf;
00234     return;
00235   }
00236   pOrder = order;
00237 }
00238 
00239 
00240 
00241 QString KLFLibEntrySorter::entryValue(const KLFLibEntry& entry, int propId) const
00242 {
00243   if (pCloneOf != NULL)
00244     return pCloneOf->entryValue(entry, propId);
00245 
00246   // return an internal string representation of the value of the property 'propId' in libentry 'entry'
00247 
00248   // user friendliness. sort by date when selecting preview.
00249   if (propId == KLFLibEntry::Preview)
00250     propId = KLFLibEntry::DateTime;
00251 
00252   if (propId == KLFLibEntry::PreviewSize) {
00253     QSize s = entry.previewSize();
00254     // eg. "0000000280,0000000180" for 280x180
00255     return QString("%1,%2").arg(s.width(), 10, 10, QChar('0')).arg(s.height(), 10, 10, QChar('0'));
00256   }
00257   if (propId == KLFLibEntry::DateTime) {
00258     return entry.property(KLFLibEntry::DateTime).toDateTime().toString("yyyy-MM-dd+hh:mm:ss.zzz");
00259   }
00260   return entry.property(propId).toString();
00261 }
00262 
00263 bool KLFLibEntrySorter::compareLessThan(const KLFLibEntry& a, const KLFLibEntry& b,
00264                                         int propId, Qt::SortOrder order) const
00265 {
00266   if (pCloneOf != NULL)
00267     return pCloneOf->compareLessThan(a, b, propId, order);
00268 
00269   QString as = entryValue(a, propId);
00270   QString bs = entryValue(b, propId);
00271   if (order == Qt::AscendingOrder)
00272     return QString::localeAwareCompare(as, bs) < 0;
00273   return QString::localeAwareCompare(as, bs) > 0;
00274 }
00275 
00276 bool KLFLibEntrySorter::operator()(const KLFLibEntry& a, const KLFLibEntry& b) const
00277 {
00278   if (pCloneOf != NULL)
00279     return pCloneOf->operator()(a, b);
00280 
00281   return compareLessThan(a, b, pPropId, pOrder);
00282 }
00283 
00284 
00285 // ---------------------------------------------------
00286 
00287 KLFAbstractLibEntryMimeEncoder::KLFAbstractLibEntryMimeEncoder()
00288 {
00289   registerEncoder(this);
00290 }
00291 KLFAbstractLibEntryMimeEncoder::~KLFAbstractLibEntryMimeEncoder()
00292 {
00293 }
00294 void KLFAbstractLibEntryMimeEncoder::registerEncoder(KLFAbstractLibEntryMimeEncoder *encoder)
00295 {
00296   staticEncoderList.append(encoder);
00297 }
00298 
00299 QList<KLFAbstractLibEntryMimeEncoder*> KLFAbstractLibEntryMimeEncoder::encoderList()
00300 {
00301   return staticEncoderList;
00302 }
00303 
00304 // static
00305 QStringList KLFAbstractLibEntryMimeEncoder::allEncodingMimeTypes()
00306 {
00307   QStringList encTypes;
00308   int k;
00309   for (k = 0; k < staticEncoderList.size(); ++k) {
00310     encTypes << staticEncoderList[k]->supportedEncodingMimeTypes();
00311   }
00312   return encTypes;
00313 }
00314 // static
00315 QStringList KLFAbstractLibEntryMimeEncoder::allDecodingMimeTypes()
00316 {
00317   QStringList decTypes;
00318   int k;
00319   for (k = 0; k < staticEncoderList.size(); ++k) {
00320     decTypes << staticEncoderList[k]->supportedDecodingMimeTypes();
00321   }
00322   return decTypes;
00323 }
00324 
00325 // static
00326 QMimeData *KLFAbstractLibEntryMimeEncoder::createMimeData(const KLFLibEntryList& entryList,
00327                                                           const QVariantMap& metaData)
00328 {
00329   QMimeData *mime = new QMimeData;
00330   int k, j;
00331   for (k = 0; k < staticEncoderList.size(); ++k) {
00332     QStringList mimeTypeList = staticEncoderList[k]->supportedEncodingMimeTypes();
00333     for (j = 0; j < mimeTypeList.size(); ++j) {
00334       QByteArray data =
00335         staticEncoderList[k]->encodeMime(entryList, metaData, mimeTypeList[j]);
00336       if (data.isEmpty()) {
00337         klfDbg("Skipping mime type "<<mimeTypeList[k]<<" because it did not provide any data.");
00338       } else {
00339         mime->setData(mimeTypeList[j], data);
00340       }
00341     }
00342   }
00343   return mime;
00344 }
00345 
00346 
00347 // static
00348 bool KLFAbstractLibEntryMimeEncoder::canDecodeMimeData(const QMimeData *mimeData)
00349 {
00350   QStringList fmts = mimeData->formats();
00351   int k;
00352   for (k = 0; k < fmts.size(); ++k) {
00353     if (findDecoderFor(fmts[k], false) != NULL)
00354       return true;
00355   }
00356   return false;
00357 }
00358 
00359 // static
00360 bool KLFAbstractLibEntryMimeEncoder::decodeMimeData(const QMimeData *mimeData,
00361                                                     KLFLibEntryList *entryListPtr,
00362                                                     QVariantMap *metaDataPtr)
00363 {
00364   QStringList fmts = mimeData->formats();
00365   int k;
00366   for (k = 0; k < fmts.size(); ++k) {
00367     KLFAbstractLibEntryMimeEncoder *decoder = findDecoderFor(fmts[k], false);
00368     if (decoder == NULL)
00369       continue;
00370     bool result = decoder->decodeMime(mimeData->data(fmts[k]), fmts[k], entryListPtr, metaDataPtr);
00371     if ( result )
00372       return true;
00373     // else continue trying
00374   }
00375   return false;
00376 }
00377 
00378 
00379 
00380 KLFAbstractLibEntryMimeEncoder *KLFAbstractLibEntryMimeEncoder::findEncoderFor(const QString& mimeType,
00381                                                                                bool warn)
00382 {
00383   int k;
00384   for (k = 0; k < staticEncoderList.size(); ++k)
00385     if (staticEncoderList[k]->supportedEncodingMimeTypes().contains(mimeType))
00386       return staticEncoderList[k];
00387   if (warn)
00388     qWarning()<<KLF_FUNC_NAME<<": Failed to find encoder for mime-type "<<mimeType;
00389   return NULL;
00390 }
00391 
00392 KLFAbstractLibEntryMimeEncoder *KLFAbstractLibEntryMimeEncoder::findDecoderFor(const QString& mimeType,
00393                                                                                bool warn)
00394 {
00395   int k;
00396   for (k = 0; k < staticEncoderList.size(); ++k)
00397     if (staticEncoderList[k]->supportedDecodingMimeTypes().contains(mimeType))
00398       return staticEncoderList[k];
00399   if (warn)
00400     qWarning()<<KLF_FUNC_NAME<<": Failed to find decoder for mime-type "<<mimeType;
00401   return NULL;
00402 }
00403 
00404 
00405 QList<KLFAbstractLibEntryMimeEncoder*> KLFAbstractLibEntryMimeEncoder::staticEncoderList;
00406 
00407 
00408 
00409 
00410 // The instance of the basic encoder, that will auto-register itself
00411 KLFLibEntryMimeEncoder __klf_lib_mime_encoder;
00412 
00413 
00414 // ---------------------------------------------------
00415 
00416 KLFLibResourceEngine::KLFLibResourceEngine(const QUrl& url, uint featureflags,
00417                                            QObject *parent)
00418   : QObject(parent), KLFPropertizedObject("KLFLibResourceEngine"), pUrl(url),
00419     pFeatureFlags(featureflags), pReadOnly(false), pDefaultSubResource(QString()),
00420     pProgressBlocked(false), pThisOperationProgressBlockedOnly(false)
00421 {
00422   initRegisteredProperties();
00423 
00424   //  klfDbg( "KLFLibResourceEngine::KLFLibResourceEngine("<<url<<","<<pFeatureFlags<<","
00425   //      <<parent<<")" ) ;
00426 
00427   QStringList rdonly = pUrl.allQueryItemValues("klfReadOnly");
00428   if (rdonly.size() && rdonly.last() == "true") {
00429     if (pFeatureFlags & FeatureReadOnly)
00430       pReadOnly = true;
00431   }
00432   pUrl.removeAllQueryItems("klfReadOnly");
00433 
00434   if (pFeatureFlags & FeatureSubResources) {
00435     QStringList defaultsubresource = pUrl.allQueryItemValues("klfDefaultSubResource");
00436     if (!defaultsubresource.isEmpty()) {
00437       pUrl.removeAllQueryItems("klfDefaultSubResource");
00438       pDefaultSubResource = defaultsubresource.last();
00439     }
00440   }
00441 
00442 }
00443 KLFLibResourceEngine::~KLFLibResourceEngine()
00444 {
00445 }
00446 
00447 void KLFLibResourceEngine::initRegisteredProperties()
00448 {
00449   KLF_FUNC_SINGLE_RUN
00450 
00451   registerBuiltInProperty(PropTitle, "Title");
00452   registerBuiltInProperty(PropLocked, "Locked");
00453   registerBuiltInProperty(PropViewType, "ViewType");
00454   registerBuiltInProperty(PropAccessShared, "AccessShared");
00455 }
00456 
00457 QUrl KLFLibResourceEngine::url(uint flags) const
00458 {
00459   QUrl url = pUrl;
00460   if (flags & WantUrlDefaultSubResource &&
00461       (pFeatureFlags & FeatureSubResources) &&
00462       !pDefaultSubResource.isNull()) {
00463     url.addQueryItem("klfDefaultSubResource", pDefaultSubResource);
00464   }
00465   if (flags & WantUrlReadOnly) {
00466     url.addQueryItem("klfReadOnly", pReadOnly?QString("true"):QString("false"));
00467   }
00468   return url;
00469 }
00470 
00471 
00472 bool KLFLibResourceEngine::canModifyData(const QString& subResource,
00473                                          ModifyType /*modifytype*/) const
00474 {
00475   return baseCanModifyStatus(true, subResource) == MS_CanModify;
00476 }
00477 
00478 bool KLFLibResourceEngine::canModifyData(ModifyType modifytype) const
00479 {
00480   KLFLIBRESOURCEENGINE_WARN_NO_DEFAULT_SUBRESOURCE("canModifyData")
00481   return canModifyData(pDefaultSubResource, modifytype);
00482 }
00483 
00484 
00485 bool KLFLibResourceEngine::canModifyProp(int propId) const
00486 {
00487   ModifyStatus ms = baseCanModifyStatus(false);
00488   return ms == MS_CanModify ||
00489     (ms == MS_IsLocked && propId == PropLocked); // allow un-locking (!)
00490 }
00491 bool KLFLibResourceEngine::canRegisterProperty(const QString& /*propName*/) const
00492 {
00493   return false;
00494 }
00495 
00496 bool KLFLibResourceEngine::hasSubResource(const QString& subResource) const
00497 {
00498   if ( !(pFeatureFlags & FeatureSubResources) )
00499     return false;
00500 
00501   return subResourceList().contains(subResource);
00502 }
00503 
00504 QString KLFLibResourceEngine::defaultSubResource() const
00505 {
00506   return pDefaultSubResource;
00507 }
00508 
00509 bool KLFLibResourceEngine::compareDefaultSubResourceEquals(const QString& subResourceName) const
00510 {
00511   return QString::compare(pDefaultSubResource, subResourceName) == 0;
00512 }
00513 
00514 bool KLFLibResourceEngine::canCreateSubResource() const
00515 {
00516   return false;
00517 }
00518 
00519 bool KLFLibResourceEngine::canRenameSubResource(const QString& /*subResource*/) const
00520 {
00521   return false;
00522 }
00523 bool KLFLibResourceEngine::canDeleteSubResource(const QString& /*subResource*/) const
00524 {
00525   return false;
00526 }
00527 
00528 QVariant KLFLibResourceEngine::subResourceProperty(const QString& /*subResource*/, int /*propId*/) const
00529 {
00530   return QVariant();
00531 }
00532 
00533 QString KLFLibResourceEngine::subResourcePropertyName(int propId) const
00534 {
00535   switch (propId) {
00536   case SubResPropTitle:
00537     return QLatin1String("Title");
00538   case SubResPropLocked:
00539     return QLatin1String("Locked");
00540   case SubResPropViewType:
00541     return QLatin1String("ViewType");
00542   default:
00543     ;
00544   }
00545   return QString::number(propId);
00546 }
00547 
00548 bool KLFLibResourceEngine::canModifySubResourceProperty(const QString& subResource, int propId) const
00549 {
00550   ModifyStatus ms = baseCanModifyStatus(true, subResource);
00551   return ms == MS_CanModify ||
00552     (ms == MS_SubResLocked && propId == SubResPropLocked); // allow sub-resource un-locking
00553 }
00554 
00555 bool KLFLibResourceEngine::setTitle(const QString& title)
00556 {
00557   return setResourceProperty(PropTitle, title);
00558 }
00559 bool KLFLibResourceEngine::setLocked(bool setlocked)
00560 {
00561   // if locked feature is supported, setResourceProperty().
00562   // immediately return FALSE otherwise.
00563   if (pFeatureFlags & FeatureLocked) {
00564     return setResourceProperty(PropLocked, setlocked);
00565   }
00566   return false;
00567 }
00568 
00569 bool KLFLibResourceEngine::setViewType(const QString& viewType)
00570 {
00571   return setResourceProperty(PropViewType, viewType);
00572 }
00573 
00574 bool KLFLibResourceEngine::setReadOnly(bool readonly)
00575 {
00576   if ( !(pFeatureFlags & FeatureReadOnly) )
00577     return false;
00578 
00579   pReadOnly = readonly;
00580   return true;
00581 }
00582 
00583 
00584 void KLFLibResourceEngine::setDefaultSubResource(const QString& subResource)
00585 {
00586   if (pDefaultSubResource == subResource)
00587     return;
00588 
00589   pDefaultSubResource = subResource;
00590   emit defaultSubResourceChanged(subResource);
00591 }
00592 
00593 bool KLFLibResourceEngine::setSubResourceProperty(const QString& /*subResource*/, int /*propId*/,
00594                                                   const QVariant& /*value*/)
00595 {
00596   return false;
00597 }
00598 
00599 bool KLFLibResourceEngine::createSubResource(const QString& /*subResource*/,
00600                                              const QString& /*subResourceTitle*/)
00601 {
00602   return false;
00603 }
00604 bool KLFLibResourceEngine::createSubResource(const QString& subResource)
00605 {
00606   return createSubResource(subResource, QString());
00607 }
00608 bool KLFLibResourceEngine::renameSubResource(const QString& /*old*/, const QString& /*new*/)
00609 {
00610   return false;
00611 }
00612 bool KLFLibResourceEngine::deleteSubResource(const QString& /*subResource*/)
00613 {
00614   return false;
00615 }
00616 
00617 
00618 KLFLibEntry KLFLibResourceEngine::entry(entryId id)
00619 {
00620   KLFLIBRESOURCEENGINE_WARN_NO_DEFAULT_SUBRESOURCE("entry");
00621   return entry(pDefaultSubResource, id);
00622 }
00623 bool KLFLibResourceEngine::hasEntry(entryId id)
00624 {
00625   KLFLIBRESOURCEENGINE_WARN_NO_DEFAULT_SUBRESOURCE("hasEntry");
00626   return hasEntry(pDefaultSubResource, id);
00627 }
00628 QList<KLFLibResourceEngine::KLFLibEntryWithId>
00629 /* */ KLFLibResourceEngine::entries(const QList<KLFLib::entryId>& idList,
00630                                     const QList<int>& wantedEntryProperties)
00631 {
00632   KLFLIBRESOURCEENGINE_WARN_NO_DEFAULT_SUBRESOURCE("entries");
00633   return entries(pDefaultSubResource, idList, wantedEntryProperties);
00634 }
00635 
00636 QList<KLFLibResourceEngine::KLFLibEntryWithId>
00637 /* */ KLFLibResourceEngine::allEntries(const QList<int>& wantedEntryProperties)
00638 {
00639   KLFLIBRESOURCEENGINE_WARN_NO_DEFAULT_SUBRESOURCE("allEntries");
00640   return allEntries(pDefaultSubResource, wantedEntryProperties);
00641 }
00642 QList<KLFLib::entryId> KLFLibResourceEngine::allIds()
00643 {
00644   KLFLIBRESOURCEENGINE_WARN_NO_DEFAULT_SUBRESOURCE("allIds");
00645   return allIds(pDefaultSubResource);
00646 }
00647 
00648 void KLFLibResourceEngine::blockProgressReportingForNextOperation()
00649 {
00650   pProgressBlocked = true;
00651   pThisOperationProgressBlockedOnly = true;
00652 }
00653 
00654 void KLFLibResourceEngine::blockProgressReporting(bool block)
00655 {
00656   pProgressBlocked = true;
00657   pThisOperationProgressBlockedOnly = false;
00658 }
00659 
00660 bool KLFLibResourceEngine::thisOperationProgressBlocked() const
00661 {
00662   bool blocked = pProgressBlocked;
00663   if (pThisOperationProgressBlockedOnly)
00664     pProgressBlocked = false; // reset for next operation
00665   return blocked;
00666 }
00667 
00668 
00669 KLFLibResourceEngine::entryId KLFLibResourceEngine::insertEntry(const QString& subResource,
00670                                                                 const KLFLibEntry& entry)
00671 {
00672   QList<entryId> ids = insertEntries(subResource, KLFLibEntryList() << entry);
00673   if (ids.size() == 0)
00674     return -1;
00675 
00676   return ids[0];
00677 }
00678 KLFLibResourceEngine::entryId KLFLibResourceEngine::insertEntry(const KLFLibEntry& entry)
00679 { 
00680   KLFLIBRESOURCEENGINE_WARN_NO_DEFAULT_SUBRESOURCE("insertEntry");
00681   return insertEntry(pDefaultSubResource, entry);
00682 }
00683 QList<KLFLibResourceEngine::entryId> KLFLibResourceEngine::insertEntries(const KLFLibEntryList& entrylist)
00684 {
00685   KLFLIBRESOURCEENGINE_WARN_NO_DEFAULT_SUBRESOURCE("insertEntries");
00686   return insertEntries(pDefaultSubResource, entrylist);
00687 }
00688 
00689 bool KLFLibResourceEngine::changeEntries(const QList<entryId>& idlist, const QList<int>& properties,
00690                                          const QList<QVariant>& values)
00691 {
00692   KLFLIBRESOURCEENGINE_WARN_NO_DEFAULT_SUBRESOURCE("changeEntries");
00693   return changeEntries(pDefaultSubResource, idlist, properties, values);
00694 }
00695 
00696 bool KLFLibResourceEngine::deleteEntries(const QList<entryId>& idList)
00697 {
00698   KLFLIBRESOURCEENGINE_WARN_NO_DEFAULT_SUBRESOURCE("deleteEntries");
00699   return deleteEntries(pDefaultSubResource, idList);
00700 }
00701 
00702 
00703 
00704 bool KLFLibResourceEngine::saveTo(const QUrl&)
00705 {
00706   // not implemented by default. Subclasses must reimplement
00707   // to support this feature.
00708   return false;
00709 }
00710 
00711 QVariant KLFLibResourceEngine::resourceProperty(const QString& name) const
00712 {
00713   return KLFPropertizedObject::property(name);
00714 }
00715 
00716 bool KLFLibResourceEngine::loadResourceProperty(const QString& propName, const QVariant& value)
00717 {
00718   int propId = propertyIdForName(propName);
00719   if (propId < 0) {
00720     if (!canRegisterProperty(propName))
00721       return false;
00722     // register the property
00723     propId = registerProperty(propName);
00724     if (propId < 0)
00725       return false;
00726   }
00727   // finally set the property
00728   return setResourceProperty(propId, value);
00729 }
00730 
00731 bool KLFLibResourceEngine::setResourceProperty(int propId, const QVariant& value)
00732 {
00733   if ( ! KLFPropertizedObject::propertyIdRegistered(propId) )
00734     return false;
00735 
00736   if ( !canModifyProp(propId) ) {
00737     return false;
00738   }
00739 
00740   bool result = saveResourceProperty(propId, value);
00741   if (!result) // operation not permitted or failed
00742     return false;
00743 
00744   // operation succeeded: set KLFPropertizedObject-based property.
00745   KLFPropertizedObject::setProperty(propId, value);
00746   emit resourcePropertyChanged(propId);
00747   return true;
00748 }
00749 
00750 
00751 KLFLibResourceEngine::ModifyStatus
00752 /* */ KLFLibResourceEngine::baseCanModifyStatus(bool inSubResource, const QString& subResource) const
00753 {
00754   if (pFeatureFlags & FeatureLocked) {
00755     if (locked())
00756       return MS_IsLocked;
00757     if (inSubResource &&
00758         (pFeatureFlags & FeatureSubResources) &&
00759         (pFeatureFlags & FeatureSubResourceProps)) {
00760       if (subResourceProperty(subResource, SubResPropLocked).toBool())
00761         return MS_SubResLocked;
00762     }
00763   }
00764 
00765   if (pFeatureFlags & FeatureReadOnly) {
00766     if (isReadOnly())
00767       return MS_NotModifiable;
00768   }
00769 
00770   return MS_CanModify;
00771 }
00772 
00773 
00774 
00775 // static
00776 KLFLib::EntryMatchCondition KLFLib::EntryMatchCondition::mkMatchAll()
00777 {
00778   return EntryMatchCondition(MatchAllType);
00779 }
00780 // static
00781 KLFLib::EntryMatchCondition KLFLib::EntryMatchCondition::mkPropertyMatch(PropertyMatch pmatch)
00782 {
00783   EntryMatchCondition c(PropertyMatchType);
00784   c.mPropertyMatch = pmatch;
00785   return c;
00786 }
00787 // static
00788 KLFLib::EntryMatchCondition KLFLib::EntryMatchCondition::mkNegateMatch(const EntryMatchCondition& condition)
00789 {
00790   EntryMatchCondition c(NegateMatchType);
00791   c.mConditionList = QList<EntryMatchCondition>() << condition;
00792   return c;
00793 }
00794 // static
00795 KLFLib::EntryMatchCondition KLFLib::EntryMatchCondition::mkOrMatch(QList<EntryMatchCondition> conditions)
00796 {
00797   EntryMatchCondition c(OrMatchType);
00798   c.mConditionList = conditions;
00799   return c;
00800 }
00801 // static
00802 KLFLib::EntryMatchCondition KLFLib::EntryMatchCondition::mkAndMatch(QList<EntryMatchCondition> conditions)
00803 {
00804   EntryMatchCondition c(AndMatchType);
00805   c.mConditionList = conditions;
00806   return c;
00807 }
00808 
00809 
00810 
00811 
00812 
00813 
00814 // -----
00815 
00816 // DATA STREAM OPERATORS
00817 KLF_EXPORT QDataStream& operator<<(QDataStream& stream, const KLFLibResourceEngine::KLFLibEntryWithId& entrywid)
00818 {
00819   return stream << entrywid.id << entrywid.entry;
00820 }
00821 KLF_EXPORT QDataStream& operator>>(QDataStream& stream, KLFLibResourceEngine::KLFLibEntryWithId& entrywid)
00822 {
00823   return stream >> entrywid.id >> entrywid.entry;
00824 }
00825 
00826 // DEBUG OPERATOR<<'S
00827 KLF_EXPORT  QDebug& operator<<(QDebug& dbg, const KLFLib::StringMatch& smatch)
00828 {
00829   return dbg << "StringMatch[ref="<<smatch.matchValueString()<<";flags="<<smatch.matchFlags()<<"]";
00830 }
00831 KLF_EXPORT  QDebug& operator<<(QDebug& dbg, const KLFLib::PropertyMatch& pmatch)
00832 {
00833   return dbg << "PropertyMatch[prop-id="<<pmatch.propertyId()<<"; ref="<<pmatch.matchValueString()
00834              <<"; flags="<<pmatch.matchFlags()<<"]";
00835 }
00836 KLF_EXPORT  QDebug& operator<<(QDebug& dbg, const KLFLib::EntryMatchCondition& c)
00837 {
00838 #ifdef Q_WS_MAC
00839   return dbg<<"EntryMatchCondition{...}";
00840 #endif
00841   dbg << "EntryMatchCondition{type=";
00842   if (c.type() == KLFLib::EntryMatchCondition::MatchAllType)
00843     return dbg << "match-all}";
00844   if (c.type() == KLFLib::EntryMatchCondition::PropertyMatchType)
00845     return dbg << "property-match; "<<c.propertyMatch()<<"}";
00846   if (c.type() != KLFLib::EntryMatchCondition::NegateMatchType &&
00847       c.type() != KLFLib::EntryMatchCondition::AndMatchType &&
00848       c.type() != KLFLib::EntryMatchCondition::OrMatchType)
00849     return dbg << "unknown-type}";
00850   // NOT, AND or OR type:
00851   static const char *w_and = " AND ";
00852   static const char *w_or  = " OR ";
00853   static const char *w_not = " NOT ";
00854   const char * word =  (c.type()==KLFLib::EntryMatchCondition::NegateMatchType)? w_not :
00855                         ((c.type()==KLFLib::EntryMatchCondition::AndMatchType) ? w_and : w_or) ;
00856   dbg << (word+1/*nospace*/) << "; list: ";
00857   QList<KLFLib::EntryMatchCondition> conditions = c.conditionList();
00858   int k;
00859   for (k = 0; k < conditions.size(); ++k) {
00860     if (k > 0)
00861       dbg << word;
00862     dbg << conditions[k];
00863   }
00864   dbg << ".}";
00865   return dbg;
00866 }
00867 KLF_EXPORT  QDebug& operator<<(QDebug& dbg, const KLFLibResourceEngine::KLFLibEntryWithId& e)
00868 {
00869   return dbg <<"KLFLibEntryWithId(id="<<e.id<<";"<<e.entry.category()<<","<<e.entry.tags()<<","
00870              <<e.entry.latex()<<")";
00871 }
00872 KLF_EXPORT  QDebug& operator<<(QDebug& dbg, const KLFLibResourceEngine::Query& q)
00873 {
00874   return dbg << "Query(cond.="<<q.matchCondition<<"; skip="<<q.skip<<",limit="<<q.limit
00875              <<"; orderpropid="<<q.orderPropId<<"/"<<(q.orderDirection==Qt::AscendingOrder ? "Asc":"Desc")
00876              <<"; wanted props="<<q.wantedEntryProperties<<")" ;
00877 }
00878 
00879 
00880 
00881 
00882 // ---------------------------------------------------
00883 
00884 QList<KLFLib::entryId> KLFLibResourceSimpleEngine::allIds(const QString& subResource)
00885 {
00886   QList<KLFLib::entryId> idList;
00887   QList<KLFLibResourceEngine::KLFLibEntryWithId> elist = allEntries(subResource);
00888   int k;
00889   for (k = 0; k < idList.size(); ++k)
00890     idList << elist[k].id;
00891   return idList;
00892 }
00893 
00894 bool KLFLibResourceSimpleEngine::hasEntry(const QString& subResource, entryId id)
00895 {
00897   return entry(subResource, id).latex().size();
00898 }
00899 
00900 QList<KLFLibResourceEngine::KLFLibEntryWithId>
00901 /* */ KLFLibResourceSimpleEngine::entries(const QString& subResource, const QList<KLFLib::entryId>& idList,
00902                                           const QList<int>& /*wantedEntryProperties*/)
00903 {
00904   QList<KLFLibEntryWithId> elist;
00905   int k;
00906   for (k = 0; k < idList.size(); ++k)
00907     elist << KLFLibEntryWithId(idList[k], entry(subResource, idList[k]));
00908   return elist;
00909 }
00910 
00911 
00912 int KLFLibResourceSimpleEngine::query(const QString& subResource,
00913                                       const Query& query,
00914                                       QueryResult *result)
00915 {
00916   return queryImpl(this, subResource, query, result);
00917 }
00918 
00919 QList<QVariant> KLFLibResourceSimpleEngine::queryValues(const QString& subResource, int entryPropId)
00920 {
00921   return queryValuesImpl(this, subResource, entryPropId);
00922 }
00923 
00924 
00925 template<class T>
00926 static void qlist_skip_and_limit(QList<T> *list, int skip, int limit)
00927 {
00928   KLF_ASSERT_NOT_NULL( list, "list is NULL!", return; ) ;
00929 
00930   // skip `skip' first entries
00931 
00932   if (skip <= 0) {
00933     // nothing to do
00934   } else if (list->size() <= skip) {
00935     list->clear();
00936   } else {
00937     *list = list->mid(skip);
00938   }
00939 
00940   // and limit to `limit'
00941   if (limit < 0)
00942     return; // no limit
00943 
00944   if (list->size() > limit)
00945     *list = list->mid(0, limit);
00946 
00947   return;
00948 }
00949 
00950 // static
00951 int KLFLibResourceSimpleEngine::queryImpl(KLFLibResourceEngine *resource, const QString& subResource,
00952                                           const Query& query, QueryResult *result)
00953 {
00955 
00956   KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
00957   klfDbgSt("Query: "<<query);
00958 
00959   if (result == NULL) {
00960     qWarning()<<KLF_FUNC_NAME<<": expected valid `result' pointer";
00961     return -1;
00962   }
00963 
00964   QList<KLFLibEntryWithId> allEList = resource->allEntries(subResource);
00965 
00966   KLFLibEntrySorter sorter(query.orderPropId, query.orderDirection);
00967   QueryResultListSorter lsorter(&sorter, result);
00968 
00969   // we first need to order _all_ the entries (yes, since the order of allEntries()
00970   // is undefined ... and limit/skip refer to _ordered_ entry list...)
00971   int k;
00972   for (k = 0; k < allEList.size(); ++k) {
00973     // test match condition
00974     const KLFLibEntryWithId& ewid = allEList[k];
00975     if (testEntryMatchConditionImpl(query.matchCondition, ewid.entry)) {
00976       lsorter.insertIntoOrderedResult(ewid);
00977     }
00978   }
00979 
00980   klfDbgSt("queried ordered list. result->entryWithIdList: \n"<<result->entryWithIdList) ;
00981 
00982   // now we need to remove the first 'query.skip' number of results.
00983   // we can't do this while inserting because the order counts.
00984 
00985   qlist_skip_and_limit(&result->entryIdList, query.skip, query.limit);
00986   qlist_skip_and_limit(&result->rawEntryList, query.skip, query.limit);
00987   qlist_skip_and_limit(&result->entryWithIdList, query.skip, query.limit);
00988 
00989   klfDbgSt("About to return. Number of entries in TEE VALUE.") ;
00990 
00991   return KLF_DEBUG_TEE( lsorter.numberOfEntries() );
00992 }
00993 
00994 // static
00995 QList<QVariant> KLFLibResourceSimpleEngine::queryValuesImpl(KLFLibResourceEngine *resource,
00996                                                             const QString& subResource, int entryPropId)
00997 {
00998   QList<KLFLibEntryWithId> allEList = resource->allEntries(subResource);
00999   QList<QVariant> values;
01000   int k;
01001   for (k = 0; k < allEList.size(); ++k) {
01002     QVariant p = allEList[k].entry.property(entryPropId);
01003     if (!values.contains(p))
01004       values << p;
01005   }
01006   return values;
01007 }
01008 
01009 
01010 // static
01011 bool KLFLibResourceSimpleEngine::testEntryMatchConditionImpl(const KLFLib::EntryMatchCondition& condition,
01012                                                              const KLFLibEntry& libentry)
01013 {
01014   int k;
01015   KLFLib::PropertyMatch pmatch;
01016   QList<KLFLib::EntryMatchCondition> condlist;
01017 
01018   switch (condition.type()) {
01019   case KLFLib::EntryMatchCondition::MatchAllType:
01020     return true;
01021   case KLFLib::EntryMatchCondition::PropertyMatchType:
01022     pmatch = condition.propertyMatch();
01023     return klfMatch(libentry.property(pmatch.propertyId()), // test value
01024                     pmatch.matchValue(), // match value
01025                     pmatch.matchFlags(), // flags
01026                     pmatch.matchValueString()); // variant converted to string, cached
01027   case KLFLib::EntryMatchCondition::NegateMatchType:
01028     condlist = condition.conditionList(); // only first item is used
01029     if (condlist.isEmpty()) {
01030       qWarning()<<KLF_FUNC_NAME<<": NOT condition with no arguments!";
01031       return false;
01032     }
01033     return  ! testEntryMatchConditionImpl(condlist[0], libentry); // negate test
01034   case KLFLib::EntryMatchCondition::OrMatchType:
01035     condlist = condition.conditionList();
01036     if (condlist.isEmpty())
01037       return true;
01038     for (k = 0; k < condlist.size(); ++k) {
01039       if (testEntryMatchConditionImpl(condlist[k], libentry)) // recurse
01040         return true; // 'OR' -> find one that's OK and the condition is OK
01041     }
01042     return false; // but if none is OK then we're not OK
01043   case KLFLib::EntryMatchCondition::AndMatchType:
01044     condlist = condition.conditionList();
01045     if (condlist.isEmpty())
01046       return true;
01047     for (k = 0; k < condlist.size(); ++k) {
01048       if ( ! testEntryMatchConditionImpl(condlist[k], libentry) ) // recurse
01049         return false; // 'AND' -> find one that's not OK and the condition is globally false
01050     }
01051     return true; // but if all are OK then we're OK
01052   default:
01053     qWarning()<<KLF_FUNC_NAME<<": KLFLib::EntryMatchCondition type "<<condition.type()<<" not known!";
01054   }
01055   return false;
01056 }
01057 
01058 
01059 KLFLibResourceSimpleEngine::QueryResultListSorter::QueryResultListSorter(KLFLibEntrySorter *sorter,
01060                                                                          QueryResult *result)
01061   : mSorter(sorter), mResult(result)
01062 {
01063   KLF_ASSERT_NOT_NULL( result, "result ptr is NULL!", return ) ;
01064 
01065   fillflags = result->fillFlags;
01066 
01067   if (fillflags & QueryResult::FillRawEntryList) {
01068     reference_is_rawentrylist = true;
01069   } else if (fillflags & QueryResult::FillEntryWithIdList) {
01070     reference_is_rawentrylist = false;
01071   } else {
01072     // fill also the raw entry list to have a reference (!)
01073     fillflags |= QueryResult::FillRawEntryList;
01074     reference_is_rawentrylist = true;
01075   }
01076 }
01077 int KLFLibResourceSimpleEngine::QueryResultListSorter::numberOfEntries()
01078 {
01079   if (reference_is_rawentrylist)
01080     return mResult->rawEntryList.size();
01081   else
01082     return mResult->entryWithIdList.size();
01083 }
01084 
01085 
01086 /*
01087 KLFLibResourceSimpleEngine::QueryResultListSorter::QueryResultListSorter(const QueryResultListSorter& other)
01088   : mSorter(other.mSorter), mResult(other.mResult), fillflags(other.fillflags),
01089     reference_is_rawentrylist(other.reference_is_rawentrylist)
01090 {
01091 }
01092 */
01093 
01094 #define klf_lower_bound_entry                                           \
01095   qLowerBound<KLFLibEntryList::iterator,KLFLibEntry,const KLFLibEntrySorter&>
01096 #define klf_lower_bound_ewid                                            \
01097   qLowerBound<QList<KLFLibEntryWithId>::iterator,KLFLibEntryWithId,const QueryResultListSorter&>
01098 
01099 void KLFLibResourceSimpleEngine::QueryResultListSorter::insertIntoOrderedResult(const KLFLibEntryWithId& ewid)
01100 {
01101   int pos;
01102 
01103   if (mSorter->propId() == -1) {
01104     // just append
01105     if (reference_is_rawentrylist)
01106       pos = mResult->rawEntryList.size();
01107     else
01108       pos = mResult->entryWithIdList.size();
01109   } else {
01110     // insert at right place
01111     if (reference_is_rawentrylist) {
01112       KLFLibEntryList::iterator it =
01113         klf_lower_bound_entry(mResult->rawEntryList.begin(), mResult->rawEntryList.end(), ewid.entry, *mSorter);
01114       pos = it - mResult->rawEntryList.begin();
01115     } else {
01116       QList<KLFLibEntryWithId>::iterator it =
01117         klf_lower_bound_ewid(mResult->entryWithIdList.begin(), mResult->entryWithIdList.end(), ewid, *this);
01118       pos = it - mResult->entryWithIdList.begin();
01119     }
01120   }
01121   // actually insert the items into appropriate lists
01122   if (fillflags & QueryResult::FillEntryIdList)
01123     mResult->entryIdList.insert(pos, ewid.id);
01124   if (fillflags & QueryResult::FillRawEntryList)
01125     mResult->rawEntryList.insert(pos, ewid.entry);
01126   if (fillflags & QueryResult::FillEntryWithIdList)
01127     mResult->entryWithIdList.insert(pos, ewid);
01128 }
01129 
01130 
01131 // ---------------------------------------------------
01132 
01133 // static
01134 KLFFactoryManager KLFLibEngineFactory::pFactoryManager;
01135 
01136 
01137 KLFLibEngineFactory::KLFLibEngineFactory(QObject *parent)
01138   : QObject(parent), KLFFactoryBase(&pFactoryManager)
01139 {
01140 }
01141 KLFLibEngineFactory::~KLFLibEngineFactory()
01142 {
01143 }
01144 
01145 uint KLFLibEngineFactory::schemeFunctions(const QString& /*scheme*/) const
01146 {
01147   return FuncOpen;
01148 }
01149 
01150 KLFLibEngineFactory *KLFLibEngineFactory::findFactoryFor(const QUrl& url)
01151 {
01152   return findFactoryFor(url.scheme());
01153 }
01154 
01155 KLFLibEngineFactory *KLFLibEngineFactory::findFactoryFor(const QString& urlscheme)
01156 {
01157   return dynamic_cast<KLFLibEngineFactory*>(pFactoryManager.findFactoryFor(urlscheme));
01158 }
01159 
01160 QStringList KLFLibEngineFactory::allSupportedSchemes()
01161 {
01162   return pFactoryManager.allSupportedTypes();
01163 }
01164 
01165 KLFLibResourceEngine *KLFLibEngineFactory::createResource(const QString& /*scheme*/,
01166                                                           const Parameters& /*param*/,
01167                                                           QObject */*parent*/)
01168 {
01169   return NULL;
01170 }
01171 
01172 bool KLFLibEngineFactory::saveResourceTo(KLFLibResourceEngine */*resource*/, const QUrl& /*newLocation*/)
01173 {
01174   return false;
01175 }
01176 
01177 
01178 KLFLibResourceEngine *KLFLibEngineFactory::openURL(const QUrl& url, QObject *parent)
01179 {
01180   KLFLibEngineFactory *factory = findFactoryFor(url.scheme());
01181   if ( factory == NULL ) {
01182     qWarning()<<"KLFLibEngineFactory::openURL("<<url<<"): No suitable factory found!";
01183     return NULL;
01184   }
01185   return factory->openResource(url, parent);
01186 }
01187 
01188 // static
01189 QMap<QString,QString> KLFLibEngineFactory::listSubResourcesWithTitles(const QUrl& urlbase)
01190 {
01191   QUrl url = urlbase;
01192   url.addQueryItem("klfReadOnly", "true");
01193   KLFLibResourceEngine *resource = openURL(url, NULL); // NULL parent
01194   if ( resource == NULL ) {
01195     qWarning()<<"KLFLibEngineFactory::listSubResources("<<url<<"): Unable to open resource!";
01196     return QMap<QString,QString>();
01197   }
01198   if ( !(resource->supportedFeatureFlags() & KLFLibResourceEngine::FeatureSubResources) ) {
01199     qWarning()<<"KLFLibEngineFactory::listSubResources("<<url<<"): Resource does not support sub-resources!";
01200     return QMap<QString,QString>();
01201   }
01202   QStringList subreslist = resource->subResourceList();
01203   int k;
01204   QMap<QString,QString> subresmap;
01205   for (k = 0; k < subreslist.size(); ++k) {
01206     if (resource->supportedFeatureFlags() & KLFLibResourceEngine::FeatureSubResourceProps)
01207       subresmap[subreslist[k]]
01208         = resource->subResourceProperty(subreslist[k],
01209                                         KLFLibResourceEngine::SubResPropTitle).toString();
01210     else
01211       subresmap[subreslist[k]] = QString();
01212   }
01213   delete resource;
01214   return subresmap;
01215 }
01216 
01217 // static
01218 QStringList KLFLibEngineFactory::listSubResources(const QUrl& urlbase)
01219 {
01220   return listSubResourcesWithTitles(urlbase).keys();
01221 }
01222 

Generated by doxygen 1.7.3