00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <QApplication>
00026 #include <QDebug>
00027 #include <QImage>
00028 #include <QString>
00029 #include <QDataStream>
00030 #include <QMessageBox>
00031 #include <QAbstractItemModel>
00032 #include <QModelIndex>
00033 #include <QPainter>
00034 #include <QStyle>
00035 #include <QVBoxLayout>
00036 #include <QStackedWidget>
00037 #include <QComboBox>
00038 #include <QHeaderView>
00039 #include <QTextDocument>
00040 #include <QTextCursor>
00041 #include <QTextCharFormat>
00042 #include <QListView>
00043 #include <QMenu>
00044 #include <QAction>
00045 #include <QEvent>
00046 #include <QDropEvent>
00047 #include <QDragEnterEvent>
00048 #include <QDragMoveEvent>
00049 #include <QStandardItemModel>
00050 #include <QItemDelegate>
00051 #include <QShortcut>
00052
00053 #include <ui_klflibopenresourcedlg.h>
00054 #include <ui_klflibrespropeditor.h>
00055 #include <ui_klflibnewsubresdlg.h>
00056
00057 #include <klfguiutil.h>
00058 #include "klfconfig.h"
00059 #include "klflibview.h"
00060
00061 #include "klflibview_p.h"
00062
00063
00064
00065
00066
00068 static QImage transparentify_image(const QImage& img, qreal factor)
00069 {
00070
00071 QImage img2 = img.convertToFormat(QImage::Format_ARGB32_Premultiplied);
00072 int k, j;
00073 for (k = 0; k < img.height(); ++k) {
00074 for (j = 0; j < img.width(); ++j) {
00075 QRgb c = img2.pixel(j, k);
00076 img2.setPixel(j, k, qRgba(qRed(c),qGreen(c),qBlue(c),(int)(factor*qAlpha(c))));
00077 }
00078 }
00079 return img2;
00080 }
00081
00082
00084 static QImage autocrop_image(const QImage& img, int alpha_threshold = 0)
00085 {
00086
00087 int x, y;
00088 int min_x = -1, max_x = -1, min_y = -1, max_y = -1;
00089
00090 for (x = 0; x < img.width(); ++x) {
00091 for (y = 0; y < img.height(); ++y) {
00092 if (qAlpha(img.pixel(x,y)) - alpha_threshold > 0) {
00093
00094 if (min_x == -1 || min_x > x) min_x = x;
00095 if (max_x == -1 || max_x < x) max_x = x;
00096 if (min_y == -1 || min_y > y) min_y = y;
00097 if (max_y == -1 || max_y < y) max_y = y;
00098 }
00099 }
00100 }
00101 return img.copy(QRect(QPoint(min_x, min_y), QPoint(max_x, max_y)));
00102 }
00103
00105 static float color_distinguishable_distance(QRgb a, QRgb b, bool aPremultiplied = false) {
00106 static const float C_r = 11.f, C_g = 16.f, C_b = 5.f;
00107 static const float C_avg = (C_r + C_g + C_b) / 3.f;
00108
00109
00110
00111
00112
00113
00114
00115 static const float drkfactor = 1;
00116
00117 float alpha = qAlpha(a)/255.f;
00118 QRgb m;
00119 if (aPremultiplied)
00120 m = qRgb((int)(qRed(a)+(1-alpha)*qRed(b)),
00121 (int)(qGreen(a)+(1-alpha)*qGreen(b)),
00122 (int)(qBlue(a)+(1-alpha)*qBlue(b)));
00123 else
00124 m = qRgb((int)(alpha*qRed(a)+(1-alpha)*qRed(b)),
00125 (int)(alpha*qGreen(a)+(1-alpha)*qGreen(b)),
00126 (int)(alpha*qBlue(a)+(1-alpha)*qBlue(b)));
00127
00128 float dst = qMax( qMax(C_r*abs(qRed(m) - qRed(b)), C_g*abs(qGreen(m) - qGreen(b))),
00129 C_b*abs(qBlue(m) - qBlue(b)) ) * drkfactor / C_avg;
00130
00131
00132 return dst;
00133 }
00134
00135
00137 static bool image_is_distinguishable(const QImage& imgsrc, QColor background, float threshold)
00138 {
00139 int fmt = imgsrc.format();
00140 bool apremultiplied;
00141 QImage img;
00142 switch (fmt) {
00143 case QImage::Format_ARGB32: img = imgsrc; apremultiplied = false; break;
00144 case QImage::Format_ARGB32_Premultiplied: img = imgsrc; apremultiplied = true; break;
00145 default:
00146 img = imgsrc.convertToFormat(QImage::Format_ARGB32);
00147 apremultiplied = false;
00148 break;
00149 }
00150 QRgb bg = background.rgb();
00151
00152 int x, y;
00153 for (x = 0; x < img.width(); ++x) {
00154 for (y = 0; y < img.height(); ++y) {
00155
00156
00157 float dist = color_distinguishable_distance(img.pixel(x,y), bg, apremultiplied);
00158 if (dist > threshold) {
00159
00160 return true;
00161 }
00162 }
00163 }
00164 return false;
00165 }
00166
00167
00168
00169
00170
00171 KLFAbstractLibView::KLFAbstractLibView(QWidget *parent)
00172 : QWidget(parent), pResourceEngine(NULL)
00173 {
00174 }
00175
00176 void KLFAbstractLibView::setResourceEngine(KLFLibResourceEngine *resource)
00177 {
00178 if (pResourceEngine)
00179 disconnect(pResourceEngine, 0, this, 0);
00180 pResourceEngine = resource;
00181 connect(pResourceEngine, SIGNAL(dataChanged(const QString&, int, const QList<KLFLib::entryId>&)),
00182 this, SLOT(updateResourceData(const QString&, int, const QList<KLFLib::entryId>&)));
00183 connect(pResourceEngine, SIGNAL(resourcePropertyChanged(int)),
00184 this, SLOT(updateResourceProp(int)));
00185 connect(pResourceEngine, SIGNAL(defaultSubResourceChanged(const QString&)),
00186 this, SLOT(updateResourceDefaultSubResourceChanged(const QString&)));
00187 updateResourceEngine();
00188 }
00189
00190 void KLFAbstractLibView::updateResourceDefaultSubResourceChanged(const QString& )
00191 {
00192 updateResourceEngine();
00193 }
00194
00195 void KLFAbstractLibView::wantMoreCategorySuggestions()
00196 {
00197 emit moreCategorySuggestions(getCategorySuggestions());
00198 }
00199
00200 QList<QAction*> KLFAbstractLibView::addContextMenuActions(const QPoint&)
00201 {
00202 return QList<QAction*>();
00203 }
00204
00205
00206
00207
00208
00209 QList<KLFLibViewFactory*> KLFLibViewFactory::pRegisteredFactories =
00210 QList<KLFLibViewFactory*>();
00211
00212
00213 KLFLibViewFactory::KLFLibViewFactory(const QStringList& viewTypeIdentifiers,
00214 QObject *parent)
00215 : QObject(parent), pViewTypeIdentifiers(viewTypeIdentifiers)
00216 {
00217 registerFactory(this);
00218 }
00219 KLFLibViewFactory::~KLFLibViewFactory()
00220 {
00221 unRegisterFactory(this);
00222 }
00223
00224
00225 QString KLFLibViewFactory::defaultViewTypeIdentifier()
00226 {
00227 if (pRegisteredFactories.size() > 0)
00228 return pRegisteredFactories[0]->pViewTypeIdentifiers.first();
00229 return QString();
00230 }
00231
00232 KLFLibViewFactory *KLFLibViewFactory::findFactoryFor(const QString& viewTypeIdentifier)
00233 {
00234 if (viewTypeIdentifier.isEmpty()) {
00235 if (pRegisteredFactories.size() > 0)
00236 return pRegisteredFactories[0];
00237 return NULL;
00238 }
00239 int k;
00240
00241 for (k = 0; k < pRegisteredFactories.size(); ++k) {
00242 if (pRegisteredFactories[k]->viewTypeIdentifiers().contains(viewTypeIdentifier))
00243 return pRegisteredFactories[k];
00244 }
00245
00246 return NULL;
00247 }
00248
00249 QStringList KLFLibViewFactory::allSupportedViewTypeIdentifiers()
00250 {
00251 QStringList list;
00252 int k;
00253 for (k = 0; k < pRegisteredFactories.size(); ++k)
00254 list << pRegisteredFactories[k]->viewTypeIdentifiers();
00255 return list;
00256 }
00257
00258
00259 void KLFLibViewFactory::registerFactory(KLFLibViewFactory *factory)
00260 {
00261 KLF_ASSERT_NOT_NULL( factory, "Attempt to register NULL factory!", return )
00262 ;
00263
00264 if (factory->pViewTypeIdentifiers.size() == 0) {
00265 qWarning("KLFLibViewFactory::registerFactory: factory must provide at least one view type!");
00266 return;
00267 }
00268 if (pRegisteredFactories.indexOf(factory) != -1)
00269 return;
00270 pRegisteredFactories.append(factory);
00271 }
00272
00273 void KLFLibViewFactory::unRegisterFactory(KLFLibViewFactory *factory)
00274 {
00275 if (pRegisteredFactories.indexOf(factory) == -1)
00276 return;
00277 pRegisteredFactories.removeAll(factory);
00278 }
00279
00280
00281
00282
00283
00284
00285
00286 KLFFactoryManager KLFLibWidgetFactory::pFactoryManager;
00287
00288 KLFLibWidgetFactory::KLFLibWidgetFactory(QObject *parent)
00289 : QObject(parent), KLFFactoryBase(&pFactoryManager)
00290 {
00291 }
00292
00293
00294 KLFLibWidgetFactory *KLFLibWidgetFactory::findFactoryFor(const QString& wtype)
00295 {
00296 return dynamic_cast<KLFLibWidgetFactory*>(pFactoryManager.findFactoryFor(wtype));
00297 }
00298
00299
00300 QStringList KLFLibWidgetFactory::allSupportedWTypes()
00301 {
00302 return pFactoryManager.allSupportedTypes();
00303 }
00304
00305
00306 bool KLFLibWidgetFactory::hasCreateWidget(const QString& ) const
00307 {
00308 return false;
00309 }
00310
00311 QWidget * KLFLibWidgetFactory::createPromptCreateParametersWidget(QWidget *,
00312 const QString& ,
00313 const Parameters& )
00314 {
00315 return NULL;
00316 }
00317 KLFLibWidgetFactory::Parameters
00318 KLFLibWidgetFactory::retrieveCreateParametersFromWidget(const QString& ,
00319 QWidget *)
00320 {
00321 return Parameters();
00322 }
00323
00324 bool KLFLibWidgetFactory::hasSaveToWidget(const QString& ) const
00325 {
00326 return false;
00327 }
00328 QWidget *KLFLibWidgetFactory::createPromptSaveToWidget(QWidget *,
00329 const QString& ,
00330 KLFLibResourceEngine* ,
00331 const QUrl& )
00332 {
00333 return NULL;
00334 }
00335 QUrl KLFLibWidgetFactory::retrieveSaveToUrlFromWidget(const QString& ,
00336 QWidget *)
00337 {
00338 return QUrl();
00339 }
00340
00341
00342
00343
00344
00345
00346 KLF_EXPORT QDebug& operator<<(QDebug& dbg, const KLFLibModelCache::NodeId& n)
00347 {
00348 const char * skind =
00349 ( (n.kind == KLFLibModelCache::EntryKind) ? "EntryKind" :
00350 ((n.kind == KLFLibModelCache::CategoryLabelKind) ? "CategoryLabelKind" :
00351 "*UnknownKind*") );
00352 return dbg.nospace() << "NodeId("<<skind<<"+"<<n.index<<")";
00353 }
00354 KLF_EXPORT QDebug& operator<<(QDebug& dbg, const KLFLibModelCache::Node& n)
00355 {
00356 return dbg << "[kind="<<n.kind<<", children/sz="<<n.children.size()
00357 <<",allfetched="<<n.allChildrenFetched<<"]";
00358 }
00359 KLF_EXPORT QDebug& operator<<(QDebug& dbg, const KLFLibModelCache::EntryNode& en)
00360 {
00361 return dbg << "EntryNode(entryid="<<en.entryid<<"; entry/latex="<<en.entry.latex()<<"; parent="
00362 <<en.parent<<")";
00363 }
00364 KLF_EXPORT QDebug& operator<<(QDebug& dbg, const KLFLibModelCache::CategoryLabelNode& cn)
00365 {
00366 return dbg << "CategoryLabelNode(label="<<cn.categoryLabel<<";fullCategoryPath="<<cn.fullCategoryPath
00367 << "; parent="<<cn.parent<<";"<<(const KLFLibModelCache::Node&)cn<<")";
00368 }
00369 KLF_EXPORT QDebug& operator<<(QDebug& dbg, const KLFLibModel::PersistentId& n)
00370 {
00371 return dbg << "PersistentId("<<n.kind<<", entry_id="<<n.entry_id<<", cat...path="<<n.categorylabel_fullpath<<")";
00372 }
00373 KLF_EXPORT QDebug& operator<<(QDebug& d, const KLFLibViewDelegate::ColorRegion& c)
00374 {
00375 return d << "ColorRegion["<<c.start<<"->+"<<c.len<<"]";
00376 }
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387 bool KLFLibModelCache::KLFLibModelSorter::operator()(const NodeId& a, const NodeId& b)
00388 {
00389 if ( ! a.valid() || ! b.valid() )
00390 return false;
00391
00392 if ( groupCategories ) {
00393
00394 if ( a.kind != EntryKind && b.kind == EntryKind ) {
00395 return true;
00396 } else if ( a.kind == EntryKind && b.kind != EntryKind ) {
00397 return false;
00398 }
00399 if ( a.kind != EntryKind && b.kind != EntryKind ) {
00400 if ( ! (a.kind == CategoryLabelKind && b.kind == CategoryLabelKind) ) {
00401 qWarning("KLFLibModelSorter::operator(): Bad node kinds!! a: %d and b: %d",
00402 a.kind, b.kind);
00403 return false;
00404 }
00405
00406 return QString::localeAwareCompare(cache->getCategoryLabelNodeRef(a).categoryLabel,
00407 cache->getCategoryLabelNodeRef(b).categoryLabel) < 0;
00408 }
00409
00410 return entrysorter->operator()(cache->getEntryNodeRef(a).entry, cache->getEntryNodeRef(b).entry);
00411 }
00412
00413 int entryProp = entrysorter->propId();
00414 int sortorderfactor = (entrysorter->order() == Qt::AscendingOrder) ? 1 : -1;
00415 QString nodevaluea = cache->nodeValue(a, entryProp);
00416 QString nodevalueb = cache->nodeValue(b, entryProp);
00417 return sortorderfactor*QString::localeAwareCompare(nodevaluea, nodevalueb) < 0;
00418 }
00419
00420
00421
00422
00423
00424 void KLFLibModelCache::rebuildCache()
00425 {
00426 uint flavorFlags = pModel->pFlavorFlags;
00427
00428 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
00429 klfDbg(klfFmtCC("flavorFlags=%#010x", flavorFlags));
00430 int k;
00431
00432
00433 #ifndef Q_WS_MAC
00434 KLFProgressReporter progressReporter(0, 100, NULL);
00435 QString msg = QObject::tr("Updating View...", "[[KLFLibModelCache, progress text]]");
00436 emit pModel->operationStartReportingProgress(&progressReporter, msg);
00437 progressReporter.doReportProgress(0);
00438 #endif
00439
00440 klfDbgT("saving persistent indexes ...");
00441 QModelIndexList persistentIndexes = pModel->persistentIndexList();
00442 QList<KLFLibModel::PersistentId> persistentIndexIds = pModel->persistentIdList(persistentIndexes);
00443 klfDbgT("... done saving persistent indexes.");
00444
00445
00446 pEntryCache.clear();
00447 pCategoryLabelCache.clear();
00448
00449 pCategoryLabelCache.append(CategoryLabelNode());
00450 CategoryLabelNode& root = pCategoryLabelCache[0];
00451 root.fullCategoryPath = "/";
00452 root.categoryLabel = "/";
00453 root.allChildrenFetched = false;
00454
00455 QList<int> wantedProps = minimalistEntryPropIds();
00456 KLFLibResourceEngine::Query q;
00457 q.orderPropId = pLastSortPropId;
00458 q.orderDirection = pLastSortOrder;
00459 if (pModel->pFlavorFlags & KLFLibModel::CategoryTree) {
00460
00461 KLFLib::PropertyMatch pmatch(KLFLibEntry::Category, KLFLib::StringMatch(QString("")));
00462 q.matchCondition = KLFLib::EntryMatchCondition::mkPropertyMatch(pmatch);
00463 }
00464 q.wantedEntryProperties = minimalistEntryPropIds();
00465 q.limit = pModel->pFetchBatchCount;
00466 KLFLibResourceEngine::QueryResult qr(KLFLibResourceEngine::QueryResult::FillEntryWithIdList);
00467
00468 klfDbgT("about to query resource...");
00469 int count = pModel->pResource->query(pModel->pResource->defaultSubResource(), q, &qr);
00470 klfDbgT("resource returned "<<count<<" entries.");
00471 if (count < 0) {
00472 qWarning()<<KLF_FUNC_NAME<<": query() returned an error.";
00473
00474 }
00475 if (count < pModel->pFetchBatchCount) {
00476
00477 klfDbg("all children have been fetched.") ;
00478 root.allChildrenFetched = true;
00479 }
00480 const QList<KLFLibResourceEngine::KLFLibEntryWithId>& everything = qr.entryWithIdList;
00481 QList<KLFLibResourceEngine::KLFLibEntryWithId>::const_iterator it;
00482
00483 k = 0;
00484 for (it = everything.begin(); it != everything.end(); ++it) {
00485 const KLFLibResourceEngine::KLFLibEntryWithId& ewid = *it;
00486 klfDbgT( "Adding entry id="<<ewid.id<<"; entry="<<ewid.entry ) ;
00487 EntryNode e;
00488 e.entryid = ewid.id;
00489 e.minimalist = true;
00490 e.entry = ewid.entry;
00491 treeInsertEntry(e, true);
00492
00493 #ifndef Q_WS_MAC
00494 if (k % 10 == 0)
00495 progressReporter.doReportProgress((++k) * 100 / everything.size());
00496 #endif
00497 }
00498
00499 if (pModel->pFlavorFlags & KLFLibModel::CategoryTree) {
00500
00501 klfDbgT("About to query categories...");
00502 QVariantList vcatlist = pModel->pResource->queryValues(pModel->pResource->defaultSubResource(),
00503 KLFLibEntry::Category);
00504 klfDbgT("... got categories. inserting them ...");
00505 for (QVariantList::const_iterator vcit = vcatlist.begin(); vcit != vcatlist.end(); ++vcit) {
00506 QString cat = (*vcit).toString();
00507 if (cat.isEmpty() || cat == "/")
00508 continue;
00509
00510 QStringList catelements = cat.split('/', QString::SkipEmptyParts);
00511 int i = cacheFindCategoryLabel(catelements, true, false, false);
00512 if (i < 0) {
00513 qWarning()<<KLF_FUNC_NAME<<": Failed to create category node for category "<<cat;
00514 }
00515
00516 insertCategoryStringInSuggestionCache(catelements);
00517 }
00518 klfDbgT("... ins catnodes done.") ;
00519 }
00520
00521 fullDump();
00522
00523 emit pModel->reset();
00524
00525 klfDbg("restoring persistent indexes ...");
00526 QModelIndexList newPersistentIndexes = pModel->newPersistentIndexList(persistentIndexIds);
00527
00528 pModel->changePersistentIndexList(persistentIndexes, newPersistentIndexes);
00529 klfDbg("... done restoring persistent indexes.");
00530
00531 klfDbgT( " end of func" ) ;
00532 }
00533
00534
00535 QModelIndex KLFLibModelCache::createIndexFromId(NodeId nodeid, int row, int column)
00536 {
00537 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00538
00539 if ( ! nodeid.valid() || nodeid == NodeId::rootNode())
00540 return QModelIndex();
00541
00542
00543 if ( row < 0 ) {
00544 row = getNodeRow(nodeid);
00545 }
00546
00547
00548
00549 klfDbg( ": nodeid="<<nodeid<<"; row="<<row<<"; col="<<column ) ;
00550
00551
00552 Node node = getNode(nodeid);
00553 NodeId parentid = node.parent;
00554 if (!parentid.valid())
00555 parentid = NodeId::rootNode();
00556
00557
00558 klfDbg("row="<<row) ;
00559 while ( getNode(parentid).children.size() <= row && canFetchMore(parentid) ) {
00560 klfDbgT(": need to fetch more children/size="
00561 <<getNode(parentid).children.size()<<"<row="<<row<<" !");
00562 fetchMore(parentid);
00563 }
00564
00565
00566 return pModel->createIndex(row, column, nodeid.universalId());
00567 }
00568
00569
00570 KLFLibModelCache::NodeId KLFLibModelCache::getNodeForIndex(const QModelIndex& index)
00571 {
00572 if ( ! index.isValid() )
00573 return NodeId();
00574 NodeId n = NodeId::fromUID(index.internalId());
00575
00576 if (n.kind == EntryKind) {
00577 if (n.index < 0 || n.index >= pEntryCache.size()) {
00578 qWarning()<<KLF_FUNC_NAME<<": Invalid entry node reference: "<<n;
00579 return NodeId();
00580 }
00581 } else if (n.kind == CategoryLabelKind) {
00582 if (n.index < 0 || n.index >= pCategoryLabelCache.size()) {
00583 qWarning()<<KLF_FUNC_NAME<<": Invalid category label node reference: "<<n;
00584 return NodeId();
00585 }
00586 } else {
00587 qWarning()<<KLF_FUNC_NAME<<": Invalid node kind: "<<n;
00588 return NodeId();
00589 }
00590 return n;
00591 }
00592
00593 KLFLibModelCache::Node KLFLibModelCache::getNode(NodeId nodeid)
00594 {
00595 if (!nodeid.valid())
00596 return CategoryLabelNode();
00597 Node &n = getNodeRef(nodeid);
00598 return n;
00599 }
00600 KLFLibModelCache::Node& KLFLibModelCache::getNodeRef(NodeId nodeid)
00601 {
00602 if (!nodeid.valid()) {
00603 qWarning()<<"KLFLibModelCache::getNodeRef: Invalid Node Id: "<<nodeid;
00604 return pInvalidEntryNode;
00605 }
00606 if (nodeid.kind == EntryKind) {
00607 if (nodeid.index < 0 || nodeid.index >= pEntryCache.size()) {
00608 qWarning()<<"KLFLibModelCache::getNodeRef: Invalid Entry Node Id: "<<nodeid<<" : index out of range!";
00609 return pInvalidEntryNode;
00610 }
00611 return pEntryCache[nodeid.index];
00612 } else if (nodeid.kind == CategoryLabelKind) {
00613 if (nodeid.index < 0 || nodeid.index >= pCategoryLabelCache.size()) {
00614 qWarning()<<"KLFLibModelCache::getNodeRef: Invalid Category Label Node Id: "<<nodeid
00615 <<" : index out of range!";
00616 return pInvalidEntryNode;
00617 }
00618 return pCategoryLabelCache[nodeid.index];
00619 }
00620 qWarning("KLFLibModelCache::getNodeRef(): Invalid kind: %d (index=%d)\n", nodeid.kind, nodeid.index);
00621 return pInvalidEntryNode;
00622 }
00623 KLFLibModelCache::EntryNode& KLFLibModelCache::getEntryNodeRef(NodeId nodeid, bool enforceNotMinimalist)
00624 {
00625 static EntryNode dummyerrornode;
00626 if (!nodeid.valid() || nodeid.kind != EntryKind ||
00627 nodeid.index < 0 || nodeid.index >= pEntryCache.size()) {
00628 qWarning()<<"KLFLibModelCache::getEntryNodeRef: Invalid Entry Node "<<nodeid<<"!";
00629 return dummyerrornode;
00630 }
00631 if (enforceNotMinimalist && pEntryCache[nodeid.index].minimalist)
00632 ensureNotMinimalist(nodeid);
00633
00634 return pEntryCache[nodeid.index];
00635 }
00636
00637 KLFLibModelCache::CategoryLabelNode& KLFLibModelCache::getCategoryLabelNodeRef(NodeId nodeid)
00638 {
00639 if (!nodeid.valid() || nodeid.kind != CategoryLabelKind ||
00640 nodeid.index < 0 || nodeid.index >= pCategoryLabelCache.size()) {
00641 qWarning()<<"KLFLibModelCache::getCat.LabelNode: Invalid Category Label Node "<<nodeid<<"!";
00642 return pCategoryLabelCache[0];
00643 }
00644 return pCategoryLabelCache[nodeid.index];
00645 }
00646
00647 int KLFLibModelCache::getNodeRow(NodeId node)
00648 {
00649 if ( ! node.valid() )
00650 return -1;
00651 if ( node == NodeId::rootNode() )
00652 return 0;
00653
00654 Node n = getNode(node);
00655
00656 NodeId pparentid = n.parent;
00657 if ( !pparentid.valid() ) {
00658
00659 qWarning()<<KLF_FUNC_NAME<<": Found parentless non-root node: "<<node;
00660 return 0;
00661 }
00662 Node pparent = getNode(pparentid);
00663
00664 int k;
00665 for (k = 0; k < pparent.children.size(); ++k)
00666 if (pparent.children[k] == node)
00667 return k;
00668
00669
00670 qWarning()<<KLF_FUNC_NAME<<": Unable to get node row: parent-child one-way broken!! node="<<node;
00671 return -1;
00672 }
00673
00674 void KLFLibModelCache::ensureNotMinimalist(NodeId p, int countdown)
00675 {
00676 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
00677
00678 NodeId n;
00679
00680 QMap<KLFLib::entryId, NodeId> wantedIds;
00681 if (countdown < 0)
00682 countdown = pModel->pFetchBatchCount;
00683
00684
00685 n = p;
00686 for (; n.valid() && countdown-- > 0; n = nextNode(n)) {
00687 if (n.kind == CategoryLabelKind) {
00688 ++countdown;
00689 continue;
00690 }
00691 if (n.kind == EntryKind) {
00692 EntryNode en = getEntryNodeRef(n);
00693 if (en.minimalist)
00694 wantedIds[en.entryid] = n;
00695 continue;
00696 }
00697 qWarning()<<KLF_FUNC_NAME<<": Got unknown kind="<<n.kind;
00698 }
00699
00700 QList<KLFLibResourceEngine::KLFLibEntryWithId> updatedentries =
00701 pModel->pResource->entries(wantedIds.keys(), QList<int>());
00702 int k;
00703 for (k = 0; k < updatedentries.size(); ++k) {
00704 KLFLib::entryId eid = updatedentries[k].id;
00705 if ( ! wantedIds.contains(eid) ) {
00706 qWarning()<<KLF_FUNC_NAME<<" got unrequested updated entry ID ?! id="<<eid;
00707 continue;
00708 }
00709 NodeId nid = wantedIds[eid];
00710 pEntryCache[nid.index].entry = updatedentries[k].entry;
00711 pEntryCache[nid.index].minimalist = false;
00712 }
00713 klfDbg( ": updated entries "<<wantedIds.keys() ) ;
00714 }
00715
00716 bool KLFLibModelCache::canFetchMore(NodeId parentId)
00717 {
00718 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
00719 if (pIsFetchingMore)
00720 return false;
00721
00722 if (!parentId.valid())
00723 parentId = NodeId::rootNode();
00724
00725 klfDbg("parentId="<<parentId) ;
00726
00727 const Node& node = getNodeRef(parentId);
00728
00729 klfDbg("node="<<node) ;
00730
00731 if (!node.allChildrenFetched)
00732 return true;
00733
00734 klfDbg("cannot fetchmore.") ;
00735 return false;
00736 }
00737 void KLFLibModelCache::fetchMore(NodeId n, int fetchBatchCount)
00738 {
00739 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME);
00740 klfDbg( "\t parentId: n="<<n<<"; valid="<<n.valid() <<"; url="<<pModel->url() ) ;
00741
00742 if (fetchBatchCount < 0)
00743 fetchBatchCount = pModel->pFetchBatchCount;
00744
00745 if (pIsFetchingMore)
00746 return;
00747 pIsFetchingMore = true;
00748
00749
00750
00751 if (!n.valid())
00752 n = NodeId::rootNode();
00753
00754 if (n.kind != CategoryLabelKind) {
00755 klfDbg("can't fetch more in this node kind. n="<<n);
00756 qWarning()<<KLF_FUNC_NAME<<": Can't fetch more children of a non-category-label node.";
00757 return;
00758 }
00759
00760 CategoryLabelNode& noderef = getCategoryLabelNodeRef(n);
00761 klfDbg( "\t -> n="<<n<<"; noderef: kind="<<noderef.kind<<", allChildrenFetched="<<noderef.allChildrenFetched ) ;
00762
00763 if (noderef.allChildrenFetched) {
00764
00765 klfDbg("can't fetch more: all children are fetched! noderef="<<noderef<<"; n (the id)="<<n) ;
00766
00767 pIsFetchingMore = false;
00768 return;
00769 }
00770
00771
00772 KLFLibResourceEngine::Query q;
00773 if (pModel->pFlavorFlags & KLFLibModel::CategoryTree) {
00774 QString c = KLFLibEntry::normalizeCategoryPath(noderef.fullCategoryPath);
00775 KLFLib::PropertyMatch pmatch(KLFLibEntry::Category, KLFLib::StringMatch(c));
00776 q.matchCondition = KLFLib::EntryMatchCondition::mkPropertyMatch(pmatch);
00777 }
00778 q.orderPropId = pLastSortPropId;
00779 q.orderDirection = pLastSortOrder;
00780 q.limit = pModel->pFetchBatchCount;
00781 q.skip = noderef.children.size();
00782 q.wantedEntryProperties = minimalistEntryPropIds();
00783 KLFLibResourceEngine::QueryResult qr(KLFLibResourceEngine::QueryResult::FillEntryWithIdList);
00784
00785 int count = pModel->pResource->query(pModel->pResource->defaultSubResource(), q, &qr);
00786 if (count < 0) {
00787 qWarning()<<KLF_FUNC_NAME<<": error fetching more results: count is "<<count;
00788 pIsFetchingMore = false;
00789 return;
00790 }
00791
00798
00799
00800
00801 pModel->startLayoutChange(false);
00802 pModel->beginInsertRows(createIndexFromId(n, -1, 0), noderef.children.size(),
00803 noderef.children.size() + qr.entryWithIdList.size()-1);
00804
00805
00806 if (count < q.limit) {
00807 noderef.allChildrenFetched = true;
00808 }
00809
00810 int k;
00811 for (k = 0; k < qr.entryWithIdList.size(); ++k) {
00812 const KLFLibResourceEngine::KLFLibEntryWithId& ewid = qr.entryWithIdList[k];
00813 EntryNode e;
00814 e.entryid = ewid.id;
00815 e.minimalist = true;
00816 e.entry = ewid.entry;
00817 e.parent = n;
00818 pEntryCache.append(e);
00819 NodeId entryindex;
00820 entryindex.kind = EntryKind;
00821 entryindex.index = pEntryCache.size()-1;
00822
00823 klfDbg("appending "<<e<<" in category node.") ;
00824
00825 noderef.children.append(entryindex);
00826 }
00827
00828 klfDbg("Fetched more. About to notify view of end of rows inserted ... meanwile the dump:") ;
00829 fullDump();
00830
00831 pModel->endInsertRows();
00832 klfDbg("signal emitted. restore persistent indexes...") ;
00833 pModel->endLayoutChange(false);
00834
00835 klfDbg("views notified, persistent indexes restored.") ;
00836
00837 pIsFetchingMore = false;
00838 }
00839
00840
00841
00842 void KLFLibModelCache::updateData(const QList<KLFLib::entryId>& entryIdList, int modifyType)
00843 {
00844 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
00845 klfDbg( "modifyType="<<modifyType<<" entryIdList="<<entryIdList ) ;
00846
00847 if (modifyType == KLFLibResourceEngine::UnknownModification) {
00848 klfDbg("Performing full refresh.") ;
00849 rebuildCache();
00850 return;
00851 }
00852
00853 if (entryIdList.size() > 10 &&
00854 (entryIdList.size() > pEntryCache.size()/3 || entryIdList.size() > 100)) {
00855
00856 klfDbg("Performing full refresh.") ;
00857 rebuildCache();
00858 return;
00859 }
00860
00861 #ifndef Q_WS_MAC
00862
00863 KLFProgressReporter progressReporter(0, entryIdList.size(), NULL);
00864 emit pModel->operationStartReportingProgress(&progressReporter,
00865 QObject::tr("Updating View...", "[[KLFLibModelCache, progress text]]"));
00866 progressReporter.doReportProgress(0);
00867 #endif
00868
00869 switch (modifyType) {
00870 case KLFLibResourceEngine::InsertData:
00871 {
00872 QList<KLFLibResourceEngine::KLFLibEntryWithId> entryList = pModel->pResource->entries(entryIdList);
00873 int k;
00874 for (k = 0; k < entryList.size(); ++k) {
00875 EntryNode en;
00876 en.entryid = entryList[k].id;
00877 en.minimalist = false;
00878 en.entry = entryList[k].entry;
00881 treeInsertEntry(en);
00882 qDebug("%s: entry ID %d inserted", KLF_FUNC_NAME, entryIdList[k]);
00883 #ifndef Q_WS_MAC
00884 if (k % 20 == 0)
00885 progressReporter.doReportProgress(k+1);
00886 #endif
00887 }
00888 break;
00889 }
00890 case KLFLibResourceEngine::ChangeData:
00891 {
00892 QList<KLFLibResourceEngine::KLFLibEntryWithId> entryList = pModel->pResource->entries(entryIdList);
00893 int k;
00894 for (k = 0; k < entryIdList.size(); ++k) {
00895 klfDbg("modifying entry ID="<<entryIdList[k]<<", modif."<<k) ;
00896 NodeId n = findEntryId(entryIdList[k]);
00897 if (!n.valid()) {
00898 qWarning()<<KLF_FUNC_NAME<<": n is invalid! (kind="<<n.kind<<", index="<<n.index<<")";
00899 continue;
00900 }
00901 KLFLibEntry oldentry = pEntryCache[n.index].entry;
00902 KLFLibEntry newentry = entryList[k].entry;
00903 klfDbg("entry change: old="<<oldentry<<"; new="<<newentry) ;
00904
00905 if (newentry.category() != oldentry.category() && (pModel->pFlavorFlags & KLFLibModel::CategoryTree)) {
00906 pModel->startLayoutChange(false);
00907 EntryNode entrynode = treeTakeEntry(n, true);
00908
00909
00910
00911
00912 entrynode.entryid = entryIdList[k];
00913 entrynode.entry = newentry;
00914
00915 treeInsertEntry(entrynode);
00916 pModel->endLayoutChange(false);
00917 QModelIndex idx = createIndexFromId(n, -1, 0);
00918 emit pModel->dataChanged(idx, idx);
00919 } else {
00920
00921 pEntryCache[n.index].entry = newentry;
00922 QModelIndex idx = createIndexFromId(n, -1, 0);
00923 emit pModel->dataChanged(idx, idx);
00924 }
00925 #ifndef Q_WS_MAC
00926 if (k % 20 == 0)
00927 progressReporter.doReportProgress(k+1);
00928 #endif
00929 }
00930 break;
00931 }
00932 case KLFLibResourceEngine::DeleteData:
00933 {
00934 int k;
00935 for (k = 0; k < entryIdList.size(); ++k) {
00936 qDebug("%s: deleting entry ID=%d.", KLF_FUNC_NAME, entryIdList[k]);
00937
00938 NodeId n = findEntryId(entryIdList[k]);
00939 if (!n.valid()) {
00940 qWarning()<<KLF_FUNC_NAME<<": n not valid! n=(kind="<<n.kind<<", index="<<n.index<<")";
00941 continue;
00942 }
00943 (void) treeTakeEntry(n);
00944 #ifndef Q_WS_MAC
00945 if (k % 20 == 0)
00946 progressReporter.doReportProgress(k+1);
00947 #endif
00948 }
00949 break;
00950 }
00951 default:
00952 {
00953 qWarning()<<KLF_FUNC_NAME<<": Bad modify-type parameter: "<<modifyType;
00954 rebuildCache();
00955 return;
00956 }
00957 }
00958
00959
00960 klfDbg( ": udpated; full tree dump:" ) ;
00961 fullDump();
00962 }
00963
00964
00965 void KLFLibModelCache::treeInsertEntry(const EntryNode& entrynode, bool rebuildingcache)
00966 {
00967 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
00968
00969 bool notifyQtApi = !rebuildingcache;
00970 klfDbg( "entrynode="<<entrynode<<",notifyQtApi="<<notifyQtApi<<"" ) ;
00971
00972
00973
00974
00975
00976 QString category = entrynode.entry.category();
00977 QStringList catelements = category.split('/', QString::SkipEmptyParts);
00978 insertCategoryStringInSuggestionCache(catelements);
00979
00980
00981
00982 IndexType catindex;
00983 if (pModel->displayType() == KLFLibModel::LinearList) {
00984
00985 catindex = 0;
00986 } else if (pModel->displayType() == KLFLibModel::CategoryTree) {
00987
00988 catindex = cacheFindCategoryLabel(catelements, true, notifyQtApi, rebuildingcache?false:true);
00989 } else {
00990 qWarning("Flavor Flags have unknown display type! flavorFlags=%#010x", pModel->pFlavorFlags);
00991 catindex = 0;
00992 }
00993
00994 NodeId parentid = NodeId(CategoryLabelKind, catindex);
00995
00996
00997 int index = pEntryCache.insertNewNode(entrynode);
00998 NodeId n = NodeId(EntryKind, index);
00999
01000
01001 pEntryCache[index].parent = NodeId();
01002
01003
01004
01005 Node& parentref = getNodeRef(parentid);
01006 QList<NodeId> & childlistref = parentref.children;
01007 int insertPos;
01008 if (rebuildingcache || pLastSortPropId < 0) {
01009 insertPos = childlistref.size();
01010 } else {
01011 KLFLibModelSorter srt =
01012 KLFLibModelSorter(this, pModel->pEntrySorter, pModel->pFlavorFlags & KLFLibModel::GroupSubCategories);
01013
01014
01015 bool retry;
01016 do {
01017 retry = false;
01018
01019 insertPos = qLowerBound(childlistref.begin(), childlistref.end(), n, srt) - childlistref.begin();
01020 if (insertPos > childlistref.size()-10 && canFetchMore(parentid)) {
01021 fetchMore(parentid);
01022 retry = true;
01023 }
01024 } while (retry);
01025
01026
01027 if (insertPos < childlistref.size() && childlistref[insertPos] == n)
01028 return;
01029 }
01030
01031 CategoryLabelNode &catLabelNodeRef = getCategoryLabelNodeRef(parentid);
01032
01033
01034 if (notifyQtApi) {
01035 QModelIndex parentidx = createIndexFromId(parentid, -1, 0);
01036 pModel->beginInsertRows(parentidx, insertPos, insertPos);
01037 }
01038
01039 qDebug("\tinserting (%d,%d) at pos %d in category '%s'", n.kind, n.index, insertPos,
01040 qPrintable(catLabelNodeRef.fullCategoryPath));
01041
01042 pEntryCache[n.index].parent = parentid;
01043
01044 childlistref.insert(insertPos, n);
01045
01046 if (notifyQtApi)
01047 pModel->endInsertRows();
01048 }
01049
01050 KLFLibModelCache::EntryNode KLFLibModelCache::treeTakeEntry(const NodeId& nodeid, bool notifyQtApi)
01051 {
01052 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
01053
01054 klfDbg( "("<<nodeid<<","<<notifyQtApi<<")" ) ;
01055 NodeId n = nodeid;
01056
01057
01058 if (nodeid.kind != EntryKind) {
01059 qWarning()<<KLF_FUNC_NAME<<": nodeid="<<nodeid<<" does not reference an entry node!";
01060 return EntryNode();
01061 }
01062 EntryNode entrynode = getEntryNodeRef(nodeid);
01063
01064 klfDbg("The entrynode in question is "<<entrynode) ;
01065
01066 NodeId parentid;
01067 bool willRemoveParent;
01068 do {
01069 if (!n.valid())
01070 break;
01071 parentid = getNode(n).parent;
01072 if (n == NodeId::rootNode())
01073 break;
01074 klfDbg("Getting interested to remove entry ID="<<n<<", from its parent of id="<<parentid) ;
01075 if (parentid.kind != CategoryLabelKind) {
01076 qWarning()<<KLF_FUNC_NAME<<"("<<n<<"): Bad parent node kind: "<<parentid.kind<<"!";
01077 return entrynode;
01078 }
01079 QModelIndex parent = createIndexFromId(parentid, -1, 0);
01080 int childIndex = pCategoryLabelCache[parentid.index].children.indexOf(n);
01081 if (childIndex < 0) {
01082 qWarning()<<KLF_FUNC_NAME<<"("<<n<<"): !!?! bad child-parent relation, can't find "<<n
01083 <<" in child list "<<pCategoryLabelCache[parentid.index].children<<"; full dump:\n"
01084 <<"\tEntryCache = "<<pEntryCache<<"\n"
01085 <<"\tCat.Lbl.Cache = "<<pCategoryLabelCache;
01086 return entrynode;
01087 }
01088 if (notifyQtApi)
01089 pModel->beginRemoveRows(parent, childIndex, childIndex);
01090
01091 willRemoveParent = parentid.valid() && getNode(parentid).children.size() <= 1;
01092
01093 if (n.kind == EntryKind) {
01094 klfDbg("unlinking entry node "<<n);
01095 pEntryCache.unlinkNode(n);
01096 } else if (n.kind == CategoryLabelKind) {
01097 klfDbg("unlinking category label node "<<n);
01098 pCategoryLabelCache.unlinkNode(n);
01099 } else {
01100 qWarning()<<KLF_FUNC_NAME<<": unlinking elements: unknown node kind in id="<<n<<"!";
01101 }
01102
01103 Node & parentref = getNodeRef(parentid);
01104 klfDbg("removing child #"<<childIndex<<" from parent id="<<parentid<<"; parent itself is "<<parentref) ;
01105 parentref.children.removeAt(childIndex);
01106 if (notifyQtApi)
01107 pModel->endRemoveRows();
01108 n = parentid;
01109 } while (willRemoveParent);
01110
01111 return entrynode;
01112 }
01113
01114
01115
01116
01117 KLFLibModelCache::IndexType
01118 KLFLibModelCache::cacheFindCategoryLabel(QStringList catelements, bool createIfNotExists,
01119 bool notifyQtApi, bool newlyCreatedAreChildrenFetched)
01120 {
01121 klfDbg( "catelmnts="<<catelements<<", createIfNotExists="<<createIfNotExists<<", notifyQtApi="<<notifyQtApi ) ;
01122
01123 QString catelpath = catelements.join("/");
01124
01125 int i;
01126 for (i = 0; i < pCategoryLabelCache.size(); ++i) {
01127 if (pCategoryLabelCache.isAllocated(i) &&
01128 pCategoryLabelCache[i].parent.valid() &&
01129 pCategoryLabelCache[i].fullCategoryPath == catelpath) {
01130
01131 return i;
01132 }
01133 }
01134 if (catelements.isEmpty())
01135 return 0;
01136
01137
01138
01139 if ( ! createIfNotExists )
01140 return -1;
01141
01142 if (pModel->displayType() != KLFLibModel::CategoryTree) {
01143 qWarning("cacheFindCategoryLabel: but not in a category tree display type (flavor flags=%#010x)",
01144 pModel->pFlavorFlags);
01145 return 0;
01146 }
01147
01148 QStringList catelementsparent = catelements.mid(0, catelements.size()-1);
01149 IndexType parent_index = cacheFindCategoryLabel(catelementsparent, true, notifyQtApi);
01150
01151 KLFLibModelCache::KLFLibModelSorter srt =
01152 KLFLibModelCache::KLFLibModelSorter(this, pModel->pEntrySorter,
01153 pModel->pFlavorFlags & KLFLibModel::GroupSubCategories);
01154
01155
01156 CategoryLabelNode c;
01157 c.allChildrenFetched = newlyCreatedAreChildrenFetched;
01158 c.fullCategoryPath = catelpath;
01159 c.categoryLabel = catelements.last();
01160
01161 IndexType this_index = pCategoryLabelCache.insertNewNode(c);
01162 int insertPos;
01163 CategoryLabelNode & parentCatLabelNodeRef = pCategoryLabelCache[parent_index];
01164 QList<NodeId> & childlistref = parentCatLabelNodeRef.children;
01165 if (pLastSortPropId < 0) {
01166 insertPos = childlistref.size();
01167 } else {
01168
01169 insertPos = qLowerBound(childlistref.begin(), childlistref.end(),
01170 NodeId(CategoryLabelKind, this_index), srt) - childlistref.begin();
01171 }
01172 klfDbg( ": About to insert rows in "<<NodeId(CategoryLabelKind, parent_index)
01173 <<" at position "<<insertPos ) ;
01174 if (notifyQtApi) {
01175 QModelIndex parentidx = createIndexFromId(NodeId(CategoryLabelKind, parent_index), -1, 0);
01176 pModel->beginInsertRows(parentidx, insertPos, insertPos);
01177 }
01178 qDebug("%s: Inserting this_index=%d in parent_index=%d 's children", KLF_FUNC_NAME, this_index,
01179 parent_index);
01180
01181 childlistref.insert(insertPos, NodeId(CategoryLabelKind, this_index));
01182 pCategoryLabelCache[this_index].parent = NodeId(CategoryLabelKind, parent_index);
01183
01184 if (notifyQtApi)
01185 pModel->endInsertRows();
01186
01187
01188 return this_index;
01189 }
01190
01191 QString KLFLibModelCache::nodeValue(NodeId n, int entryProperty)
01192 {
01193
01194
01195
01196 if (!n.valid() || n.isRoot())
01197 return QString();
01198 if (entryProperty < 0) {
01199 qWarning()<<KLF_FUNC_NAME<<": invalid entry property ID : "<<entryProperty;
01200 return QString();
01201 }
01202 if (n.kind == EntryKind) {
01203 EntryNode en = getEntryNodeRef(n);
01204
01205 return pModel->entrySorter()->entryValue(en.entry, entryProperty);
01206 }
01207 if (n.kind == CategoryLabelKind)
01208 return getCategoryLabelNodeRef(n).categoryLabel;
01209
01210 qWarning()<<KLF_FUNC_NAME<<": Bad Item Kind: "<<n;
01211 return QString();
01212 }
01213
01214
01215 void KLFLibModelCache::sortCategory(NodeId category, KLFLibModelSorter *sorter, bool rootCall)
01216 {
01217 bool requireSimpleReverse = false;
01218
01219
01220 if (sorter->entrySorter()->propId() == pLastSortPropId) {
01221
01222 if (sorter->entrySorter()->order() == pLastSortOrder) {
01223
01224 return;
01225 } else {
01226
01227
01228 requireSimpleReverse = true;
01229 }
01230 }
01231
01232 int k;
01233
01234
01235
01236
01237
01238 if (category.kind != CategoryLabelKind)
01239 return;
01240 if (category.index < 0 || category.index >= pCategoryLabelCache.size())
01241 return;
01242
01243 if (sorter->entrySorter()->propId() < 0)
01244 return;
01245
01246 QList<NodeId>& childlistref = pCategoryLabelCache[category.index].children;
01247 if (requireSimpleReverse) {
01248
01249 int N = childlistref.size();
01250 int firstEntryInd = 0;
01251 if (pModel->pFlavorFlags & KLFLibModel::GroupSubCategories) {
01252 for (firstEntryInd = 0; firstEntryInd < N &&
01253 childlistref[firstEntryInd].kind != EntryKind; ++firstEntryInd)
01254 ;
01255
01256 }
01257
01258 for (k = 0; k < (N-firstEntryInd)/2; ++k)
01259 qSwap(childlistref[firstEntryInd+k], childlistref[N-k-1]);
01260 } else {
01261 qSort(childlistref.begin(), childlistref.end(), *sorter);
01262 }
01263
01264
01265 for (k = 0; k < childlistref.size(); ++k)
01266 if (childlistref[k].kind == CategoryLabelKind)
01267 sortCategory(childlistref[k], sorter, false );
01268
01269 if (rootCall) {
01270 pLastSortPropId = sorter->entrySorter()->propId();
01271 pLastSortOrder = sorter->entrySorter()->order();
01272 }
01273 }
01274
01275
01276 KLFLibModelCache::NodeId KLFLibModelCache::nextNode(NodeId n)
01277 {
01278
01279
01280
01281 if (!n.valid()) {
01282
01283 n = NodeId::rootNode();
01284 }
01285
01286 Node nn = getNode(n);
01287 if (nn.children.size() > 0) {
01288 return nn.children[0];
01289 }
01290 if (!nn.allChildrenFetched && canFetchMore(n)) {
01291
01292 fetchMore(n);
01293
01294 return nextNode(n);
01295 }
01296
01297 NodeId parentid;
01298 while ( (parentid = nn.parent).valid() ) {
01299 Node parent = getNode(parentid);
01300 int row = getNodeRow(n);
01301 if (row+1 < parent.children.size()) {
01302
01303 return parent.children[row+1];
01304 }
01305 if (!parent.allChildrenFetched && canFetchMore(parentid)) {
01306
01307 fetchMore(parentid);
01308
01309 return nextNode(n);
01310 }
01311
01312 n = parentid;
01313 nn = parent;
01314 }
01315
01316 return NodeId();
01317 }
01318
01319 KLFLibModelCache::NodeId KLFLibModelCache::prevNode(NodeId n)
01320 {
01321 if (!n.valid() || n.isRoot()) {
01322
01323 return lastNode(NodeId());
01324 }
01325
01326 NodeId parentId = getNode(n).parent;
01327 Node parent = getNode(parentId);
01328 int row = getNodeRow(n);
01329 if (row > 0) {
01330
01331 return lastNode(parent.children[row-1]);
01332 }
01333
01334
01335 if (parentId == NodeId::rootNode())
01336 return NodeId();
01337
01338 return parentId;
01339 }
01340
01341 KLFLibModelCache::NodeId KLFLibModelCache::lastNode(NodeId n)
01342 {
01343 if (!n.valid())
01344 n = NodeId::rootNode();
01345
01346 Node nn = getNode(n);
01347
01348
01349
01350 while (!nn.allChildrenFetched) {
01351 if (!canFetchMore(n)) {
01352 qWarning()<<KLF_FUNC_NAME<<": internal error: node "<<n<<", node="<<nn
01353 <<" has allChildrenFetched=false, but can't fetch more!";
01354 break;
01355 }
01356 fetchMore(n);
01357 }
01358
01359 if (nn.children.size() == 0)
01360 return n;
01361
01362
01363 return lastNode(nn.children[nn.children.size()-1]);
01364 }
01365
01366
01367 QList<KLFLib::entryId> KLFLibModelCache::entryIdList(const QModelIndexList& indexlist)
01368 {
01369
01370
01371 QList<KLFLib::entryId> idList;
01372 int k;
01373 QList<NodeId> nodeIds;
01374
01375 for (k = 0; k < indexlist.size(); ++k) {
01376 NodeId n = getNodeForIndex(indexlist[k]);
01377 if ( !n.valid() || n.kind != EntryKind)
01378 continue;
01379 if ( nodeIds.contains(n) )
01380 continue;
01381 nodeIds << n;
01382 idList << getEntryNodeRef(n).entryid;
01383 }
01384 return idList;
01385 }
01386
01387
01388
01389 QList<KLFLib::entryId> KLFLibModelCache::entryIdForIndexList(const QModelIndexList& indexlist)
01390 {
01391
01392
01393 QList<KLFLib::entryId> eidlist;
01394 int k;
01395 for (k = 0; k < indexlist.size(); ++k) {
01396 NodeId node = getNodeForIndex(indexlist[k]);
01397 if ( !node.valid() || node.kind != EntryKind ) {
01398 eidlist << (KLFLib::entryId) -1;
01399 continue;
01400 }
01401 eidlist << getEntryNodeRef(node).entryid;
01402 }
01403 return eidlist;
01404 }
01405 QModelIndexList KLFLibModelCache::findEntryIdList(const QList<KLFLib::entryId>& eidlist)
01406 {
01407 klfDbg( ": eidlist="<<eidlist ) ;
01408 int k;
01409 int count = 0;
01410 QModelIndexList indexlist;
01411
01412 for (k = 0; k < eidlist.size(); ++k)
01413 indexlist << QModelIndex();
01414
01415
01416 for (k = 0; k < pEntryCache.size(); ++k) {
01417 if (!pEntryCache[k].entryIsValid())
01418 continue;
01419 int i = eidlist.indexOf(pEntryCache[k].entryid);
01420 if (i >= 0) {
01421 indexlist[i] = createIndexFromId(NodeId(EntryKind, k), -1, 0);
01422 if (++count == eidlist.size())
01423 break;
01424 }
01425 }
01426 return indexlist;
01427 }
01428
01429 KLFLibModelCache::NodeId KLFLibModelCache::findEntryId(KLFLib::entryId eId)
01430 {
01431 klfDbg("eId="<<eId) ;
01432 int k;
01433 for (k = 0; k < pEntryCache.size(); ++k)
01434 if (pEntryCache[k].entryid == eId && pEntryCache[k].entryIsValid())
01435 return NodeId(EntryKind, k);
01436
01437 klfDbg("...not found.") ;
01438 return NodeId();
01439 }
01440
01441
01442 void KLFLibModelCache::fullDump()
01443 {
01444 #ifdef KLF_DEBUG
01445 int k;
01446 qDebug("---------------------------------------------------------");
01447 qDebug("------------- FULL CACHE DUMP ---------------------------");
01448 qDebug("---------------------------------------------------------");
01449 qDebug(" ");
01450 qDebug("Entry cache dump:");
01451 for (k = 0; k < pEntryCache.size(); ++k)
01452 qDebug()<<"#"<<k<<": "<<pEntryCache[k];
01453 qDebug(" ");
01454 qDebug("Category Label cache dump: ");
01455 for (k = 0; k < pCategoryLabelCache.size(); ++k)
01456 qDebug()<<"#"<<k<<": "<<pCategoryLabelCache[k];
01457 qDebug(" ");
01458 dumpNodeTree(NodeId::rootNode());
01459 qDebug(" ");
01460 qDebug("---------------------------------------------------------");
01461 qDebug("---------------------------------------------------------");
01462 qDebug("---------------------------------------------------------");
01463 #endif
01464 }
01465
01466 void KLFLibModelCache::dumpNodeTree(NodeId node, int indent)
01467 {
01468 #ifdef KLF_DEBUG
01469
01470 if (indent == 0) {
01471 qDebug(" ");
01472 qDebug("---------------- NODE TREE DUMP -------------------------");
01473 }
01474 char sindent[] = " + ";
01475 if (indent < (signed)strlen(sindent))
01476 sindent[indent] = '\0';
01477
01478 if (!node.valid())
01479 qDebug() << sindent << "(Invalid Node)";
01480
01481 EntryNode en;
01482 CategoryLabelNode cn;
01483 switch (node.kind) {
01484 case EntryKind:
01485 en = getEntryNodeRef(node);
01486 qDebug() << sindent << node <<"\n"<<sindent<<"\t\t"<<en;
01487 break;
01488 case CategoryLabelKind:
01489 cn = getCategoryLabelNodeRef(node);
01490 qDebug() << sindent << node << "\n"<<sindent<<"\t\t"<<cn;
01491 break;
01492 default:
01493 qDebug() << sindent << node << "\n"<<sindent<<"\t\t*InvalidNodeKind*(kind="<<node.kind<<")";
01494 }
01495
01496 if (node.valid()) {
01497 Node n = getNode(node);
01498 int k;
01499 for (k = 0; k < n.children.size(); ++k) {
01500 dumpNodeTree(getNode(node).children[k], indent+4);
01501 }
01502 }
01503
01504 if (indent == 0) {
01505 qDebug("---------------------------------------------------------");
01506 qDebug("---------------------------------------------------------");
01507 }
01508
01509 #endif
01510 }
01511
01512
01513
01514
01515
01516
01517
01518
01519
01520
01521 KLFLibModel::KLFLibModel(KLFLibResourceEngine *engine, uint flavorFlags, QObject *parent)
01522 : QAbstractItemModel(parent), pFlavorFlags(flavorFlags)
01523 {
01524 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
01525
01526
01527
01528
01529
01530
01531
01532 setFetchBatchCount(30);
01533
01534
01535 pEntrySorter = new KLFLibEntrySorter(KLFLibEntry::DateTime, Qt::DescendingOrder);
01536
01537 pCache = new KLFLibModelCache(this);
01538
01539
01540 setResource(engine);
01541
01542
01543
01544
01545 }
01546
01547 KLFLibModel::~KLFLibModel()
01548 {
01549 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
01550 delete pCache;
01551 if (pEntrySorter)
01552 delete pEntrySorter;
01553 }
01554
01555 void KLFLibModel::setResource(KLFLibResourceEngine *resource)
01556 {
01557 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
01558
01559 KLF_DEBUG_ASSIGN_SAME_REF_INSTANCE(pCache) ;
01560
01561 pResource = resource;
01562 updateCacheSetupModel();
01563 }
01564
01565 QUrl KLFLibModel::url() const
01566 {
01567 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
01568 if (pResource == NULL) {
01569 qWarning()<<KLF_FUNC_NAME<<": resource is NULL!";
01570 return QUrl();
01571 }
01572 if ((pResource->supportedFeatureFlags() & KLFLibResourceEngine::FeatureSubResources) == 0)
01573 return pResource->url();
01574
01575
01576 return pResource->url(KLFLibResourceEngine::WantUrlDefaultSubResource);
01577 }
01578
01579
01580
01581 void KLFLibModel::setFlavorFlags(uint flags, uint modify_mask)
01582 {
01583 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
01584 if ( (flags & modify_mask) == (pFlavorFlags & modify_mask) )
01585 return;
01586 uint other_flags = pFlavorFlags & ~modify_mask;
01587 pFlavorFlags = flags | other_flags;
01588
01589
01590 if (modify_mask & DisplayTypeMask) {
01591 updateCacheSetupModel();
01592 }
01593 if (modify_mask & GroupSubCategories) {
01594 int col = columnForEntryPropertyId(pEntrySorter->propId());
01595 Qt::SortOrder ord = pEntrySorter->order();
01596
01597 sort(-1, ord);
01598 sort(col, ord);
01599 }
01600 }
01601 uint KLFLibModel::flavorFlags() const
01602 {
01603 return pFlavorFlags;
01604 }
01605
01606 void KLFLibModel::prefetch(const QModelIndexList& indexes) const
01607 {
01608 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
01609 int k;
01610 for (k = 0; k < indexes.size(); ++k) {
01611 if (!indexes[k].isValid())
01612 continue;
01613 KLFLibModelCache::NodeId p = pCache->getNodeForIndex(indexes[k]);
01614 if (!p.valid() || p.isRoot()) {
01615 klfDbg("Invalid index: indexes[k].row="<<indexes[k].row());
01616 continue;
01617 }
01618 pCache->ensureNotMinimalist(p);
01619 }
01620 }
01621
01622 QVariant KLFLibModel::data(const QModelIndex& index, int role) const
01623 {
01624 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
01625
01626
01627
01628 KLFLibModelCache::NodeId p = pCache->getNodeForIndex(index);
01629 if (!p.valid() || p.isRoot())
01630 return QVariant();
01631
01632
01633 KLFLibModelCache::Node thisNode = pCache->getNode(p);
01634 KLFLibModelCache::NodeId parent = thisNode.parent;
01635 KLFLibModelCache::Node parentNode = pCache->getNode(parent);
01636
01637 if (role == ItemKindItemRole)
01638 return QVariant::fromValue<int>(p.kind);
01639
01640 if (ItemKind(p.kind) == EntryKind) {
01641
01642 const KLFLibModelCache::EntryNode& ep = pCache->getEntryNodeRef(p);
01643
01644 if (role == EntryContentsTypeItemRole)
01645 return entryColumnContentsPropertyId(index.column());
01646 if (role == EntryIdItemRole)
01647 return QVariant::fromValue<KLFLib::entryId>(ep.entryid);
01648
01649 if (role == Qt::ToolTipRole || role == Qt::DisplayRole) {
01650 int propId = entryColumnContentsPropertyId(index.column());
01651 if (propId == KLFLibEntry::Preview)
01652 propId = KLFLibEntry::Tags;
01653 role = entryItemRole(propId);
01654
01655 }
01656
01657
01658 if (role < Qt::UserRole)
01659 return QVariant();
01660
01661
01662
01663 KLFLibEntry entry = ep.entry;
01664
01665 if ( ! pCache->minimalistEntryPropIds().contains(entryPropIdForItemRole(role)) &&
01666 ep.minimalist) {
01667
01668 pCache->ensureNotMinimalist(p);
01669 }
01670
01671 if (role == entryItemRole(KLFLibEntry::Latex))
01672 return entry.latex();
01673 if (role == entryItemRole(KLFLibEntry::DateTime))
01674 return entry.dateTime();
01675 if (role == entryItemRole(KLFLibEntry::Category))
01676 return entry.category();
01677 if (role == entryItemRole(KLFLibEntry::Tags))
01678
01679 return entry.tags();
01680 if (role == entryItemRole(KLFLibEntry::PreviewSize))
01681 return entry.previewSize();
01682
01683 entry = ep.entry;
01684
01685 if (role == FullEntryItemRole)
01686 return QVariant::fromValue(entry);
01687
01688 if (role == entryItemRole(KLFLibEntry::Preview))
01689 return QVariant::fromValue<QImage>(entry.preview());
01690 if (role == entryItemRole(KLFLibEntry::Style))
01691 return QVariant::fromValue(entry.style());
01692
01693 return QVariant();
01694 }
01695 else if (ItemKind(p.kind) == CategoryLabelKind) {
01696
01697 const KLFLibModelCache::CategoryLabelNode& cp = pCache->getCategoryLabelNodeRef(p);
01698 if (role == Qt::ToolTipRole)
01699 return cp.fullCategoryPath;
01700 if (role == CategoryLabelItemRole)
01701 return cp.categoryLabel;
01702 if (role == FullCategoryPathItemRole)
01703 return cp.fullCategoryPath;
01704
01705 return QVariant();
01706 }
01707
01708
01709 return QVariant();
01710 }
01711 Qt::ItemFlags KLFLibModel::flags(const QModelIndex& index) const
01712 {
01713 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
01714 Qt::ItemFlags flagdropenabled = 0;
01715 if ( index.column() == 0 &&
01716 (pResource->canModifyData(KLFLibResourceEngine::InsertData) ||
01717 pResource->canModifyData(KLFLibResourceEngine::ChangeData)) )
01718 flagdropenabled = Qt::ItemIsDropEnabled;
01719
01720 if (!index.isValid())
01721 return flagdropenabled;
01722
01723 KLFLibModelCache::NodeId p = pCache->getNodeForIndex(index);
01724 if (!p.valid())
01725 return 0;
01726 if (p.kind == KLFLibModelCache::EntryKind)
01727 return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled;
01728 if (p.kind == KLFLibModelCache::CategoryLabelKind)
01729 return Qt::ItemIsEnabled | flagdropenabled;
01730
01731 qWarning()<<KLF_FUNC_NAME<<": bad item kind! index-row="<<index.row()<<"; p="<<p;
01732
01733
01734 return 0;
01735 }
01736 bool KLFLibModel::hasChildren(const QModelIndex &parent) const
01737 {
01738 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
01739 if (parent.column() > 0)
01740 return false;
01741
01742 KLFLibModelCache::NodeId p = pCache->getNodeForIndex(parent);
01743 if (!p.valid() || p.isRoot()) {
01744
01745 p = KLFLibModelCache::NodeId::rootNode();
01746 }
01747
01748 return !pCache->getNode(p).allChildrenFetched || pCache->getNode(p).children.size() > 0;
01749 }
01750 QVariant KLFLibModel::headerData(int section, Qt::Orientation orientation, int role) const
01751 {
01752 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
01753 if (role == Qt::FontRole) {
01754 return qApp->font();
01755 }
01756 if (role == Qt::SizeHintRole && orientation == Qt::Horizontal) {
01757 switch (entryColumnContentsPropertyId(section)) {
01758 case KLFLibEntry::Preview:
01759 return QSize(280,30);
01760 case KLFLibEntry::Latex:
01761 return QSize(350,30);
01762 case KLFLibEntry::Category:
01763 case KLFLibEntry::Tags:
01764 return QSize(200,30);
01765 default:
01766 return QVariant();
01767 }
01768 }
01769 if (role == Qt::DisplayRole) {
01770 if (orientation == Qt::Horizontal)
01771 return KLFLibEntry().propertyNameForId(entryColumnContentsPropertyId(section));
01772 return QString("-");
01773 }
01774 return QVariant();
01775 }
01776
01777 bool KLFLibModel::hasIndex(int row, int column, const QModelIndex &parent) const
01778 {
01779 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
01780
01781 return index(row, column, parent).isValid();
01782 }
01783
01784 QModelIndex KLFLibModel::index(int row, int column, const QModelIndex &parent) const
01785 {
01786 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
01787
01788 const KLFLibModelCache::CategoryLabelNode& cat_p =
01789 pCache->getCategoryLabelNodeRef(KLFLibModelCache::NodeId::rootNode());
01790 KLFLibModelCache::CategoryLabelNode p = cat_p;
01791
01792 if (parent.isValid()) {
01793 KLFLibModelCache::NodeId pp = pCache->getNodeForIndex(parent);
01794 if (pp.kind != KLFLibModelCache::CategoryLabelKind)
01795 return QModelIndex();
01796 if (pp.valid())
01797 p = pCache->getCategoryLabelNodeRef(pp);
01798 }
01799 if (row < 0 || row >= p.children.size() || column < 0 || column >= columnCount(parent))
01800 return QModelIndex();
01801 klfDbgT(": row="<<row<<"; column="<<column<<"; parent="<<parent);
01802 return pCache->createIndexFromId(p.children[row], row, column);
01803 }
01804 QModelIndex KLFLibModel::parent(const QModelIndex &index) const
01805 {
01806 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
01807 klfDbgT(": requesting parent of index "<<index);
01808 KLFLibModelCache::NodeId p = pCache->getNodeForIndex(index);
01809 if ( !p.valid() )
01810 return QModelIndex();
01811 KLFLibModelCache::Node n = pCache->getNode(p);
01812 if ( ! n.parent.valid() )
01813 return QModelIndex();
01814 return KLF_DEBUG_TEE( pCache->createIndexFromId(n.parent, -1 , 0) ) ;
01815 }
01816 int KLFLibModel::rowCount(const QModelIndex &parent) const
01817 {
01818 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
01819
01820 if (parent.column() > 0)
01821 return 0;
01822
01823 KLFLibModelCache::NodeId p = pCache->getNodeForIndex(parent);
01824 if (!p.valid())
01825 p = KLFLibModelCache::NodeId::rootNode();
01826
01827 KLFLibModelCache::Node n = pCache->getNode(p);
01828 klfDbg( " parent="<<parent<<"; numchildren="<<n.children.size() ) ;
01829
01830 return n.children.size();
01831 }
01832
01833 int KLFLibModel::columnCount(const QModelIndex & ) const
01834 {
01835 return 5;
01836 }
01837 int KLFLibModel::entryColumnContentsPropertyId(int column) const
01838 {
01839
01840 switch (column) {
01841 case 0:
01842 return KLFLibEntry::Preview;
01843 case 1:
01844 return KLFLibEntry::Tags;
01845 case 2:
01846 return KLFLibEntry::Category;
01847 case 3:
01848 return KLFLibEntry::Latex;
01849 case 4:
01850 return KLFLibEntry::DateTime;
01851 default:
01852 return -1;
01853 }
01854 }
01855 int KLFLibModel::columnForEntryPropertyId(int entryPropertyId) const
01856 {
01857
01858 switch (entryPropertyId) {
01859 case KLFLibEntry::Preview:
01860 return 0;
01861 case KLFLibEntry::Tags:
01862 return 1;
01863 case KLFLibEntry::Category:
01864 return 2;
01865 case KLFLibEntry::Latex:
01866 return 3;
01867 case KLFLibEntry::DateTime:
01868 return 4;
01869 default:
01870 return -1;
01871 }
01872 }
01873
01874
01875 bool KLFLibModel::canFetchMore(const QModelIndex& parent) const
01876 {
01877 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
01878
01879
01880 KLFLibModelCache::NodeId n = pCache->getNodeForIndex(parent);
01881 if (!n.valid())
01882 n = KLFLibModelCache::NodeId::rootNode();
01883
01884 return pCache->canFetchMore(pCache->getNodeForIndex(parent));
01885 }
01886 void KLFLibModel::fetchMore(const QModelIndex& parent)
01887 {
01888 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
01889 pCache->fetchMore(pCache->getNodeForIndex(parent), pFetchBatchCount);
01890 }
01891
01892
01893 Qt::DropActions KLFLibModel::supportedDropActions() const
01894 {
01895 return Qt::CopyAction|Qt::MoveAction;
01896 }
01897
01898 QStringList KLFLibModel::mimeTypes() const
01899 {
01900 return QStringList() << "application/x-klf-internal-lib-move-entries"
01901 << KLFAbstractLibEntryMimeEncoder::allEncodingMimeTypes();
01902 }
01903 QMimeData *KLFLibModel::mimeData(const QModelIndexList& indlist) const
01904 {
01905 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
01906
01907
01908 QModelIndexList indexes = indlist;
01909
01910
01911 KLFLibEntryList entries;
01912 QList<KLFLib::entryId> entryids;
01913 QList<KLFLibModelCache::NodeId> entriesnodeids;
01914 int k;
01915 for (k = 0; k < indexes.size(); ++k) {
01916 KLFLibModelCache::NodeId n = pCache->getNodeForIndex(indexes[k]);
01917 if (!n.valid() || n.isRoot())
01918 continue;
01919 if (n.kind != KLFLibModelCache::EntryKind)
01920 continue;
01921 if (entriesnodeids.contains(n))
01922 continue;
01923 const KLFLibModelCache::EntryNode& en = pCache->getEntryNodeRef(n);
01924 entries << pResource->entry(en.entryid);
01925 entryids << en.entryid;
01926 entriesnodeids << n;
01927 }
01928
01929
01930
01931
01932 QVariantMap vprop;
01933 QUrl myurl = url();
01934 vprop["Url"] = myurl;
01935
01936 QMimeData *mimedata = KLFAbstractLibEntryMimeEncoder::createMimeData(entries, vprop);
01937
01938 QByteArray internalmovedata;
01939
01940
01941 { QDataStream imstr(&internalmovedata, QIODevice::WriteOnly);
01942 imstr.setVersion(QDataStream::Qt_4_4);
01943 imstr << vprop << entryids;
01944 }
01945 mimedata->setData("application/x-klf-internal-lib-move-entries", internalmovedata);
01946
01947 return mimedata;
01948 }
01949
01950
01951 bool KLFLibModel::dropCanInternal(const QMimeData *mimedata)
01952 {
01953 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
01954 if ( ! mimedata->hasFormat("application/x-klf-internal-lib-move-entries") ||
01955 ! pResource->canModifyData(KLFLibResourceEngine::ChangeData))
01956 return false;
01957
01958 QByteArray imdata = mimedata->data("application/x-klf-internal-lib-move-entries");
01959 QDataStream imstr(imdata);
01960 imstr.setVersion(QDataStream::Qt_4_4);
01961 QVariantMap vprop;
01962 imstr >> vprop;
01963 QUrl theirurl = vprop.value("Url").toUrl();
01964 QUrl oururl = url();
01965 bool ok = (oururl.toEncoded() == theirurl.toEncoded());
01966 klfDbg( "drag originated from "<<theirurl<<"; we are "<<oururl<<"; OK="<<ok ) ;
01967 return ok;
01968 }
01969
01970 bool KLFLibModel::dropMimeData(const QMimeData *mimedata, Qt::DropAction action, int row,
01971 int column, const QModelIndex& parent)
01972 {
01973 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
01974 klfDbg( "Drop data: action="<<action<<" row="<<row<<" col="<<column
01975 << " parent="<<parent ) ;
01976
01977 if (action == Qt::IgnoreAction)
01978 return true;
01979 if (action != Qt::CopyAction)
01980 return false;
01981
01982 if ( ! (mimedata->hasFormat("application/x-klf-internal-lib-move-entries") &&
01983 pResource->canModifyData(KLFLibResourceEngine::ChangeData)) &&
01984 ! (KLFAbstractLibEntryMimeEncoder::canDecodeMimeData(mimedata) &&
01985 pResource->canModifyData(KLFLibResourceEngine::InsertData)) ) {
01986
01987
01988 return false;
01989 }
01990
01991 if (column > 0)
01992 return false;
01993
01994
01995 bool useinternalmove = dropCanInternal(mimedata);
01996 if (useinternalmove) {
01997 klfDbg( "Dropping application/x-klf-internal-lib-move-entries" ) ;
01998 if ( !(pFlavorFlags & CategoryTree) )
01999 return false;
02000
02001 QByteArray imdata = mimedata->data("application/x-klf-internal-lib-move-entries");
02002 QDataStream imstr(imdata);
02003 imstr.setVersion(QDataStream::Qt_4_4);
02004 QList<KLFLib::entryId> idlist;
02005 QVariantMap vprop;
02006 imstr >> vprop >> idlist;
02007
02008 KLFLibModelCache::NodeId pn = pCache->getNodeForIndex(parent);
02009 if (!pn.valid()) {
02010 pn = KLFLibModelCache::NodeId::rootNode();
02011 }
02012 if (ItemKind(pn.kind) != CategoryLabelKind) {
02013 qWarning()<<"Dropped in a non-category index! (kind="<<pn.kind<<")";
02014 return false;
02015 }
02016 const KLFLibModelCache::CategoryLabelNode& cn = pCache->getCategoryLabelNodeRef(pn);
02017
02018 QString newcategory = cn.fullCategoryPath;
02019 if (newcategory.endsWith("/"))
02020 newcategory.chop(1);
02021
02022 bool r = pResource->changeEntries(idlist, QList<int>() << KLFLibEntry::Category,
02023 QList<QVariant>() << QVariant(newcategory));
02024 klfDbg( "Accepted drop of type application/x-klf-internal-lib-move-entries. Res="<<r<<"\n"
02025 <<"ID list is "<<idlist<<" new category is "<<newcategory ) ;
02026 if (!r) {
02027 return false;
02028 }
02029
02030 return true;
02031 }
02032
02033 klfDbg( "Dropping entry list." ) ;
02034
02035 KLFLibEntryList elist;
02036 QVariantMap vprop;
02037 bool res = KLFAbstractLibEntryMimeEncoder::decodeMimeData(mimedata, &elist, &vprop);
02038 if ( ! res ) {
02039 qWarning()<<KLF_FUNC_NAME<<": Drop: Can't decode mime data! provided types="
02040 <<mimedata->formats();
02041 QMessageBox::warning(NULL, tr("Drop Error", "[[message box title]]"),
02042 tr("Error dropping data."));
02043 return false;
02044 }
02045
02046 if ( elist.isEmpty() )
02047 return true;
02048
02049
02050 QList<KLFLib::entryId> inserted = pResource->insertEntries(elist);
02051 res = (inserted.size() && !inserted.contains(-1));
02052 klfDbg( "Dropped entry list "<<elist<<". Originating URL="
02053 <<(vprop.contains("Url")?vprop["Url"]:"(none)")<<". result="<<res ) ;
02054 if (!res)
02055 return false;
02056
02057
02058 return true;
02059 }
02060
02061 uint KLFLibModel::dropFlags(QDragMoveEvent *event, QAbstractItemView *view)
02062 {
02063 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02064 const QMimeData *mdata = event->mimeData();
02065 if (dropCanInternal(mdata)) {
02066 if ( !(pFlavorFlags & CategoryTree) ) {
02067 return 0;
02068
02069 }
02070
02071 QModelIndex dropOnIndex = view->indexAt(event->pos());
02072 if (pResource->canModifyData(KLFLibResourceEngine::ChangeData) &&
02073 (!dropOnIndex.isValid() || dropOnIndex.column() == 0) )
02074 return DropWillAccept|DropWillMove|DropWillCategorize;
02075 return 0;
02076 }
02077 if (KLFAbstractLibEntryMimeEncoder::canDecodeMimeData(mdata) &&
02078 pResource->canModifyData(KLFLibResourceEngine::InsertData))
02079 return DropWillAccept;
02080 return 0;
02081 }
02082
02083 QImage KLFLibModel::dragImage(const QModelIndexList& indexes)
02084 {
02085 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02086 if (indexes.isEmpty())
02087 return QImage();
02088
02089 const int MAX = 5;
02090 const QSize s1 = 0.8*QSize(250,75);
02091 const QPointF delta(18.0, 20.0);
02092 QList<QImage> previewlist;
02093 QList<KLFLibModelCache::NodeId> alreadydone;
02094 int k, j;
02095 int iS = indexes.size();
02096 int n = qMin(1+MAX, iS);
02097 for (j = 0, k = 0; k < iS && j < n; ++k) {
02098 KLFLibModelCache::NodeId n = pCache->getNodeForIndex(indexes[iS-k-1]);
02099 if (!n.valid() || n.kind != KLFLibModelCache::EntryKind)
02100 continue;
02101 if (alreadydone.contains(n))
02102 continue;
02103 const KLFLibModelCache::EntryNode& en = pCache->getEntryNodeRef(n, true);
02104 alreadydone << n;
02105 previewlist << en.entry.preview().scaled(s1, Qt::KeepAspectRatio, Qt::SmoothTransformation);
02106 ++j;
02107 }
02108 if (previewlist.isEmpty())
02109 return QImage();
02110
02111 int N = qMin(MAX, previewlist.size());
02112 QSize s2 = (s1 + (N-1)*pointToSizeF(delta)).toSize();
02113 QImage image(s2, QImage::Format_ARGB32_Premultiplied);
02114 image.fill(qRgba(0,0,0,0));
02115 {
02116 QPainter p(&image);
02117 QPointF P(0,0);
02118 QPointF lastimgbr;
02119 for (k = 0; k < N; ++k) {
02120
02121 QImage i = transparentify_image(previewlist[k], 0.7);
02122 p.drawImage(P, i);
02123
02124 lastimgbr = P+sizeToPointF(i.size());
02125 P += delta;
02126 }
02127 if (k == MAX) {
02128 p.setCompositionMode(QPainter::CompositionMode_DestinationOver);
02129 p.setPen(QPen(QColor(0,0,0),2.0));
02130 QPointF br = lastimgbr;
02131 p.drawPoint(br - QPointF(5,5));
02132 p.drawPoint(br - QPointF(10,5));
02133 p.drawPoint(br - QPointF(15,5));
02134 }
02135 }
02136
02137 return autocrop_image(image);
02138 }
02139
02140
02141 bool KLFLibModel::isDesendantOf(const QModelIndex& child, const QModelIndex& ancestor)
02142 {
02143 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02144 if (!child.isValid())
02145 return false;
02146
02147 return child.parent() == ancestor || isDesendantOf(child.parent(), ancestor);
02148 }
02149
02150 QStringList KLFLibModel::categoryList() const
02151 {
02152 return pCache->categoryListCache();
02153 }
02154
02155 void KLFLibModel::updateData(const QList<KLFLib::entryId>& entryIdList, int modifyType)
02156 {
02157 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02158 pCache->updateData(entryIdList, modifyType);
02159 }
02160
02161 QModelIndex KLFLibModel::walkNextIndex(const QModelIndex& cur)
02162 {
02163 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02164 KLFLibModelCache::NodeId nextnode = pCache->nextNode(pCache->getNodeForIndex(cur));
02165
02166 return pCache->createIndexFromId(nextnode, -1, 0);
02167 }
02168 QModelIndex KLFLibModel::walkPrevIndex(const QModelIndex& cur)
02169 {
02170 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02171 KLFLibModelCache::NodeId prevnode = pCache->prevNode(pCache->getNodeForIndex(cur));
02172 return pCache->createIndexFromId(prevnode, -1, 0);
02173 }
02174
02175 KLFLib::entryId KLFLibModel::entryIdForIndex(const QModelIndex& index) const
02176 {
02177 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02178 return entryIdForIndexList(QModelIndexList() << index) [0];
02179 }
02180
02181 QModelIndex KLFLibModel::findEntryId(KLFLib::entryId eid) const
02182 {
02183 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02184 return findEntryIdList(QList<KLFLib::entryId>() << eid) [0];
02185 }
02186
02187 QList<KLFLib::entryId> KLFLibModel::entryIdForIndexList(const QModelIndexList& indexlist) const
02188 {
02189 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02190 return pCache->entryIdForIndexList(indexlist);
02191 }
02192 QModelIndexList KLFLibModel::findEntryIdList(const QList<KLFLib::entryId>& eidlist) const
02193 {
02194 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02195 return pCache->findEntryIdList(eidlist);
02196 }
02197
02198
02199 void KLFLibModel::setEntrySorter(KLFLibEntrySorter *entrySorter)
02200 {
02201 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02202 if (pEntrySorter == entrySorter)
02203 return;
02204 if (entrySorter == NULL) {
02205 qWarning()<<KLF_FUNC_NAME<<": NULL entrySorter given!";
02206 }
02207
02208 if (pEntrySorter)
02209 delete pEntrySorter;
02210 pEntrySorter = entrySorter;
02211 }
02212
02213
02214 QModelIndex KLFLibModel::searchFind(const QString& queryString, const QModelIndex& fromIndex,
02215 bool forward)
02216 {
02217 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02218 klfDbg( " s="<<queryString<<" from "<<fromIndex<<" forward="<<forward ) ;
02219 pSearchAborted = false;
02220 pSearchString = queryString;
02221 pSearchCurNode = fromIndex;
02222 return searchFindNext(forward);
02223 }
02224 QModelIndex KLFLibModel::searchFindNext(bool forward)
02225 {
02226 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02227 pSearchAborted = false;
02228 if (pSearchString.isEmpty())
02229 return QModelIndex();
02230
02231 QTime t;
02232
02233 KLFLibModelCache::NodeId curNode = pCache->getNodeForIndex(pSearchCurNode);
02234
02235
02236 KLFLibModelCache::NodeId (KLFLibModelCache::*stepfunc)(KLFLibModelCache::NodeId) =
02237 forward
02238 ? &KLFLibModelCache::nextNode
02239 : &KLFLibModelCache::prevNode;
02240
02241
02242 Qt::CaseSensitivity cs = Qt::CaseInsensitive;
02243 if (pSearchString.contains(QRegExp("[A-Z]")))
02244 cs = Qt::CaseSensitive;
02245
02246 bool found = false;
02247 while ( ! found &&
02248 (curNode = (pCache->*stepfunc)(curNode)).valid() ) {
02249 if ( pCache->searchNodeMatches(curNode, pSearchString, cs) ) {
02250 found = true;
02251 }
02252 if (t.elapsed() > 150) {
02253 pSearchCurNode = pCache->createIndexFromId(curNode, -1, 0);
02254 qApp->processEvents();
02255 if (pSearchAborted)
02256 break;
02257 t.restart();
02258 }
02259 }
02260 pSearchCurNode = pCache->createIndexFromId(curNode, -1, 0);
02261 if (found) {
02262 klfDbg( "found "<<pSearchString<<" at "<<pSearchCurNode ) ;
02263 return pSearchCurNode;
02264 }
02265 return QModelIndex();
02266 }
02267
02268 void KLFLibModel::searchAbort()
02269 {
02270 pSearchAborted = true;
02271 }
02272
02273 bool KLFLibModelCache::searchNodeMatches(const NodeId& nodeId, const QString& searchString,
02274 Qt::CaseSensitivity cs)
02275 {
02276 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02277 if (nodeId.kind == CategoryLabelKind) {
02278 if (nodeValue(nodeId).contains(searchString, cs))
02279 return true;
02280 return false;
02281 }
02282 if (nodeValue(nodeId, KLFLibEntry::Latex).contains(searchString, cs) ||
02283 nodeValue(nodeId, KLFLibEntry::Tags).contains(searchString, cs))
02284 return true;
02285
02286
02287 if ((pModel->pFlavorFlags & KLFLibModel::CategoryTree) == 0 &&
02288 nodeValue(nodeId, KLFLibEntry::Category).contains(searchString, cs)) {
02289 return true;
02290 }
02291
02292 return false;
02293 }
02294
02295
02296
02297
02298
02299
02300
02301
02302
02303
02304
02305
02306
02307
02308
02309
02310
02311
02312
02313
02314
02315
02316
02317
02318
02319
02320
02321
02322
02323
02324
02325
02326
02327
02328
02329
02330
02331
02332
02333
02334
02335
02336
02337
02338
02339
02340
02341
02342 void KLFLibModel::completeRefresh()
02343 {
02344 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02345 updateCacheSetupModel();
02346 }
02347
02348
02349 void KLFLibModel::redoSort()
02350 {
02351 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02352
02353
02354 updateCacheSetupModel();
02355 return;
02356
02357
02358
02359
02360
02361
02362
02363
02364
02365
02366
02367 }
02368
02369 void KLFLibModel::sort(int column, Qt::SortOrder order)
02370 {
02371 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02372
02373
02374 int propId = entryColumnContentsPropertyId(column);
02375
02376 if (propId == KLFLibEntry::Preview) {
02377 propId = KLFLibEntry::DateTime;
02378 }
02379
02380 pEntrySorter->setPropId(propId);
02381 pEntrySorter->setOrder(order);
02382
02383 pCache->setSortingBy(propId, order);
02384
02385 redoSort();
02386 }
02387
02388
02389
02390 QList<KLFLibModel::PersistentId> KLFLibModel::persistentIdList(const QModelIndexList& persistentIndexes)
02391 {
02392 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02393
02394 QList<PersistentId> persistentIndexIds;
02395 int k;
02396 for (k = 0; k < persistentIndexes.size(); ++k) {
02397 PersistentId id;
02398 KLFLibModelCache::NodeId n = pCache->getNodeForIndex(persistentIndexes[k]);
02399 if (!n.valid()) {
02400 id.kind = (ItemKind)-1;
02401 } else {
02402 id.kind = n.kind;
02403 if (ItemKind(id.kind) == EntryKind)
02404 id.entry_id = pCache->getEntryNodeRef(n).entryid;
02405 else if (ItemKind(id.kind) == CategoryLabelKind)
02406 id.categorylabel_fullpath = pCache->getCategoryLabelNodeRef(n).fullCategoryPath;
02407 else
02408 qWarning("KLFLibModel::persistentIdList: Bad Node kind: %d!!", id.kind);
02409 }
02410 id.column = persistentIndexes[k].column();
02411 persistentIndexIds << id;
02412 klfDbg("saved persistent id "<<id) ;
02413 }
02414 return persistentIndexIds;
02415 }
02416 QModelIndexList KLFLibModel::newPersistentIndexList(const QList<PersistentId>& persistentIndexIds)
02417 {
02418 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02419 QModelIndexList newPersistentIndexes;
02420 int k;
02421 for (k = 0; k < persistentIndexIds.size(); ++k) {
02422
02423 PersistentId id = persistentIndexIds[k];
02424 QModelIndex index;
02425 if (ItemKind(id.kind) == EntryKind) {
02426 QModelIndexList ilist = pCache->findEntryIdList(QList<KLFLib::entryId>() << id.entry_id);
02427 index = ilist[0];
02428 } else if (id.kind == CategoryLabelKind) {
02429 int idx = pCache->cacheFindCategoryLabel(id.categorylabel_fullpath.split('/'));
02430 KLFLibModelCache::NodeId nodeId(KLFLibModelCache::CategoryLabelKind, idx);
02431 index = pCache->createIndexFromId(nodeId, -1, 0);
02432 } else {
02433 qWarning("%s: bad persistent id node kind! :%d", KLF_FUNC_NAME, id.kind);
02434 }
02435
02436 newPersistentIndexes << index;
02437 klfDbg("restoring persistent id "<<id<<" as index "<<index) ;
02438 }
02439 return newPersistentIndexes;
02440 }
02441
02442
02443 void KLFLibModel::startLayoutChange(bool withQtLayoutChangedSignal)
02444 {
02445 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02446
02447 if (withQtLayoutChangedSignal)
02448 emit layoutAboutToBeChanged();
02449
02450 pLytChgIndexes = persistentIndexList();
02451 pLytChgIds = persistentIdList(pLytChgIndexes);
02452 }
02453 void KLFLibModel::endLayoutChange(bool withQtLayoutChangedSignal)
02454 {
02455 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
02456
02457 QModelIndexList newpindexes = newPersistentIndexList(pLytChgIds);
02458 changePersistentIndexList(pLytChgIndexes, newpindexes);
02459
02460 if (withQtLayoutChangedSignal)
02461 emit layoutChanged();
02462 }
02463
02464
02465 void KLFLibModel::updateCacheSetupModel()
02466 {
02467 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02468 pCache->rebuildCache();
02469 }
02470
02471
02472
02473
02474
02475
02476 KLFLibViewDelegate::KLFLibViewDelegate(QObject *parent)
02477 : QAbstractItemDelegate(parent), pSelModel(NULL), pTheTreeView(NULL),
02478 pPreviewSize(klfconfig.UI.labelOutputFixedSize)
02479 {
02480 pAutoBackgroundItems = true;
02481 }
02482 KLFLibViewDelegate::~KLFLibViewDelegate()
02483 {
02484 }
02485
02486 QWidget * KLFLibViewDelegate::createEditor(QWidget *,
02487 const QStyleOptionViewItem& ,
02488 const QModelIndex& ) const
02489 {
02490 return 0;
02491 }
02492 bool KLFLibViewDelegate::editorEvent(QEvent *, QAbstractItemModel *,
02493 const QStyleOptionViewItem& ,
02494 const QModelIndex& )
02495 {
02496 return false;
02497 }
02498
02499
02501 class _klf_block_progress_blocker
02502 {
02503 KLFLibResourceEngine *res;
02504 public:
02505 _klf_block_progress_blocker(KLFLibResourceEngine *r) : res(r)
02506 {
02507 if (res != NULL)
02508 res->blockProgressReporting(true);
02509 }
02510 ~_klf_block_progress_blocker()
02511 {
02512 if (res != NULL)
02513 res->blockProgressReporting(false);
02514 }
02515 };
02516
02517
02518 void KLFLibViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem& option,
02519 const QModelIndex& index) const
02520 {
02521 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02522 klfDbg( "\tindex="<<index<<"; rect="<<option.rect ) ;
02523 PaintPrivate pp;
02524 pp.p = painter;
02525 pp.option = &option;
02526 pp.innerRectImage = QRect(option.rect.topLeft()+QPoint(2,2), option.rect.size()-QSize(4,4));
02527 pp.innerRectText = QRect(option.rect.topLeft()+QPoint(4,2), option.rect.size()-QSize(8,3));
02528
02529 #ifdef Q_WS_MAC
02530
02531 KLFLibResourceEngine *rres = NULL;
02532 KLFLibModel *rmodel = qobject_cast<KLFLibModel*>(const_cast<QAbstractItemModel*>(index.model()));
02533 if (rmodel != NULL) rres = rmodel->resource();
02534 _klf_block_progress_blocker blocker(rres);
02535 #endif
02536
02537 painter->save();
02538
02539 QPen pen = painter->pen();
02540 pp.isselected = (option.state & QStyle::State_Selected);
02541 QPalette::ColorGroup cg = option.state & QStyle::State_Enabled
02542 ? QPalette::Normal : QPalette::Disabled;
02543 if (cg == QPalette::Normal && !(option.state & QStyle::State_Active))
02544 cg = QPalette::Inactive;
02545 if (pp.isselected) {
02546 pp.background = option.palette.brush(cg, QPalette::Highlight);
02547 painter->setPen(option.palette.color(cg, QPalette::HighlightedText));
02548 painter->fillRect(option.rect, pp.background);
02549 } else {
02550 pp.background = pAutoBackgroundColor.isValid()
02551 ? pAutoBackgroundColor
02552 : option.palette.brush(cg, QPalette::Base);
02553 painter->setPen(option.palette.color(cg, QPalette::Text));
02554 }
02555
02556 int kind = index.data(KLFLibModel::ItemKindItemRole).toInt();
02557 if (kind == KLFLibModel::EntryKind)
02558 paintEntry(&pp, index);
02559 else if (kind == KLFLibModel::CategoryLabelKind)
02560 paintCategoryLabel(&pp, index);
02561
02562 if (option.state & QStyle::State_HasFocus) {
02563 QStyleOptionFocusRect o;
02564 o.QStyleOption::operator=(option);
02565 o.rect = option.rect;
02566 o.state |= QStyle::State_KeyboardFocusChange;
02567 o.state |= QStyle::State_Item;
02568 QPalette::ColorGroup cg = (option.state & QStyle::State_Enabled)
02569 ? QPalette::Normal : QPalette::Disabled;
02570 o.backgroundColor = option.palette.color(cg, (option.state & QStyle::State_Selected)
02571 ? QPalette::Highlight : QPalette::Window);
02572 const QWidget *w = 0;
02573 if (const QStyleOptionViewItemV3 *v3 = qstyleoption_cast<const QStyleOptionViewItemV3 *>(&option))
02574 w = v3->widget;
02575 QStyle *style = w ? w->style() : QApplication::style();
02576 style->drawPrimitive(QStyle::PE_FrameFocusRect, &o, painter, w);
02577 }
02578
02579 painter->restore();
02580 }
02581
02582 void KLFLibViewDelegate::paintEntry(PaintPrivate *p, const QModelIndex& index) const
02583 {
02584 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02585 uint fl = PTF_HighlightSearch;
02586 if (index.parent() == pSearchIndex.parent() && index.row() == pSearchIndex.row())
02587 fl |= PTF_HighlightSearchCurrent;
02588
02589 switch (index.data(KLFLibModel::EntryContentsTypeItemRole).toInt()) {
02590 case KLFLibEntry::Latex:
02591
02592 fl |= PTF_FontTT;
02593 paintText(p, index.data(KLFLibModel::entryItemRole(KLFLibEntry::Latex)).toString(), fl);
02594 break;
02595 case KLFLibEntry::Preview:
02596
02597 {
02598 QImage img = index.data(KLFLibModel::entryItemRole(KLFLibEntry::Preview)).value<QImage>();
02599 QImage img2 = img.scaled(p->innerRectImage.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
02600 if (p->isselected)
02601 img2 = transparentify_image(img2, 0.85);
02602 QPoint pos = p->innerRectImage.topLeft()
02603 + QPoint(0, (p->innerRectImage.height()-img2.height()) / 2);
02604 if (pAutoBackgroundItems) {
02605
02606
02607 klfDbg( " BG Brush is "<<p->background ) ;
02608 QColor bgcolor = p->background.color();
02609 QList<QColor> bglista, bglistb, bglist;
02610
02611
02612
02613
02614
02615
02616
02617
02618
02619 bglist << bgcolor;
02620 bglista = bglistb = bglist;
02621 int count;
02622 for (count = 0; count < 5; ++count)
02623 bglista << bglista.last().darker(105+count*2);
02624 for (count = 0; count < 5; ++count)
02625 bglistb << bglistb.last().lighter(105+count*2);
02626
02627 bglist << bglista.mid(1) << bglistb.mid(1) << QColor(255,255,255) << QColor(0,0,0);
02628 klfDbg( "alt. bg list is "<<bglist );
02629 int k;
02630 for (k = 0; k < bglist.size(); ++k) {
02631
02632
02633 bool distinguishable = image_is_distinguishable(img2, bglist[k], 20);
02634 if ( distinguishable )
02635 break;
02636 }
02637
02638 if (k > 0 && k < bglist.size())
02639 p->p->fillRect(QRect(pos, img2.size()), QBrush(bglist[k]));
02640 }
02641
02642 p->p->save();
02643 p->p->translate(pos);
02644 if (klfconfig.UI.glowEffect)
02645 klfDrawGlowedImage(p->p, img2, klfconfig.UI.glowEffectColor, klfconfig.UI.glowEffectRadius, false);
02646 p->p->drawImage(QPoint(0,0), img2);
02647 p->p->restore();
02648 break;
02649 }
02650 case KLFLibEntry::Category:
02651
02652 paintText(p, index.data(KLFLibModel::entryItemRole(KLFLibEntry::Category)).toString(), fl);
02653 break;
02654 case KLFLibEntry::Tags:
02655
02656 fl |= PTF_FontLarge;
02657 paintText(p, index.data(KLFLibModel::entryItemRole(KLFLibEntry::Tags)).toString(), fl);
02658 break;
02659 case KLFLibEntry::DateTime:
02660
02661 { QLocale loc;
02662 paintText(p, loc.toString(index.data(KLFLibModel::entryItemRole(KLFLibEntry::DateTime))
02663 .toDateTime(), QLocale::LongFormat), fl);
02664 break;
02665 }
02666 default:
02667 qDebug("KLFLibViewDelegate::paintEntry(): Got bad contents type %d !",
02668 index.data(KLFLibModel::EntryContentsTypeItemRole).toInt());
02669
02670
02671 }
02672 }
02673
02674 void KLFLibViewDelegate::paintCategoryLabel(PaintPrivate *p, const QModelIndex& index) const
02675 {
02676 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02677
02678
02679
02680
02681 if (index.column() > 0)
02682 return;
02683
02684
02685
02686 uint fl = PTF_HighlightSearch;
02687 if (index.parent() == pSearchIndex.parent() && index.row() == pSearchIndex.row())
02688 fl |= PTF_HighlightSearchCurrent;
02689 if ( pTheTreeView != NULL && !pTheTreeView->isExpanded(index) &&
02690 indexHasSelectedDescendant(index) ) {
02691 fl |= PTF_SelUnderline;
02692 }
02693
02694
02695
02696
02697
02698 if (fl & PTF_HighlightSearchCurrent) {
02699
02700 QPen pen = p->p->pen();
02701 QPalette::ColorGroup cg = p->option->state & QStyle::State_Enabled
02702 ? QPalette::Normal : QPalette::Disabled;
02703 if (cg == QPalette::Normal && !(p->option->state & QStyle::State_Active))
02704 cg = QPalette::Inactive;
02705 p->p->fillRect(p->option->rect, p->option->palette.brush(cg, QPalette::Highlight));
02706 p->p->setPen(p->option->palette.color(cg, QPalette::HighlightedText));
02707 }
02708
02709
02710 paintText(p, index.data(KLFLibModel::CategoryLabelItemRole).toString(), fl);
02711 }
02712
02713 void KLFLibViewDelegate::paintText(PaintPrivate *p, const QString& text, uint flags) const
02714 {
02715 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02716
02717 QFont font = p->option->font;
02718
02719 if (flags & PTF_FontTT)
02720 font = klfconfig.UI.preambleEditFont;
02721 if (flags & PTF_FontLarge) {
02722 font.setPointSize(QFontInfo(font).pointSize()+1);
02723
02724 }
02725
02726 QColor textcol = p->option->palette.color(QPalette::Text);
02727 QColor textcoltransp = textcol; textcoltransp.setAlpha(0);
02728 QGradientStops borderfadelingrstops;
02729 borderfadelingrstops << QGradientStop(0.0f, textcoltransp)
02730 << QGradientStop(0.1f, textcol)
02731 << QGradientStop(0.9f, textcol)
02732 << QGradientStop(1.0f, textcoltransp);
02733 QLinearGradient borderfadelingr(p->innerRectText.topLeft(), p->innerRectText.bottomLeft());
02734 borderfadelingr.setStops(borderfadelingrstops);
02735 borderfadelingr.setCoordinateMode(QGradient::LogicalMode);
02736 QPen borderfadepen = QPen(QBrush(borderfadelingr), 1.0f);
02737 QPen normalpen = QPen(textcol, 1.0f);
02738
02739 int drawnTextWidth;
02740 int drawnBaseLineY;
02741 if ( (pSearchString.isEmpty() || !(flags&PTF_HighlightSearch) ||
02742 text.indexOf(pSearchString, 0, Qt::CaseInsensitive) == -1) &&
02743 !(flags & PTF_SelUnderline) &&
02744 !(flags & PTF_ForceRichTextRender) ) {
02745
02746 QSize s = QFontMetrics(font).size(0, text);
02747 drawnTextWidth = s.width();
02748 drawnBaseLineY = (int)(p->innerRectText.bottom() - 0.5f*(p->innerRectText.height()-s.height()));
02749 p->p->setFont(font);
02750 if (s.height() > p->innerRectText.height()) {
02751 klfDbg("Need border fade pen for text "<<text) ;
02752 p->p->setPen(borderfadepen);
02753 } else {
02754 klfDbg("Don't need border fade pen for text "<<text) ;
02755 p->p->setPen(normalpen);
02756 }
02757 p->p->drawText(p->innerRectText, Qt::AlignLeft|Qt::AlignVCenter, text);
02758 } else {
02759
02760
02761 QList<ColorRegion> c;
02762 QTextCharFormat f_highlight;
02763 if (flags & PTF_HighlightSearchCurrent)
02764 f_highlight.setBackground(QColor(0,255,0,80));
02765 f_highlight.setForeground(QColor(128,0,0));
02766 f_highlight.setFontItalic(true);
02767 f_highlight.setFontWeight(QFont::Bold);
02768 int i = -1, ci, j;
02769 if (!pSearchString.isEmpty()) {
02770 while ((i = text.indexOf(pSearchString, i+1, Qt::CaseInsensitive)) != -1)
02771 c << ColorRegion(f_highlight, i, pSearchString.length());
02772 }
02773 qSort(c);
02774
02775 QTextDocument textDocument;
02776 textDocument.setDefaultFont(font);
02777 QTextCursor cur(&textDocument);
02778 QList<ColorRegion> appliedfmts;
02779 for (i = ci = 0; i < text.length(); ++i) {
02780
02781 if (ci >= c.size() && appliedfmts.size() == 0) {
02782
02783 cur.insertText(Qt::escape(text.mid(i)), QTextCharFormat());
02784 break;
02785 }
02786 while (ci < c.size() && c[ci].start == i) {
02787 appliedfmts.append(c[ci]);
02788 ++ci;
02789 }
02790 QTextCharFormat f;
02791 for (j = 0; j < appliedfmts.size(); ++j) {
02792 if (i >= appliedfmts[j].start + appliedfmts[j].len) {
02793
02794 appliedfmts.removeAt(j);
02795 --j;
02796 continue;
02797 }
02798 f.merge(appliedfmts[j].fmt);
02799 }
02800 cur.insertText(Qt::escape(text[i]), f);
02801 }
02802
02803 QSizeF s = textDocument.size();
02804 QRectF textRect = p->innerRectText;
02805
02806 textRect.setLeft(textRect.left()-4);
02807
02808
02809 if (flags & PTF_SelUnderline) {
02810 QColor h1 = p->option->palette.color(QPalette::Highlight);
02811 QColor h2 = h1;
02812 h1.setAlpha(0);
02813 h2.setAlpha(220);
02814 QLinearGradient gr(0.f, 0.f, 0.f, 1.f);
02815 gr.setCoordinateMode(QGradient::ObjectBoundingMode);
02816 gr.setColorAt(0.f, h1);
02817 gr.setColorAt(1.f, h2);
02818 QBrush selbrush(gr);
02819 p->p->save();
02820
02821 p->p->fillRect(QRectF(textRect.left(), textRect.bottom()-10,
02822 textRect.width(), 10), selbrush);
02823 p->p->restore();
02824 }
02825
02826 drawnTextWidth = (int)s.width();
02827 if (s.width() > textRect.width()) {
02828 s.setWidth(textRect.width());
02829 }
02830 p->p->save();
02831 p->p->setClipRect(textRect);
02832 if (s.height() > textRect.height()) {
02833 klfDbg("Need borderfadepen for (rich) text "<<textDocument.toHtml());
02834 p->p->setPen(borderfadepen);
02835 } else {
02836 p->p->setPen(normalpen);
02837 }
02838 p->p->translate(textRect.topLeft());
02839 p->p->translate( QPointF( 0,
02840 textRect.height() - s.height()) / 2.f );
02841 textDocument.drawContents(p->p);
02842 p->p->restore();
02843 drawnBaseLineY = (int)(textRect.bottom() - (textRect.height() - s.height()) / 2.f);
02844 }
02845
02846
02847
02848 if (drawnTextWidth > p->innerRectText.width()) {
02849
02850
02851 p->p->save();
02852 p->p->translate(p->option->rect.right()-2, drawnBaseLineY-2);
02853 p->p->setPen(textcol);
02854 p->p->drawLine(0, 0, -16, 0);
02855 p->p->drawLine(0, 0, -2, +2);
02856 p->p->restore();
02857 }
02858 }
02859
02860 void KLFLibViewDelegate::setEditorData(QWidget *, const QModelIndex& ) const
02861 {
02862 }
02863 void KLFLibViewDelegate::setModelData(QWidget *, QAbstractItemModel *,
02864 const QModelIndex& ) const
02865 {
02866 }
02867 QSize KLFLibViewDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
02868 {
02869 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02870 klfDbg( "\tindex="<<index ) ;
02871 int kind = index.data(KLFLibModel::ItemKindItemRole).toInt();
02872 if (kind == KLFLibModel::EntryKind) {
02873 int prop = -1;
02874 switch (index.data(KLFLibModel::EntryContentsTypeItemRole).toInt()) {
02875 case KLFLibEntry::Latex: prop = KLFLibEntry::Latex;
02876 case KLFLibEntry::Category: prop = (prop > 0) ? prop : KLFLibEntry::Category;
02877 case KLFLibEntry::Tags: prop = (prop > 0) ? prop : KLFLibEntry::Tags;
02878 return QFontMetrics(option.font)
02879 .size(0, index.data(KLFLibModel::entryItemRole(prop)).toString())+QSize(4,4);
02880 case KLFLibEntry::DateTime:
02881 { QLocale loc;
02882 return QFontMetrics(option.font)
02883 .size(0, loc.toString(index.data(KLFLibModel::entryItemRole(KLFLibEntry::DateTime))
02884 .toDateTime(), QLocale::LongFormat) )+QSize(4,2);
02885 }
02886 case KLFLibEntry::Preview:
02887 {
02888 QSize s = index.data(KLFLibModel::entryItemRole(KLFLibEntry::PreviewSize)).value<QSize>() + QSize(4,3);
02889 if (s.width() > pPreviewSize.width() || s.height() > pPreviewSize.height()) {
02890
02891 s.scale(pPreviewSize, Qt::KeepAspectRatio);
02892 }
02893 return s+QSize(2,2);
02894 }
02895 default:
02896 return QSize();
02897 }
02898 } else if (kind == KLFLibModel::CategoryLabelKind) {
02899 return QFontMetrics(option.font)
02900 .size(0, index.data(KLFLibModel::CategoryLabelItemRole).toString())+QSize(4,4);
02901 } else {
02902 qWarning("KLFLibItemViewDelegate::sizeHint(): Bad Item kind: %d\n", kind);
02903 return QSize();
02904 }
02905 }
02906 void KLFLibViewDelegate::updateEditorGeometry(QWidget *,
02907 const QStyleOptionViewItem& ,
02908 const QModelIndex& ) const
02909 {
02910 }
02911
02912
02913 bool KLFLibViewDelegate::indexHasSelectedDescendant(const QModelIndex& parent) const
02914 {
02915 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02916 klfDbg( "\t parent="<<parent ) ;
02917
02918 if (!parent.isValid())
02919 return false;
02920
02921 QTime tm; tm.start();
02922 return func_indexHasSelectedDescendant(parent, tm, 200);
02923 }
02924
02925 bool KLFLibViewDelegate::selectionIntersectsIndexChildren(const QItemSelection& selection,
02926 const QModelIndex& parent) const
02927 {
02928 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02929 klfDbg( "selection size is "<<selection.size() ) ;
02930 int k;
02931 for (k = 0; k < selection.size(); ++k) {
02932 if (selection[k].parent() != parent)
02933 continue;
02934 if (selection[k].isValid())
02935 return true;
02936 }
02937 return false;
02938 }
02939
02940 bool KLFLibViewDelegate::func_indexHasSelectedDescendant(const QModelIndex& parent, const QTime& timer,
02941 int timeLimitMs) const
02942 {
02943 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02944 if (!parent.isValid()) {
02945 qWarning()<<KLF_FUNC_NAME<<": parent is invalid!";
02946 return false;
02947 }
02948 if (selectionIntersectsIndexChildren(pSelModel->selection(), parent)) {
02949 klfDbg( "selection under index parent="<<parent ) ;
02950 return true;
02951 }
02952 const QAbstractItemModel *model = parent.model();
02953 if (model == NULL) {
02954 qWarning()<<KLF_FUNC_NAME<<": parent has NULL model!";
02955 return false;
02956 }
02957
02958 int k;
02959 QModelIndex idx;
02960 for (k = 0; k < model->rowCount(parent); ++k) {
02961 idx = model->index(k, 0, parent);
02962
02963 if (!idx.isValid() || !model->hasChildren(idx))
02964 continue;
02965 if (func_indexHasSelectedDescendant(idx, timer, timeLimitMs))
02966 return true;
02967
02968 if (timer.elapsed() > timeLimitMs)
02969 return false;
02970
02971 }
02972 return false;
02973 }
02974
02975
02976
02977
02978
02979
02980
02981
02982 KLFLibDefaultView::KLFLibDefaultView(QWidget *parent, ViewType view)
02983 : KLFAbstractLibView(parent), pViewType(view)
02984 {
02985 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02986
02987 pModel = NULL;
02988
02989 pPreviewSizeMenu = NULL;
02990
02991 pEventFilterNoRecurse = false;
02992
02993 QVBoxLayout *lyt = new QVBoxLayout(this);
02994 lyt->setMargin(0);
02995 lyt->setSpacing(0);
02996 pDelegate = new KLFLibViewDelegate(this);
02997
02998
02999 switch (pViewType) {
03000 case CategoryTreeView:
03001 pDelegate->setPreviewSize(klfconfig.UI.labelOutputFixedSize*klfconfig.LibraryBrowser.treePreviewSizePercent/100.0);
03002 break;
03003 case ListTreeView:
03004 pDelegate->setPreviewSize(klfconfig.UI.labelOutputFixedSize*klfconfig.LibraryBrowser.listPreviewSizePercent/100.0);
03005 break;
03006 case IconView:
03007 pDelegate->setPreviewSize(klfconfig.UI.labelOutputFixedSize*klfconfig.LibraryBrowser.iconPreviewSizePercent/100.0);
03008 break;
03009 default:
03010 break;
03011 }
03012
03013 setFocusPolicy(Qt::NoFocus);
03014
03015 KLFLibDefTreeView *treeView = NULL;
03016 KLFLibDefListView *listView = NULL;
03017 switch (pViewType) {
03018 case IconView:
03019 listView = new KLFLibDefListView(this);
03020 klfDbg( "Created list view." ) ;
03021 listView->setViewMode(QListView::IconMode);
03022 listView->setSpacing(15);
03023 listView->setMovement(QListView::Free);
03024
03025 listView->setResizeMode(QListView::Adjust);
03026 klfDbg( "prepared list view." ) ;
03027 pView = listView;
03028 break;
03029 case CategoryTreeView:
03030 case ListTreeView:
03031 default:
03032 treeView = new KLFLibDefTreeView(this);
03033 treeView->setSortingEnabled(true);
03034 treeView->setIndentation(16);
03035 treeView->setAllColumnsShowFocus(true);
03036
03037 pDelegate->setTheTreeView(treeView);
03038 pView = treeView;
03039 break;
03040 };
03041
03042 lyt->addWidget(pView);
03043
03044
03045 pView->setSelectionBehavior(QAbstractItemView::SelectRows);
03046 pView->setSelectionMode(QAbstractItemView::ExtendedSelection);
03047 pView->setDragEnabled(true);
03048 pView->setDragDropMode(QAbstractItemView::DragDrop);
03049 pView->setDragDropOverwriteMode(false);
03050 pView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
03051 pView->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
03052 pView->setItemDelegate(pDelegate);
03053 pView->viewport()->installEventFilter(this);
03054 pView->installEventFilter(this);
03055 installEventFilter(this);
03056
03057 connect(pView, SIGNAL(clicked(const QModelIndex&)),
03058 this, SLOT(slotViewItemClicked(const QModelIndex&)));
03059 connect(pView, SIGNAL(doubleClicked(const QModelIndex&)),
03060 this, SLOT(slotEntryDoubleClicked(const QModelIndex&)));
03061 }
03062 KLFLibDefaultView::~KLFLibDefaultView()
03063 {
03064 }
03065
03066 QUrl KLFLibDefaultView::url() const
03067 {
03068 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
03069
03070 if (pModel == NULL)
03071 return QUrl();
03072 return pModel->url();
03073 }
03074 uint KLFLibDefaultView::compareUrlTo(const QUrl& other, uint interestFlags) const
03075 {
03076 bool baseequal = false;
03077 uint resultFlags = 0x0;
03078
03079
03080 baseequal = resourceEngine()->compareUrlTo(other, KlfUrlCompareBaseEqual);
03081 if (baseequal)
03082 resultFlags |= KlfUrlCompareBaseEqual;
03083
03084
03085 if (interestFlags & KlfUrlCompareLessSpecific) {
03086 if (!baseequal) {
03087
03088 } else {
03089
03090
03091
03092 if ( ! (resourceEngine()->supportedFeatureFlags() & KLFLibResourceEngine::FeatureSubResources) ) {
03093 resultFlags |= KlfUrlCompareLessSpecific;
03094 } else if (other.hasQueryItem("klfDefaultSubResource")) {
03095 if (resourceEngine()->compareDefaultSubResourceEquals(other.queryItemValue("klfDefaultSubResource")))
03096 resultFlags |= KlfUrlCompareLessSpecific;
03097 }
03098 }
03099 }
03100 if (interestFlags & KlfUrlCompareMoreSpecific) {
03101 if (!baseequal) {
03102
03103 } else {
03104
03105
03106
03107
03108 if (!other.hasQueryItem("klfDefaultSubResource")) {
03109 resultFlags |= KlfUrlCompareMoreSpecific;
03110 } else if (! (resourceEngine()->supportedFeatureFlags() & KLFLibResourceEngine::FeatureSubResources)) {
03111
03112 } else {
03113
03114 if (resourceEngine()->compareDefaultSubResourceEquals(other.queryItemValue("klfDefaultSubResource")))
03115 resultFlags |= KlfUrlCompareMoreSpecific;
03116 }
03117 }
03118 }
03119 if (interestFlags & KlfUrlCompareEqual) {
03120 bool wesupportsubres = (resourceEngine()->supportedFeatureFlags() & KLFLibResourceEngine::FeatureSubResources);
03121 bool hesupportssubres = other.hasQueryItem("klfDefaultSubResource");
03122 if ( wesupportsubres && hesupportssubres ) {
03123
03124 if (baseequal && resourceEngine()->compareDefaultSubResourceEquals(other.queryItemValue("klfDefaultSubResource")))
03125 resultFlags |= KlfUrlCompareEqual;
03126 } else if ( !wesupportsubres && ! hesupportssubres ) {
03127
03128 resultFlags |= KlfUrlCompareEqual;
03129 } else {
03130
03131 }
03132 }
03133
03134 klfDbg( "and the final resultFlags are"<<klfFmtCC("%#010x",resultFlags) ) ;
03135
03136 return resultFlags;
03137 }
03138
03139 class __klf_guarded_bool {
03140 bool *x;
03141 public:
03142 __klf_guarded_bool(bool *var) : x(var) { *x = true; }
03143 ~__klf_guarded_bool() { *x = false; }
03144 };
03145
03146 bool KLFLibDefaultView::event(QEvent *event)
03147 {
03148 return KLFAbstractLibView::event(event);
03149 }
03150 bool KLFLibDefaultView::eventFilter(QObject *object, QEvent *event)
03151 {
03152 if (pEventFilterNoRecurse) {
03153 klfDbg("Avoiding recursion") ;
03154 return KLFAbstractLibView::eventFilter(object, event);
03155 }
03156 __klf_guarded_bool guard_object(&pEventFilterNoRecurse);
03157
03158 if (object == pView && event->type() == QEvent::KeyPress) {
03159 QKeyEvent *ke = (QKeyEvent*)event;
03160 QKeySequence thisKey = QKeySequence(ke->key() | ke->modifiers());
03161 int k;
03162 for (k = 0; k < pViewActionsWithShortcut.size(); ++k) {
03163 QAction *a = pViewActionsWithShortcut[k];
03164 if (a->shortcut() == thisKey) {
03165 klfDbg("Activating view action "<<a->text()<<" for shortcut key "<<thisKey<<".") ;
03166 a->trigger();
03167 return true;
03168 }
03169 }
03170 }
03171 return KLFAbstractLibView::eventFilter(object, event);
03172 }
03173
03174 QList<KLFLib::entryId> KLFLibDefaultView::selectedEntryIds() const
03175 {
03176 QList<KLFLib::entryId> idListWithDupl = pModel->entryIdForIndexList(pView->selectionModel()->selectedIndexes());
03177
03178 QList<KLFLib::entryId> idList;
03179 int k;
03180 for (k = 0; k < idListWithDupl.size(); ++k) {
03181 if (!idList.contains(idListWithDupl[k]))
03182 idList << idListWithDupl[k];
03183 }
03184 return idList;
03185 }
03186
03187 KLFLibEntryList KLFLibDefaultView::selectedEntries() const
03188 {
03189 QModelIndexList selectedindexes = selectedEntryIndexes();
03190 KLFLibEntryList elist;
03191
03192 int k;
03193 for (k = 0; k < selectedindexes.size(); ++k) {
03194 if ( selectedindexes[k].data(KLFLibModel::ItemKindItemRole) != KLFLibModel::EntryKind )
03195 continue;
03196 KLFLibEntry entry = selectedindexes[k].data(KLFLibModel::FullEntryItemRole).value<KLFLibEntry>();
03197 klfDbg( "selection list: adding item [latex="<<entry.latex()<<"; tags="<<entry.tags()<<"]" ) ;
03198 elist << entry;
03199 }
03200 return elist;
03201 }
03202
03203 QList<QAction*> KLFLibDefaultView::addContextMenuActions(const QPoint& )
03204 {
03205 QList<QAction*> actionList = QList<QAction*>() << pCommonActions;
03206 if (pViewType == IconView) {
03207 actionList << pIconViewActions;
03208 }
03209 if (pViewType == CategoryTreeView || pViewType == ListTreeView) {
03210 actionList << pShowColumnActions;
03211 }
03212 return actionList;
03213 }
03214
03215
03216 QVariantMap KLFLibDefaultView::saveGuiState() const
03217 {
03218 QVariantMap vst;
03219 if (pViewType == CategoryTreeView || pViewType == ListTreeView) {
03220 QTreeView *tv = qobject_cast<QTreeView*>(pView);
03221 KLF_ASSERT_NOT_NULL( tv, "Tree View is NULL in view type "<<pViewType<<" !!", return QVariantMap() )
03222 ;
03223 vst["ColumnsState"] = QVariant::fromValue<QByteArray>(tv->header()->saveState());
03224 }
03225 if (pViewType == IconView) {
03226
03227 }
03228 vst["IconPreviewSize"] = QVariant::fromValue<QSize>(previewSize());
03229 return vst;
03230 }
03231 bool KLFLibDefaultView::restoreGuiState(const QVariantMap& vstate)
03232 {
03233 if (pViewType == CategoryTreeView || pViewType == ListTreeView) {
03234 QByteArray colstate = vstate["ColumnsState"].toByteArray();
03235 QTreeView *tv = qobject_cast<QTreeView*>(pView);
03236 KLF_ASSERT_NOT_NULL( tv, "Tree View is NULL in view type"<<pViewType<<"!!", return false )
03237 ;
03238 tv->header()->restoreState(colstate);
03239 }
03240 if (pViewType == IconView) {
03241
03242 }
03243 setPreviewSize(vstate["IconPreviewSize"].value<QSize>());
03244 return true;
03245 }
03246
03247 QModelIndex KLFLibDefaultView::currentVisibleIndex() const
03248 {
03249 QModelIndex index;
03250 if (pViewType == IconView) {
03251 KLFLibDefListView *lv = qobject_cast<KLFLibDefListView*>(pView);
03252 KLF_ASSERT_NOT_NULL( lv, "KLFLibDefListView List View is NULL in view type "<<pViewType<<" !!",
03253 return QModelIndex() )
03254 ;
03255 index = lv->curVisibleIndex();
03256 } else if (pViewType == CategoryTreeView || pViewType == ListTreeView) {
03257 KLFLibDefTreeView *tv = qobject_cast<KLFLibDefTreeView*>(pView);
03258 KLF_ASSERT_NOT_NULL( tv, "KLFLibDefTreeView List View is NULL in view type "<<pViewType<<" !!",
03259 return QModelIndex() )
03260 ;
03261 index = tv->curVisibleIndex();
03262 } else {
03263 index = QModelIndex();
03264 }
03265 return index;
03266 }
03267
03268
03269 #ifdef KLF_DEBUG_USE_MODELTEST
03270 #include <modeltest.h>
03271 #endif
03272
03273 void KLFLibDefaultView::updateResourceEngine()
03274 {
03275 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
03276
03277 int k;
03278 KLFLibResourceEngine *resource = resourceEngine();
03279 if (resource == NULL) {
03280 pModel = NULL;
03281 pView->setModel(NULL);
03282 for (k = 0; k < pShowColumnActions.size(); ++k)
03283 delete pShowColumnActions[k];
03284 pShowColumnActions.clear();
03285 }
03286
03287
03288 uint model_flavor = 0;
03289 switch (pViewType) {
03290 case IconView:
03291 case ListTreeView:
03292 model_flavor = KLFLibModel::LinearList;
03293 break;
03294 case CategoryTreeView:
03295 default:
03296 model_flavor = KLFLibModel::CategoryTree;
03297 break;
03298 };
03299
03300
03301 setGroupSubCategories(klfconfig.LibraryBrowser.groupSubCategories);
03302
03303 if (pGroupSubCategories)
03304 model_flavor |= KLFLibModel::GroupSubCategories;
03305
03306 pModel = new KLFLibModel(resource, model_flavor, this);
03307 pView->setModel(pModel);
03308
03309 KLF_DEBUG_ASSIGN_SAME_REF_INSTANCE(pModel) ;
03310
03311 klfDbg("created model. pModel="<<klfFmtCC("%p", (void*)pModel)<<"; view type="<<pViewType);
03312
03313 #ifdef KLF_DEBUG_USE_MODELTEST
03314 new ModelTest(pModel, this);
03315 #endif
03316
03317 if (pViewType == IconView) {
03318 qobject_cast<KLFLibDefListView*>(pView)->modelInitialized();
03319 } else {
03320 qobject_cast<KLFLibDefTreeView*>(pView)->modelInitialized();
03321 }
03322
03323
03324 QItemSelectionModel *s = pView->selectionModel();
03325 connect(s, SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
03326 this, SLOT(slotViewSelectionChanged(const QItemSelection&, const QItemSelection&)));
03327
03328 connect(pModel, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),
03329 this, SLOT(slotResourceDataChanged(const QModelIndex&, const QModelIndex&)));
03330
03331
03332 connect(pModel, SIGNAL(operationStartReportingProgress(KLFProgressReporter *, const QString&)),
03333 this, SIGNAL(operationStartReportingProgress(KLFProgressReporter *, const QString&)));
03334
03335
03336
03337 pDelegate->setSelectionModel(s);
03338
03339 QKeySequence selectAllKey = QKeySequence::SelectAll;
03340 QKeySequence refreshKey = QKeySequence::Refresh;
03341 QAction *selectAllAction = new QAction(tr("Select All", "[[menu action]]"), pView);
03342 selectAllAction->setShortcut(selectAllKey);
03343 connect(selectAllAction, SIGNAL(triggered()), this, SLOT(slotSelectAll()));
03344 QAction *refreshAction = new QAction(tr("Refresh", "[[menu action]]"), pView);
03345 refreshAction->setShortcut(refreshKey);
03346 connect(refreshAction, SIGNAL(triggered()), this, SLOT(slotRefresh()));
03347
03348 QActionGroup * ag = new QActionGroup(pView);
03349 ag->setExclusive(true);
03350 QAction *aPreviewSizeLarge = new QAction(tr("Large", "[[icon preview size menu item]]"), ag);
03351 aPreviewSizeLarge->setCheckable(true);
03352 aPreviewSizeLarge->setData(100);
03353 connect(aPreviewSizeLarge, SIGNAL(triggered()), this, SLOT(slotPreviewSizeFromActionSender()));
03354 QAction *aPreviewSizeMedium = new QAction(tr("Medium", "[[icon preview size menu item]]"), ag);
03355 aPreviewSizeMedium->setCheckable(true);
03356 aPreviewSizeMedium->setData(75);
03357 connect(aPreviewSizeMedium, SIGNAL(triggered()), this, SLOT(slotPreviewSizeFromActionSender()));
03358 QAction *aPreviewSizeSmall = new QAction(tr("Small", "[[icon preview size menu item]]"), ag);
03359 aPreviewSizeSmall->setCheckable(true);
03360 aPreviewSizeSmall->setData(50);
03361 connect(aPreviewSizeSmall, SIGNAL(triggered()), this, SLOT(slotPreviewSizeFromActionSender()));
03362
03363 pPreviewSizeMenu = new QMenu(this);
03364 pPreviewSizeMenu->addAction(aPreviewSizeLarge);
03365 pPreviewSizeMenu->addAction(aPreviewSizeMedium);
03366 pPreviewSizeMenu->addAction(aPreviewSizeSmall);
03367
03368 QAction *aPreviewSize = new QAction(tr("Icon Size", "[[icon preview size option menu]]"), pView);
03369 aPreviewSize->setMenu(pPreviewSizeMenu);
03370
03371 slotPreviewSizeActionsRefreshChecked();
03372
03373 pCommonActions = QList<QAction*>() << selectAllAction << refreshAction << aPreviewSize;
03374 pViewActionsWithShortcut << selectAllAction << refreshAction;
03375
03376 if (pViewType == IconView) {
03377 klfDbg( "About to prepare iconview." ) ;
03378 QAction * iconViewRelayoutAction = new QAction(tr("Relayout All Icons", "[[menu action]]"), this);
03379 connect(iconViewRelayoutAction, SIGNAL(triggered()), this, SLOT(slotRelayoutIcons()));
03380 pIconViewActions = QList<QAction*>() << iconViewRelayoutAction ;
03381 }
03382 if (pViewType == CategoryTreeView || pViewType == ListTreeView) {
03383 QTreeView *treeView = qobject_cast<QTreeView*>(pView);
03384
03385 treeView->setColumnHidden(pModel->columnForEntryPropertyId(KLFLibEntry::Preview), false);
03386 treeView->setColumnHidden(pModel->columnForEntryPropertyId(KLFLibEntry::Latex), true);
03387 treeView->setColumnHidden(pModel->columnForEntryPropertyId(KLFLibEntry::Tags), false);
03388 treeView->setColumnHidden(pModel->columnForEntryPropertyId(KLFLibEntry::Category), true);
03389 treeView->setColumnHidden(pModel->columnForEntryPropertyId(KLFLibEntry::DateTime), true);
03390
03391 for (k = 0; k < pModel->columnCount(); ++k)
03392 treeView->resizeColumnToContents(k);
03393 treeView->setColumnWidth(0, 35+treeView->columnWidth(0));
03394
03395 int col;
03396 QMenu *colMenu = new QMenu(this);
03397 for (col = 0; col < pModel->columnCount(); ++col) {
03398 QString title = pModel->headerData(col, Qt::Horizontal, Qt::DisplayRole).toString();
03399 QAction *a;
03400 a = new QAction(title, this);
03401 a->setProperty("klfModelColumn", col);
03402 a->setCheckable(true);
03403 a->setChecked(!treeView->isColumnHidden(col));
03404 connect(a, SIGNAL(toggled(bool)), this, SLOT(slotShowColumnSenderAction(bool)));
03405 colMenu->addAction(a);
03406 }
03407 QAction *menuAction = new QAction(tr("Show/Hide Columns", "[[menu with sub-menu]]"), this);
03408 menuAction->setMenu(colMenu);
03409 pShowColumnActions = QList<QAction*>() << menuAction;
03410
03411
03412 int numRootItems = pModel->rowCount(QModelIndex());
03413 for (k = 0; k < pModel->rowCount(QModelIndex()); ++k) {
03414 QModelIndex i = pModel->index(k, 0, QModelIndex());
03415 if (pModel->rowCount(i) < 6 || numRootItems < 6)
03416 treeView->expand(i);
03417 }
03418 }
03419
03420 updateResourceProp(-1);
03421 updateResourceOwnData(QList<KLFLib::entryId>());
03422
03423 wantMoreCategorySuggestions();
03424 }
03425
03426 void KLFLibDefaultView::updateResourceData(const QString& subRes, int modifyType,
03427 const QList<KLFLib::entryId>& entryIdList)
03428 {
03429 KLF_ASSERT_NOT_NULL( pModel , "Model is NULL!" , return )
03430 ;
03431 klfDbg("The resource modified its data [type="<<modifyType<<"] in subres="<<subRes<<". Our subres="<<resourceEngine()->defaultSubResource()<<"; matches?="<<resourceEngine()->compareDefaultSubResourceEquals(subRes));
03432 if (!resourceEngine()->compareDefaultSubResourceEquals(subRes))
03433 return;
03434 pModel->updateData(entryIdList, modifyType);
03435
03436 updateResourceOwnData(entryIdList);
03437 }
03438 void KLFLibDefaultView::updateResourceOwnData(const QList<KLFLib::entryId>& )
03439 {
03441 klfDbg( KLF_FUNC_NAME ) ;
03442 if (pViewType == IconView) {
03443
03444 }
03445 }
03446 void KLFLibDefaultView::updateResourceProp(int propId)
03447 {
03448 klfDbg( "propId="<<propId ) ;
03449
03450 KLF_ASSERT_NOT_NULL( resourceEngine() , "Resource Engine is NULL, skipping !" , return ) ;
03451
03452
03453 }
03454
03455 void KLFLibDefaultView::showEvent(QShowEvent *event)
03456 {
03457 if (pModel)
03458 pModel->setFetchBatchCount(80);
03459 }
03460
03461
03462 QListView::Flow KLFLibDefaultView::iconViewFlow() const
03463 {
03464 if (pViewType == IconView) {
03465 KLFLibDefListView *lv = qobject_cast<KLFLibDefListView*>(pView);
03466 KLF_ASSERT_NOT_NULL( lv, "KLFLibDefListView List View is NULL in view type "<<pViewType<<" !!",
03467 return QListView::TopToBottom)
03468 ;
03469 return lv->flow();
03470 }
03471 qWarning()<<KLF_FUNC_NAME<<": requesting icon view flow in the wrong mode `"<<pViewType
03472 <<"'. Should only be called for icon view modes.";
03473 return QListView::TopToBottom;
03474 }
03475
03476
03477 QStringList KLFLibDefaultView::getCategorySuggestions()
03478 {
03479 return pModel->categoryList();
03480 }
03481
03482
03483
03484
03485
03486
03487
03488
03489
03490
03491
03492
03493
03494
03495
03496
03497
03498
03499
03500
03501
03502
03503
03504
03505
03506 bool KLFLibDefaultView::selectEntries(const QList<KLFLib::entryId>& idList)
03507 {
03508 klfDbg("selecting entries: "<<idList) ;
03509
03510 QModelIndexList mil = pModel->findEntryIdList(idList);
03511 QItemSelection sel;
03512 int k;
03513 for (k = 0; k < mil.size(); ++k)
03514 sel << QItemSelectionRange(mil[k]);
03515
03516 pView->selectionModel()->select(sel, QItemSelectionModel::ClearAndSelect);
03517
03518 if (pViewType == CategoryTreeView && pView->inherits("KLFLibDefTreeView")) {
03519 KLFLibDefTreeView *v = qobject_cast<KLFLibDefTreeView*>(pView);
03520 v->ensureExpandedTo(mil);
03521 }
03522 return true;
03523 }
03524
03525
03526
03527 void KLFLibDefaultView::restore(uint restoreflags)
03528 {
03529 QModelIndexList sel = selectedEntryIndexes();
03530 if (sel.size() != 1) {
03531 qWarning("KLFLibDefaultView::restoreWithStyle(): Cannot restore: %d items selected.", sel.size());
03532 return;
03533 }
03534
03535 KLFLibEntry e = sel[0].data(KLFLibModel::FullEntryItemRole).value<KLFLibEntry>();
03536
03537 emit requestRestore(e, restoreflags);
03538 }
03539
03540 void KLFLibDefaultView::showColumns(int propIdColumn, bool show)
03541 {
03542 if ( ! pView->inherits("QTreeView") ) {
03543 qWarning("KLFLibDefaultView::showColumns(%d,%s): Resource view for %s: view does not inherit QTreeView!",
03544 propIdColumn, show?"[show]":"[hide]", qPrintable(resourceEngine()->url().toString()));
03545 return;
03546 }
03547 int colNo = pModel->columnForEntryPropertyId(propIdColumn);
03548 qobject_cast<QTreeView*>(pView)->setColumnHidden(colNo, show);
03549 }
03550
03551 void KLFLibDefaultView::sortBy(int propIdColumn, Qt::SortOrder sortorder)
03552 {
03553 if ( ! pView->inherits("QTreeView") ) {
03554 qWarning("KLFLibDefaultView::showBy(%d,%s): Resource view for %s: view does not inherit QTreeView!",
03555 propIdColumn, (sortorder == Qt::AscendingOrder)?"[Ascending]":"[Descending]" ,
03556 qPrintable(resourceEngine()->url().toString()));
03557 return;
03558 }
03559 QTreeView * tree = qobject_cast<QTreeView*>(pView);
03560 int colNo = pModel->columnForEntryPropertyId(propIdColumn);
03561 if (colNo < 0 || colNo >= pModel->columnCount()) {
03562 qWarning("KLFLibDefaultView::showBy(%d,%s): column number %d is not valid or hidden!",
03563 propIdColumn, (sortorder == Qt::AscendingOrder)?"[Ascending]":"[Descending]", colNo);
03564 return;
03565 }
03566 tree->sortByColumn(colNo, sortorder);
03567 }
03568
03569
03570 void KLFLibDefaultView::slotSelectAll(bool expandItems)
03571 {
03572 slotSelectAll( QModelIndex(), NoSignals | (expandItems?ExpandItems:0) );
03573 updateDisplay();
03574 }
03575 void KLFLibDefaultView::slotSelectAll(const QModelIndex& parent, uint selectAllFlags)
03576 {
03577 KLFDelayedPleaseWaitPopup pleaseWait(tr("Fetching and selecting all, please wait ..."), this);
03578 pleaseWait.setDisableUi(true);
03579 pleaseWait.setDelay(500);
03580
03581 if (selectAllFlags & NoSignals)
03582 pView->selectionModel()->blockSignals(true);
03583
03584 QTime tm;
03585 tm.start();
03586 func_selectAll(parent, selectAllFlags, &tm, &pleaseWait);
03587
03588 if (selectAllFlags & NoSignals)
03589 pView->selectionModel()->blockSignals(false);
03590
03591 emit entriesSelected(selectedEntries());
03592 updateDisplay();
03593 }
03594
03595
03596 bool KLFLibDefaultView::func_selectAll(const QModelIndex& parent, uint selectAllFlags, QTime *tm,
03597 KLFDelayedPleaseWaitPopup *pleaseWait)
03598 {
03599 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
03600
03601
03602 while (pModel->canFetchMore(parent)) {
03603 pModel->fetchMore(parent);
03604 pleaseWait->process();
03605 if (pleaseWait->wasUserDiscarded())
03606 return false;
03607 if (tm->elapsed() > 300) {
03608
03609 qApp->processEvents();
03610 tm->restart();
03611 }
03612 }
03613
03614 int k;
03615 QModelIndex topLeft = pModel->index(0, 0, parent);
03616 QModelIndex bottomRight = pModel->index(pModel->rowCount(parent)-1,
03617 pModel->columnCount(parent)-1, parent);
03618 pView->selectionModel()->select(QItemSelection(topLeft, bottomRight), QItemSelectionModel::Select);
03619 if ( ! pModel->hasChildren(parent) )
03620 return true;
03621
03622 if (selectAllFlags & ExpandItems) {
03623 QTreeView *treeView = pView->inherits("QTreeView") ? qobject_cast<QTreeView*>(pView) : NULL;
03624 if (treeView != NULL)
03625 treeView->expand(parent);
03626 }
03627
03628 for (k = 0; k < pModel->rowCount(parent); ++k) {
03629 QModelIndex child = pModel->index(k, 0, parent);
03630 if ( ! func_selectAll(child, selectAllFlags, tm, pleaseWait) )
03631 return false;
03632 if (tm->elapsed() > 300) {
03633 qApp->processEvents();
03634 pleaseWait->process();
03635 if (pleaseWait->wasUserDiscarded())
03636 return false;
03637 tm->restart();
03638 }
03639 }
03640
03641 return true;
03642 }
03643
03644 void KLFLibDefaultView::slotRefresh()
03645 {
03646 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
03647 pModel->completeRefresh();
03648 }
03649
03650 void KLFLibDefaultView::slotPreviewSizeFromActionSender()
03651 {
03652 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
03653 QAction *a = qobject_cast<QAction*>(sender());
03654 KLF_ASSERT_NOT_NULL(a, "action sender is NULL!", return ; ) ;
03655
03656 pDelegate->setPreviewSize(klfconfig.UI.labelOutputFixedSize * a->data().toInt() / 100.0);
03657 pView->reset();
03658
03659 slotPreviewSizeActionsRefreshChecked();
03660 }
03661
03662 void KLFLibDefaultView::slotPreviewSizeActionsRefreshChecked()
03663 {
03664 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
03665
03666 KLF_ASSERT_NOT_NULL(pPreviewSizeMenu, "pPreviewSizeMenu is NULL!", return ) ;
03667
03668 int curPreviewSizePercent
03669 = pDelegate->previewSize().width() * 100 / klfconfig.UI.labelOutputFixedSize.width();
03670
03671 curPreviewSizePercent = (int)(curPreviewSizePercent/5 +0.5)*5;
03672
03673 QList<QAction*> alist = pPreviewSizeMenu->actions();
03674 klfDbg("There are "<<alist.size()<<" actions...") ;
03675 for (QList<QAction*>::iterator it = alist.begin(); it != alist.end(); ++it) {
03676 QAction *a = (*it);
03677 int a_sz = (int)(a->data().toInt()/5 +0.5)*5;
03678 klfDbg("Processing action "<< a->text() << " (data="<<a->data().toInt()<<" ~= "<<a_sz
03679 <<") curPreviewSizePercent="<<curPreviewSizePercent) ;
03680
03681 if ( a_sz == curPreviewSizePercent )
03682 a->setChecked(true);
03683 else
03684 a->setChecked(false);
03685 }
03686 }
03687
03688
03689 void KLFLibDefaultView::slotRelayoutIcons()
03690 {
03691 if (pViewType != IconView || !pView->inherits("KLFLibDefListView")) {
03692 return;
03693 }
03694 KLFLibDefListView *lv = qobject_cast<KLFLibDefListView*>(pView);
03695
03696 lv->forceRelayout();
03697 }
03698
03699 void KLFLibDefaultView::setIconViewFlow(QListView::Flow flow)
03700 {
03701 if (pViewType == IconView) {
03702 KLFLibDefListView *lv = qobject_cast<KLFLibDefListView*>(pView);
03703 KLF_ASSERT_NOT_NULL( lv, "KLFLibDefListView List View is NULL in view type "<<pViewType<<" !!",
03704 return )
03705 ;
03706
03707 lv->setFlow(flow);
03708 }
03709 }
03710
03711 void KLFLibDefaultView::updateDisplay()
03712 {
03713 KLF_ASSERT_NOT_NULL(pView, "view is NULL!", return ) ;
03714 pView->viewport()->update();
03715 }
03716
03717 bool KLFLibDefaultView::searchFind(const QString& queryString, bool forward)
03718 {
03719 QModelIndex fromIndex = currentVisibleIndex();
03720
03721 fromIndex = pModel->walkPrevIndex(fromIndex);
03722 QModelIndex i = pModel->searchFind(queryString, fromIndex, forward);
03723 pDelegate->setSearchString(queryString);
03724
03725
03726 searchFound(i);
03727 return i.isValid();
03728 }
03729
03730 bool KLFLibDefaultView::searchFindNext(bool forward)
03731 {
03732 QModelIndex i = pModel->searchFindNext(forward);
03733 searchFound(i);
03734 return i.isValid();
03735 }
03736
03737 void KLFLibDefaultView::searchAbort()
03738 {
03739 pModel->searchAbort();
03740 pDelegate->setSearchString(QString());
03741 pDelegate->setSearchIndex(QModelIndex());
03742 updateDisplay();
03743
03744
03745
03746 }
03747
03748
03749 void KLFLibDefaultView::searchFound(const QModelIndex& i)
03750 {
03751 pDelegate->setSearchIndex(i);
03752 if ( ! i.isValid() ) {
03753 pView->scrollToTop();
03754
03755 pView->selectionModel()->setCurrentIndex(QModelIndex(), QItemSelectionModel::Clear);
03756 return;
03757 } else {
03758 pView->scrollTo(i, QAbstractItemView::EnsureVisible);
03759 }
03760 if (pViewType == CategoryTreeView) {
03761
03762 qobject_cast<QTreeView*>(pView)->expand(i);
03763 }
03764
03765 pView->selectionModel()->setCurrentIndex(i,
03766 QItemSelectionModel::ClearAndSelect|
03767 QItemSelectionModel::Rows);
03768 updateDisplay();
03769 }
03770
03771
03772 void KLFLibDefaultView::slotViewSelectionChanged(const QItemSelection& ,
03773 const QItemSelection& )
03774 {
03775 #ifndef Q_WS_WIN
03776
03777
03778 updateDisplay();
03779 #endif
03780
03781 emit entriesSelected(selectedEntries());
03782 }
03783
03784 void KLFLibDefaultView::slotResourceDataChanged(const QModelIndex& topLeft,
03785 const QModelIndex& bottomRight)
03786 {
03787 QItemSelectionRange rng = QItemSelectionRange(topLeft, bottomRight);
03788 QModelIndexList indexes = rng.indexes();
03789 QList<KLFLib::entryId> eids = pModel->entryIdForIndexList(indexes);
03790 emit resourceDataChanged(eids);
03791 }
03792
03793
03794
03795
03796
03797
03798
03799
03800
03801
03802
03803
03804
03805
03806
03807
03808
03809
03810
03811
03812
03813
03814
03815
03816
03817
03818
03819
03820
03821
03822
03823
03824
03825
03826
03827
03828
03829
03830
03831
03832
03833
03834
03835
03836
03837
03838
03839
03840
03841
03842 void KLFLibDefaultView::slotViewItemClicked(const QModelIndex& index)
03843 {
03844 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
03845
03846 if (index.column() != 0)
03847 return;
03848
03849 slotSelectAll(index, ExpandItems);
03850
03851
03852
03853
03854
03855
03856
03857
03858
03859 }
03860 void KLFLibDefaultView::slotEntryDoubleClicked(const QModelIndex& index)
03861 {
03862 if (index.data(KLFLibModel::ItemKindItemRole).toInt() != KLFLibModel::EntryKind)
03863 return;
03864 emit requestRestore(index.data(KLFLibModel::FullEntryItemRole).value<KLFLibEntry>(),
03865 KLFLib::RestoreLatex|KLFLib::RestoreStyle);
03866 }
03867
03868
03869
03870
03871
03872
03873
03874
03875
03876
03877 void KLFLibDefaultView::slotShowColumnSenderAction(bool showCol)
03878 {
03879 QObject *a = sender();
03880 if (a == NULL)
03881 return;
03882
03883 if ( ! pView->inherits("QTreeView") )
03884 return;
03885 int colNo = a->property("klfModelColumn").toInt();
03886 qobject_cast<QTreeView*>(pView)->setColumnHidden(colNo, !showCol);
03887 }
03888
03889
03890
03891
03892 QModelIndexList KLFLibDefaultView::selectedEntryIndexes() const
03893 {
03896 QModelIndexList selection = pView->selectionModel()->selectedIndexes();
03897 QModelIndexList entryindexes;
03898 int k;
03899 QList<KLFLib::entryId> doneEntryIds;
03900
03901 for (k = 0; k < selection.size(); ++k) {
03902 KLFLib::entryId eid = selection[k].data(KLFLibModel::EntryIdItemRole).toInt();
03903 int iPos = qLowerBound(doneEntryIds.begin(), doneEntryIds.end(), eid) - doneEntryIds.begin();
03904 if ( iPos < doneEntryIds.size() && doneEntryIds[iPos] == eid )
03905 continue;
03906 doneEntryIds.insert(iPos, eid);
03907 entryindexes << selection[k];
03908 }
03909 return entryindexes;
03910 }
03911
03912
03913
03914
03915
03916 static QStringList defaultViewTypeIds = QStringList()<<"default"<<"default+list"<<"default+icons";
03917
03918
03919 KLFLibDefaultViewFactory::KLFLibDefaultViewFactory(QObject *parent)
03920 : KLFLibViewFactory(defaultViewTypeIds, parent)
03921 {
03922 }
03923
03924
03925 QString KLFLibDefaultViewFactory::viewTypeTitle(const QString& viewTypeIdent) const
03926 {
03927 if (viewTypeIdent == "default")
03928 return tr("Category Tree View");
03929 if (viewTypeIdent == "default+list")
03930 return tr("List View");
03931 if (viewTypeIdent == "default+icons")
03932 return tr("Icon View");
03933
03934 return QString();
03935 }
03936
03937
03938 KLFAbstractLibView * KLFLibDefaultViewFactory::createLibView(const QString& viewTypeIdent,
03939 QWidget *parent,
03940 KLFLibResourceEngine *resourceEngine)
03941 {
03942 KLFLibDefaultView::ViewType v = KLFLibDefaultView::CategoryTreeView;
03943 if (viewTypeIdent == "default")
03944 v = KLFLibDefaultView::CategoryTreeView;
03945 else if (viewTypeIdent == "default+list")
03946 v = KLFLibDefaultView::ListTreeView;
03947 else if (viewTypeIdent == "default+icons")
03948 v = KLFLibDefaultView::IconView;
03949
03950 KLFLibDefaultView *view = new KLFLibDefaultView(parent, v);
03951 view->setResourceEngine(resourceEngine);
03952 return view;
03953 }
03954
03955
03956
03957
03958
03959
03960 KLFLibOpenResourceDlg::KLFLibOpenResourceDlg(const QUrl& defaultlocation, QWidget *parent)
03961 : QDialog(parent)
03962 {
03963 pUi = new Ui::KLFLibOpenResourceDlg;
03964 pUi->setupUi(this);
03965 setWindowIcon(QPixmap(":/pics/klatexformula-64.png"));
03966
03967
03968 KLFLibEngineFactory *efactory = NULL;
03969 if (!defaultlocation.isEmpty())
03970 KLFLibEngineFactory::findFactoryFor(defaultlocation.scheme());
03971 QString defaultwtype;
03972 if (efactory == NULL) {
03973 if (!defaultlocation.isEmpty())
03974 qWarning()<<"No Factory for URL "<<defaultlocation<<"'s scheme!";
03975 } else {
03976 defaultwtype = efactory->correspondingWidgetType(defaultlocation.scheme());
03977 }
03978
03979
03980 QStringList wtypeList = KLFLibWidgetFactory::allSupportedWTypes();
03981 int k;
03982 for (k = 0; k < wtypeList.size(); ++k) {
03983 qDebug("KLFLibOpenRes.Dlg::[constr.]() Adding widget for wtype %s", qPrintable(wtypeList[k]));
03984 KLFLibWidgetFactory *factory = KLFLibWidgetFactory::findFactoryFor(wtypeList[k]);
03985 QUrl thisdefaultlocation;
03986 if (wtypeList[k] == defaultwtype)
03987 thisdefaultlocation = defaultlocation;
03988 QWidget *openWidget = factory->createPromptUrlWidget(pUi->stkOpenWidgets, wtypeList[k],
03989 thisdefaultlocation);
03990 pUi->stkOpenWidgets->insertWidget(k, openWidget);
03991 pUi->cbxType->insertItem(k, factory->widgetTypeTitle(wtypeList[k]),
03992 QVariant::fromValue(wtypeList[k]));
03993
03994 connect(openWidget, SIGNAL(readyToOpen(bool)), this, SLOT(updateReadyToOpenFromSender(bool)));
03995 }
03996
03997 if (defaultwtype.isEmpty()) {
03998 pUi->cbxType->setCurrentIndex(0);
03999 pUi->stkOpenWidgets->setCurrentIndex(0);
04000 } else {
04001 pUi->cbxType->setCurrentIndex(k = wtypeList.indexOf(defaultwtype));
04002 pUi->stkOpenWidgets->setCurrentIndex(k);
04003 }
04004
04005 btnGo = pUi->btnBar->button(QDialogButtonBox::Open);
04006
04007 connect(pUi->cbxType, SIGNAL(activated(int)), this, SLOT(updateReadyToOpen()));
04008 updateReadyToOpen();
04009 }
04010
04011 KLFLibOpenResourceDlg::~KLFLibOpenResourceDlg()
04012 {
04013 delete pUi;
04014 }
04015
04016 QUrl KLFLibOpenResourceDlg::retrieveRawUrl() const
04017 {
04018 int k = pUi->cbxType->currentIndex();
04019 QString wtype = pUi->cbxType->itemData(k).toString();
04020 KLFLibWidgetFactory *factory
04021 = KLFLibWidgetFactory::findFactoryFor(wtype);
04022 return factory->retrieveUrlFromWidget(wtype, pUi->stkOpenWidgets->widget(k));
04023 }
04024
04025 QUrl KLFLibOpenResourceDlg::url() const
04026 {
04027 QUrl url = retrieveRawUrl();
04028 if (url.isEmpty()) {
04029
04030 return QUrl();
04031 }
04032 if (pUi->chkReadOnly->isChecked())
04033 url.addQueryItem("klfReadOnly", "true");
04034 if (pUi->cbxSubResource->count())
04035 url.addQueryItem("klfDefaultSubResource",
04036 pUi->cbxSubResource->itemData(pUi->cbxSubResource->currentIndex()).toString());
04037 klfDbg( "Got URL: "<<url ) ;
04038 return url;
04039 }
04040
04041 void KLFLibOpenResourceDlg::updateReadyToOpenFromSender(bool isready)
04042 {
04043 QObject *w = sender();
04044
04045 w->setProperty("__klflibopenresourcedlg_readyToOpen", isready);
04046 updateReadyToOpen();
04047 }
04048 void KLFLibOpenResourceDlg::updateReadyToOpen()
04049 {
04050 QWidget *w = pUi->stkOpenWidgets->currentWidget();
04051 KLF_ASSERT_NOT_NULL( w, "widget is NULL!", return ) ;
04052
04053 bool w_is_ready = w->property("readyToOpen").toBool();
04054 if (!w_is_ready) {
04055
04056
04057 QVariant v = w->property("__klflibopenresourcedlg_readyToOpen");
04058 if (v.isValid())
04059 w_is_ready = v.toBool();
04060 }
04061 btnGo->setEnabled(w_is_ready);
04062
04063 pUi->frmSubResource->show();
04064 pUi->cbxSubResource->clear();
04065 if (!w_is_ready) {
04066 pUi->frmSubResource->hide();
04067 } else {
04068
04069 QMap<QString,QString> subResMap = KLFLibEngineFactory::listSubResourcesWithTitles(retrieveRawUrl());
04070 if (subResMap.isEmpty()) {
04071 pUi->frmSubResource->hide();
04072 } else {
04073 for (QMap<QString,QString>::const_iterator it = subResMap.begin(); it != subResMap.end(); ++it) {
04074 QString subres = it.key();
04075 QString subrestitle = it.value();
04076 if (subrestitle.isEmpty())
04077 subrestitle = subres;
04078 pUi->cbxSubResource->addItem(subrestitle, QVariant(subres));
04079 }
04080 }
04081 }
04082 }
04083
04084
04085 QUrl KLFLibOpenResourceDlg::queryOpenResource(const QUrl& defaultlocation, QWidget *parent)
04086 {
04087 KLFLibOpenResourceDlg dlg(defaultlocation, parent);
04088 int result = dlg.exec();
04089 if (result != QDialog::Accepted)
04090 return QUrl();
04091 QUrl url = dlg.url();
04092 return url;
04093 }
04094
04095
04096
04097
04098
04099
04100 KLFLibCreateResourceDlg::KLFLibCreateResourceDlg(const QString& defaultWtype, QWidget *parent)
04101 : QDialog(parent)
04102 {
04103 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
04104
04105 pUi = new Ui::KLFLibOpenResourceDlg;
04106 pUi->setupUi(this);
04107 setWindowIcon(QPixmap(":/pics/klatexformula-64.png"));
04108
04109 pUi->lblMain->setText(tr("Create New Library Resource", "[[dialog label title]]"));
04110 setWindowTitle(tr("Create New Library Resource", "[[dialog window title]]"));
04111 pUi->chkReadOnly->hide();
04112
04113 pUi->cbxSubResource->setEnabled(true);
04114 pUi->cbxSubResource->setEditable(true);
04115 pUi->cbxSubResource->setEditText(tr("SubResource1"));
04116
04117 pUi->btnBar->setStandardButtons(QDialogButtonBox::Save|QDialogButtonBox::Cancel);
04118 btnGo = pUi->btnBar->button(QDialogButtonBox::Save);
04119
04120 int defaultIndex = 0;
04121
04122 QStringList wtypeList = KLFLibWidgetFactory::allSupportedWTypes();
04123 int k;
04124 for (k = 0; k < wtypeList.size(); ++k) {
04125 KLFLibWidgetFactory *factory
04126 = KLFLibWidgetFactory::findFactoryFor(wtypeList[k]);
04127 QWidget *createResWidget =
04128 factory->createPromptCreateParametersWidget(pUi->stkOpenWidgets, wtypeList[k],
04129 Parameters());
04130 pUi->stkOpenWidgets->insertWidget(k, createResWidget);
04131 pUi->cbxType->insertItem(k, factory->widgetTypeTitle(wtypeList[k]),
04132 QVariant::fromValue(wtypeList[k]));
04133
04134 if (wtypeList[k] == defaultWtype)
04135 defaultIndex = k;
04136
04137 connect(createResWidget, SIGNAL(readyToCreate(bool)),
04138 this, SLOT(updateReadyToCreateFromSender(bool)));
04139 klfDbg("Added create-res-widget of type "<<wtypeList[k]) ;
04140 }
04141
04142 pUi->cbxType->setCurrentIndex(defaultIndex);
04143 pUi->stkOpenWidgets->setCurrentIndex(defaultIndex);
04144
04145 connect(pUi->cbxType, SIGNAL(activated(int)), this, SLOT(updateReadyToCreate()));
04146 updateReadyToCreate();
04147 }
04148 KLFLibCreateResourceDlg::~KLFLibCreateResourceDlg()
04149 {
04150 delete pUi;
04151 }
04152
04153 KLFLibEngineFactory::Parameters KLFLibCreateResourceDlg::getCreateParameters() const
04154 {
04155 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
04156
04157 int k = pUi->cbxType->currentIndex();
04158 QString wtype = pUi->cbxType->itemData(k).toString();
04159 KLFLibWidgetFactory *factory
04160 = KLFLibWidgetFactory::findFactoryFor(wtype);
04161 Parameters p = factory->retrieveCreateParametersFromWidget(wtype, pUi->stkOpenWidgets->widget(k));
04162 p["klfWidgetType"] = wtype;
04163 p["klfDefaultSubResource"] = pUi->cbxSubResource->currentText();
04164 p["klfDefaultSubResourceTitle"] = pUi->cbxSubResource->currentText();
04165
04166 klfDbg("Create parameters are: "<<p) ;
04167
04168 return p;
04169 }
04170
04171
04172 void KLFLibCreateResourceDlg::accept()
04173 {
04174 const Parameters p = getCreateParameters();
04175 if (p == Parameters() || p["klfCancel"].toBool() == true) {
04176 QDialog::reject();
04177 return;
04178 }
04179 if (p["klfRetry"].toBool() == true)
04180 return;
04181
04182
04183
04184
04185 pParam = p;
04186 QDialog::accept();
04187 }
04188 void KLFLibCreateResourceDlg::reject()
04189 {
04190 QDialog::reject();
04191 }
04192
04193 void KLFLibCreateResourceDlg::updateReadyToCreateFromSender(bool isready)
04194 {
04195 QObject *w = sender();
04196 w->setProperty("__klflibcreateresourcedlg_readyToCreate", isready);
04197 updateReadyToCreate();
04198 }
04199 void KLFLibCreateResourceDlg::updateReadyToCreate()
04200 {
04201 QWidget *w = pUi->stkOpenWidgets->currentWidget();
04202 if (w == NULL) return;
04203 QVariant v = w->property("__klflibcreateresourcedlg_readyToCreate");
04204
04205
04206 btnGo->setEnabled(!v.isValid() || v.toBool());
04207 }
04208
04209
04210 KLFLibResourceEngine *KLFLibCreateResourceDlg::createResource(const QString& defaultWtype,
04211 QObject *resourceParent, QWidget *parent)
04212 {
04213 KLFLibCreateResourceDlg dlg(defaultWtype, parent);
04214 int result = dlg.exec();
04215 if (result != QDialog::Accepted)
04216 return NULL;
04217
04218 Parameters p = dlg.pParam;
04219 QString scheme = p["klfScheme"].toString();
04220
04221 if (scheme.isEmpty()) {
04222 qWarning()<<"KLFLibCr.Res.Dlg::createRes.(): Widget Type "<<p["klfWidgetType"]
04223 <<" failed to announce what scheme it wanted in p[\"klfScheme\"]!";
04224 return NULL;
04225 }
04226
04227 KLFLibEngineFactory * factory = KLFLibEngineFactory::findFactoryFor(scheme);
04228 KLF_ASSERT_NOT_NULL( factory ,
04229 qPrintable(QString("Couldn't find factory for scheme %1 ?!?").arg(scheme)),
04230 return NULL )
04231 ;
04232
04233 KLFLibResourceEngine *resource = factory->createResource(scheme, p, resourceParent);
04234 return resource;
04235 }
04236
04237
04238
04239
04240
04241 KLFLibResPropEditor::KLFLibResPropEditor(KLFLibResourceEngine *res, QWidget *parent)
04242 : QWidget(parent)
04243 {
04244 U = new Ui::KLFLibResPropEditor;
04245 U->setupUi(this);
04246 setWindowIcon(QPixmap(":/pics/klatexformula-64.png"));
04247
04248 QPalette pal = U->txtUrl->palette();
04249 pal.setColor(QPalette::Base, pal.color(QPalette::Window));
04250 pal.setColor(QPalette::Background, pal.color(QPalette::Window));
04251 U->txtUrl->setPalette(pal);
04252
04253 if (res == NULL)
04254 qWarning("KLFLibResPropEditor: NULL Resource! Expect CRASH!");
04255
04256 pResource = res;
04257
04258 pSuppSubRes =
04259 (pResource->supportedFeatureFlags() & KLFLibResourceEngine::FeatureSubResources);
04260 pSuppSubResProps =
04261 (pResource->supportedFeatureFlags() & KLFLibResourceEngine::FeatureSubResourceProps) ;
04262
04263 connect(pResource, SIGNAL(resourcePropertyChanged(int)),
04264 this, SLOT(slotResourcePropertyChanged(int)));
04265 connect(pResource, SIGNAL(subResourcePropertyChanged(const QString&, int)),
04266 this, SLOT(slotSubResourcePropertyChanged(const QString&, int)));
04267
04268 pPropModel = new QStandardItemModel(this);
04269 pPropModel->setColumnCount(2);
04270 pPropModel->setHorizontalHeaderLabels(QStringList() << tr("Name") << tr("Value"));
04271 U->tblProperties->setModel(pPropModel);
04272 U->tblProperties->setItemDelegate(new QItemDelegate(this));
04273
04274 connect(pPropModel, SIGNAL(itemChanged(QStandardItem *)),
04275 this, SLOT(advPropEdited(QStandardItem *)));
04276
04277 pSubResPropModel = new QStandardItemModel(this);
04278 pSubResPropModel->setColumnCount(2);
04279 pSubResPropModel->setHorizontalHeaderLabels(QStringList() << tr("Name") << tr("Value"));
04280 U->tblSubResProperties->setModel(pSubResPropModel);
04281 U->tblSubResProperties->setItemDelegate(new QItemDelegate(this));
04282
04283 connect(pSubResPropModel, SIGNAL(itemChanged(QStandardItem *)),
04284 this, SLOT(advSubResPropEdited(QStandardItem *)));
04285
04286 U->frmAdvanced->setShown(U->btnAdvanced->isChecked());
04287
04288
04289 updateResourceProperties();
04290
04291 updateSubResources(pResource->defaultSubResource());
04292
04293 updateSubResourceProperties();
04294
04295 connect(U->btnApply, SIGNAL(clicked()), this, SLOT(apply()));
04296 }
04297
04298 KLFLibResPropEditor::~KLFLibResPropEditor()
04299 {
04300 delete U;
04301 }
04302
04303 bool KLFLibResPropEditor::apply()
04304 {
04305 bool res = true;
04306
04307
04308 if (pResource->supportedFeatureFlags() & KLFLibResourceEngine::FeatureSubResources)
04309 pResource->setDefaultSubResource(curSubResource());
04310
04311 bool srislocked = false;
04312 if (pSuppSubRes && pSuppSubResProps)
04313 srislocked = pResource->subResourceProperty(curSubResource(),
04314 KLFLibResourceEngine::SubResPropLocked).toBool();
04315
04316 bool lockmodified = (pResource->locked() != U->chkLocked->isChecked());
04317 bool srlockmodified = false;
04318 if (pSuppSubRes && pSuppSubResProps && srislocked != U->chkSubResLocked->isChecked()) {
04319 srlockmodified = true;
04320 }
04321 bool wantunlock = lockmodified && !U->chkLocked->isChecked();
04322 bool srwantunlock = srlockmodified && !U->chkSubResLocked->isChecked();
04323 bool wantlock = lockmodified && !wantunlock;
04324 bool srwantlock = srlockmodified && !srwantunlock;
04325 bool titlemodified = (pResource->title() != U->txtTitle->text());
04326 bool subrestitlemodified = false;
04327 if (pSuppSubRes && pSuppSubResProps &&
04328 pResource->subResourceProperty(curSubResource(), KLFLibResourceEngine::SubResPropTitle).toString()
04329 != U->txtSubResTitle->text()) {
04330 subrestitlemodified = true;
04331 }
04332
04333 klfDbg( ": lockmodif="<<lockmodified<<"; srlockmodified="<<srlockmodified
04334 <<"; wantunlock="<<wantunlock<<"; srwantunlock="<<srwantunlock<<"; wantlock="<<wantlock
04335 <<"; srwantlock="<<srwantlock<<"; titlemodif="<<titlemodified
04336 <<"; srtitlemodif="<<subrestitlemodified ) ;
04337
04338 if ( (pResource->locked() && !lockmodified) ||
04339 (srislocked && !srlockmodified) ) {
04340
04341 if (titlemodified || subrestitlemodified) {
04342 QMessageBox::critical(this, tr("Error"), tr("Can't rename a locked resource!"));
04343 return false;
04344 } else {
04345 return true;
04346 }
04347 }
04348 if (wantunlock) {
04349 if ( ! pResource->setLocked(false) ) {
04350 res = false;
04351 QMessageBox::critical(this, tr("Error"), tr("Failed to unlock resource."));
04352 }
04353 }
04354 if (srwantunlock) {
04355 if ( ! pResource->setSubResourceProperty(curSubResource(), KLFLibResourceEngine::SubResPropLocked,
04356 false) ) {
04357 res = false;
04358 QMessageBox::critical(this, tr("Error"), tr("Failed to unlock sub-resource \"%1\".")
04359 .arg(curSubResource()));
04360 }
04361 }
04362
04363 QString newTitle = U->txtTitle->text();
04364 QString newSubResTitle = U->txtSubResTitle->text();
04365
04366 if ( titlemodified && ! pResource->setTitle(newTitle) ) {
04367 res = false;
04368 QMessageBox::critical(this, tr("Error"), tr("Failed to rename resource."));
04369 }
04370
04371 if ( subrestitlemodified &&
04372 ! pResource->setSubResourceProperty(curSubResource(),
04373 KLFLibResourceEngine::SubResPropTitle,
04374 newSubResTitle) ) {
04375 res = false;
04376 QMessageBox::critical(this, tr("Error"), tr("Failed to rename sub-resource \"%1\".")
04377 .arg(curSubResource()));
04378 }
04379
04380 if (wantlock) {
04381 if ( ! pResource->setLocked(true) ) {
04382 res = false;
04383 QMessageBox::critical(this, tr("Error"), tr("Failed to lock resource."));
04384 }
04385 }
04386 if (srwantlock) {
04387 if ( ! pResource->setSubResourceProperty(curSubResource(), KLFLibResourceEngine::SubResPropLocked,
04388 true) ) {
04389 res = false;
04390 QMessageBox::critical(this, tr("Error"), tr("Failed to lock sub-resource \"%1\".")
04391 .arg(curSubResource()));
04392 }
04393 }
04394
04395 return res;
04396 }
04397
04398 void KLFLibResPropEditor::on_btnAdvanced_toggled(bool on)
04399 {
04400
04401 U->frmAdvanced->setShown(on);
04402 if (U->frmAdvanced->isVisible()) {
04403
04404 int w = width() / 3;
04405 U->tblProperties->setColumnWidth(0, w);
04406 U->tblProperties->setColumnWidth(1, w);
04407 U->tblSubResProperties->setColumnWidth(0, w);
04408 U->tblSubResProperties->setColumnWidth(1, w);
04409 }
04410 update();
04411 adjustSize();
04412 if (parentWidget()) {
04413 klfDbg( "Parent widget is "<<parentWidget() ) ;
04414 parentWidget()->update();
04415 parentWidget()->adjustSize();
04416 }
04417 }
04418
04419 void KLFLibResPropEditor::updateSubResources(const QString& curSubRes)
04420 {
04421 klfDbg( "KLFLibResPropEditor::updateSubResources("<<curSubRes<<")" ) ;
04422 if ( pSuppSubRes ) {
04423 U->cbxSubResource->blockSignals(true);
04424 U->cbxSubResource->clear();
04425 QStringList subResList = pResource->subResourceList();
04426 int k;
04427 int curSubResIndex = 0;
04428 for (k = 0; k < subResList.size(); ++k) {
04429 QString title;
04430 QString thissrtitle
04431 = pResource->subResourceProperty(subResList[k], KLFLibResourceEngine::SubResPropTitle).toString();
04432 if (!thissrtitle.isEmpty())
04433 title = QString("%1 (%2)").arg(thissrtitle, subResList[k]);
04434 else
04435 title = subResList[k];
04436 U->cbxSubResource->addItem(title, subResList[k]);
04437 if (subResList[k] == curSubRes)
04438 curSubResIndex = k;
04439 }
04440 klfDbg( "KLFLibResPropEditor::updateSubResources("<<curSubRes<<") : setting cur index="<<curSubResIndex ) ;
04441 U->cbxSubResource->setCurrentIndex(curSubResIndex);
04442 U->cbxSubResource->blockSignals(false);
04443 if ( pSuppSubResProps ) {
04444 U->wSubResProps->show();
04445 U->txtSubResTitle->setEnabled(true);
04446 U->chkSubResLocked->setEnabled(true);
04447 slotSubResourcePropertyChanged(curSubResource(), -2);
04448 U->txtSubResTitle->setEnabled(pResource
04449 ->canModifySubResourceProperty(curSubResource(),
04450 KLFLibResourceEngine::SubResPropTitle));
04451 U->txtSubResTitle->setText(pResource->subResourceProperty(curSubResource(),
04452 KLFLibResourceEngine::SubResPropTitle)
04453 .toString());
04454 U->chkSubResLocked->setEnabled(pResource
04455 ->canModifySubResourceProperty(curSubResource(),
04456 KLFLibResourceEngine::SubResPropLocked));
04457 U->chkSubResLocked->setChecked(pResource->subResourceProperty(curSubResource(),
04458 KLFLibResourceEngine::SubResPropLocked)
04459 .toBool());
04460 } else {
04461 U->wSubResProps->hide();
04462 U->chkSubResLocked->setEnabled(false);
04463 U->txtSubResTitle->setText("");
04464 U->txtSubResTitle->setEnabled(false);
04465 }
04466 } else {
04467 U->cbxSubResource->clear();
04468 U->cbxSubResource->setEnabled(false);
04469 U->wSubResProps->hide();
04470 U->chkSubResLocked->setEnabled(false);
04471 U->txtSubResTitle->setText("");
04472 U->txtSubResTitle->setEnabled(false);
04473 }
04474 }
04475
04476 void KLFLibResPropEditor::advPropEdited(QStandardItem *item)
04477 {
04478 klfDbg( "advPropEdited("<<item<<")" ) ;
04479 QVariant value = item->data(Qt::EditRole);
04480 int propId = item->data(Qt::UserRole).toInt();
04481 bool r = pResource->setResourceProperty(propId, value);
04482 if ( ! r ) {
04483 QMessageBox::critical(this, tr("Error"),
04484 tr("Failed to set resource property \"%1\".")
04485 .arg(pResource->propertyNameForId(propId)));
04486 }
04487
04488 }
04489
04490 void KLFLibResPropEditor::slotResourcePropertyChanged(int )
04491 {
04492
04493 updateResourceProperties();
04494 updateSubResources();
04495 }
04496 void KLFLibResPropEditor::updateResourceProperties()
04497 {
04498 pPropModel->setRowCount(0);
04499 int k;
04500 QStringList props = pResource->registeredPropertyNameList();
04501 QPalette pal = U->tblSubResProperties->palette();
04502 for (k = 0; k < props.size(); ++k) {
04503 QString prop = props[k];
04504 int propId = pResource->propertyIdForName(prop);
04505 QVariant val = pResource->resourceProperty(prop);
04506 QStandardItem *i1 = new QStandardItem(prop);
04507 i1->setEditable(false);
04508 QStandardItem *i2 = new QStandardItem(val.toString());
04509 bool editable = pResource->canModifyProp(propId);
04510 i2->setEditable(editable);
04511 QPalette::ColorGroup cg = editable ? QPalette::Active : QPalette::Disabled;
04512 i2->setForeground(pal.brush(cg, QPalette::Text));
04513 i2->setBackground(pal.brush(cg, QPalette::Base));
04514 i2->setData(val, Qt::EditRole);
04515 i2->setData(propId, Qt::UserRole);
04516 pPropModel->appendRow(QList<QStandardItem*>() << i1 << i2);
04517 }
04518
04519 U->txtTitle->setText(pResource->title());
04520 U->txtTitle->setEnabled(pResource->canModifyProp(KLFLibResourceEngine::PropTitle));
04521 QString surl = pResource->url().toString();
04522 if (surl.endsWith("?"))
04523 surl.chop(1);
04524 U->txtUrl->setText(surl);
04525 U->chkLocked->setChecked(pResource->locked());
04526 U->chkLocked->setEnabled(pResource->canModifyProp(KLFLibResourceEngine::PropLocked));
04527 }
04528
04529 QString KLFLibResPropEditor::curSubResource() const
04530 {
04531 return U->cbxSubResource->itemData(U->cbxSubResource->currentIndex()).toString();
04532 }
04533
04534 void KLFLibResPropEditor::advSubResPropEdited(QStandardItem *item)
04535 {
04536 klfDbg( "item="<<item<<"" ) ;
04537 QVariant value = item->data(Qt::EditRole);
04538 int propId = item->data(Qt::UserRole).toInt();
04539 bool r = pResource->setSubResourceProperty(curSubResource(), propId, value);
04540 if ( ! r ) {
04541 QMessageBox::critical(this, tr("Error"),
04542 tr("Failed to set sub-resource \"%1\"'s property \"%2\".")
04543 .arg(curSubResource(), propId));
04544 }
04545
04546 }
04547 void KLFLibResPropEditor::on_cbxSubResource_currentIndexChanged(int newSubResItemIndex)
04548 {
04549 slotSubResourcePropertyChanged(curSubResource(), -2);
04550 U->txtSubResTitle->setText(pResource->subResourceProperty(curSubResource(),
04551 KLFLibResourceEngine::SubResPropTitle)
04552 .toString());
04553 U->chkSubResLocked->setChecked(pResource->subResourceProperty(curSubResource(),
04554 KLFLibResourceEngine::SubResPropLocked)
04555 .toBool());
04556 }
04557
04558 void KLFLibResPropEditor::slotSubResourcePropertyChanged(const QString& subResource, int subResPropId)
04559 {
04560 if (subResource != curSubResource())
04561 return;
04562
04563 if (subResPropId != -2) {
04564
04565 updateSubResources(curSubResource());
04566
04567
04568 return;
04569 }
04570
04571 if ( ! pSuppSubResProps )
04572 return;
04573
04574
04575 updateSubResourceProperties();
04576 }
04577 void KLFLibResPropEditor::updateSubResourceProperties()
04578 {
04579
04580 pSubResPropModel->setRowCount(0);
04581 QPalette pal = U->tblSubResProperties->palette();
04582 int k;
04583 QList<int> props = pResource->subResourcePropertyIdList();
04584 for (k = 0; k < props.size(); ++k) {
04585 int propId = props[k];
04586 QVariant val = pResource->subResourceProperty(curSubResource(), propId);
04587 QStandardItem *i1 = new QStandardItem(pResource->subResourcePropertyName(propId));
04588 i1->setEditable(false);
04589 QStandardItem *i2 = new QStandardItem(val.toString());
04590 bool editable = pResource->canModifySubResourceProperty(curSubResource(), propId);
04591 i2->setEditable(editable);
04592 QPalette::ColorGroup cg = editable ? QPalette::Active : QPalette::Disabled;
04593 i2->setForeground(pal.brush(cg, QPalette::Text));
04594 i2->setBackground(pal.brush(cg, QPalette::Base));
04595 i2->setData(val, Qt::EditRole);
04596 i2->setData(propId, Qt::UserRole);
04597 pSubResPropModel->appendRow(QList<QStandardItem*>() << i1 << i2);
04598 }
04599 }
04600
04601
04602
04603
04604
04605
04606
04607
04608 KLFLibResPropEditorDlg::KLFLibResPropEditorDlg(KLFLibResourceEngine *resource, QWidget *parent)
04609 : QDialog(parent)
04610 {
04611 QVBoxLayout *lyt = new QVBoxLayout(this);
04612
04613 pEditor = new KLFLibResPropEditor(resource, this);
04614 lyt->addWidget(pEditor);
04615
04616 QDialogButtonBox *btns = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel,
04617 Qt::Horizontal, this);
04618 lyt->addWidget(btns);
04619
04620 connect(btns->button(QDialogButtonBox::Ok), SIGNAL(clicked()),
04621 this, SLOT(applyAndClose()));
04622
04623
04624 connect(btns->button(QDialogButtonBox::Cancel), SIGNAL(clicked()),
04625 this, SLOT(cancelAndClose()));
04626
04627 setModal(false);
04628 setWindowTitle(pEditor->windowTitle());
04629 setAttribute(Qt::WA_DeleteOnClose, true);
04630 }
04631
04632 KLFLibResPropEditorDlg::~KLFLibResPropEditorDlg()
04633 {
04634 }
04635
04636 void KLFLibResPropEditorDlg::applyAndClose()
04637 {
04638 if (pEditor->apply()) {
04639 accept();
04640 }
04641 }
04642
04643 void KLFLibResPropEditorDlg::cancelAndClose()
04644 {
04645 reject();
04646 }
04647
04648
04649
04650
04651 KLFLibNewSubResDlg::KLFLibNewSubResDlg(KLFLibResourceEngine *resource, QWidget *parent)
04652 : QDialog(parent), isAutoName(true)
04653 {
04654 u = new Ui::KLFLibNewSubResDlg;
04655 u->setupUi(this);
04656 setWindowIcon(QPixmap(":/pics/klatexformula-64.png"));
04657
04658 u->lblNoTitle->hide();
04659
04660 uint fl = resource->supportedFeatureFlags();
04661 if ( (fl & KLFLibResourceEngine::FeatureSubResources) == 0 ) {
04662 u->lblName->setEnabled(false);
04663 u->txtName->setEnabled(false);
04664 u->lblTitle->setEnabled(false);
04665 u->txtTitle->setEnabled(false);
04666 u->btns->button(QDialogButtonBox::Ok)->setEnabled(false);
04667 } else if ( (fl & KLFLibResourceEngine::FeatureSubResourceProps) == 0) {
04668 u->lblTitle->setEnabled(false);
04669 u->txtTitle->setEnabled(false);
04670 u->lblNoTitle->show();
04671 }
04672
04673 u->lblResource->setText(resource->title());
04674 }
04675
04676 KLFLibNewSubResDlg::~KLFLibNewSubResDlg()
04677 {
04678 }
04679
04680 QString KLFLibNewSubResDlg::newSubResourceName() const
04681 {
04682 return u->txtName->text();
04683 }
04684
04685 QString KLFLibNewSubResDlg::newSubResourceTitle() const
04686 {
04687 return u->txtTitle->text();
04688 }
04689
04690
04691 QString KLFLibNewSubResDlg::makeSubResInternalName(const QString& title)
04692 {
04693 QString nm = title;
04694
04695 QRegExp rx("(?:\\s|-)([a-z])");
04696 int i;
04697 while ((i = rx.indexIn(nm,i+1)) >= 0) {
04698 QChar c = rx.cap(1).length() ? rx.cap(1)[0] : QChar('_');
04699 nm.replace(i, rx.matchedLength(), c.toUpper());
04700 }
04701 nm.replace(QRegExp("\\s"), "");
04702 nm.replace(QRegExp("[^A-Za-z0-9_]"), "_");
04703 return nm;
04704 }
04705
04706 void KLFLibNewSubResDlg::on_txtTitle_textChanged(const QString& text)
04707 {
04708 if (isAutoName) {
04709 u->txtName->blockSignals(true);
04710 u->txtName->setText(makeSubResInternalName(text));
04711 u->txtName->blockSignals(false);
04712 }
04713 }
04714
04715 void KLFLibNewSubResDlg::on_txtName_textChanged(const QString& text)
04716 {
04717 if (!text.isEmpty())
04718 isAutoName = false;
04719 else
04720 isAutoName = true;
04721 }
04722
04723 QString KLFLibNewSubResDlg::createSubResourceIn(KLFLibResourceEngine *resource, QWidget *parent)
04724 {
04725 if ( (resource->supportedFeatureFlags() & KLFLibResourceEngine::FeatureSubResources) == 0 ) {
04726 qWarning("KLFLibNewSubResDlg::createSubResourceIn: can't create sub-resource in resource not "
04727 "supporting sub-resources (!) : %s", qPrintable(resource->url().toString()));
04728 return QString();
04729 }
04730 KLFLibNewSubResDlg d(resource, parent);
04731 int r = d.exec();
04732 if (r != QDialog::Accepted)
04733 return QString();
04734 QString name = d.newSubResourceName();
04735 QString title = d.newSubResourceTitle();
04736
04737 bool result = resource->createSubResource(name, title);
04738 if (!result)
04739 return QString();
04740
04741 return name;
04742 }
04743
04744
04745
04746 KLFLibLocalFileSchemeGuesser::KLFLibLocalFileSchemeGuesser()
04747 {
04748 KLFLibBasicWidgetFactory::addLocalFileSchemeGuesser(this);
04749 }
04750 KLFLibLocalFileSchemeGuesser::~KLFLibLocalFileSchemeGuesser()
04751 {
04752 KLFLibBasicWidgetFactory::removeLocalFileSchemeGuesser(this);
04753 }
04754
04755
04756
04757 KLFLibBasicWidgetFactory::KLFLibBasicWidgetFactory(QObject *parent)
04758 : KLFLibWidgetFactory(parent)
04759 {
04760 }
04761 KLFLibBasicWidgetFactory::~KLFLibBasicWidgetFactory()
04762 {
04763 }
04764
04765
04766 QStringList KLFLibBasicWidgetFactory::supportedTypes() const
04767 {
04768 return QStringList() << QLatin1String("LocalFile");
04769 }
04770
04771
04772 QString KLFLibBasicWidgetFactory::widgetTypeTitle(const QString& wtype) const
04773 {
04774 if (wtype == QLatin1String("LocalFile"))
04775 return tr("Local File");
04776 return QString();
04777 }
04778
04779
04780
04781 QWidget * KLFLibBasicWidgetFactory::createPromptUrlWidget(QWidget *parent, const QString& wtype,
04782 QUrl defaultlocation)
04783 {
04784 if (wtype == QLatin1String("LocalFile")) {
04785 KLFLibLocalFileOpenWidget *w = new KLFLibLocalFileOpenWidget(parent, pLocalFileTypes);
04786 w->setUrl(defaultlocation);
04787 return w;
04788 }
04789 return NULL;
04790 }
04791
04792 QUrl KLFLibBasicWidgetFactory::retrieveUrlFromWidget(const QString& wtype, QWidget *widget)
04793 {
04794 if (wtype == "LocalFile") {
04795 if (widget == NULL || !widget->inherits("KLFLibLocalFileOpenWidget")) {
04796 qWarning("KLFLibBasicWidgetFactory::retrieveUrlFromWidget(): Bad Widget provided!");
04797 return QUrl();
04798 }
04799 return qobject_cast<KLFLibLocalFileOpenWidget*>(widget)->url();
04800 } else {
04801 qWarning()<<"KLFLibB.W.Factory::retrieveUrlFromWidget(): Bad widget type: "<<wtype;
04802 return QUrl();
04803 }
04804 }
04805
04806
04807 QWidget *KLFLibBasicWidgetFactory::createPromptCreateParametersWidget(QWidget *parent,
04808 const QString& wtype,
04809 const Parameters& defaultparameters)
04810 {
04811 if (wtype == QLatin1String("LocalFile")) {
04812 KLFLibLocalFileCreateWidget *w = new KLFLibLocalFileCreateWidget(parent, pLocalFileTypes);
04813 w->setUrl(defaultparameters["Url"].toUrl());
04814 return w;
04815 }
04816 return NULL;
04817 }
04818
04819 KLFLibWidgetFactory::Parameters
04820 KLFLibBasicWidgetFactory::retrieveCreateParametersFromWidget(const QString& scheme,
04821 QWidget *widget)
04822 {
04823 if (scheme == QLatin1String("LocalFile")) {
04824 if (widget == NULL || !widget->inherits("KLFLibLocalFileCreateWidget")) {
04825 qWarning("KLFLibBasicWidgetFactory::retrieveUrlFromWidget(): Bad Widget provided!");
04826 return Parameters();
04827 }
04828 KLFLibLocalFileCreateWidget *w = qobject_cast<KLFLibLocalFileCreateWidget*>(widget);
04829 Parameters p;
04830 QString filename = w->selectedFName();
04831 if (QFile::exists(filename) && !w->confirmedOverwrite()) {
04832 QMessageBox::StandardButton result =
04833 QMessageBox::warning(widget, tr("Overwrite?"),
04834 tr("The specified file already exists. Overwrite it?"),
04835 QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel,
04836 QMessageBox::No);
04837 if (result == QMessageBox::No) {
04838 p["klfRetry"] = true;
04839 return p;
04840 } else if (result == QMessageBox::Cancel) {
04841 return Parameters();
04842 }
04843
04844 bool r = QFile::remove(filename);
04845 if ( !r ) {
04846 QMessageBox::critical(widget, tr("Error"), tr("Failed to overwrite the file %1.")
04847 .arg(filename));
04848 return Parameters();
04849 }
04850 }
04851
04852 p["Filename"] = filename;
04853 p["klfScheme"] = w->selectedScheme();
04854 return p;
04855 }
04856
04857 return Parameters();
04858 }
04859
04860
04861 void KLFLibBasicWidgetFactory::addLocalFileType(const LocalFileType& f)
04862 {
04863 pLocalFileTypes << f;
04864 }
04865
04866
04867 QList<KLFLibBasicWidgetFactory::LocalFileType> KLFLibBasicWidgetFactory::localFileTypes()
04868 {
04869 return pLocalFileTypes;
04870 }
04871
04872
04873
04874 QString KLFLibBasicWidgetFactory::guessLocalFileScheme(const QString& fileName)
04875 {
04876 int k;
04877 for (k = 0; k < pSchemeGuessers.size(); ++k) {
04878 QString s = pSchemeGuessers[k]->guessScheme(fileName);
04879 if (!s.isEmpty())
04880 return s;
04881 }
04882 return QString();
04883 }
04884
04885
04886 void KLFLibBasicWidgetFactory::addLocalFileSchemeGuesser(KLFLibLocalFileSchemeGuesser *schemeguesser)
04887 {
04888 pSchemeGuessers << schemeguesser;
04889 }
04890
04891
04892 void KLFLibBasicWidgetFactory::removeLocalFileSchemeGuesser(KLFLibLocalFileSchemeGuesser *schemeguesser)
04893 {
04894 pSchemeGuessers.removeAll(schemeguesser);
04895 }
04896
04897
04898
04899
04900 QList<KLFLibBasicWidgetFactory::LocalFileType> KLFLibBasicWidgetFactory::pLocalFileTypes ;
04901
04902 QList<KLFLibLocalFileSchemeGuesser*> KLFLibBasicWidgetFactory::pSchemeGuessers ;
04903