[KLF Application][KLF Tools][KLF Backend][KLF Home]
KLatexFormula Project
klflibview.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * file klflibview.cpp
3  * This file is part of the KLatexFormula Project.
4  * Copyright (C) 2011 by Philippe Faist
5  * philippe.faist at bluewin.ch
6  * *
7  * This program is free software; you can redistribute it and/or modify *
8  * it under the terms of the GNU General Public License as published by *
9  * the Free Software Foundation; either version 2 of the License, or *
10  * (at your option) any later version. *
11  * *
12  * This program is distributed in the hope that it will be useful, *
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15  * GNU General Public License for more details. *
16  * *
17  * You should have received a copy of the GNU General Public License *
18  * along with this program; if not, write to the *
19  * Free Software Foundation, Inc., *
20  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
21  ***************************************************************************/
22 /* $Id: klflibview.cpp 627 2011-04-12 12:36:22Z phfaist $ */
23 
24 
25 #include <QApplication>
26 #include <QDebug>
27 #include <QImage>
28 #include <QString>
29 #include <QDataStream>
30 #include <QMessageBox>
31 #include <QAbstractItemModel>
32 #include <QModelIndex>
33 #include <QPainter>
34 #include <QStyle>
35 #include <QVBoxLayout>
36 #include <QStackedWidget>
37 #include <QComboBox>
38 #include <QHeaderView>
39 #include <QTextDocument>
40 #include <QTextCursor>
41 #include <QTextCharFormat>
42 #include <QListView>
43 #include <QMenu>
44 #include <QAction>
45 #include <QEvent>
46 #include <QDropEvent>
47 #include <QDragEnterEvent>
48 #include <QDragMoveEvent>
49 #include <QStandardItemModel>
50 #include <QItemDelegate>
51 #include <QShortcut>
52 
53 #include <ui_klflibopenresourcedlg.h>
54 #include <ui_klflibrespropeditor.h>
55 #include <ui_klflibnewsubresdlg.h>
56 
57 #include <klfguiutil.h>
58 #include "klfconfig.h"
59 #include "klflibview.h"
60 
61 #include "klflibview_p.h"
62 
63 
64 
65 // ---------------------------------------------------
66 
68 static QImage transparentify_image(const QImage& img, qreal factor)
69 {
70  // set the image opacity to factor (by multiplying each alpha value by factor)
71  QImage img2 = img.convertToFormat(QImage::Format_ARGB32_Premultiplied);
72  int k, j;
73  for (k = 0; k < img.height(); ++k) {
74  for (j = 0; j < img.width(); ++j) {
75  QRgb c = img2.pixel(j, k);
76  img2.setPixel(j, k, qRgba(qRed(c),qGreen(c),qBlue(c),(int)(factor*qAlpha(c))));
77  }
78  }
79  return img2;
80 }
81 
82 
84 static QImage autocrop_image(const QImage& img, int alpha_threshold = 0)
85 {
86  // crop transparent borders
87  int x, y;
88  int min_x = -1, max_x = -1, min_y = -1, max_y = -1;
89  // so first find borders
90  for (x = 0; x < img.width(); ++x) {
91  for (y = 0; y < img.height(); ++y) {
92  if (qAlpha(img.pixel(x,y)) - alpha_threshold > 0) {
93  // opaque pixel: include it.
94  if (min_x == -1 || min_x > x) min_x = x;
95  if (max_x == -1 || max_x < x) max_x = x;
96  if (min_y == -1 || min_y > y) min_y = y;
97  if (max_y == -1 || max_y < y) max_y = y;
98  }
99  }
100  }
101  return img.copy(QRect(QPoint(min_x, min_y), QPoint(max_x, max_y)));
102 }
103 
105 static float color_distinguishable_distance(QRgb a, QRgb b, bool aPremultiplied = false) {
106  static const float C_r = 11.f, C_g = 16.f, C_b = 5.f;
107  static const float C_avg = (C_r + C_g + C_b) / 3.f;
108 
109  // (?) really-> NO? ON SECOND THOUGHT, REMOVE THIS FACTOR
110  // // * drkfactor reduces distances for dark colors, accounting for the fact that the eye
111  // // distinguishes less dark colors than light colors
112  // // * 0 <= qGray(...) <= 255
113  // // * drkfactor <= 1 -> reducing factor
114  // float drkfactor = 1 - (qGray(b)/1000.f);
115  static const float drkfactor = 1;
116 
117  float alpha = qAlpha(a)/255.f;
118  QRgb m;
119  if (aPremultiplied)
120  m = qRgb((int)(qRed(a)+(1-alpha)*qRed(b)),
121  (int)(qGreen(a)+(1-alpha)*qGreen(b)),
122  (int)(qBlue(a)+(1-alpha)*qBlue(b)));
123  else
124  m = qRgb((int)(alpha*qRed(a)+(1-alpha)*qRed(b)),
125  (int)(alpha*qGreen(a)+(1-alpha)*qGreen(b)),
126  (int)(alpha*qBlue(a)+(1-alpha)*qBlue(b)));
127 
128  float dst = qMax( qMax(C_r*abs(qRed(m) - qRed(b)), C_g*abs(qGreen(m) - qGreen(b))),
129  C_b*abs(qBlue(m) - qBlue(b)) ) * drkfactor / C_avg;
130  // klfDbg("a="<<klfFmt("%#010x", a).data()<<" qRed(a)="<<qRed(a)<<" b="<<klfFmt("%#010x", b).data()
131  // <<" m="<<klfFmt("%#010x", m)<<"drkfactor="<<drkfactor<<" a/alpha="<<alpha<<" => distance="<<dst) ;
132  return dst;
133 }
134 
135 
137 static bool image_is_distinguishable(const QImage& imgsrc, QColor background, float threshold)
138 {
139  int fmt = imgsrc.format();
140  bool apremultiplied;
141  QImage img;
142  switch (fmt) {
143  case QImage::Format_ARGB32: img = imgsrc; apremultiplied = false; break;
144  case QImage::Format_ARGB32_Premultiplied: img = imgsrc; apremultiplied = true; break;
145  default:
146  img = imgsrc.convertToFormat(QImage::Format_ARGB32);
147  apremultiplied = false;
148  break;
149  }
150  QRgb bg = background.rgb();
151  // crop transparent borders
152  int x, y;
153  for (x = 0; x < img.width(); ++x) {
154  for (y = 0; y < img.height(); ++y) {
155  // klfDbg("src/format="<<imgsrc.format()<<"; thisformat="<<img.format()
156  // <<" Testing pixel at ("<<x<<","<<y<<") pixel="<<klfFmt("%#010x", img.pixel(x,y))) ;
157  float dist = color_distinguishable_distance(img.pixel(x,y), bg, apremultiplied);
158  if (dist > threshold) {
159  // ok we have one pixel at least we can distinguish.
160  return true;
161  }
162  }
163  }
164  return false;
165 }
166 
167 
168 
169 // -------------------------------------------------------
170 
172  : QWidget(parent), pResourceEngine(NULL)
173 {
174 }
175 
177 {
178  if (pResourceEngine)
179  disconnect(pResourceEngine, 0, this, 0);
180  pResourceEngine = resource;
181  connect(pResourceEngine, SIGNAL(dataChanged(const QString&, int, const QList<KLFLib::entryId>&)),
182  this, SLOT(updateResourceData(const QString&, int, const QList<KLFLib::entryId>&)));
183  connect(pResourceEngine, SIGNAL(resourcePropertyChanged(int)),
184  this, SLOT(updateResourceProp(int)));
185  connect(pResourceEngine, SIGNAL(defaultSubResourceChanged(const QString&)),
188 }
189 
191 {
193 }
194 
196 {
198 }
199 
201 {
202  return QList<QAction*>();
203 }
204 
205 
206 
207 // -------------------------------------------------------
208 
209 QList<KLFLibViewFactory*> KLFLibViewFactory::pRegisteredFactories =
211 
212 
214  QObject *parent)
215  : QObject(parent), pViewTypeIdentifiers(viewTypeIdentifiers)
216 {
217  registerFactory(this);
218 }
220 {
221  unRegisterFactory(this);
222 }
223 
224 
226 {
227  if (pRegisteredFactories.size() > 0)
228  return pRegisteredFactories[0]->pViewTypeIdentifiers.first();
229  return QString();
230 }
231 
233 {
234  if (viewTypeIdentifier.isEmpty()) {
235  if (pRegisteredFactories.size() > 0)
236  return pRegisteredFactories[0]; // first registered factory is default
237  return NULL;
238  }
239  int k;
240  // walk registered factories, and return the first that supports this scheme.
241  for (k = 0; k < pRegisteredFactories.size(); ++k) {
242  if (pRegisteredFactories[k]->viewTypeIdentifiers().contains(viewTypeIdentifier))
243  return pRegisteredFactories[k];
244  }
245  // no factory found
246  return NULL;
247 }
248 
250 {
251  QStringList list;
252  int k;
253  for (k = 0; k < pRegisteredFactories.size(); ++k)
254  list << pRegisteredFactories[k]->viewTypeIdentifiers();
255  return list;
256 }
257 
258 
259 void KLFLibViewFactory::registerFactory(KLFLibViewFactory *factory)
260 {
261  KLF_ASSERT_NOT_NULL( factory, "Attempt to register NULL factory!", return )
262  ;
263  // WARNING: THIS FUNCTION IS CALLED FROM CONSTRUCTOR. NO VIRTUAL METHOD CALLS!
264  if (factory->pViewTypeIdentifiers.size() == 0) {
265  qWarning("KLFLibViewFactory::registerFactory: factory must provide at least one view type!");
266  return;
267  }
268  if (pRegisteredFactories.indexOf(factory) != -1) // already registered
269  return;
270  pRegisteredFactories.append(factory);
271 }
272 
273 void KLFLibViewFactory::unRegisterFactory(KLFLibViewFactory *factory)
274 {
275  if (pRegisteredFactories.indexOf(factory) == -1)
276  return;
277  pRegisteredFactories.removeAll(factory);
278 }
279 
280 
281 
282 // ---------------------------------------------------
283 
284 
285 // static
286 KLFFactoryManager KLFLibWidgetFactory::pFactoryManager;
287 
289  : QObject(parent), KLFFactoryBase(&pFactoryManager)
290 {
291 }
292 
293 // static
295 {
296  return dynamic_cast<KLFLibWidgetFactory*>(pFactoryManager.findFactoryFor(wtype));
297 }
298 
299 // static
301 {
302  return pFactoryManager.allSupportedTypes();
303 }
304 
305 
306 bool KLFLibWidgetFactory::hasCreateWidget(const QString& /*scheme*/) const
307 {
308  return false;
309 }
310 
312  const QString& /*scheme*/,
313  const Parameters& /*par*/)
314 {
315  return NULL;
316 }
319  QWidget */*parent*/)
320 {
321  return Parameters();
322 }
323 
324 bool KLFLibWidgetFactory::hasSaveToWidget(const QString& /*scheme*/) const
325 {
326  return false;
327 }
329  const QString& /*scheme*/,
330  KLFLibResourceEngine* /*resource*/,
331  const QUrl& /*defaultUrl*/)
332 {
333  return NULL;
334 }
336  QWidget */*widget*/)
337 {
338  return QUrl();
339 }
340 
341 
342 
343 // --------------------------------------------
344 
345 
346 KLF_EXPORT QDebug& operator<<(QDebug& dbg, const KLFLibModelCache::NodeId& n)
347 {
348  const char * skind =
349  ( (n.kind == KLFLibModelCache::EntryKind) ? "EntryKind" :
350  ((n.kind == KLFLibModelCache::CategoryLabelKind) ? "CategoryLabelKind" :
351  "*UnknownKind*") );
352  return dbg.nospace() << "NodeId("<<skind<<"+"<<n.index<<")";
353 }
354 KLF_EXPORT QDebug& operator<<(QDebug& dbg, const KLFLibModelCache::Node& n)
355 {
356  return dbg << "[kind="<<n.kind<<", children/sz="<<n.children.size()
357  <<",allfetched="<<n.allChildrenFetched<<"]";
358 }
359 KLF_EXPORT QDebug& operator<<(QDebug& dbg, const KLFLibModelCache::EntryNode& en)
360 {
361  return dbg << "EntryNode(entryid="<<en.entryid<<"; entry/latex="<<en.entry.latex()<<"; parent="
362  <<en.parent<<")";
363 }
364 KLF_EXPORT QDebug& operator<<(QDebug& dbg, const KLFLibModelCache::CategoryLabelNode& cn)
365 {
366  return dbg << "CategoryLabelNode(label="<<cn.categoryLabel<<";fullCategoryPath="<<cn.fullCategoryPath
367  << "; parent="<<cn.parent<<";"<<(const KLFLibModelCache::Node&)cn<<")";
368 }
369 KLF_EXPORT QDebug& operator<<(QDebug& dbg, const KLFLibModel::PersistentId& n)
370 {
371  return dbg << "PersistentId("<<n.kind<<", entry_id="<<n.entry_id<<", cat...path="<<n.categorylabel_fullpath<<")";
372 }
373 KLF_EXPORT QDebug& operator<<(QDebug& d, const KLFLibViewDelegate::ColorRegion& c)
374 {
375  return d << "ColorRegion["<<c.start<<"->+"<<c.len<<"]";
376 }
377 
378 
379 
380 // -------------------------------------------------------
381 
382 // MODEL CACHE OBJECT
383 
384 
385 
386 
388 {
389  if ( ! a.valid() || ! b.valid() )
390  return false;
391 
392  if ( groupCategories ) {
393  // category kind always smaller than entry kind in category grouping mode
394  if ( a.kind != EntryKind && b.kind == EntryKind ) {
395  return true;
396  } else if ( a.kind == EntryKind && b.kind != EntryKind ) {
397  return false;
398  }
399  if ( a.kind != EntryKind && b.kind != EntryKind ) {
400  if ( ! (a.kind == CategoryLabelKind && b.kind == CategoryLabelKind) ) {
401  qWarning("KLFLibModelSorter::operator(): Bad node kinds!! a: %d and b: %d",
402  a.kind, b.kind);
403  return false;
404  }
405  // when grouping sub-categories, always sort the categories *ascending*
406  return QString::localeAwareCompare(cache->getCategoryLabelNodeRef(a).categoryLabel,
407  cache->getCategoryLabelNodeRef(b).categoryLabel) < 0;
408  }
409  // both are entrykind
410  return entrysorter->operator()(cache->getEntryNodeRef(a).entry, cache->getEntryNodeRef(b).entry);
411  }
412 
413  int entryProp = entrysorter->propId();
414  int sortorderfactor = (entrysorter->order() == Qt::AscendingOrder) ? 1 : -1;
415  QString nodevaluea = cache->nodeValue(a, entryProp);
416  QString nodevalueb = cache->nodeValue(b, entryProp);
417  return sortorderfactor*QString::localeAwareCompare(nodevaluea, nodevalueb) < 0;
418 }
419 
420 
421 
422 // ---
423 
425 {
427  klfDbg(klfFmtCC("flavorFlags=%#010x", pModel->pFlavorFlags));
428  int k;
429 
430  // report progress
431 #ifndef Q_WS_MAC
432  KLFProgressReporter progressReporter(0, 100, NULL);
433  QString msg = QObject::tr("Updating View...", "[[KLFLibModelCache, progress text]]");
434  emit pModel->operationStartReportingProgress(&progressReporter, msg);
435  progressReporter.doReportProgress(0);
436 #endif
437 
438  klfDbgT("saving persistent indexes ...");
439  QModelIndexList persistentIndexes = pModel->persistentIndexList();
440  QList<KLFLibModel::PersistentId> persistentIndexIds = pModel->persistentIdList(persistentIndexes);
441  klfDbgT("... done saving persistent indexes.");
442 
443  // clear cache first
444  pEntryCache.clear();
445  pCategoryLabelCache.clear();
446  // root category label MUST ALWAYS (in every display flavor) occupy index 0 in category label cache
447  pCategoryLabelCache.append(CategoryLabelNode());
448  CategoryLabelNode& root = pCategoryLabelCache[0];
449  root.fullCategoryPath = "/";
450  root.categoryLabel = "/";
451  root.allChildrenFetched = false;
452 
453  QList<int> wantedProps = minimalistEntryPropIds();
455  q.orderPropId = pLastSortPropId;
456  q.orderDirection = pLastSortOrder;
457  if (pModel->pFlavorFlags & KLFLibModel::CategoryTree) {
458  // fetch only elements in root category
461  }
462  q.wantedEntryProperties = minimalistEntryPropIds();
463  q.limit = pModel->pFetchBatchCount; // limit number of results
465  // query the resource
466  klfDbgT("about to query resource...");
467  int count = pModel->pResource->query(pModel->pResource->defaultSubResource(), q, &qr);
468  klfDbgT("resource returned "<<count<<" entries.");
469  if (count < 0) {
470  qWarning()<<KLF_FUNC_NAME<<": query() returned an error.";
471  // don't return, continue with empty list
472  }
473  if (count < pModel->pFetchBatchCount) {
474  // we have fetched all children
475  klfDbg("all children have been fetched.") ;
476  root.allChildrenFetched = true;
477  }
480 
481  k = 0; // used for progress reporting
482  for (it = everything.begin(); it != everything.end(); ++it) {
483  const KLFLibResourceEngine::KLFLibEntryWithId& ewid = *it;
484  klfDbgT( "Adding entry id="<<ewid.id<<"; entry="<<ewid.entry ) ;
485  EntryNode e;
486  e.entryid = ewid.id;
487  e.minimalist = true;
488  e.entry = ewid.entry;
489  treeInsertEntry(e, true); // rebuildingCache=TRUE
490 
491 #ifndef Q_WS_MAC
492  if (k % 10 == 0)
493  progressReporter.doReportProgress((++k) * 100 / everything.size());
494 #endif
495  }
496 
497  if (pModel->pFlavorFlags & KLFLibModel::CategoryTree) {
498  // now fetch all categories, and insert them
499  klfDbgT("About to query categories...");
500  QVariantList vcatlist = pModel->pResource->queryValues(pModel->pResource->defaultSubResource(),
502  klfDbgT("... got categories. inserting them ...");
503  for (QVariantList::const_iterator vcit = vcatlist.begin(); vcit != vcatlist.end(); ++vcit) {
504  QString cat = (*vcit).toString();
505  if (cat.isEmpty() || cat == "/")
506  continue;
507  // cacheFindCategoryLabel(categoryelements, createIfNotExists, notifyQtApi, newCreatedAreChildrenFetched)
508  QStringList catelements = cat.split('/', QString::SkipEmptyParts);
509  int i = cacheFindCategoryLabel(catelements, true, false, false);
510  if (i < 0) {
511  qWarning()<<KLF_FUNC_NAME<<": Failed to create category node for category "<<cat;
512  }
513  // remember this category as suggestion
514  insertCategoryStringInSuggestionCache(catelements);
515  }
516  klfDbgT("... ins catnodes done.") ;
517  }
518 
519  fullDump(); // DEBUG
520 
521  pModel->reset();
522 
523  klfDbg("restoring persistent indexes ...");
524  QModelIndexList newPersistentIndexes = pModel->newPersistentIndexList(persistentIndexIds);
525  // and refresh all persistent indexes
526  pModel->changePersistentIndexList(persistentIndexes, newPersistentIndexes);
527  klfDbg("... done restoring persistent indexes.");
528 
529  klfDbgT( " end of func" ) ;
530 }
531 
532 
534 {
536 
537  if ( ! nodeid.valid() || nodeid == NodeId::rootNode())
538  return QModelIndex();
539 
540  // if row is -1, then we need to find the row of the item
541  if ( row < 0 ) {
542  row = getNodeRow(nodeid);
543  }
544 
545  // make sure all elements have been "fetched" up to this row
546 
547  klfDbg( ": nodeid="<<nodeid<<"; row="<<row<<"; col="<<column ) ;
548 
549  // get the parent node
550  Node node = getNode(nodeid);
551  NodeId parentid = node.parent;
552  if (!parentid.valid())
553  parentid = NodeId::rootNode();
554 
555  // if we cache getNode(parentid) make sure to keep a reference! it changes!
556  klfDbg("row="<<row) ;
557  while ( getNode(parentid).children.size() <= row && canFetchMore(parentid) ) {
558  klfDbgT(": need to fetch more children/size="
559  <<getNode(parentid).children.size()<<"<row="<<row<<" !");
560  fetchMore(parentid);
561  }
562 
563  // create & return the index
564  return pModel->createIndex(row, column, nodeid.universalId());
565 }
566 
567 
569 {
570  if ( ! index.isValid() )
571  return NodeId();
572  NodeId n = NodeId::fromUID(index.internalId());
573  // perform validity check on 'n'
574  if (n.kind == EntryKind) {
575  if (n.index < 0 || n.index >= pEntryCache.size()) {
576  qWarning()<<KLF_FUNC_NAME<<": Invalid entry node reference: "<<n;
577  return NodeId();
578  }
579  } else if (n.kind == CategoryLabelKind) {
580  if (n.index < 0 || n.index >= pCategoryLabelCache.size()) {
581  qWarning()<<KLF_FUNC_NAME<<": Invalid category label node reference: "<<n;
582  return NodeId();
583  }
584  } else {
585  qWarning()<<KLF_FUNC_NAME<<": Invalid node kind: "<<n;
586  return NodeId();
587  }
588  return n;
589 }
590 
592 {
593  if (!nodeid.valid())
594  return CategoryLabelNode();
595  Node &n = getNodeRef(nodeid);
596  return n;
597 }
599 {
600  if (!nodeid.valid()) {
601  qWarning()<<"KLFLibModelCache::getNodeRef: Invalid Node Id: "<<nodeid;
602  return pInvalidEntryNode;
603  }
604  if (nodeid.kind == EntryKind) {
605  if (nodeid.index < 0 || nodeid.index >= pEntryCache.size()) {
606  qWarning()<<"KLFLibModelCache::getNodeRef: Invalid Entry Node Id: "<<nodeid<<" : index out of range!";
607  return pInvalidEntryNode;
608  }
609  return pEntryCache[nodeid.index];
610  } else if (nodeid.kind == CategoryLabelKind) {
611  if (nodeid.index < 0 || nodeid.index >= pCategoryLabelCache.size()) {
612  qWarning()<<"KLFLibModelCache::getNodeRef: Invalid Category Label Node Id: "<<nodeid
613  <<" : index out of range!";
614  return pInvalidEntryNode;
615  }
616  return pCategoryLabelCache[nodeid.index];
617  }
618  qWarning("KLFLibModelCache::getNodeRef(): Invalid kind: %d (index=%d)\n", nodeid.kind, nodeid.index);
619  return pInvalidEntryNode;
620 }
622 {
623  static EntryNode dummyerrornode;
624  if (!nodeid.valid() || nodeid.kind != EntryKind ||
625  nodeid.index < 0 || nodeid.index >= pEntryCache.size()) {
626  qWarning()<<"KLFLibModelCache::getEntryNodeRef: Invalid Entry Node "<<nodeid<<"!";
627  return dummyerrornode;
628  }
629  if (enforceNotMinimalist && pEntryCache[nodeid.index].minimalist)
630  ensureNotMinimalist(nodeid);
631 
632  return pEntryCache[nodeid.index];
633 }
634 
636 {
637  if (!nodeid.valid() || nodeid.kind != CategoryLabelKind ||
638  nodeid.index < 0 || nodeid.index >= pCategoryLabelCache.size()) {
639  qWarning()<<"KLFLibModelCache::getCat.LabelNode: Invalid Category Label Node "<<nodeid<<"!";
640  return pCategoryLabelCache[0];
641  }
642  return pCategoryLabelCache[nodeid.index];
643 }
644 
646 {
647  if ( ! node.valid() )
648  return -1;
649  if ( node == NodeId::rootNode() )
650  return 0;
651 
652  Node n = getNode(node);
653 
654  NodeId pparentid = n.parent;
655  if ( !pparentid.valid() ) {
656  // shouldn't happen (!?!), only parentless item should be root node !
657  qWarning()<<KLF_FUNC_NAME<<": Found parentless non-root node: "<<node;
658  return 0;
659  }
660  Node pparent = getNode(pparentid);
661  // find child in parent
662  int k;
663  for (k = 0; k < pparent.children.size(); ++k)
664  if (pparent.children[k] == node)
665  return k;
666 
667  // search failed
668  qWarning()<<KLF_FUNC_NAME<<": Unable to get node row: parent-child one-way broken!! node="<<node;
669  return -1;
670 }
671 
673 {
675  // fetch & complete some minimalist entry(ies)
676  NodeId n;
677  // prepare some entry IDs to fetch
679  if (countdown < 0)
680  countdown = pModel->pFetchBatchCount;
681  // n = prevNode(p);
682  // if (!n.valid())
683  n = p;
684  for (; n.valid() && countdown-- > 0; n = nextNode(n)) {
685  if (n.kind == CategoryLabelKind) {
686  ++countdown; // don't count category labels
687  continue;
688  }
689  if (n.kind == EntryKind) {
690  EntryNode en = getEntryNodeRef(n);
691  if (en.minimalist) // if this entry is "minimalist", update it
692  wantedIds[en.entryid] = n;
693  continue;
694  }
695  qWarning()<<KLF_FUNC_NAME<<": Got unknown kind="<<n.kind;
696  }
697  // fetch the required entries
699  pModel->pResource->entries(wantedIds.keys(), QList<int>()); // fetch all properties
700  int k;
701  for (k = 0; k < updatedentries.size(); ++k) {
702  KLFLib::entryId eid = updatedentries[k].id;
703  if ( ! wantedIds.contains(eid) ) {
704  qWarning()<<KLF_FUNC_NAME<<" got unrequested updated entry ID ?! id="<<eid;
705  continue;
706  }
707  NodeId nid = wantedIds[eid];
708  pEntryCache[nid.index].entry = updatedentries[k].entry;
709  pEntryCache[nid.index].minimalist = false;
710  }
711  klfDbg( ": updated entries "<<wantedIds.keys() ) ;
712 }
713 
715 {
717  if (pIsFetchingMore)
718  return false;
719 
720  if (!parentId.valid())
721  parentId = NodeId::rootNode();
722 
723  klfDbg("parentId="<<parentId) ;
724 
725  const Node& node = getNodeRef(parentId);
726 
727  klfDbg("node="<<node) ;
728 
729  if (!node.allChildrenFetched)
730  return true;
731 
732  klfDbg("cannot fetchmore.") ;
733  return false;
734 }
735 void KLFLibModelCache::fetchMore(NodeId n, int fetchBatchCount)
736 {
738  klfDbg( "\t parentId: n="<<n<<"; valid="<<n.valid() <<"; url="<<pModel->url() ) ;
739 
740  if (fetchBatchCount < 0) // set default value
741  fetchBatchCount = pModel->pFetchBatchCount;
742 
743  if (pIsFetchingMore)
744  return;
745  pIsFetchingMore = true;
746 
747  // see function doxygen doc for nIndex param info.
748 
749  if (!n.valid())
750  n = NodeId::rootNode();
751 
752  if (n.kind != CategoryLabelKind) {
753  klfDbg("can't fetch more in this node kind. n="<<n);
754  qWarning()<<KLF_FUNC_NAME<<": Can't fetch more children of a non-category-label node.";
755  return;
756  }
757 
758  CategoryLabelNode& noderef = getCategoryLabelNodeRef(n);
759  klfDbg( "\t -> n="<<n<<"; noderef: kind="<<noderef.kind<<", allChildrenFetched="<<noderef.allChildrenFetched ) ;
760 
761  if (noderef.allChildrenFetched) {
762  // all children have been fetched, cannot do anything more.
763  klfDbg("can't fetch more: all children are fetched! noderef="<<noderef<<"; n (the id)="<<n) ;
764  // qWarning()<<KLF_FUNC_NAME<<": can't fetch any more items!";
765  pIsFetchingMore = false;
766  return;
767  }
768 
769  // fetch more items, using query().
771  if (pModel->pFlavorFlags & KLFLibModel::CategoryTree) {
775  }
776  q.orderPropId = pLastSortPropId;
777  q.orderDirection = pLastSortOrder;
778  q.limit = pModel->pFetchBatchCount;
779  q.skip = noderef.children.size();
780  q.wantedEntryProperties = minimalistEntryPropIds();
782  // _query()_ the resource
783  int count = pModel->pResource->query(pModel->pResource->defaultSubResource(), q, &qr);
784  if (count < 0) {
785  qWarning()<<KLF_FUNC_NAME<<": error fetching more results: count is "<<count;
786  pIsFetchingMore = false;
787  return;
788  }
789 
796  // append all results into category-label-noderef 'noderef'
797 
798  // notify any views
799  pModel->startLayoutChange(false);
800  pModel->beginInsertRows(createIndexFromId(n, -1, 0), noderef.children.size(),
801  noderef.children.size() + qr.entryWithIdList.size()-1);
802 
803  // if we fetched all the remaining entries, then set allChildrenFetched to TRUE
804  if (count < q.limit) {
805  noderef.allChildrenFetched = true;
806  }
807 
808  int k;
809  for (k = 0; k < qr.entryWithIdList.size(); ++k) {
811  EntryNode e;
812  e.entryid = ewid.id;
813  e.minimalist = true;
814  e.entry = ewid.entry;
815  e.parent = n;
816  pEntryCache.append(e);
817  NodeId entryindex;
818  entryindex.kind = EntryKind;
819  entryindex.index = pEntryCache.size()-1;
820 
821  klfDbg("appending "<<e<<" in category node.") ;
822 
823  noderef.children.append(entryindex);
824  }
825 
826  klfDbg("Fetched more. About to notify view of end of rows inserted ... meanwile the dump:") ;
827  fullDump();
828 
829  pModel->endInsertRows();
830  klfDbg("signal emitted. restore persistent indexes...") ;
831  pModel->endLayoutChange(false);
832 
833  klfDbg("views notified, persistent indexes restored.") ;
834 
835  pIsFetchingMore = false;
836 }
837 
838 
839 
840 void KLFLibModelCache::updateData(const QList<KLFLib::entryId>& entryIdList, int modifyType)
841 {
843  klfDbg( "modifyType="<<modifyType<<" entryIdList="<<entryIdList ) ;
844 
845  if (modifyType == KLFLibResourceEngine::UnknownModification) {
846  klfDbg("Performing full refresh.") ;
847  rebuildCache();
848  return;
849  }
850 
851  if (entryIdList.size() > 10 &&
852  (entryIdList.size() > pEntryCache.size()/3 || entryIdList.size() > 100)) {
853  // too big a modification, just rebuild the cache
854  klfDbg("Performing full refresh.") ;
855  rebuildCache();
856  return;
857  }
858 
859 #ifndef Q_WS_MAC
860  // progress reporting [here, not above, because rebuildCache() has its own progress reporting]
861  KLFProgressReporter progressReporter(0, entryIdList.size(), NULL);
862  emit pModel->operationStartReportingProgress(&progressReporter,
863  QObject::tr("Updating View...", "[[KLFLibModelCache, progress text]]"));
864  progressReporter.doReportProgress(0);
865 #endif
866 
867  switch (modifyType) {
869  { // entries inserted
870  QList<KLFLibResourceEngine::KLFLibEntryWithId> entryList = pModel->pResource->entries(entryIdList);
871  int k;
872  for (k = 0; k < entryList.size(); ++k) {
873  EntryNode en;
874  en.entryid = entryList[k].id;
875  en.minimalist = false;
876  en.entry = entryList[k].entry;
879  treeInsertEntry(en);
880  qDebug("%s: entry ID %d inserted", KLF_FUNC_NAME, entryIdList[k]);
881 #ifndef Q_WS_MAC
882  if (k % 20 == 0)
883  progressReporter.doReportProgress(k+1);
884 #endif
885  }
886  break;
887  }
889  { // entry moved in category tree or just changed
890  QList<KLFLibResourceEngine::KLFLibEntryWithId> entryList = pModel->pResource->entries(entryIdList);
891  int k;
892  for (k = 0; k < entryIdList.size(); ++k) {
893  klfDbg("modifying entry ID="<<entryIdList[k]<<", modif."<<k) ;
894  NodeId n = findEntryId(entryIdList[k]);
895  if (!n.valid()) {
896  qWarning()<<KLF_FUNC_NAME<<": n is invalid! (kind="<<n.kind<<", index="<<n.index<<")";
897  continue;
898  }
899  KLFLibEntry oldentry = pEntryCache[n.index].entry;
900  KLFLibEntry newentry = entryList[k].entry;
901  klfDbg("entry change: old="<<oldentry<<"; new="<<newentry) ;
902  // the modified entry may have a different category, move it if needed
903  if (newentry.category() != oldentry.category() && (pModel->pFlavorFlags & KLFLibModel::CategoryTree)) {
904  pModel->startLayoutChange(false);
905  EntryNode entrynode = treeTakeEntry(n, true); // remove it from its position in tree
906  // klfDbg( "\tremoved entry. dump:\n"
907  // <<"\t Entry Cache="<<pEntryCache<<"\n\t CategoryLabelCache = "<<pCategoryLabelCache ) ;
908  // dumpNodeTree(NodeId::rootNode());
909  // revalidate the removed entry
910  entrynode.entryid = entryIdList[k];
911  entrynode.entry = newentry;
912  // and insert it at the (new) correct position (automatically positioned!)
913  treeInsertEntry(entrynode);
914  pModel->endLayoutChange(false);
915  QModelIndex idx = createIndexFromId(n, -1, 0);
916  emit pModel->dataChanged(idx, idx);
917  } else {
918  // just some data change
919  pEntryCache[n.index].entry = newentry;
920  QModelIndex idx = createIndexFromId(n, -1, 0);
921  emit pModel->dataChanged(idx, idx);
922  }
923 #ifndef Q_WS_MAC
924  if (k % 20 == 0)
925  progressReporter.doReportProgress(k+1);
926 #endif
927  }
928  break;
929  }
931  { // entry removed
932  int k;
933  for (k = 0; k < entryIdList.size(); ++k) {
934  qDebug("%s: deleting entry ID=%d.", KLF_FUNC_NAME, entryIdList[k]);
935  // entry deleted
936  NodeId n = findEntryId(entryIdList[k]);
937  if (!n.valid()) {
938  qWarning()<<KLF_FUNC_NAME<<": n not valid! n=(kind="<<n.kind<<", index="<<n.index<<")";
939  continue;
940  }
941  (void) treeTakeEntry(n);
942 #ifndef Q_WS_MAC
943  if (k % 20 == 0)
944  progressReporter.doReportProgress(k+1);
945 #endif
946  }
947  break;
948  }
949  default:
950  {
951  qWarning()<<KLF_FUNC_NAME<<": Bad modify-type parameter: "<<modifyType;
952  rebuildCache();
953  return;
954  }
955  }
956 
957  // updateCacheSetupModel();
958  klfDbg( ": udpated; full tree dump:" ) ;
959  fullDump();
960 }
961 
962 
963 void KLFLibModelCache::treeInsertEntry(const EntryNode& entrynode, bool rebuildingcache)
964 {
966 
967  bool notifyQtApi = !rebuildingcache;
968  klfDbg( "entrynode="<<entrynode<<",notifyQtApi="<<notifyQtApi<<"" ) ;
969 
970  // first find the appropriate category label parent
971 
972  // start by looking at category
973 
974  QString category = entrynode.entry.category();
975  QStringList catelements = category.split('/', QString::SkipEmptyParts);
976  insertCategoryStringInSuggestionCache(catelements);
977 
978  // and find the category parent
979 
980  IndexType catindex;
981  if (pModel->displayType() == KLFLibModel::LinearList) {
982  // add as child of root element
983  catindex = 0;
984  } else if (pModel->displayType() == KLFLibModel::CategoryTree) {
985  // find/create category label node (creating the full tree if needed)
986  catindex = cacheFindCategoryLabel(catelements, true, notifyQtApi, rebuildingcache?false:true);
987  } else {
988  qWarning("Flavor Flags have unknown display type! flavorFlags=%#010x", pModel->pFlavorFlags);
989  catindex = 0;
990  }
991 
992  NodeId parentid = NodeId(CategoryLabelKind, catindex);
993 
994  // now actually create the entry cache node
995  int index = pEntryCache.insertNewNode(entrynode);
996  NodeId n = NodeId(EntryKind, index);
997  // invalidate the node until the insert process is finished.
998  // the (invalid but with correct info) entry needs to reside in the cache for qLowerBound() below.
999  pEntryCache[index].parent = NodeId();
1000 
1001  // now we determined the parent of the new entry in the category tree, we will actually
1002  // insert the item according to current sort instructions.
1003  Node& parentref = getNodeRef(parentid);
1004  QList<NodeId> & childlistref = parentref.children;
1005  int insertPos;
1006  if (rebuildingcache || pLastSortPropId < 0) {
1007  insertPos = childlistref.size(); // no sorting, just append the item
1008  } else {
1009  KLFLibModelSorter srt =
1010  KLFLibModelSorter(this, pModel->pEntrySorter, pModel->pFlavorFlags & KLFLibModel::GroupSubCategories);
1011  // Note: as long as we are instructed to insert the new item at the end, we need to fetchMore() to ensure
1012  // that all elements logically appearing before the new element are fetched.
1013  bool retry;
1014  do {
1015  retry = false;
1016  // qLowerBound returns an iterator. subtract begin() to get absolute index
1017  insertPos = qLowerBound(childlistref.begin(), childlistref.end(), n, srt) - childlistref.begin();
1018  if (insertPos > childlistref.size()-10 && canFetchMore(parentid)) {
1019  fetchMore(parentid);
1020  retry = true;
1021  }
1022  } while (retry);
1023  // by fetching more, we may possibly have actually fetched the entry that we were instructed to insert
1024  // in the first place. Check.
1025  if (insertPos < childlistref.size() && childlistref[insertPos] == n)
1026  return; // job already done.
1027  }
1028 
1029  CategoryLabelNode &catLabelNodeRef = getCategoryLabelNodeRef(parentid);
1030 
1031  // and insert it again at the required spot
1032  if (notifyQtApi) {
1033  QModelIndex parentidx = createIndexFromId(parentid, -1, 0);
1034  pModel->beginInsertRows(parentidx, insertPos, insertPos);
1035  }
1036 
1037  qDebug("\tinserting (%d,%d) at pos %d in category '%s'", n.kind, n.index, insertPos,
1038  qPrintable(catLabelNodeRef.fullCategoryPath));
1039 
1040  pEntryCache[n.index].parent = parentid; // set the parent, thus validating the node
1041 
1042  childlistref.insert(insertPos, n); // insert into list of children
1043 
1044  if (notifyQtApi)
1045  pModel->endInsertRows();
1046 }
1047 
1049 {
1051 
1052  klfDbg( "("<<nodeid<<","<<notifyQtApi<<")" ) ;
1053  NodeId n = nodeid;
1054  // keep it in cache to keep indexes valid, but invalidate the entry so findEntryIdList() doesn't find it
1055  // then remove all empty categories above the removed item.
1056  if (nodeid.kind != EntryKind) {
1057  qWarning()<<KLF_FUNC_NAME<<": nodeid="<<nodeid<<" does not reference an entry node!";
1058  return EntryNode();
1059  }
1060  EntryNode entrynode = getEntryNodeRef(nodeid);
1061 
1062  klfDbg("The entrynode in question is "<<entrynode) ;
1063 
1064  NodeId parentid;
1065  bool willRemoveParent;
1066  do {
1067  if (!n.valid())
1068  break; // what's going on?
1069  parentid = getNode(n).parent;
1070  if (n == NodeId::rootNode())
1071  break; // stop before removing root node (!)
1072  klfDbg("Getting interested to remove entry ID="<<n<<", from its parent of id="<<parentid) ;
1073  if (parentid.kind != CategoryLabelKind) {
1074  qWarning()<<KLF_FUNC_NAME<<"("<<n<<"): Bad parent node kind: "<<parentid.kind<<"!";
1075  return entrynode;
1076  }
1077  QModelIndex parent = createIndexFromId(parentid, -1, 0);
1078  int childIndex = pCategoryLabelCache[parentid.index].children.indexOf(n);
1079  if (childIndex < 0) {
1080  qWarning()<<KLF_FUNC_NAME<<"("<<n<<"): !!?! bad child-parent relation, can't find "<<n
1081  <<" in child list "<<pCategoryLabelCache[parentid.index].children<<"; full dump:\n"
1082  <<"\tEntryCache = "<<pEntryCache<<"\n"
1083  <<"\tCat.Lbl.Cache = "<<pCategoryLabelCache;
1084  return entrynode;
1085  }
1086  if (notifyQtApi)
1087  pModel->beginRemoveRows(parent, childIndex, childIndex);
1088  // will-Remove-Parent if node 'n' is the sole remaining child of node 'parentid'
1089  willRemoveParent = parentid.valid() && getNode(parentid).children.size() <= 1;
1090  // remove 'n'
1091  if (n.kind == EntryKind) {
1092  klfDbg("unlinking entry node "<<n);
1093  pEntryCache.unlinkNode(n);
1094  } else if (n.kind == CategoryLabelKind) {
1095  klfDbg("unlinking category label node "<<n);
1096  pCategoryLabelCache.unlinkNode(n);
1097  } else {
1098  qWarning()<<KLF_FUNC_NAME<<": unlinking elements: unknown node kind in id="<<n<<"!";
1099  }
1100  // remove n from parents
1101  Node & parentref = getNodeRef(parentid);
1102  klfDbg("removing child #"<<childIndex<<" from parent id="<<parentid<<"; parent itself is "<<parentref) ;
1103  parentref.children.removeAt(childIndex);
1104  if (notifyQtApi)
1105  pModel->endRemoveRows();
1106  n = parentid;
1107  } while (willRemoveParent);
1108 
1109  return entrynode;
1110 }
1111 
1112 
1113 
1114 
1116 /* */ KLFLibModelCache::cacheFindCategoryLabel(QStringList catelements, bool createIfNotExists,
1117  bool notifyQtApi, bool newlyCreatedAreChildrenFetched)
1118 {
1119  klfDbg( "catelmnts="<<catelements<<", createIfNotExists="<<createIfNotExists<<", notifyQtApi="<<notifyQtApi ) ;
1120 
1121  QString catelpath = catelements.join("/");
1122 
1123  int i;
1124  for (i = 0; i < pCategoryLabelCache.size(); ++i) {
1125  if (pCategoryLabelCache.isAllocated(i) &&
1126  pCategoryLabelCache[i].parent.valid() &&
1127  pCategoryLabelCache[i].fullCategoryPath == catelpath) {
1128  // found the valid category label
1129  return i;
1130  }
1131  }
1132  if (catelements.isEmpty())
1133  return 0; // index of root category label
1134 
1135  // if we haven't found the correct category, we may need to create it if requested by
1136  // caller. If not, return failure immediately
1137  if ( ! createIfNotExists )
1138  return -1;
1139 
1140  if (pModel->displayType() != KLFLibModel::CategoryTree) {
1141  qWarning("cacheFindCategoryLabel: but not in a category tree display type (flavor flags=%#010x)",
1142  pModel->pFlavorFlags);
1143  return 0;
1144  }
1145 
1146  QStringList catelementsparent = catelements.mid(0, catelements.size()-1);
1147  IndexType parent_index = cacheFindCategoryLabel(catelementsparent, true, notifyQtApi);
1148 
1150  KLFLibModelCache::KLFLibModelSorter(this, pModel->pEntrySorter,
1151  pModel->pFlavorFlags & KLFLibModel::GroupSubCategories);
1152 
1153  // the category label node to add
1155  c.allChildrenFetched = newlyCreatedAreChildrenFetched;
1156  c.fullCategoryPath = catelpath;
1157  c.categoryLabel = catelements.last(); // catelements is non-empty, see above
1158  // now create this last category label
1159  IndexType this_index = pCategoryLabelCache.insertNewNode(c);
1160  int insertPos;
1161  CategoryLabelNode & parentCatLabelNodeRef = pCategoryLabelCache[parent_index];
1162  QList<NodeId> & childlistref = parentCatLabelNodeRef.children;
1163  if (pLastSortPropId < 0) {
1164  insertPos = childlistref.size(); // no sorting, just append the item
1165  } else {
1166  // qLowerBound returns an iterator. subtract begin() to get absolute index
1167  insertPos = qLowerBound(childlistref.begin(), childlistref.end(),
1168  NodeId(CategoryLabelKind, this_index), srt) - childlistref.begin();
1169  }
1170  klfDbg( ": About to insert rows in "<<NodeId(CategoryLabelKind, parent_index)
1171  <<" at position "<<insertPos ) ;
1172  if (notifyQtApi) {
1173  QModelIndex parentidx = createIndexFromId(NodeId(CategoryLabelKind, parent_index), -1, 0);
1174  pModel->beginInsertRows(parentidx, insertPos, insertPos);
1175  }
1176  qDebug("%s: Inserting this_index=%d in parent_index=%d 's children", KLF_FUNC_NAME, this_index,
1177  parent_index);
1178 
1179  childlistref.insert(insertPos, NodeId(CategoryLabelKind, this_index));
1180  pCategoryLabelCache[this_index].parent = NodeId(CategoryLabelKind, parent_index);
1181 
1182  if (notifyQtApi)
1183  pModel->endInsertRows();
1184 
1185  // and return the created category label index
1186  return this_index;
1187 }
1188 
1190 {
1191  // return an internal string representation of the value of the property 'entryProperty' in node ptr.
1192  // or the category title if node is a category
1193 
1194  if (!n.valid() || n.isRoot())
1195  return QString();
1196  if (entryProperty < 0) {
1197  qWarning()<<KLF_FUNC_NAME<<": invalid entry property ID : "<<entryProperty;
1198  return QString();
1199  }
1200  if (n.kind == EntryKind) {
1201  EntryNode en = getEntryNodeRef(n);
1202  // don't update minimalist nodes (assume minimalist info is enough)
1203  return pModel->entrySorter()->entryValue(en.entry, entryProperty);
1204  }
1205  if (n.kind == CategoryLabelKind)
1206  return getCategoryLabelNodeRef(n).categoryLabel;
1207 
1208  qWarning()<<KLF_FUNC_NAME<<": Bad Item Kind: "<<n;
1209  return QString();
1210 }
1211 
1212 // private
1213 void KLFLibModelCache::sortCategory(NodeId category, KLFLibModelSorter *sorter, bool rootCall)
1214 {
1215  bool requireSimpleReverse = false;
1216 
1217  // some optimizations based on the current sorting
1218  if (sorter->entrySorter()->propId() == pLastSortPropId) {
1219  // already sorting according to that column
1220  if (sorter->entrySorter()->order() == pLastSortOrder) {
1221  // exact same sorting required, already done.
1222  return;
1223  } else {
1224  // opposite sorting (eg. Ascending instead of Descending)
1225  // -> reverse child list
1226  requireSimpleReverse = true;
1227  }
1228  }
1229 
1230  int k;
1231  // sort this category's children
1232 
1233  // This works both in LinearList and in CategoryTree display types. (In LinearList
1234  // display type, call this function on root category node)
1235 
1236  if (category.kind != CategoryLabelKind)
1237  return;
1238  if (category.index < 0 || category.index >= pCategoryLabelCache.size())
1239  return;
1240 
1241  if (sorter->entrySorter()->propId() < 0)
1242  return; // no sorting required
1243 
1244  QList<NodeId>& childlistref = pCategoryLabelCache[category.index].children;
1245  if (requireSimpleReverse) {
1246  // reverse the child list (but not category list if flavor is to group them)
1247  int N = childlistref.size();
1248  int firstEntryInd = 0;
1249  if (pModel->pFlavorFlags & KLFLibModel::GroupSubCategories) {
1250  for (firstEntryInd = 0; firstEntryInd < N &&
1251  childlistref[firstEntryInd].kind != EntryKind; ++firstEntryInd)
1252  ;
1253  // in case the GroupSubCategories flag is false, firstEntryInd is zero -> reverse all
1254  }
1255  // swap all entries, skipping the grouped sub-categories
1256  for (k = 0; k < (N-firstEntryInd)/2; ++k)
1257  qSwap(childlistref[firstEntryInd+k], childlistref[N-k-1]);
1258  } else {
1259  qSort(childlistref.begin(), childlistref.end(), *sorter); // normal sort
1260  }
1261 
1262  // and sort all children's children
1263  for (k = 0; k < childlistref.size(); ++k)
1264  if (childlistref[k].kind == CategoryLabelKind)
1265  sortCategory(childlistref[k], sorter, false /* not root call */);
1266 
1267  if (rootCall) {
1268  pLastSortPropId = sorter->entrySorter()->propId();
1269  pLastSortOrder = sorter->entrySorter()->order();
1270  }
1271 }
1272 
1273 
1275 {
1276  // klfDbg( "KLFLibModelCache::nextNode("<<n<<"): full tree dump:" ) ;
1277  // fullDump();
1278 
1279  if (!n.valid()) {
1280  // start with root category (but don't return the root category itself)
1281  n = NodeId::rootNode();
1282  }
1283  // walk children, if any
1284  Node nn = getNode(n);
1285  if (nn.children.size() > 0) {
1286  return nn.children[0];
1287  }
1288  if (!nn.allChildrenFetched && canFetchMore(n)) {
1289  // we may have children, so try to fetch children
1290  fetchMore(n);
1291  // and recurse, now that more children have possibly been fetched.
1292  return nextNode(n);
1293  }
1294  // no children, find next sibling.
1295  NodeId parentid;
1296  while ( (parentid = nn.parent).valid() ) {
1297  Node parent = getNode(parentid);
1298  int row = getNodeRow(n);
1299  if (row+1 < parent.children.size()) {
1300  // there is a next sibling: return it
1301  return parent.children[row+1];
1302  }
1303  if (!parent.allChildrenFetched && canFetchMore(parentid)) {
1304  // there is possibly a next sibling, it just possibly hasn't been fetched.
1305  fetchMore(parentid);
1306  // now that the more children has been fetched for this parent, try again: (by recursing)
1307  return nextNode(n);
1308  }
1309  // no next sibling, so go up the tree
1310  n = parentid;
1311  nn = parent;
1312  }
1313  // last entry passed
1314  return NodeId();
1315 }
1316 
1318 {
1319  if (!n.valid() || n.isRoot()) {
1320  // look for last node in tree.
1321  return lastNode(NodeId()); // NodeId() is accepted by lastNode.
1322  }
1323  // find previous sibling
1324  NodeId parentId = getNode(n).parent;
1325  Node parent = getNode(parentId);
1326  int row = getNodeRow(n);
1327  if (row > 0) {
1328  // there is a previous sibling: find its last node
1329  return lastNode(parent.children[row-1]);
1330  }
1331  // there is no previous sibling: so we can return the parent
1332  // except if parent is the root node, in which case we return an invalid NodeId.
1333  if (parentId == NodeId::rootNode())
1334  return NodeId();
1335 
1336  return parentId;
1337 }
1338 
1340 {
1341  if (!n.valid())
1342  n = NodeId::rootNode(); // root category
1343 
1344  Node nn = getNode(n);
1345 
1346  // get the last child of node 'n'
1347  // this includes fetching _all_ its children if applicable
1348  while (!nn.allChildrenFetched) {
1349  if (!canFetchMore(n)) {
1350  qWarning()<<KLF_FUNC_NAME<<": internal error: node "<<n<<", node="<<nn
1351  <<" has allChildrenFetched=false, but can't fetch more!";
1352  break;
1353  }
1354  fetchMore(n);
1355  nn = getNode(n);
1356  }
1357 
1358  if (nn.children.size() == 0)
1359  return n; // no children: n is itself the "last node"
1360 
1361  // children: return last node of last child.
1362  return lastNode(nn.children[nn.children.size()-1]);
1363 }
1364 
1365 
1367 {
1368  // ORDER OF RESULT IS NOT GARANTEED != entryIdForIndexList()
1369 
1370  QList<KLFLib::entryId> idList;
1371  int k;
1372  QList<NodeId> nodeIds;
1373  // walk all indexes and get their IDs
1374  for (k = 0; k < indexlist.size(); ++k) {
1375  NodeId n = getNodeForIndex(indexlist[k]);
1376  if ( !n.valid() || n.kind != EntryKind)
1377  continue;
1378  if ( nodeIds.contains(n) ) // duplicate, probably for another column
1379  continue;
1380  nodeIds << n;
1381  idList << getEntryNodeRef(n).entryid;
1382  }
1383  return idList;
1384 }
1385 
1386 
1387 
1389 {
1390  // ORDER OF RESULT GARANTEED != entryIdList()
1391 
1392  QList<KLFLib::entryId> eidlist;
1393  int k;
1394  for (k = 0; k < indexlist.size(); ++k) {
1395  NodeId node = getNodeForIndex(indexlist[k]);
1396  if ( !node.valid() || node.kind != EntryKind ) {
1397  eidlist << (KLFLib::entryId) -1;
1398  continue;
1399  }
1400  eidlist << getEntryNodeRef(node).entryid;
1401  }
1402  return eidlist;
1403 }
1405 {
1406  klfDbg( ": eidlist="<<eidlist ) ;
1407  int k;
1408  int count = 0;
1409  QModelIndexList indexlist;
1410  // pre-fill index list
1411  for (k = 0; k < eidlist.size(); ++k)
1412  indexlist << QModelIndex();
1413 
1414  // walk entry list
1415  for (k = 0; k < pEntryCache.size(); ++k) {
1416  if (!pEntryCache[k].entryIsValid())
1417  continue;
1418  int i = eidlist.indexOf(pEntryCache[k].entryid);
1419  if (i >= 0) {
1420  indexlist[i] = createIndexFromId(NodeId(EntryKind, k), -1, 0);
1421  if (++count == eidlist.size())
1422  break; // found 'em all
1423  }
1424  }
1425  return indexlist;
1426 }
1427 
1429 {
1430  klfDbg("eId="<<eId) ;
1431  int k;
1432  for (k = 0; k < pEntryCache.size(); ++k)
1433  if (pEntryCache[k].entryid == eId && pEntryCache[k].entryIsValid())
1434  return NodeId(EntryKind, k);
1435 
1436  klfDbg("...not found.") ;
1437  return NodeId();
1438 }
1439 
1440 
1442 {
1443 #ifdef KLF_DEBUG
1444  int k;
1445  qDebug("---------------------------------------------------------");
1446  qDebug("------------- FULL CACHE DUMP ---------------------------");
1447  qDebug("---------------------------------------------------------");
1448  qDebug(" ");
1449  qDebug("Entry cache dump:");
1450  for (k = 0; k < pEntryCache.size(); ++k)
1451  qDebug()<<"#"<<k<<": "<<pEntryCache[k];
1452  qDebug(" ");
1453  qDebug("Category Label cache dump: ");
1454  for (k = 0; k < pCategoryLabelCache.size(); ++k)
1455  qDebug()<<"#"<<k<<": "<<pCategoryLabelCache[k];
1456  qDebug(" ");
1457  dumpNodeTree(NodeId::rootNode());
1458  qDebug(" ");
1459  qDebug("---------------------------------------------------------");
1460  qDebug("---------------------------------------------------------");
1461  qDebug("---------------------------------------------------------");
1462 #endif
1463 }
1464 
1466 {
1467 #ifdef KLF_DEBUG
1468 
1469  if (indent == 0) {
1470  qDebug(" ");
1471  qDebug("---------------- NODE TREE DUMP -------------------------");
1472  }
1473  char sindent[] = " + ";
1474  if (indent < (signed)strlen(sindent))
1475  sindent[indent] = '\0';
1476 
1477  if (!node.valid())
1478  qDebug() << sindent << "(Invalid Node)";
1479 
1480  EntryNode en;
1481  CategoryLabelNode cn;
1482  switch (node.kind) {
1483  case EntryKind:
1484  en = getEntryNodeRef(node);
1485  qDebug() << sindent << node <<"\n"<<sindent<<"\t\t"<<en;
1486  break;
1487  case CategoryLabelKind:
1488  cn = getCategoryLabelNodeRef(node);
1489  qDebug() << sindent << node << "\n"<<sindent<<"\t\t"<<cn;
1490  break;
1491  default:
1492  qDebug() << sindent << node << "\n"<<sindent<<"\t\t*InvalidNodeKind*(kind="<<node.kind<<")";
1493  }
1494 
1495  if (node.valid()) {
1496  Node n = getNode(node);
1497  int k;
1498  for (k = 0; k < n.children.size(); ++k) {
1499  dumpNodeTree(getNode(node).children[k], indent+4);
1500  }
1501  }
1502 
1503  if (indent == 0) {
1504  qDebug("---------------------------------------------------------");
1505  qDebug("---------------------------------------------------------");
1506  }
1507 
1508 #endif
1509 }
1510 
1511 
1512 
1513 
1514 // -------------------------------------------------------
1515 
1516 // MODEL ITSELF
1517 
1518 
1519 
1521  : QAbstractItemModel(parent), pFlavorFlags(flavorFlags)
1522 {
1524 
1525  // set the default value of N items per batch
1526  // the initial default value is ridicuously small because fetchMore() is called during startup
1527  // sequence too many times (in my opinion). the batch count is increased once the widget is
1528  // shown, see KLFLibDefaultView::showEvent().
1529  // EDIT: the fetchMore() seems to be called when applying skins
1530  // EDIT(2): with new optimizations, the above not may not apply any more. needs testing.
1531  setFetchBatchCount(30);
1532 
1533  // by default, sort according to DateTime, recent first
1534  pEntrySorter = new KLFLibEntrySorter(KLFLibEntry::DateTime, Qt::DescendingOrder);
1535 
1536  pCache = new KLFLibModelCache(this);
1537  // assign KLF_DEBUG ref-instance later, as we don't have one yet!
1538 
1539  setResource(engine);
1540  // DON'T CONNECT SIGNALs FROM RESOURCE ENGINE HERE, we are informed from
1541  // the view. This is because of the KLFAbstractLibView API.
1542  // connect(engine, SIGNAL(dataChanged(...)), this, SLOT(updateData(...)));
1543 
1544 }
1545 
1547 {
1549  delete pCache;
1550  if (pEntrySorter)
1551  delete pEntrySorter;
1552 }
1553 
1555 {
1557 
1559 
1560  pResource = resource;
1561  updateCacheSetupModel();
1562 }
1563 
1565 {
1567  if (pResource == NULL) {
1568  qWarning()<<KLF_FUNC_NAME<<": resource is NULL!";
1569  return QUrl();
1570  }
1572  return pResource->url();
1573 
1574  // return URL with the default sub-resource (as we're displaying that one only)
1576 }
1577 
1578 
1579 
1580 void KLFLibModel::setFlavorFlags(uint flags, uint modify_mask)
1581 {
1583  if ( (flags & modify_mask) == (pFlavorFlags & modify_mask) )
1584  return; // no change
1585  uint other_flags = pFlavorFlags & ~modify_mask;
1586  pFlavorFlags = flags | other_flags;
1587 
1588  // stuff that needs update
1589  if (modify_mask & DisplayTypeMask) {
1590  updateCacheSetupModel();
1591  }
1592  if (modify_mask & GroupSubCategories) {
1593  int col = columnForEntryPropertyId(pEntrySorter->propId());
1594  Qt::SortOrder ord = pEntrySorter->order();
1595  // force full re-sort
1596  sort(-1, ord); // by first setting to unsorted
1597  sort(col, ord); // and then re-sorting correctly
1598  }
1599 }
1601 {
1602  return pFlavorFlags;
1603 }
1604 
1605 void KLFLibModel::prefetch(const QModelIndexList& indexes) const
1606 {
1608  int k;
1609  for (k = 0; k < indexes.size(); ++k) {
1610  if (!indexes[k].isValid())
1611  continue;
1612  KLFLibModelCache::NodeId p = pCache->getNodeForIndex(indexes[k]);
1613  if (!p.valid() || p.isRoot()) {
1614  klfDbg("Invalid index: indexes[k].row="<<indexes[k].row());
1615  continue;
1616  }
1617  pCache->ensureNotMinimalist(p);
1618  }
1619 }
1620 
1622 {
1624  // KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
1625  // klfDbg( "\tindex="<<index<<"; role="<<role ) ;
1626 
1627  KLFLibModelCache::NodeId p = pCache->getNodeForIndex(index);
1628  if (!p.valid() || p.isRoot())
1629  return QVariant();
1630 
1631  // if this node is not yet visible, hide it...
1632  KLFLibModelCache::Node thisNode = pCache->getNode(p);
1634  KLFLibModelCache::Node parentNode = pCache->getNode(parent);
1635 
1636  if (role == ItemKindItemRole)
1637  return QVariant::fromValue<int>(p.kind);
1638 
1639  if (ItemKind(p.kind) == EntryKind) {
1640  // --- GET ENTRY DATA ---
1641  const KLFLibModelCache::EntryNode& ep = pCache->getEntryNodeRef(p);
1642 
1643  if (role == EntryContentsTypeItemRole)
1644  return entryColumnContentsPropertyId(index.column());
1645  if (role == EntryIdItemRole)
1646  return QVariant::fromValue<KLFLib::entryId>(ep.entryid);
1647 
1648  if (role == Qt::ToolTipRole || role == Qt::DisplayRole) { // current contents
1650  if (propId == KLFLibEntry::Preview)
1651  propId = KLFLibEntry::Tags;
1652  role = entryItemRole(propId);
1653  // role readjusted, continue below to return correct data
1654  }
1655 
1656  // now, only custom roles are recognized.
1657  if (role < Qt::UserRole)
1658  return QVariant();
1659 
1660  // klfDbg( "(): role="<<role ) ;
1661 
1662  KLFLibEntry entry = ep.entry;
1663 
1664  if ( ! pCache->minimalistEntryPropIds().contains(entryPropIdForItemRole(role)) &&
1665  ep.minimalist) {
1666  // we are requesting for a property which is not included in minimalist property set
1667  pCache->ensureNotMinimalist(p);
1668  }
1669 
1670  if (role == entryItemRole(KLFLibEntry::Latex))
1671  return entry.latex();
1672  if (role == entryItemRole(KLFLibEntry::DateTime))
1673  return entry.dateTime();
1674  if (role == entryItemRole(KLFLibEntry::Category))
1675  return entry.category();
1676  if (role == entryItemRole(KLFLibEntry::Tags))
1677  // return KLF_DEBUG_TEE( entry.tags() );
1678  return entry.tags();
1680  return entry.previewSize();
1681 
1682  entry = ep.entry; // now the full entry
1683 
1684  if (role == FullEntryItemRole)
1685  return QVariant::fromValue(entry);
1686 
1687  if (role == entryItemRole(KLFLibEntry::Preview))
1688  return QVariant::fromValue<QImage>(entry.preview());
1689  if (role == entryItemRole(KLFLibEntry::Style))
1690  return QVariant::fromValue(entry.style());
1691  // by default
1692  return QVariant();
1693  }
1694  else if (ItemKind(p.kind) == CategoryLabelKind) {
1695  // --- GET CATEGORY LABEL DATA ---
1697  if (role == Qt::ToolTipRole)
1698  return cp.fullCategoryPath;
1699  if (role == CategoryLabelItemRole)
1700  return cp.categoryLabel;
1701  if (role == FullCategoryPathItemRole)
1702  return cp.fullCategoryPath;
1703  // by default
1704  return QVariant();
1705  }
1706 
1707  // default
1708  return QVariant();
1709 }
1710 Qt::ItemFlags KLFLibModel::flags(const QModelIndex& index) const
1711 {
1713  Qt::ItemFlags flagdropenabled = 0;
1714  if ( index.column() == 0 &&
1717  flagdropenabled = Qt::ItemIsDropEnabled;
1718 
1719  if (!index.isValid())
1720  return flagdropenabled;
1721 
1722  KLFLibModelCache::NodeId p = pCache->getNodeForIndex(index);
1723  if (!p.valid())
1724  return 0; // ?!!?
1726  return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled;
1728  return Qt::ItemIsEnabled | flagdropenabled;
1729 
1730  qWarning()<<KLF_FUNC_NAME<<": bad item kind! index-row="<<index.row()<<"; p="<<p;
1731 
1732  // by default (should never happen)
1733  return 0;
1734 }
1736 {
1738  if (parent.column() > 0)
1739  return false;
1740 
1741  KLFLibModelCache::NodeId p = pCache->getNodeForIndex(parent);
1742  if (!p.valid() || p.isRoot()) {
1743  // invalid index -> interpret as root node
1745  }
1746 
1747  return !pCache->getNode(p).allChildrenFetched || pCache->getNode(p).children.size() > 0;
1748 }
1749 QVariant KLFLibModel::headerData(int section, Qt::Orientation orientation, int role) const
1750 {
1752  if (role == Qt::FontRole) {
1753  return qApp->font();
1754  }
1755  if (role == Qt::SizeHintRole && orientation == Qt::Horizontal) {
1756  switch (entryColumnContentsPropertyId(section)) {
1757  case KLFLibEntry::Preview:
1758  return QSize(280,30);
1759  case KLFLibEntry::Latex:
1760  return QSize(350,30);
1761  case KLFLibEntry::Category:
1762  case KLFLibEntry::Tags:
1763  return QSize(200,30);
1764  default:
1765  return QVariant();
1766  }
1767  }
1768  if (role == Qt::DisplayRole) {
1769  if (orientation == Qt::Horizontal)
1771  return QString("-");
1772  }
1773  return QVariant();
1774 }
1775 
1776 bool KLFLibModel::hasIndex(int row, int column, const QModelIndex &parent) const
1777 {
1779  // better implementation in the future
1780  return index(row, column, parent).isValid();
1781 }
1782 
1783 QModelIndex KLFLibModel::index(int row, int column, const QModelIndex &parent) const
1784 {
1786 
1790 
1791  if (parent.isValid()) {
1792  KLFLibModelCache::NodeId pp = pCache->getNodeForIndex(parent);
1794  return QModelIndex();
1795  if (pp.valid())
1796  p = pCache->getCategoryLabelNodeRef(pp);
1797  }
1798  if (row < 0 || row >= p.children.size() || column < 0 || column >= columnCount(parent))
1799  return QModelIndex();
1800  klfDbgT(": row="<<row<<"; column="<<column<<"; parent="<<parent);
1801  return pCache->createIndexFromId(p.children[row], row, column);
1802 }
1804 {
1806  klfDbgT(": requesting parent of index "<<index);
1807  KLFLibModelCache::NodeId p = pCache->getNodeForIndex(index);
1808  if ( !p.valid() ) // invalid index
1809  return QModelIndex();
1810  KLFLibModelCache::Node n = pCache->getNode(p);
1811  if ( ! n.parent.valid() ) // invalid parent (should never happen!)
1812  return QModelIndex();
1813  return KLF_DEBUG_TEE( pCache->createIndexFromId(n.parent, -1 /* figure out row */, 0) ) ;
1814 }
1816 {
1818 
1819  if (parent.column() > 0)
1820  return 0;
1821 
1822  KLFLibModelCache::NodeId p = pCache->getNodeForIndex(parent);
1823  if (!p.valid())
1825 
1826  KLFLibModelCache::Node n = pCache->getNode(p);
1827  klfDbg( " parent="<<parent<<"; numchildren="<<n.children.size() ) ;
1828 
1829  return n.children.size();
1830 }
1831 
1832 int KLFLibModel::columnCount(const QModelIndex & /*parent*/) const
1833 {
1834  return 5;
1835 }
1837 {
1838  // WARNING: ANY CHANGES MADE HERE MUST BE REPEATED IN THE NEXT FUNCTION
1839  switch (column) {
1840  case 0:
1841  return KLFLibEntry::Preview;
1842  case 1:
1843  return KLFLibEntry::Tags;
1844  case 2:
1845  return KLFLibEntry::Category;
1846  case 3:
1847  return KLFLibEntry::Latex;
1848  case 4:
1849  return KLFLibEntry::DateTime;
1850  default:
1851  return -1;
1852  }
1853 }
1854 int KLFLibModel::columnForEntryPropertyId(int entryPropertyId) const
1855 {
1856  // WARNING: ANY CHANGES MADE HERE MUST BE REPEATED IN THE PREVIOUS FUNCTION
1857  switch (entryPropertyId) {
1858  case KLFLibEntry::Preview:
1859  return 0;
1860  case KLFLibEntry::Tags:
1861  return 1;
1862  case KLFLibEntry::Category:
1863  return 2;
1864  case KLFLibEntry::Latex:
1865  return 3;
1866  case KLFLibEntry::DateTime:
1867  return 4;
1868  default:
1869  return -1;
1870  }
1871 }
1872 
1873 
1875 {
1877  // KLF_DEBUG_BLOCK(KLF_FUNC_NAME); klfDbg( "\t parent="<<parent ) ;
1878 
1879  KLFLibModelCache::NodeId n = pCache->getNodeForIndex(parent);
1880  if (!n.valid())
1882 
1883  return pCache->canFetchMore(pCache->getNodeForIndex(parent));
1884 }
1886 {
1888  pCache->fetchMore(pCache->getNodeForIndex(parent), pFetchBatchCount);
1889 }
1890 
1891 
1892 Qt::DropActions KLFLibModel::supportedDropActions() const
1893 {
1894  return Qt::CopyAction|Qt::MoveAction;
1895 }
1896 
1898 {
1899  return QStringList() << "application/x-klf-internal-lib-move-entries"
1901 }
1902 QMimeData *KLFLibModel::mimeData(const QModelIndexList& indlist) const
1903 {
1905  // in the future, this will serve when dragging a category label, to redifine the index
1906  // list as containing all the child entries.
1907  QModelIndexList indexes = indlist;
1908 
1909  // get all entries
1910  KLFLibEntryList entries;
1911  QList<KLFLib::entryId> entryids;
1912  QList<KLFLibModelCache::NodeId> entriesnodeids;
1913  int k;
1914  for (k = 0; k < indexes.size(); ++k) {
1915  KLFLibModelCache::NodeId n = pCache->getNodeForIndex(indexes[k]);
1916  if (!n.valid() || n.isRoot())
1917  continue;
1919  continue;
1920  if (entriesnodeids.contains(n))
1921  continue; // skip duplicates (for ex. for other model column indexes)
1922  const KLFLibModelCache::EntryNode& en = pCache->getEntryNodeRef(n);
1923  entries << pResource->entry(en.entryid);
1924  entryids << en.entryid;
1925  entriesnodeids << n;
1926  }
1927 
1928  // klfDbg( "KLFLibModel::mimeData: Encoding entries "<<entries ) ;
1929 
1930  // some meta-data properties
1931  QVariantMap vprop;
1932  QUrl myurl = url();
1933  vprop["Url"] = myurl; // originating URL
1934 
1935  QMimeData *mimedata = KLFAbstractLibEntryMimeEncoder::createMimeData(entries, vprop);
1936 
1937  QByteArray internalmovedata;
1938 
1939  // application/x-klf-internal-lib-move-entries
1940  { QDataStream imstr(&internalmovedata, QIODevice::WriteOnly);
1941  imstr.setVersion(QDataStream::Qt_4_4);
1942  imstr << vprop << entryids;
1943  }
1944  mimedata->setData("application/x-klf-internal-lib-move-entries", internalmovedata);
1945 
1946  return mimedata;
1947 }
1948 
1949 // private
1950 bool KLFLibModel::dropCanInternal(const QMimeData *mimedata)
1951 {
1953  if ( ! mimedata->hasFormat("application/x-klf-internal-lib-move-entries") ||
1955  return false;
1956 
1957  QByteArray imdata = mimedata->data("application/x-klf-internal-lib-move-entries");
1958  QDataStream imstr(imdata);
1959  imstr.setVersion(QDataStream::Qt_4_4);
1960  QVariantMap vprop;
1961  imstr >> vprop;
1962  QUrl theirurl = vprop.value("Url").toUrl();
1963  QUrl oururl = url();
1964  bool ok = (oururl.toEncoded() == theirurl.toEncoded());
1965  klfDbg( "drag originated from "<<theirurl<<"; we are "<<oururl<<"; OK="<<ok ) ;
1966  return ok;
1967 }
1968 
1969 bool KLFLibModel::dropMimeData(const QMimeData *mimedata, Qt::DropAction action, int row,
1970  int column, const QModelIndex& parent)
1971 {
1973  klfDbg( "Drop data: action="<<action<<" row="<<row<<" col="<<column
1974  << " parent="<<parent ) ;
1975 
1976  if (action == Qt::IgnoreAction)
1977  return true;
1978  if (action != Qt::CopyAction)
1979  return false;
1980 
1981  if ( ! (mimedata->hasFormat("application/x-klf-internal-lib-move-entries") &&
1985  // cannot (change items with application/x-klf-internal-lib-move-entries) AND
1986  // cannot (insert items with any supported format, eg. application/x-klf-libentries)
1987  return false;
1988  }
1989 
1990  if (column > 0)
1991  return false;
1992 
1993  // imdata, imstr : "*i*nternal *m*ove" ; ldata, lstr : "entry *l*ist"
1994  bool useinternalmove = dropCanInternal(mimedata);
1995  if (useinternalmove) {
1996  klfDbg( "Dropping application/x-klf-internal-lib-move-entries" ) ;
1997  if ( !(pFlavorFlags & CategoryTree) )
1998  return false;
1999 
2000  QByteArray imdata = mimedata->data("application/x-klf-internal-lib-move-entries");
2001  QDataStream imstr(imdata);
2002  imstr.setVersion(QDataStream::Qt_4_4);
2003  QList<KLFLib::entryId> idlist;
2004  QVariantMap vprop;
2005  imstr >> vprop >> idlist;
2006  // get the category we moved to
2007  KLFLibModelCache::NodeId pn = pCache->getNodeForIndex(parent);
2008  if (!pn.valid()) {
2010  }
2011  if (ItemKind(pn.kind) != CategoryLabelKind) {
2012  qWarning()<<"Dropped in a non-category index! (kind="<<pn.kind<<")";
2013  return false;
2014  }
2016  // move, not copy: change the selected entries to the new category.
2017  QString newcategory = cn.fullCategoryPath;
2018  if (newcategory.endsWith("/"))
2019  newcategory.chop(1);
2020 
2021  bool r = pResource->changeEntries(idlist, QList<int>() << KLFLibEntry::Category,
2022  QList<QVariant>() << QVariant(newcategory));
2023  klfDbg( "Accepted drop of type application/x-klf-internal-lib-move-entries. Res="<<r<<"\n"
2024  <<"ID list is "<<idlist<<" new category is "<<newcategory ) ;
2025  if (!r) {
2026  return false;
2027  }
2028  // dataChanged() is emitted in changeEntries()
2029  return true;
2030  }
2031 
2032  klfDbg( "Dropping entry list." ) ;
2033 
2034  KLFLibEntryList elist;
2035  QVariantMap vprop;
2036  bool res = KLFAbstractLibEntryMimeEncoder::decodeMimeData(mimedata, &elist, &vprop);
2037  if ( ! res ) {
2038  qWarning()<<KLF_FUNC_NAME<<": Drop: Can't decode mime data! provided types="
2039  <<mimedata->formats();
2040  QMessageBox::warning(NULL, tr("Drop Error", "[[message box title]]"),
2041  tr("Error dropping data."));
2042  return false;
2043  }
2044 
2045  if ( elist.isEmpty() )
2046  return true; // nothing to drop
2047 
2048  // insert list, regardless of parent (no category change)
2049  QList<KLFLib::entryId> inserted = pResource->insertEntries(elist);
2050  res = (inserted.size() && !inserted.contains(-1));
2051  klfDbg( "Dropped entry list "<<elist<<". Originating URL="
2052  <<(vprop.contains("Url")?vprop["Url"]:"(none)")<<". result="<<res ) ;
2053  if (!res)
2054  return false;
2055 
2056  // dataChanged()/rowsInserted()/... are emitted in insertEntries()
2057  return true;
2058 }
2059 
2061 {
2063  const QMimeData *mdata = event->mimeData();
2064  if (dropCanInternal(mdata)) {
2065  if ( !(pFlavorFlags & CategoryTree) ) {
2066  return 0; // will NOT accept an internal move not in a category tree.
2067  // (note: icon moves not handled in KLFLibModel; intercepted in view.)
2068  }
2069  // we're doing an internal drop in category tree:
2070  QModelIndex dropOnIndex = view->indexAt(event->pos());
2072  (!dropOnIndex.isValid() || dropOnIndex.column() == 0) )
2074  return 0;
2075  }
2078  return DropWillAccept;
2079  return 0;
2080 }
2081 
2082 QImage KLFLibModel::dragImage(const QModelIndexList& indexes)
2083 {
2085  if (indexes.isEmpty())
2086  return QImage();
2087 
2088  const int MAX = 5;
2089  const QSize s1 = 0.8*QSize(250,75); //klfconfig.UI.labelOutputFixedSize;
2090  const QPointF delta(18.0, 20.0);
2091  QList<QImage> previewlist;
2092  QList<KLFLibModelCache::NodeId> alreadydone;
2093  int k, j;
2094  int iS = indexes.size();
2095  int n = qMin(1+MAX, iS);
2096  for (j = 0, k = 0; k < iS && j < n; ++k) {
2097  KLFLibModelCache::NodeId n = pCache->getNodeForIndex(indexes[iS-k-1]); // reverse order
2098  if (!n.valid() || n.kind != KLFLibModelCache::EntryKind)
2099  continue;
2100  if (alreadydone.contains(n))
2101  continue;
2102  const KLFLibModelCache::EntryNode& en = pCache->getEntryNodeRef(n, true);
2103  alreadydone << n;
2104  previewlist << en.entry.preview().scaled(s1, Qt::KeepAspectRatio, Qt::SmoothTransformation);
2105  ++j;
2106  }
2107  if (previewlist.isEmpty())
2108  return QImage();
2109 
2110  int N = qMin(MAX, previewlist.size());
2111  QSize s2 = (s1 + (N-1)*pointToSizeF(delta)).toSize();
2112  QImage image(s2, QImage::Format_ARGB32_Premultiplied);
2113  image.fill(qRgba(0,0,0,0));
2114  {
2115  QPainter p(&image);
2116  QPointF P(0,0);
2117  QPointF lastimgbr;
2118  for (k = 0; k < N; ++k) {
2119  // and add this image
2120  QImage i = transparentify_image(previewlist[k], 0.7);
2121  p.drawImage(P, i);
2122  // p.drawRect(QRectF(P, s1));
2123  lastimgbr = P+sizeToPointF(i.size());
2124  P += delta;
2125  }
2126  if (k == MAX) {
2127  p.setCompositionMode(QPainter::CompositionMode_DestinationOver);
2128  p.setPen(QPen(QColor(0,0,0),2.0));
2129  QPointF br = lastimgbr;
2130  p.drawPoint(br - QPointF(5,5));
2131  p.drawPoint(br - QPointF(10,5));
2132  p.drawPoint(br - QPointF(15,5));
2133  }
2134  }
2135 
2136  return autocrop_image(image);
2137 }
2138 
2139 
2140 bool KLFLibModel::isDesendantOf(const QModelIndex& child, const QModelIndex& ancestor)
2141 {
2143  if (!child.isValid())
2144  return false;
2145 
2146  return child.parent() == ancestor || isDesendantOf(child.parent(), ancestor);
2147 }
2148 
2150 {
2151  return pCache->categoryListCache();
2152 }
2153 
2154 void KLFLibModel::updateData(const QList<KLFLib::entryId>& entryIdList, int modifyType)
2155 {
2157  pCache->updateData(entryIdList, modifyType);
2158 }
2159 
2161 {
2163  KLFLibModelCache::NodeId nextnode = pCache->nextNode(pCache->getNodeForIndex(cur));
2164  // klfDbg( "KLFLibModel::walkNextIndex: got next node=NodeId("<<nextnode.kind<<","<<nextnode.index<<")" ) ;
2165  return pCache->createIndexFromId(nextnode, -1, 0);
2166 }
2168 {
2170  KLFLibModelCache::NodeId prevnode = pCache->prevNode(pCache->getNodeForIndex(cur));
2171  return pCache->createIndexFromId(prevnode, -1, 0);
2172 }
2173 
2175 {
2177  return entryIdForIndexList(QModelIndexList() << index) [0];
2178 }
2179 
2181 {
2183  return findEntryIdList(QList<KLFLib::entryId>() << eid) [0];
2184 }
2185 
2186 QList<KLFLib::entryId> KLFLibModel::entryIdForIndexList(const QModelIndexList& indexlist) const
2187 {
2189  return pCache->entryIdForIndexList(indexlist);
2190 }
2191 QModelIndexList KLFLibModel::findEntryIdList(const QList<KLFLib::entryId>& eidlist) const
2192 {
2194  return pCache->findEntryIdList(eidlist);
2195 }
2196 
2197 
2199 {
2201  if (pEntrySorter == entrySorter)
2202  return;
2203  if (entrySorter == NULL) {
2204  qWarning()<<KLF_FUNC_NAME<<": NULL entrySorter given!";
2205  }
2206 
2207  if (pEntrySorter)
2208  delete pEntrySorter;
2209  pEntrySorter = entrySorter;
2210 }
2211 
2212 
2213 QModelIndex KLFLibModel::searchFind(const QString& queryString, const QModelIndex& fromIndex,
2214  bool forward)
2215 {
2217  klfDbg( " s="<<queryString<<" from "<<fromIndex<<" forward="<<forward ) ;
2218  pSearchAborted = false;
2219  pSearchString = queryString;
2220  pSearchCurNode = fromIndex;
2221  return searchFindNext(forward);
2222 }
2224 {
2226  pSearchAborted = false;
2227  if (pSearchString.isEmpty())
2228  return QModelIndex();
2229 
2230  QTime t;
2231 
2232  KLFLibModelCache::NodeId curNode = pCache->getNodeForIndex(pSearchCurNode);
2233 
2234  // search nodes
2236  forward
2239 
2240  // presence of capital letter switches case sensitivity on (like (X)Emacs)
2241  Qt::CaseSensitivity cs = Qt::CaseInsensitive;
2242  if (pSearchString.contains(QRegExp("[A-Z]")))
2243  cs = Qt::CaseSensitive;
2244 
2245  bool found = false;
2246  while ( ! found &&
2247  (curNode = (pCache->*stepfunc)(curNode)).valid() ) {
2248  if ( pCache->searchNodeMatches(curNode, pSearchString, cs) ) {
2249  found = true;
2250  }
2251  if (t.elapsed() > 150) {
2252  pSearchCurNode = pCache->createIndexFromId(curNode, -1, 0);
2253  qApp->processEvents();
2254  if (pSearchAborted)
2255  break;
2256  t.restart();
2257  }
2258  }
2259  pSearchCurNode = pCache->createIndexFromId(curNode, -1, 0);
2260  if (found) {
2261  klfDbg( "found "<<pSearchString<<" at "<<pSearchCurNode ) ;
2262  return pSearchCurNode;
2263  }
2264  return QModelIndex();
2265 }
2266 
2268 {
2269  pSearchAborted = true;
2270 }
2271 
2272 bool KLFLibModelCache::searchNodeMatches(const NodeId& nodeId, const QString& searchString,
2273  Qt::CaseSensitivity cs)
2274 {
2276  if (nodeId.kind == CategoryLabelKind) {
2277  if (nodeValue(nodeId).contains(searchString, cs))
2278  return true;
2279  return false;
2280  }
2281  if (nodeValue(nodeId, KLFLibEntry::Latex).contains(searchString, cs) ||
2282  nodeValue(nodeId, KLFLibEntry::Tags).contains(searchString, cs))
2283  return true;
2284  // let an item match its category only in NON-category tree mode (user friendlyness: category matching
2285  // will match the category title, after that, don't walk all the children...)
2286  if ((pModel->pFlavorFlags & KLFLibModel::CategoryTree) == 0 &&
2287  nodeValue(nodeId, KLFLibEntry::Category).contains(searchString, cs)) {
2288  return true;
2289  }
2290 
2291  return false;
2292 }
2293 
2294 
2295 // bool KLFLibModel::changeEntries(const QModelIndexList& indexlist, int propId, const QVariant& value)
2296 // {
2297 // if ( indexlist.size() == 0 )
2298 // return true; // no change...
2299 
2300 // QList<KLFLib::entryId> idList = pCache->entryIdList(indexlist);
2301 // klfDbg( ": Changing entries "<<idList<<"; indexlist="<<indexlist ) ;
2302 // // klfDbg( "full dump:" ) ;
2303 // // pCache->fullDump();
2304 // bool r = pResource->changeEntries(idList, QList<int>() << propId, QList<QVariant>() << value);
2305 // // klfDbg( ": entries changed, full dump:" ) ;
2306 // // pCache->fullDump();
2307 
2308 // // the resource will emit dataChanged() to the view's updateResourceData() for the model update
2309 
2310 // return r;
2311 // }
2312 
2313 // bool KLFLibModel::insertEntries(const KLFLibEntryList& entries)
2314 // {
2315 // if (entries.size() == 0)
2316 // return true; // nothing to do...
2317 
2318 // KLFLibEntryList elist = entries;
2319 
2320 // QList<KLFLib::entryId> list = pResource->insertEntries(elist);
2321 
2322 // if ( list.size() == 0 || list.contains(-1) )
2323 // return false; // error for at least one entry
2324 // return true;
2325 // }
2326 
2327 // bool KLFLibModel::deleteEntries(const QModelIndexList& indexlist)
2328 // {
2329 // if ( indexlist.size() == 0 )
2330 // return true; // no change...
2331 
2332 // QList<KLFLib::entryId> idList = pCache->entryIdList(indexlist);
2333 // if ( pResource->deleteEntries(idList) ) {
2334 // // will be automatically called via the call to resoruce->(modify-data)()!
2335 // // updateCacheSetupModel();
2336 // return true;
2337 // }
2338 // return false;
2339 // }
2340 
2342 {
2344  updateCacheSetupModel();
2345 }
2346 
2347 
2349 {
2351 
2352  // truly need to re-query the resource with our partial querying and fetching more system...
2353  updateCacheSetupModel();
2354  return;
2355  /*
2356  // this does not work with partial querying and fetching more, we truly need to re-query the resource
2357  startLayoutChange();
2358 
2359  KLFLibModelCache::KLFLibModelSorter srt =
2360  KLFLibModelCache::KLFLibModelSorter(pCache, pEntrySorter, pFlavorFlags & KLFLibModel::GroupSubCategories);
2361 
2362  pCache->sortCategory(KLFLibModelCache::NodeId::rootNode(), &srt);
2363 
2364  endLayoutChange();
2365  */
2366 }
2367 
2368 void KLFLibModel::sort(int column, Qt::SortOrder order)
2369 {
2371 
2372  // select right property ID
2373  int propId = entryColumnContentsPropertyId(column);
2374  // if property ID is preview, then request sort by DateTime (user friendliness)
2375  if (propId == KLFLibEntry::Preview) {
2376  propId = KLFLibEntry::DateTime;
2377  }
2378 
2379  pEntrySorter->setPropId(propId);
2380  pEntrySorter->setOrder(order);
2381 
2382  pCache->setSortingBy(propId, order);
2383 
2384  redoSort();
2385 }
2386 
2387 
2388 
2389 QList<KLFLibModel::PersistentId> KLFLibModel::persistentIdList(const QModelIndexList& persistentIndexes)
2390 {
2392  // save persistent indexes
2393  QList<PersistentId> persistentIndexIds;
2394  int k;
2395  for (k = 0; k < persistentIndexes.size(); ++k) {
2396  PersistentId id;
2397  KLFLibModelCache::NodeId n = pCache->getNodeForIndex(persistentIndexes[k]);
2398  if (!n.valid()) {
2399  id.kind = (ItemKind)-1;
2400  } else {
2401  id.kind = n.kind;
2402  if (ItemKind(id.kind) == EntryKind)
2403  id.entry_id = pCache->getEntryNodeRef(n).entryid;
2404  else if (ItemKind(id.kind) == CategoryLabelKind)
2405  id.categorylabel_fullpath = pCache->getCategoryLabelNodeRef(n).fullCategoryPath;
2406  else
2407  qWarning("KLFLibModel::persistentIdList: Bad Node kind: %d!!", id.kind);
2408  }
2409  id.column = persistentIndexes[k].column();
2410  persistentIndexIds << id;
2411  klfDbg("saved persistent id "<<id) ;
2412  }
2413  return persistentIndexIds;
2414 }
2415 QModelIndexList KLFLibModel::newPersistentIndexList(const QList<PersistentId>& persistentIndexIds)
2416 {
2418  QModelIndexList newPersistentIndexes;
2419  int k;
2420  for (k = 0; k < persistentIndexIds.size(); ++k) {
2421  // find node in new layout
2422  PersistentId id = persistentIndexIds[k];
2424  if (ItemKind(id.kind) == EntryKind) {
2425  QModelIndexList ilist = pCache->findEntryIdList(QList<KLFLib::entryId>() << id.entry_id);
2426  index = ilist[0];
2427  } else if (id.kind == CategoryLabelKind) {
2428  int idx = pCache->cacheFindCategoryLabel(id.categorylabel_fullpath.split('/'));
2430  index = pCache->createIndexFromId(nodeId, -1, 0);
2431  } else {
2432  qWarning("%s: bad persistent id node kind! :%d", KLF_FUNC_NAME, id.kind);
2433  }
2434 
2435  newPersistentIndexes << index;
2436  klfDbg("restoring persistent id "<<id<<" as index "<<index) ;
2437  }
2438  return newPersistentIndexes;
2439 }
2440 
2441 
2442 void KLFLibModel::startLayoutChange(bool withQtLayoutChangedSignal)
2443 {
2445  // first notify anyone who may be interested
2446  if (withQtLayoutChangedSignal)
2447  emit layoutAboutToBeChanged();
2448  // save persistent indexes
2449  pLytChgIndexes = persistentIndexList();
2450  pLytChgIds = persistentIdList(pLytChgIndexes);
2451 }
2452 void KLFLibModel::endLayoutChange(bool withQtLayoutChangedSignal)
2453 {
2455 
2456  QModelIndexList newpindexes = newPersistentIndexList(pLytChgIds);
2457  changePersistentIndexList(pLytChgIndexes, newpindexes);
2458  // and notify of layout change
2459  if (withQtLayoutChangedSignal)
2460  emit layoutChanged();
2461 }
2462 
2463 
2464 void KLFLibModel::updateCacheSetupModel()
2465 {
2467  pCache->rebuildCache();
2468 }
2469 
2470 
2471 // --------------------------------------------------------
2472 
2473 
2474 
2476  : QAbstractItemDelegate(parent), pSelModel(NULL), pTheTreeView(NULL),
2477  pPreviewSize(klfconfig.UI.labelOutputFixedSize)
2478 {
2479  pAutoBackgroundItems = true;
2480 }
2482 {
2483 }
2484 
2486  const QStyleOptionViewItem& /*option*/,
2487  const QModelIndex& /*index*/) const
2488 {
2489  return 0;
2490 }
2492  const QStyleOptionViewItem& /*option*/,
2493  const QModelIndex& /*index*/)
2494 {
2495  return false;
2496 }
2497 
2498 
2501 {
2502  KLFLibResourceEngine *res;
2503 public:
2505  {
2506  if (res != NULL)
2507  res->blockProgressReporting(true);
2508  }
2510  {
2511  if (res != NULL)
2512  res->blockProgressReporting(false);
2513  }
2514 };
2515 
2516 
2518  const QModelIndex& index) const
2519 {
2521  klfDbg( "\tindex="<<index<<"; rect="<<option.rect ) ;
2522  PaintPrivate pp;
2523  pp.p = painter;
2524  pp.option = &option;
2525  pp.innerRectImage = QRect(option.rect.topLeft()+QPoint(2,2), option.rect.size()-QSize(4,4));
2526  pp.innerRectText = QRect(option.rect.topLeft()+QPoint(4,2), option.rect.size()-QSize(8,3));
2527 
2528 #ifdef Q_WS_MAC
2529  // block progress reporting on MAC to avoid repaint recursions
2530  KLFLibResourceEngine *rres = NULL;
2531  KLFLibModel *rmodel = qobject_cast<KLFLibModel*>(const_cast<QAbstractItemModel*>(index.model()));
2532  if (rmodel != NULL) rres = rmodel->resource();
2533  _klf_block_progress_blocker blocker(rres);
2534 #endif
2535 
2536  painter->save();
2537 
2538  QPen pen = painter->pen();
2539  pp.isselected = (option.state & QStyle::State_Selected);
2540  QPalette::ColorGroup cg = option.state & QStyle::State_Enabled
2541  ? QPalette::Normal : QPalette::Disabled;
2542  if (cg == QPalette::Normal && !(option.state & QStyle::State_Active))
2543  cg = QPalette::Inactive;
2544  if (pp.isselected) {
2545  pp.background = option.palette.brush(cg, QPalette::Highlight);
2546  painter->setPen(option.palette.color(cg, QPalette::HighlightedText));
2547  painter->fillRect(option.rect, pp.background);
2548  } else {
2549  pp.background = pAutoBackgroundColor.isValid()
2550  ? pAutoBackgroundColor
2551  : option.palette.brush(cg, QPalette::Base);
2552  painter->setPen(option.palette.color(cg, QPalette::Text));
2553  }
2554 
2555  int kind = index.data(KLFLibModel::ItemKindItemRole).toInt();
2556  if (kind == KLFLibModel::EntryKind)
2557  paintEntry(&pp, index);
2558  else if (kind == KLFLibModel::CategoryLabelKind)
2559  paintCategoryLabel(&pp, index);
2560 
2561  if (option.state & QStyle::State_HasFocus) {
2563  o.QStyleOption::operator=(option);
2564  o.rect = option.rect;
2565  o.state |= QStyle::State_KeyboardFocusChange;
2566  o.state |= QStyle::State_Item;
2567  QPalette::ColorGroup cg = (option.state & QStyle::State_Enabled)
2568  ? QPalette::Normal : QPalette::Disabled;
2569  o.backgroundColor = option.palette.color(cg, (option.state & QStyle::State_Selected)
2570  ? QPalette::Highlight : QPalette::Window);
2571  const QWidget *w = 0;
2572  if (const QStyleOptionViewItemV3 *v3 = qstyleoption_cast<const QStyleOptionViewItemV3 *>(&option))
2573  w = v3->widget;
2574  QStyle *style = w ? w->style() : QApplication::style();
2575  style->drawPrimitive(QStyle::PE_FrameFocusRect, &o, painter, w);
2576  }
2577 
2578  painter->restore();
2579 }
2580 
2582 {
2584  uint fl = PTF_HighlightSearch;
2585  if (index.parent() == pSearchIndex.parent() && index.row() == pSearchIndex.row())
2587 
2588  switch (index.data(KLFLibModel::EntryContentsTypeItemRole).toInt()) {
2589  case KLFLibEntry::Latex:
2590  // paint Latex String
2591  fl |= PTF_FontTT;
2592  paintText(p, index.data(KLFLibModel::entryItemRole(KLFLibEntry::Latex)).toString(), fl);
2593  break;
2594  case KLFLibEntry::Preview:
2595  // paint Latex Equation
2596  {
2598  QImage img2 = img.scaled(p->innerRectImage.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
2599  if (p->isselected)
2600  img2 = transparentify_image(img2, 0.85);
2601  QPoint pos = p->innerRectImage.topLeft()
2602  + QPoint(0, (p->innerRectImage.height()-img2.height()) / 2);
2603  if (pAutoBackgroundItems) {
2604  // draw image on different background if it can't be "distinguished" from default background
2605  // (eg. a transparent white formula)
2606  klfDbg( " BG Brush is "<<p->background ) ;
2607  QColor bgcolor = p->background.color();
2608  QList<QColor> bglista, bglistb, bglist;
2609  // bglist << bgcolor
2610  // << QColor(255,255,255)
2611  // << QColor(220,220,220)
2612  // << QColor(180,190,190)
2613  // << QColor(200,200,200)
2614  // << QColor(150,150,150)
2615  // << QColor(100,100,100)
2616  // << QColor(50,50,50)
2617  // << QColor(0,0,0);
2618  bglist << bgcolor; // first try: default color (!)
2619  bglista = bglistb = bglist;
2620  int count;
2621  for (count = 0; count < 5; ++count) // suggest N (ever) darker colors
2622  bglista << bglista.last().darker(105+count*2);
2623  for (count = 0; count < 5; ++count) // and N (ever) lighter colors
2624  bglistb << bglistb.last().lighter(105+count*2);
2625  // build the full list, and always provide white, and black to be sure
2626  bglist << bglista.mid(1) << bglistb.mid(1) << QColor(255,255,255) << QColor(0,0,0);
2627  klfDbg( "alt. bg list is "<<bglist );
2628  int k;
2629  for (k = 0; k < bglist.size(); ++k) {
2630  // klfDbg( "calling image_is_distinguishable on entry with latex="
2631  // <<index.data(KLFLibModel::entryItemRole(KLFLibEntry::Latex)).toString() );
2632  bool distinguishable = image_is_distinguishable(img2, bglist[k], 20); // 30
2633  if ( distinguishable )
2634  break; // got distinguishable color
2635  }
2636  // if the background color is not the default one, fill the background with that color
2637  if (k > 0 && k < bglist.size())
2638  p->p->fillRect(QRect(pos, img2.size()), QBrush(bglist[k]));
2639  }
2640  // and draw the equation
2641  p->p->save();
2642  p->p->translate(pos);
2643  if (klfconfig.UI.glowEffect)
2645  p->p->drawImage(QPoint(0,0), img2);
2646  p->p->restore();
2647  break;
2648  }
2649  case KLFLibEntry::Category:
2650  // paint Category String
2652  break;
2653  case KLFLibEntry::Tags:
2654  // paint Tags String
2655  fl |= PTF_FontLarge;
2656  paintText(p, index.data(KLFLibModel::entryItemRole(KLFLibEntry::Tags)).toString(), fl);
2657  break;
2658  case KLFLibEntry::DateTime:
2659  // paint DateTime String
2660  { QLocale loc; // use the default locale, which was set to the value of klfconfig.UI.locale in main app.
2662  .toDateTime(), QLocale::LongFormat), fl);
2663  break;
2664  }
2665  default:
2666  qDebug("KLFLibViewDelegate::paintEntry(): Got bad contents type %d !",
2668  // nothing to show !
2669  // painter->fillRect(option.rect, QColor(128,0,0));
2670  }
2671 }
2672 
2674 {
2676  // klfDbg( "index="<<index<<"; pTheTreeView="<<pTheTreeView<<"; treeview->isexpanded="
2677  // <<(pTheTreeView?(pTheTreeView->isExpanded(index)?"true":"false"):"(N/A)") );
2678  // klfDbg( "index has selected desc. ?="<<indexHasSelectedDescendant(index) );
2679 
2680  if (index.column() > 0) // paint only on first column
2681  return;
2682 
2683  // klfDbg( "index="<<index<<"; pSearchIndex="<<pSearchIndex ) ;
2684 
2685  uint fl = PTF_HighlightSearch;
2686  if (index.parent() == pSearchIndex.parent() && index.row() == pSearchIndex.row())
2688  if ( pTheTreeView != NULL && !pTheTreeView->isExpanded(index) &&
2689  indexHasSelectedDescendant(index) ) { // not expanded, and has selected child
2690  fl |= PTF_SelUnderline;
2691  }
2692  // if ( sizeHint(*p->option, index).width() > p->option->rect.width() ) {
2693  // // force rich text edit to handle too-wide texts
2694  // fl |= PTF_ForceRichTextRender;
2695  // }
2696 
2697  if (fl & PTF_HighlightSearchCurrent) {
2698  // paint line as if it were selected.
2699  QPen pen = p->p->pen();
2700  QPalette::ColorGroup cg = p->option->state & QStyle::State_Enabled
2701  ? QPalette::Normal : QPalette::Disabled;
2702  if (cg == QPalette::Normal && !(p->option->state & QStyle::State_Active))
2703  cg = QPalette::Inactive;
2704  p->p->fillRect(p->option->rect, p->option->palette.brush(cg, QPalette::Highlight));
2705  p->p->setPen(p->option->palette.color(cg, QPalette::HighlightedText));
2706  }
2707 
2708  // paint Category Label
2709  paintText(p, index.data(KLFLibModel::CategoryLabelItemRole).toString(), fl);
2710 }
2711 
2712 void KLFLibViewDelegate::paintText(PaintPrivate *p, const QString& text, uint flags) const
2713 {
2715 
2716  QFont font = p->option->font;
2717 
2718  if (flags & PTF_FontTT)
2719  font = klfconfig.UI.preambleEditFont; // use preamble font
2720  if (flags & PTF_FontLarge) {
2721  font.setPointSize(QFontInfo(font).pointSize()+1);
2722  // font.setStyle(QFont::StyleOblique);
2723  }
2724 
2725  QColor textcol = p->option->palette.color(QPalette::Text);
2726  QColor textcoltransp = textcol; textcoltransp.setAlpha(0);
2727  QGradientStops borderfadelingrstops;
2728  borderfadelingrstops << QGradientStop(0.0f, textcoltransp)
2729  << QGradientStop(0.1f, textcol)
2730  << QGradientStop(0.9f, textcol)
2731  << QGradientStop(1.0f, textcoltransp);
2732  QLinearGradient borderfadelingr(p->innerRectText.topLeft(), p->innerRectText.bottomLeft());
2733  borderfadelingr.setStops(borderfadelingrstops);
2734  borderfadelingr.setCoordinateMode(QGradient::LogicalMode);
2735  QPen borderfadepen = QPen(QBrush(borderfadelingr), 1.0f);
2736  QPen normalpen = QPen(textcol, 1.0f);
2737 
2738  int drawnTextWidth;
2739  int drawnBaseLineY;
2740  if ( (pSearchString.isEmpty() || !(flags&PTF_HighlightSearch) ||
2741  text.indexOf(pSearchString, 0, Qt::CaseInsensitive) == -1) &&
2742  !(flags & PTF_SelUnderline) &&
2743  !(flags & PTF_ForceRichTextRender) ) {
2744  // no formatting required, use fast method.
2745  QSize s = QFontMetrics(font).size(0, text);
2746  drawnTextWidth = s.width();
2747  drawnBaseLineY = (int)(p->innerRectText.bottom() - 0.5f*(p->innerRectText.height()-s.height()));
2748  p->p->setFont(font);
2749  if (s.height() > p->innerRectText.height()) { // contents height exceeds available height
2750  klfDbg("Need border fade pen for text "<<text) ;
2751  p->p->setPen(borderfadepen);
2752  } else {
2753  klfDbg("Don't need border fade pen for text "<<text) ;
2754  p->p->setPen(normalpen);
2755  }
2756  p->p->drawText(p->innerRectText, Qt::AlignLeft|Qt::AlignVCenter, text);
2757  } else {
2758  // formatting required.
2759  // build a list of regions to highlight
2761  QTextCharFormat f_highlight;
2762  if (flags & PTF_HighlightSearchCurrent)
2763  f_highlight.setBackground(QColor(0,255,0,80));
2764  f_highlight.setForeground(QColor(128,0,0));
2765  f_highlight.setFontItalic(true);
2766  f_highlight.setFontWeight(QFont::Bold);
2767  int i = -1, ci, j;
2768  if (!pSearchString.isEmpty()) {
2769  while ((i = text.indexOf(pSearchString, i+1, Qt::CaseInsensitive)) != -1)
2770  c << ColorRegion(f_highlight, i, pSearchString.length());
2771  }
2772  qSort(c);
2773  // klfDbg( "searchstr="<<pSearchString<<"; label "<<text<<": c is "<<c ) ;
2774  QTextDocument textDocument;
2775  textDocument.setDefaultFont(font);
2776  QTextCursor cur(&textDocument);
2777  QList<ColorRegion> appliedfmts;
2778  for (i = ci = 0; i < text.length(); ++i) {
2779  // klfDbg( "Processing char "<<text[i]<<"; i="<<i<<"; ci="<<ci ) ;
2780  if (ci >= c.size() && appliedfmts.size() == 0) {
2781  // insert all remaining text (no more formatting needed)
2782  cur.insertText(Qt::escape(text.mid(i)), QTextCharFormat());
2783  break;
2784  }
2785  while (ci < c.size() && c[ci].start == i) {
2786  appliedfmts.append(c[ci]);
2787  ++ci;
2788  }
2789  QTextCharFormat f;
2790  for (j = 0; j < appliedfmts.size(); ++j) {
2791  if (i >= appliedfmts[j].start + appliedfmts[j].len) {
2792  // this format no longer applies
2793  appliedfmts.removeAt(j);
2794  --j;
2795  continue;
2796  }
2797  f.merge(appliedfmts[j].fmt);
2798  }
2799  cur.insertText(Qt::escape(text[i]), f);
2800  }
2801 
2802  QSizeF s = textDocument.size();
2803  QRectF textRect = p->innerRectText;
2804  // note: setLeft changes width, not right.
2805  textRect.setLeft(textRect.left()-4); // some offset because of qt's rich text drawing ..?
2806  // textRect is now correct
2807  // draw a "hidden children selection" marker, if needed
2808  if (flags & PTF_SelUnderline) {
2809  QColor h1 = p->option->palette.color(QPalette::Highlight);
2810  QColor h2 = h1;
2811  h1.setAlpha(0);
2812  h2.setAlpha(220);
2813  QLinearGradient gr(0.f, 0.f, 0.f, 1.f);
2814  gr.setCoordinateMode(QGradient::ObjectBoundingMode);
2815  gr.setColorAt(0.f, h1);
2816  gr.setColorAt(1.f, h2);
2817  QBrush selbrush(gr);
2818  p->p->save();
2819  // p->p->setClipRect(p->option->rect);
2820  p->p->fillRect(QRectF(textRect.left(), textRect.bottom()-10,
2821  textRect.width(), 10), selbrush);
2822  p->p->restore();
2823  }
2824  // check the text size
2825  drawnTextWidth = (int)s.width();
2826  if (s.width() > textRect.width()) { // sorry, too large
2827  s.setWidth(textRect.width());
2828  }
2829  p->p->save();
2830  p->p->setClipRect(textRect);
2831  if (s.height() > textRect.height()) { // contents height exceeds available height
2832  klfDbg("Need borderfadepen for (rich) text "<<textDocument.toHtml());
2833  p->p->setPen(borderfadepen);
2834  } else {
2835  p->p->setPen(normalpen);
2836  }
2837  p->p->translate(textRect.topLeft());
2838  p->p->translate( QPointF( 0, //textRect.width() - s.width(),
2839  textRect.height() - s.height()) / 2.f );
2840  textDocument.drawContents(p->p);
2841  p->p->restore();
2842  drawnBaseLineY = (int)(textRect.bottom() - (textRect.height() - s.height()) / 2.f);
2843  }
2844 
2845  // draw arrow if text too large
2846 
2847  if (drawnTextWidth > p->innerRectText.width()) {
2848  // draw small arrow indicating more text
2849  // c.setAlpha(80);
2850  p->p->save();
2851  p->p->translate(p->option->rect.right()-2, drawnBaseLineY-2);
2852  p->p->setPen(textcol);
2853  p->p->drawLine(0, 0, -16, 0);
2854  p->p->drawLine(0, 0, -2, +2);
2855  p->p->restore();
2856  }
2857 }
2858 
2859 void KLFLibViewDelegate::setEditorData(QWidget */*editor*/, const QModelIndex& /*index*/) const
2860 {
2861 }
2863  const QModelIndex& /*index*/) const
2864 {
2865 }
2867 {
2869  klfDbg( "\tindex="<<index ) ;
2870  int kind = index.data(KLFLibModel::ItemKindItemRole).toInt();
2871  if (kind == KLFLibModel::EntryKind) {
2872  int prop = -1;
2873  switch (index.data(KLFLibModel::EntryContentsTypeItemRole).toInt()) {
2875  case KLFLibEntry::Category: prop = (prop > 0) ? prop : KLFLibEntry::Category;
2876  case KLFLibEntry::Tags: prop = (prop > 0) ? prop : KLFLibEntry::Tags;
2877  return QFontMetrics(option.font)
2878  .size(0, index.data(KLFLibModel::entryItemRole(prop)).toString())+QSize(4,4);
2879  case KLFLibEntry::DateTime:
2880  { QLocale loc; // use default locale, which was set to the value of klfconfig.UI.locale;
2881  return QFontMetrics(option.font)
2883  .toDateTime(), QLocale::LongFormat) )+QSize(4,2);
2884  }
2885  case KLFLibEntry::Preview:
2886  {
2888  if (s.width() > pPreviewSize.width() || s.height() > pPreviewSize.height()) {
2889  // shrink to the requested display size, keeping aspect ratio
2890  s.scale(pPreviewSize, Qt::KeepAspectRatio);
2891  }
2892  return s+QSize(2,2); // scaling margin etc.
2893  }
2894  default:
2895  return QSize();
2896  }
2897  } else if (kind == KLFLibModel::CategoryLabelKind) {
2898  return QFontMetrics(option.font)
2899  .size(0, index.data(KLFLibModel::CategoryLabelItemRole).toString())+QSize(4,4);
2900  } else {
2901  qWarning("KLFLibItemViewDelegate::sizeHint(): Bad Item kind: %d\n", kind);
2902  return QSize();
2903  }
2904 }
2906  const QStyleOptionViewItem& /*option*/,
2907  const QModelIndex& /*index*/) const
2908 {
2909 }
2910 
2911 
2913 {
2915  klfDbg( "\t parent="<<parent ) ;
2916 
2917  if (!parent.isValid())
2918  return false;
2919 
2920  QTime tm; tm.start();
2921  return func_indexHasSelectedDescendant(parent, tm, 200);
2922 }
2923 
2925  const QModelIndex& parent) const
2926 {
2928  klfDbg( "selection size is "<<selection.size() ) ;
2929  int k;
2930  for (k = 0; k < selection.size(); ++k) {
2931  if (selection[k].parent() != parent)
2932  continue;
2933  if (selection[k].isValid()) // selection range not empty, with same parent
2934  return true;
2935  }
2936  return false;
2937 }
2938 
2940  int timeLimitMs) const
2941 {
2943  if (!parent.isValid()) {
2944  qWarning()<<KLF_FUNC_NAME<<": parent is invalid!";
2945  return false;
2946  }
2947  if (selectionIntersectsIndexChildren(pSelModel->selection(), parent)) {
2948  klfDbg( "selection under index parent="<<parent ) ;
2949  return true;
2950  }
2951  const QAbstractItemModel *model = parent.model();
2952  if (model == NULL) {
2953  qWarning()<<KLF_FUNC_NAME<<": parent has NULL model!";
2954  return false;
2955  }
2956 
2957  int k;
2958  QModelIndex idx;
2959  for (k = 0; k < model->rowCount(parent); ++k) {
2960  idx = model->index(k, 0, parent);
2961 
2962  if (!idx.isValid() || !model->hasChildren(idx))
2963  continue;
2964  if (func_indexHasSelectedDescendant(idx, timer, timeLimitMs))
2965  return true;
2966  // stop this function if it is taking too long.
2967  if (timer.elapsed() > timeLimitMs)
2968  return false;
2969 
2970  }
2971  return false;
2972 }
2973 
2974 
2975 
2976 
2977 // -------------------------------------------------------
2978 
2979 
2980 
2982  : KLFAbstractLibView(parent), pViewType(view)
2983 {
2985 
2986  pModel = NULL;
2987 
2988  pPreviewSizeMenu = NULL;
2989 
2990  pEventFilterNoRecurse = false;
2991 
2992  QVBoxLayout *lyt = new QVBoxLayout(this);
2993  lyt->setMargin(0);
2994  lyt->setSpacing(0);
2995  pDelegate = new KLFLibViewDelegate(this);
2996 
2997  // set icon size
2998  switch (pViewType) {
2999  case CategoryTreeView:
3001  break;
3002  case ListTreeView:
3004  break;
3005  case IconView:
3007  break;
3008  default:
3009  break;
3010  }
3011 
3012  setFocusPolicy(Qt::NoFocus);
3013 
3014  KLFLibDefTreeView *treeView = NULL;
3015  KLFLibDefListView *listView = NULL;
3016  switch (pViewType) {
3017  case IconView:
3018  listView = new KLFLibDefListView(this);
3019  klfDbg( "Created list view." ) ;
3020  listView->setViewMode(QListView::IconMode);
3021  listView->setSpacing(15);
3022  listView->setMovement(QListView::Free);
3023  // icon view flow is set later with setIconViewFlow()
3024  listView->setResizeMode(QListView::Adjust);
3025  klfDbg( "prepared list view." ) ;
3026  pView = listView;
3027  break;
3028  case CategoryTreeView:
3029  case ListTreeView:
3030  default:
3031  treeView = new KLFLibDefTreeView(this);
3032  treeView->setSortingEnabled(true);
3033  treeView->setIndentation(16);
3034  treeView->setAllColumnsShowFocus(true);
3035  // treeView->setUniformRowHeights(true); // optimization, but is ugly...
3036  pDelegate->setTheTreeView(treeView);
3037  pView = treeView;
3038  break;
3039  };
3040 
3041  lyt->addWidget(pView);
3042 
3043 
3044  pView->setSelectionBehavior(QAbstractItemView::SelectRows);
3045  pView->setSelectionMode(QAbstractItemView::ExtendedSelection);
3046  pView->setDragEnabled(true);
3047  pView->setDragDropMode(QAbstractItemView::DragDrop);
3048  pView->setDragDropOverwriteMode(false);
3049  pView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
3050  pView->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
3051  pView->setItemDelegate(pDelegate);
3052  pView->viewport()->installEventFilter(this);
3053  pView->installEventFilter(this);
3054  installEventFilter(this);
3055 
3056  connect(pView, SIGNAL(clicked(const QModelIndex&)),
3057  this, SLOT(slotViewItemClicked(const QModelIndex&)));
3058  connect(pView, SIGNAL(doubleClicked(const QModelIndex&)),
3059  this, SLOT(slotEntryDoubleClicked(const QModelIndex&)));
3060 }
3062 {
3063 }
3064 
3066 {
3068 
3069  if (pModel == NULL)
3070  return QUrl();
3071  return pModel->url();
3072 }
3073 uint KLFLibDefaultView::compareUrlTo(const QUrl& other, uint interestFlags) const
3074 {
3075  bool baseequal = false;
3076  uint resultFlags = 0x0;
3077 
3078  // see if base resources are equal
3079  baseequal = resourceEngine()->compareUrlTo(other, KlfUrlCompareBaseEqual);
3080  if (baseequal)
3081  resultFlags |= KlfUrlCompareBaseEqual;
3082 
3083  // perform inclusion checks
3084  if (interestFlags & KlfUrlCompareLessSpecific) {
3085  if (!baseequal) {
3086  // aren't less specific since not base equal.
3087  } else {
3088  // we can only "see" sub-resources, compare for that only
3089  // "less specific" -> our sub-resource (if we have one) must equal theirs; if we don't have one we're fine.
3090  // --> they must support sub-resources if we do, and display one
3091  if ( ! (resourceEngine()->supportedFeatureFlags() & KLFLibResourceEngine::FeatureSubResources) ) {
3092  resultFlags |= KlfUrlCompareLessSpecific;
3093  } else if (other.hasQueryItem("klfDefaultSubResource")) {
3094  if (resourceEngine()->compareDefaultSubResourceEquals(other.queryItemValue("klfDefaultSubResource")))
3095  resultFlags |= KlfUrlCompareLessSpecific;
3096  }
3097  }
3098  }
3099  if (interestFlags & KlfUrlCompareMoreSpecific) {
3100  if (!baseequal) {
3101  // aren't more specific since not base equal.
3102  } else {
3103  // we can only "see" sub-resources, compare for that only
3104  // more spec.
3105  // -> if other doesn't have sub-resource, we're fine
3106  // -> if does, if (we not) { fail; } else { compare equality }
3107  if (!other.hasQueryItem("klfDefaultSubResource")) {
3108  resultFlags |= KlfUrlCompareMoreSpecific;
3109  } else if (! (resourceEngine()->supportedFeatureFlags() & KLFLibResourceEngine::FeatureSubResources)) {
3110  // fail
3111  } else {
3112  // both support sub-resources, compare equality
3113  if (resourceEngine()->compareDefaultSubResourceEquals(other.queryItemValue("klfDefaultSubResource")))
3114  resultFlags |= KlfUrlCompareMoreSpecific;
3115  }
3116  }
3117  }
3118  if (interestFlags & KlfUrlCompareEqual) {
3120  bool hesupportssubres = other.hasQueryItem("klfDefaultSubResource");
3121  if ( wesupportsubres && hesupportssubres ) {
3122  // both have sub-resources
3123  if (baseequal && resourceEngine()->compareDefaultSubResourceEquals(other.queryItemValue("klfDefaultSubResource")))
3124  resultFlags |= KlfUrlCompareEqual;
3125  } else if ( !wesupportsubres && ! hesupportssubres ) {
3126  // both don't have sub-resources, so we're "equal"
3127  resultFlags |= KlfUrlCompareEqual;
3128  } else {
3129  // otherwise, not equal
3130  }
3131  }
3132 
3133  klfDbg( "and the final resultFlags are"<<klfFmtCC("%#010x",resultFlags) ) ;
3134 
3135  return resultFlags;
3136 }
3137 
3139  bool *x;
3140 public:
3141  __klf_guarded_bool(bool *var) : x(var) { *x = true; }
3142  ~__klf_guarded_bool() { *x = false; }
3143 };
3144 
3146 {
3147  return KLFAbstractLibView::event(event);
3148 }
3150 {
3151  if (pEventFilterNoRecurse) {
3152  klfDbg("Avoiding recursion") ;
3153  return KLFAbstractLibView::eventFilter(object, event);
3154  }
3155  __klf_guarded_bool guard_object(&pEventFilterNoRecurse);
3156 
3157  if (object == pView && event->type() == QEvent::KeyPress) {
3158  QKeyEvent *ke = (QKeyEvent*)event;
3159  QKeySequence thisKey = QKeySequence(ke->key() | ke->modifiers());
3160  int k;
3161  for (k = 0; k < pViewActionsWithShortcut.size(); ++k) {
3162  QAction *a = pViewActionsWithShortcut[k];
3163  if (a->shortcut() == thisKey) {
3164  klfDbg("Activating view action "<<a->text()<<" for shortcut key "<<thisKey<<".") ;
3165  a->trigger();
3166  return true;
3167  }
3168  }
3169  }
3170  return KLFAbstractLibView::eventFilter(object, event);
3171 }
3172 
3174 {
3175  QList<KLFLib::entryId> idListWithDupl = pModel->entryIdForIndexList(pView->selectionModel()->selectedIndexes());
3176  // remove duplicates
3177  QList<KLFLib::entryId> idList;
3178  int k;
3179  for (k = 0; k < idListWithDupl.size(); ++k) {
3180  if (!idList.contains(idListWithDupl[k]))
3181  idList << idListWithDupl[k];
3182  }
3183  return idList;
3184 }
3185 
3187 {
3188  QModelIndexList selectedindexes = selectedEntryIndexes();
3189  KLFLibEntryList elist;
3190  // fill the entry list with our selected entries
3191  int k;
3192  for (k = 0; k < selectedindexes.size(); ++k) {
3193  if ( selectedindexes[k].data(KLFLibModel::ItemKindItemRole) != KLFLibModel::EntryKind )
3194  continue;
3195  KLFLibEntry entry = selectedindexes[k].data(KLFLibModel::FullEntryItemRole).value<KLFLibEntry>();
3196  klfDbg( "selection list: adding item [latex="<<entry.latex()<<"; tags="<<entry.tags()<<"]" ) ;
3197  elist << entry;
3198  }
3199  return elist;
3200 }
3201 
3203 {
3204  QList<QAction*> actionList = QList<QAction*>() << pCommonActions;
3205  if (pViewType == IconView) {
3206  actionList << pIconViewActions;
3207  }
3208  if (pViewType == CategoryTreeView || pViewType == ListTreeView) {
3209  actionList << pShowColumnActions;
3210  }
3211  return actionList;
3212 }
3213 
3214 
3216 {
3217  QVariantMap vst;
3218  if (pViewType == CategoryTreeView || pViewType == ListTreeView) {
3219  QTreeView *tv = qobject_cast<QTreeView*>(pView);
3220  KLF_ASSERT_NOT_NULL( tv, "Tree View is NULL in view type "<<pViewType<<" !!", return QVariantMap() )
3221  ;
3222  vst["ColumnsState"] = QVariant::fromValue<QByteArray>(tv->header()->saveState());
3223  }
3224  if (pViewType == IconView) {
3225  // nothing to be done
3226  }
3227  vst["IconPreviewSize"] = QVariant::fromValue<QSize>(previewSize());
3228  return vst;
3229 }
3230 bool KLFLibDefaultView::restoreGuiState(const QVariantMap& vstate)
3231 {
3232  if (pViewType == CategoryTreeView || pViewType == ListTreeView) {
3233  QByteArray colstate = vstate["ColumnsState"].toByteArray();
3234  QTreeView *tv = qobject_cast<QTreeView*>(pView);
3235  KLF_ASSERT_NOT_NULL( tv, "Tree View is NULL in view type"<<pViewType<<"!!", return false )
3236  ;
3237  tv->header()->restoreState(colstate);
3238  }
3239  if (pViewType == IconView) {
3240  // nothing to be done
3241  }
3242  setPreviewSize(vstate["IconPreviewSize"].value<QSize>());
3243  return true;
3244 }
3245 
3247 {
3248  QModelIndex index;
3249  if (pViewType == IconView) {
3250  KLFLibDefListView *lv = qobject_cast<KLFLibDefListView*>(pView);
3251  KLF_ASSERT_NOT_NULL( lv, "KLFLibDefListView List View is NULL in view type "<<pViewType<<" !!",
3252  return QModelIndex() )
3253  ;
3254  index = lv->curVisibleIndex(forward);
3255  } else if (pViewType == CategoryTreeView || pViewType == ListTreeView) {
3256  KLFLibDefTreeView *tv = qobject_cast<KLFLibDefTreeView*>(pView);
3257  KLF_ASSERT_NOT_NULL( tv, "KLFLibDefTreeView List View is NULL in view type "<<pViewType<<" !!",
3258  return QModelIndex() )
3259  ;
3260  index = tv->curVisibleIndex(forward);
3261  } else {
3262  index = QModelIndex();
3263  }
3264  return index;
3265 }
3266 
3267 
3268 #ifdef KLF_DEBUG_USE_MODELTEST
3269 #include <modeltest.h>
3270 #endif
3271 
3273 {
3275 
3276  int k;
3277  KLFLibResourceEngine *resource = resourceEngine();
3278  if (resource == NULL) {
3279  pModel = NULL;
3280  pView->setModel(NULL);
3281  for (k = 0; k < pShowColumnActions.size(); ++k)
3282  delete pShowColumnActions[k];
3283  pShowColumnActions.clear();
3284  }
3285 
3286  // klfDbg( "KLFLibDefaultView::updateResourceEngine: All items:\n"<<resource->allEntries() ) ;
3287  uint model_flavor = 0;
3288  switch (pViewType) {
3289  case IconView:
3290  case ListTreeView:
3291  model_flavor = KLFLibModel::LinearList;
3292  break;
3293  case CategoryTreeView:
3294  default:
3295  model_flavor = KLFLibModel::CategoryTree;
3296  break;
3297  };
3298 
3299  // refresh this setting from klfconfig
3301 
3302  if (pGroupSubCategories)
3303  model_flavor |= KLFLibModel::GroupSubCategories;
3304 
3305  pModel = new KLFLibModel(resource, model_flavor, this);
3306  pView->setModel(pModel);
3307 
3309 
3310  klfDbg("created model. pModel="<<klfFmtCC("%p", (void*)pModel)<<"; view type="<<pViewType);
3311 
3312 #ifdef KLF_DEBUG_USE_MODELTEST
3313  new ModelTest(pModel, this);
3314 #endif
3315 
3316  if (pViewType == IconView) {
3317  qobject_cast<KLFLibDefListView*>(pView)->modelInitialized();
3318  } else {
3319  qobject_cast<KLFLibDefTreeView*>(pView)->modelInitialized();
3320  }
3321 
3322  // get informed about selections
3323  QItemSelectionModel *s = pView->selectionModel();
3324  connect(s, SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
3325  this, SLOT(slotViewSelectionChanged(const QItemSelection&, const QItemSelection&)));
3326 
3327  connect(pModel, SIGNAL(modelReset()), this, SLOT(slotResourceModelReset()));
3328  connect(pModel, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),
3329  this, SLOT(slotResourceDataChanged(const QModelIndex&, const QModelIndex&)));
3330 
3331  // reflect pModel's request for progress reporting
3332  connect(pModel, SIGNAL(operationStartReportingProgress(KLFProgressReporter *, const QString&)),
3334 
3335 
3336  // delegate wants to know more about selections...
3337  pDelegate->setSelectionModel(s);
3338 
3339  QKeySequence selectAllKey = QKeySequence::SelectAll;
3340  QKeySequence refreshKey = QKeySequence::Refresh;
3341  QAction *selectAllAction = new QAction(tr("Select All", "[[menu action]]"), pView);
3342  selectAllAction->setShortcut(selectAllKey);
3343  connect(selectAllAction, SIGNAL(triggered()), this, SLOT(slotSelectAll()));
3344  QAction *refreshAction = new QAction(tr("Refresh", "[[menu action]]"), pView);
3345  refreshAction->setShortcut(refreshKey);
3346  connect(refreshAction, SIGNAL(triggered()), this, SLOT(slotRefresh()));
3347 
3348  QActionGroup * ag = new QActionGroup(pView);
3349  ag->setExclusive(true);
3350  QAction *aPreviewSizeLarge = new QAction(tr("Large", "[[icon preview size menu item]]"), ag);
3351  aPreviewSizeLarge->setCheckable(true);
3352  aPreviewSizeLarge->setData(100);
3353  connect(aPreviewSizeLarge, SIGNAL(triggered()), this, SLOT(slotPreviewSizeFromActionSender()));
3354  QAction *aPreviewSizeMedium = new QAction(tr("Medium", "[[icon preview size menu item]]"), ag);
3355  aPreviewSizeMedium->setCheckable(true);
3356  aPreviewSizeMedium->setData(75);
3357  connect(aPreviewSizeMedium, SIGNAL(triggered()), this, SLOT(slotPreviewSizeFromActionSender()));
3358  QAction *aPreviewSizeSmall = new QAction(tr("Small", "[[icon preview size menu item]]"), ag);
3359  aPreviewSizeSmall->setCheckable(true);
3360  aPreviewSizeSmall->setData(50);
3361  connect(aPreviewSizeSmall, SIGNAL(triggered()), this, SLOT(slotPreviewSizeFromActionSender()));
3362 
3363  pPreviewSizeMenu = new QMenu(this);
3364  pPreviewSizeMenu->addAction(aPreviewSizeLarge);
3365  pPreviewSizeMenu->addAction(aPreviewSizeMedium);
3366  pPreviewSizeMenu->addAction(aPreviewSizeSmall);
3367 
3368  QAction *aPreviewSize = new QAction(tr("Icon Size", "[[icon preview size option menu]]"), pView);
3369  aPreviewSize->setMenu(pPreviewSizeMenu);
3370 
3372 
3373  pCommonActions = QList<QAction*>() << selectAllAction << refreshAction << aPreviewSize;
3374  pViewActionsWithShortcut << selectAllAction << refreshAction;
3375 
3376  if (pViewType == IconView) {
3377  klfDbg( "About to prepare iconview." ) ;
3378  QAction * iconViewRelayoutAction = new QAction(tr("Relayout All Icons", "[[menu action]]"), this);
3379  connect(iconViewRelayoutAction, SIGNAL(triggered()), this, SLOT(slotRelayoutIcons()));
3380  pIconViewActions = QList<QAction*>() << iconViewRelayoutAction ;
3381  }
3382  if (pViewType == CategoryTreeView || pViewType == ListTreeView) {
3383  QTreeView *treeView = qobject_cast<QTreeView*>(pView);
3384  // select some columns to show
3385  treeView->setColumnHidden(pModel->columnForEntryPropertyId(KLFLibEntry::Preview), false);
3386  treeView->setColumnHidden(pModel->columnForEntryPropertyId(KLFLibEntry::Latex), true);
3387  treeView->setColumnHidden(pModel->columnForEntryPropertyId(KLFLibEntry::Tags), false);
3388  treeView->setColumnHidden(pModel->columnForEntryPropertyId(KLFLibEntry::Category), true);
3389  treeView->setColumnHidden(pModel->columnForEntryPropertyId(KLFLibEntry::DateTime), true);
3390  // optimize column sizes
3391  for (k = 0; k < pModel->columnCount(); ++k)
3392  treeView->resizeColumnToContents(k);
3393  treeView->setColumnWidth(0, 35+treeView->columnWidth(0));
3394  // and provide a menu to show/hide these columns
3395  int col;
3396  QMenu *colMenu = new QMenu(this);
3397  for (col = 0; col < pModel->columnCount(); ++col) {
3398  QString title = pModel->headerData(col, Qt::Horizontal, Qt::DisplayRole).toString();
3399  QAction *a;
3400  a = new QAction(title, this);
3401  a->setProperty("klfModelColumn", col);
3402  a->setCheckable(true);
3403  a->setChecked(!treeView->isColumnHidden(col));
3404  connect(a, SIGNAL(toggled(bool)), this, SLOT(slotShowColumnSenderAction(bool)));
3405  colMenu->addAction(a);
3406  }
3407  QAction *menuAction = new QAction(tr("Show/Hide Columns", "[[menu with sub-menu]]"), this);
3408  menuAction->setMenu(colMenu);
3409  pShowColumnActions = QList<QAction*>() << menuAction;
3410 
3411  expandRootNice();
3412  }
3413 
3414  updateResourceProp(-1); // update all with respect to resource changes..
3416 
3418 }
3419 
3421 {
3423 
3424  if (pViewType == CategoryTreeView) {
3425  klfDbg("is category view.") ;
3426  QTreeView *treeView = qobject_cast<QTreeView*>(pView);
3427  // expand root items if they contain little number of children
3428  // or if there are little number of root items
3429  int numRootItems = pModel->rowCount(QModelIndex());
3430  int k;
3431  for (k = 0; k < pModel->rowCount(QModelIndex()); ++k) {
3432  QModelIndex i = pModel->index(k, 0, QModelIndex());
3433  klfDbg("i="<<i<<"; i/rowCount="<<pModel->rowCount(i)<<"; numRootItems="<<numRootItems) ;
3434  if (pModel->rowCount(i) < 6 || numRootItems < 6) {
3435  klfDbg("expanding item i="<<i) ;
3436  // if (pModel->canFetchMore(i))
3437  // pModel->fetchMore(i);
3438  treeView->expand(i);
3439  }
3440  }
3441  }
3442 }
3443 
3444 void KLFLibDefaultView::updateResourceData(const QString& subRes, int modifyType,
3445  const QList<KLFLib::entryId>& entryIdList)
3446 {
3447  KLF_ASSERT_NOT_NULL( pModel , "Model is NULL!" , return )
3448  ;
3449  klfDbg("The resource modified its data [type="<<modifyType<<"] in subres="<<subRes<<". Our subres="<<resourceEngine()->defaultSubResource()<<"; matches?="<<resourceEngine()->compareDefaultSubResourceEquals(subRes));
3450  if (!resourceEngine()->compareDefaultSubResourceEquals(subRes))
3451  return;
3452  pModel->updateData(entryIdList, modifyType);
3453  // update our own data (icon positions)
3454  updateResourceOwnData(entryIdList);
3455 }
3457 {
3459  klfDbg( KLF_FUNC_NAME ) ;
3460  if (pViewType == IconView) {
3461  // nothing to do
3462  }
3463 }
3465 {
3466  klfDbg( "propId="<<propId ) ;
3467 
3468  KLF_ASSERT_NOT_NULL( resourceEngine() , "Resource Engine is NULL, skipping !" , return ) ;
3469 
3470  // ... nothing to be done...
3471 }
3472 
3474 {
3475  if (pModel)
3476  pModel->setFetchBatchCount(80);
3478 }
3479 
3480 
3481 QListView::Flow KLFLibDefaultView::iconViewFlow() const
3482 {
3483  if (pViewType == IconView) {
3484  KLFLibDefListView *lv = qobject_cast<KLFLibDefListView*>(pView);
3485  KLF_ASSERT_NOT_NULL( lv, "KLFLibDefListView List View is NULL in view type "<<pViewType<<" !!",
3486  return QListView::TopToBottom)
3487  ;
3488  return lv->flow();
3489  }
3490  qWarning()<<KLF_FUNC_NAME<<": requesting icon view flow in the wrong mode `"<<pViewType
3491  <<"'. Should only be called for icon view modes.";
3492  return QListView::TopToBottom; // whatever
3493 }
3494 
3495 
3497 {
3498  return pModel->categoryList();
3499 }
3500 
3501 // bool KLFLibDefaultView::writeEntryProperty(int property, const QVariant& value)
3502 // {
3503 // return pModel->changeEntries(selectedEntryIndexes(), property, value);
3504 // }
3505 // bool KLFLibDefaultView::deleteSelected(bool requireConfirm)
3506 // {
3507 // QModelIndexList sel = selectedEntryIndexes();
3508 // if (sel.size() == 0)
3509 // return true;
3510 // if (requireConfirm) {
3511 // QMessageBox::StandardButton res
3512 // = QMessageBox::question(this, tr("Delete?"),
3513 // tr("Delete %n selected item(s) from resource \"%1\"?", "", sel.size())
3514 // .arg(pModel->resource()->title()),
3515 // QMessageBox::Yes|QMessageBox::Cancel, QMessageBox::Cancel);
3516 // if (res != QMessageBox::Yes)
3517 // return false; // abort action
3518 // }
3519 // return pModel->deleteEntries(sel);
3520 // }
3521 // bool KLFLibDefaultView::insertEntries(const KLFLibEntryList& entries)
3522 // {
3523 // return pModel->insertEntries(entries);
3524 // }
3526 {
3527  klfDbg("selecting entries: "<<idList) ;
3528 
3529  QModelIndexList mil = pModel->findEntryIdList(idList);
3530  QItemSelection sel;
3531  int k;
3532  for (k = 0; k < mil.size(); ++k)
3533  sel << QItemSelectionRange(mil[k]);
3534 
3535  pView->selectionModel()->select(sel, QItemSelectionModel::ClearAndSelect);
3536 
3537  if (pViewType == CategoryTreeView && pView->inherits("KLFLibDefTreeView")) {
3538  KLFLibDefTreeView *v = qobject_cast<KLFLibDefTreeView*>(pView);
3539  v->ensureExpandedTo(mil);
3540  }
3541  return true;
3542 }
3543 
3544 
3545 
3546 void KLFLibDefaultView::restore(uint restoreflags)
3547 {
3548  QModelIndexList sel = selectedEntryIndexes();
3549  if (sel.size() != 1) {
3550  qWarning("KLFLibDefaultView::restoreWithStyle(): Cannot restore: %d items selected.", sel.size());
3551  return;
3552  }
3553 
3554  KLFLibEntry e = sel[0].data(KLFLibModel::FullEntryItemRole).value<KLFLibEntry>();
3555 
3556  emit requestRestore(e, restoreflags);
3557 }
3558 
3559 void KLFLibDefaultView::showColumns(int propIdColumn, bool show)
3560 {
3561  if ( ! pView->inherits("QTreeView") ) {
3562  qWarning("KLFLibDefaultView::showColumns(%d,%s): Resource view for %s: view does not inherit QTreeView!",
3563  propIdColumn, show?"[show]":"[hide]", qPrintable(resourceEngine()->url().toString()));
3564  return;
3565  }
3566  int colNo = pModel->columnForEntryPropertyId(propIdColumn);
3567  qobject_cast<QTreeView*>(pView)->setColumnHidden(colNo, show);
3568 }
3569 
3570 void KLFLibDefaultView::sortBy(int propIdColumn, Qt::SortOrder sortorder)
3571 {
3572  if ( ! pView->inherits("QTreeView") ) {
3573  qWarning("KLFLibDefaultView::showBy(%d,%s): Resource view for %s: view does not inherit QTreeView!",
3574  propIdColumn, (sortorder == Qt::AscendingOrder)?"[Ascending]":"[Descending]" ,
3575  qPrintable(resourceEngine()->url().toString()));
3576  return;
3577  }
3578  QTreeView * tree = qobject_cast<QTreeView*>(pView);
3579  int colNo = pModel->columnForEntryPropertyId(propIdColumn);
3580  if (colNo < 0 || colNo >= pModel->columnCount()) {
3581  qWarning("KLFLibDefaultView::showBy(%d,%s): column number %d is not valid or hidden!",
3582  propIdColumn, (sortorder == Qt::AscendingOrder)?"[Ascending]":"[Descending]", colNo);
3583  return;
3584  }
3585  tree->sortByColumn(colNo, sortorder);
3586 }
3587 
3588 
3589 void KLFLibDefaultView::slotSelectAll(bool expandItems)
3590 {
3591  slotSelectAll( QModelIndex(), NoSignals | (expandItems?ExpandItems:0) );
3592  updateDisplay();
3593 }
3594 void KLFLibDefaultView::slotSelectAll(const QModelIndex& parent, uint selectAllFlags)
3595 {
3596  KLFDelayedPleaseWaitPopup pleaseWait(tr("Fetching and selecting all, please wait ..."), this);
3597  pleaseWait.setDisableUi(true);
3598  pleaseWait.setDelay(500);
3599 
3600  if (selectAllFlags & NoSignals)
3601  pView->selectionModel()->blockSignals(true);
3602 
3603  QTime tm;
3604  tm.start();
3605  func_selectAll(parent, selectAllFlags, &tm, &pleaseWait);
3606 
3607  if (selectAllFlags & NoSignals)
3608  pView->selectionModel()->blockSignals(false);
3609 
3611  updateDisplay();
3612 }
3613 
3614 // If this returns FALSE, then propagate the cancel/error/stop further up in recursion
3615 bool KLFLibDefaultView::func_selectAll(const QModelIndex& parent, uint selectAllFlags, QTime *tm,
3616  KLFDelayedPleaseWaitPopup *pleaseWait)
3617 {
3619  // this function requires to fetch all items in parent!
3620 
3621  while (pModel->canFetchMore(parent)) {
3622  pModel->fetchMore(parent);
3623  pleaseWait->process();
3624  if (pleaseWait->wasUserDiscarded())
3625  return false;
3626  if (tm->elapsed() > 300) {
3627  // process a few events..
3628  qApp->processEvents();
3629  tm->restart();
3630  }
3631  }
3632 
3633  int k;
3634  QModelIndex topLeft = pModel->index(0, 0, parent);
3635  QModelIndex bottomRight = pModel->index(pModel->rowCount(parent)-1,
3636  pModel->columnCount(parent)-1, parent);
3637  pView->selectionModel()->select(QItemSelection(topLeft, bottomRight), QItemSelectionModel::Select);
3638  if ( ! pModel->hasChildren(parent) )
3639  return true;
3640 
3641  if (selectAllFlags & ExpandItems) {
3642  QTreeView *treeView = pView->inherits("QTreeView") ? qobject_cast<QTreeView*>(pView) : NULL;
3643  if (treeView != NULL)
3644  treeView->expand(parent);
3645  }
3646 
3647  for (k = 0; k < pModel->rowCount(parent); ++k) {
3648  QModelIndex child = pModel->index(k, 0, parent);
3649  if ( ! func_selectAll(child, selectAllFlags, tm, pleaseWait) )
3650  return false; // cancel requested eg. by user clicking on the popup
3651  if (tm->elapsed() > 300) {
3652  qApp->processEvents();
3653  pleaseWait->process();
3654  if (pleaseWait->wasUserDiscarded())
3655  return false;
3656  tm->restart();
3657  }
3658  }
3659 
3660  return true;
3661 }
3662 
3664 {
3666  pModel->completeRefresh();
3667 }
3668 
3670 {
3672  QAction *a = qobject_cast<QAction*>(sender());
3673  KLF_ASSERT_NOT_NULL(a, "action sender is NULL!", return ; ) ;
3674 
3675  pDelegate->setPreviewSize(klfconfig.UI.labelOutputFixedSize * a->data().toInt() / 100.0);
3676  pView->reset();
3677 
3679 }
3680 
3682 {
3684 
3685  KLF_ASSERT_NOT_NULL(pPreviewSizeMenu, "pPreviewSizeMenu is NULL!", return ) ;
3686 
3687  int curPreviewSizePercent
3688  = pDelegate->previewSize().width() * 100 / klfconfig.UI.labelOutputFixedSize.width();
3689  // round off to 5 units (for comparision with some threshold)
3690  curPreviewSizePercent = (int)(curPreviewSizePercent/5 +0.5)*5;
3691 
3692  QList<QAction*> alist = pPreviewSizeMenu->actions();
3693  klfDbg("There are "<<alist.size()<<" actions...") ;
3694  for (QList<QAction*>::iterator it = alist.begin(); it != alist.end(); ++it) {
3695  QAction *a = (*it);
3696  int a_sz = (int)(a->data().toInt()/5 +0.5)*5;
3697  klfDbg("Processing action "<< a->text() << " (data="<<a->data().toInt()<<" ~= "<<a_sz
3698  <<") curPreviewSizePercent="<<curPreviewSizePercent) ;
3699 
3700  if ( a_sz == curPreviewSizePercent )
3701  a->setChecked(true);
3702  else
3703  a->setChecked(false);
3704  }
3705 }
3706 
3707 
3709 {
3710  if (pViewType != IconView || !pView->inherits("KLFLibDefListView")) {
3711  return;
3712  }
3713  KLFLibDefListView *lv = qobject_cast<KLFLibDefListView*>(pView);
3714  // force a re-layout
3715  lv->forceRelayout();
3716 }
3717 
3718 void KLFLibDefaultView::setIconViewFlow(QListView::Flow flow)
3719 {
3720  if (pViewType == IconView) {
3721  KLFLibDefListView *lv = qobject_cast<KLFLibDefListView*>(pView);
3722  KLF_ASSERT_NOT_NULL( lv, "KLFLibDefListView List View is NULL in view type "<<pViewType<<" !!",
3723  return )
3724  ;
3725  // set the flow
3726  lv->setFlow(flow);
3727  }
3728 }
3729 
3731 {
3732  KLF_ASSERT_NOT_NULL(pView, "view is NULL!", return ) ;
3733  pView->viewport()->update();
3734 }
3735 
3736 bool KLFLibDefaultView::searchFind(const QString& queryString, bool forward)
3737 {
3738  QModelIndex fromIndex = currentVisibleIndex();
3739  // take one index above in case it's partially shown
3740  fromIndex = pModel->walkPrevIndex(fromIndex);
3741  QModelIndex i = pModel->searchFind(queryString, fromIndex, forward);
3742  pDelegate->setSearchString(queryString);
3743  // for (int col = 0; i.isValid() && col < pModel->columnCount(); ++col)
3744  // pView->update(pModel->index(i.row(), col, i.parent())); // searchFound will call updateDisplay()
3745  searchFound(i);
3746  return i.isValid();
3747 }
3748 
3750 {
3751  QModelIndex i = pModel->searchFindNext(forward);
3752  searchFound(i);
3753  return i.isValid();
3754 }
3755 
3757 {
3758  pModel->searchAbort();
3759  pDelegate->setSearchString(QString());
3760  pDelegate->setSearchIndex(QModelIndex());
3761  updateDisplay(); // repaint widget to update search underline
3762 
3763  // don't un-select the found index...
3764  // searchFound(QModelIndex());
3765 }
3766 
3767 // private
3768 void KLFLibDefaultView::searchFound(const QModelIndex& i)
3769 {
3770  pDelegate->setSearchIndex(i);
3771  if ( ! i.isValid() ) {
3772  pView->scrollToTop();
3773  // unselect all
3774  pView->selectionModel()->setCurrentIndex(QModelIndex(), QItemSelectionModel::Clear);
3775  return;
3776  } else {
3777  pView->scrollTo(i, QAbstractItemView::EnsureVisible);
3778  }
3779  if (pViewType == CategoryTreeView) {
3780  // if tree view, expand item
3781  qobject_cast<QTreeView*>(pView)->expand(i);
3782  }
3783  // select the item
3784  pView->selectionModel()->setCurrentIndex(i,
3785  QItemSelectionModel::ClearAndSelect|
3786  QItemSelectionModel::Rows);
3787  updateDisplay();
3788 }
3789 
3790 
3792  const QItemSelection& /*deselected*/)
3793 {
3794 #ifndef Q_WS_WIN
3795  // This line generates QPaint* warnings on Win32
3796  // This is needed to update the parent items selection indicator
3797  updateDisplay();
3798 #endif
3799 
3801 }
3802 
3804 {
3805  if (pViewType == CategoryTreeView) {
3806  expandRootNice();
3807  }
3808 }
3809 
3811  const QModelIndex& bottomRight)
3812 {
3813  QItemSelectionRange rng = QItemSelectionRange(topLeft, bottomRight);
3814  QModelIndexList indexes = rng.indexes();
3815  QList<KLFLib::entryId> eids = pModel->entryIdForIndexList(indexes);
3816  emit resourceDataChanged(eids);
3817 }
3818 
3819 /*
3820 QItemSelection KLFLibDefaultView::fixSelection(const QModelIndexList& selidx)
3821 {
3822  QModelIndexList moreselidx;
3823  QItemSelection moresel;
3824 
3825  int k, j;
3826  for (k = 0; k < selidx.size(); ++k) {
3827  if (selidx[k].isValid() &&
3828  selidx[k].data(KLFLibModel::ItemKindItemRole).toInt() == KLFLibModel::CategoryLabelKind &&
3829  selidx[k].column() == 0) {
3830  // a category is selected -> select all its children
3831  const QAbstractItemModel *model = selidx[k].model();
3832  int nrows = model->rowCount(selidx[k]);
3833  int ncols = model->columnCount(selidx[k]);
3834  if (pViewType == CategoryTreeView) {
3835  // // if tree view, expand item
3836  // // do this delayed, since this function can be called from within a slot
3837  // QMetaObject::invokeMethod(pView, "expand", Qt::QueuedConnection, Q_ARG(QModelIndex, selidx[k]));
3838  }
3839  for (j = 0; j < nrows; ++j) {
3840  switch (selidx[k].child(j,0).data(KLFLibModel::ItemKindItemRole).toInt()) {
3841  case KLFLibModel::CategoryLabelKind:
3842  moreselidx.append(selidx[k].child(j,0));
3843  // no break; proceed to entrykind->
3844  case KLFLibModel::EntryKind:
3845  moresel.append(QItemSelectionRange(selidx[k].child(j, 0),
3846  selidx[k].child(j, ncols-1)));
3847  break;
3848  default: ;
3849  }
3850 
3851  }
3852  }
3853  }
3854 
3855  if (moresel.isEmpty()) {
3856  return QItemSelection();
3857  }
3858 
3859  QItemSelection s = moresel;
3860  QItemSelection morefixed = fixSelection(moreselidx);
3861  s.merge(morefixed, QItemSelectionModel::Select);
3862  return s;
3863 
3864 }
3865 */
3866 
3867 
3869 {
3871 
3872  if (index.column() != 0)
3873  return;
3874 
3875  slotSelectAll(index, ExpandItems);
3876  /*
3877  QItemSelection fixed = fixSelection( QModelIndexList() << index);
3878  // do this delayed, since this function can be called from within a slot
3879  bool result =
3880  QMetaObject::invokeMethod(pView->selectionModel(), "select", Qt::QueuedConnection,
3881  Q_ARG(QItemSelection, fixed),
3882  Q_ARG(QItemSelectionModel::SelectionFlags, QItemSelectionModel::Select));
3883  klfDbg("result of invoked method is "<<result) ;
3884  */
3885 }
3887 {
3889  return;
3892 }
3893 
3894 // void KLFLibDefaultView::slotExpanded(const QModelIndex& index)
3895 // {
3896 // pDelegate->setIndexExpanded(index, true);
3897 // }
3898 // void KLFLibDefaultView::slotCollapsed(const QModelIndex& index)
3899 // {
3900 // pDelegate->setIndexExpanded(index, false);
3901 // }
3902 
3904 {
3905  QObject *a = sender();
3906  if (a == NULL)
3907  return;
3908 
3909  if ( ! pView->inherits("QTreeView") )
3910  return;
3911  int colNo = a->property("klfModelColumn").toInt();
3912  qobject_cast<QTreeView*>(pView)->setColumnHidden(colNo, !showCol);
3913 }
3914 
3915 
3916 
3917 
3918 QModelIndexList KLFLibDefaultView::selectedEntryIndexes() const
3919 {
3922  QModelIndexList selection = pView->selectionModel()->selectedIndexes();
3923  QModelIndexList entryindexes;
3924  int k;
3925  QList<KLFLib::entryId> doneEntryIds;
3926  // walk selection and strip all non-zero column number indexes
3927  for (k = 0; k < selection.size(); ++k) {
3928  KLFLib::entryId eid = selection[k].data(KLFLibModel::EntryIdItemRole).toInt();
3929  int iPos = qLowerBound(doneEntryIds.begin(), doneEntryIds.end(), eid) - doneEntryIds.begin();
3930  if ( iPos < doneEntryIds.size() && doneEntryIds[iPos] == eid ) // already in list
3931  continue;
3932  doneEntryIds.insert(iPos, eid);
3933  entryindexes << selection[k];
3934  }
3935  return entryindexes;
3936 }
3937 
3938 
3939 
3940 // ------------
3941 
3942 static QStringList defaultViewTypeIds = QStringList()<<"default"<<"default+list"<<"default+icons";
3943 
3944 
3946  : KLFLibViewFactory(defaultViewTypeIds, parent)
3947 {
3948 }
3949 
3950 
3952 {
3953  if (viewTypeIdent == "default")
3954  return tr("Category Tree View");
3955  if (viewTypeIdent == "default+list")
3956  return tr("List View");
3957  if (viewTypeIdent == "default+icons")
3958  return tr("Icon View");
3959 
3960  return QString();
3961 }
3962 
3963 
3965  QWidget *parent,
3966  KLFLibResourceEngine *resourceEngine)
3967 {
3969  if (viewTypeIdent == "default")
3971  else if (viewTypeIdent == "default+list")
3973  else if (viewTypeIdent == "default+icons")
3975 
3976  KLFLibDefaultView *view = new KLFLibDefaultView(parent, v);
3977  view->setResourceEngine(resourceEngine);
3978  return view;
3979 }
3980 
3981 
3982 
3983 // ------------
3984 
3985 
3987  : QDialog(parent)
3988 {
3989  pUi = new Ui::KLFLibOpenResourceDlg;
3990  pUi->setupUi(this);
3991  setWindowIcon(QPixmap(":/pics/klatexformula-64.png"));
3992 
3993  // check to see which is the default widget to show according to defaultlocation
3994  KLFLibEngineFactory *efactory = NULL;
3995  if (!defaultlocation.isEmpty())
3996  KLFLibEngineFactory::findFactoryFor(defaultlocation.scheme());
3997  QString defaultwtype;
3998  if (efactory == NULL) {
3999  if (!defaultlocation.isEmpty())
4000  qWarning()<<"No Factory for URL "<<defaultlocation<<"'s scheme!";
4001  } else {
4002  defaultwtype = efactory->correspondingWidgetType(defaultlocation.scheme());
4003  }
4004 
4005  // add a widget for all supported widgets
4007  int k;
4008  for (k = 0; k < wtypeList.size(); ++k) {
4009  qDebug("KLFLibOpenRes.Dlg::[constr.]() Adding widget for wtype %s", qPrintable(wtypeList[k]));
4011  QUrl thisdefaultlocation;
4012  if (wtypeList[k] == defaultwtype)
4013  thisdefaultlocation = defaultlocation;
4014  QWidget *openWidget = factory->createPromptUrlWidget(pUi->stkOpenWidgets, wtypeList[k],
4015  thisdefaultlocation);
4016  pUi->stkOpenWidgets->insertWidget(k, openWidget);
4017  pUi->cbxType->insertItem(k, factory->widgetTypeTitle(wtypeList[k]),
4018  QVariant::fromValue(wtypeList[k]));
4019 
4020  connect(openWidget, SIGNAL(readyToOpen(bool)), this, SLOT(updateReadyToOpenFromSender(bool)));
4021  }
4022 
4023  if (defaultwtype.isEmpty()) {
4024  pUi->cbxType->setCurrentIndex(0);
4025  pUi->stkOpenWidgets->setCurrentIndex(0);
4026  } else {
4027  pUi->cbxType->setCurrentIndex(k = wtypeList.indexOf(defaultwtype));
4028  pUi->stkOpenWidgets->setCurrentIndex(k);
4029  }
4030 
4031  btnGo = pUi->btnBar->button(QDialogButtonBox::Open);
4032 
4033  connect(pUi->cbxType, SIGNAL(activated(int)), this, SLOT(updateReadyToOpen()));
4035 }
4036 
4038 {
4039  delete pUi;
4040 }
4041 
4043 {
4044  int k = pUi->cbxType->currentIndex();
4045  QString wtype = pUi->cbxType->itemData(k).toString();
4046  KLFLibWidgetFactory *factory
4048  return factory->retrieveUrlFromWidget(wtype, pUi->stkOpenWidgets->widget(k));
4049 }
4050 
4052 {
4053  QUrl url = retrieveRawUrl();
4054  if (url.isEmpty()) {
4055  // empty url means cancel open
4056  return QUrl();
4057  }
4058  if (pUi->chkReadOnly->isChecked())
4059  url.addQueryItem("klfReadOnly", "true");
4060  if (pUi->cbxSubResource->count())
4061  url.addQueryItem("klfDefaultSubResource",
4062  pUi->cbxSubResource->itemData(pUi->cbxSubResource->currentIndex()).toString());
4063  klfDbg( "Got URL: "<<url ) ;
4064  return url;
4065 }
4066 
4068 {
4069  QObject *w = sender();
4070  // use the widget itself to store the value
4071  w->setProperty("__klflibopenresourcedlg_readyToOpen", isready);
4073 }
4075 {
4076  QWidget *w = pUi->stkOpenWidgets->currentWidget();
4077  KLF_ASSERT_NOT_NULL( w, "widget is NULL!", return ) ;
4078 
4079  bool w_is_ready = w->property("readyToOpen").toBool();
4080  if (!w_is_ready) {
4081  // possibly the widget did not set the 'readyToOpen' property, but emitted its signal
4082  // that must have reached us in the secondary property
4083  QVariant v = w->property("__klflibopenresourcedlg_readyToOpen");
4084  if (v.isValid())
4085  w_is_ready = v.toBool();
4086  }
4087  btnGo->setEnabled(w_is_ready);
4088  // and propose choice of sub-resources
4089  pUi->frmSubResource->show();
4090  pUi->cbxSubResource->clear();
4091  if (!w_is_ready) {
4092  pUi->frmSubResource->hide();
4093  } else {
4094  // we're ready to open, read sub-resource list
4096  if (subResMap.isEmpty()) {
4097  pUi->frmSubResource->hide();
4098  } else {
4099  for (QMap<QString,QString>::const_iterator it = subResMap.begin(); it != subResMap.end(); ++it) {
4100  QString subres = it.key();
4101  QString subrestitle = it.value();
4102  if (subrestitle.isEmpty())
4103  subrestitle = subres;
4104  pUi->cbxSubResource->addItem(subrestitle, QVariant(subres));
4105  }
4106  }
4107  }
4108 }
4109 
4110 // static
4112 {
4113  KLFLibOpenResourceDlg dlg(defaultlocation, parent);
4114  int result = dlg.exec();
4115  if (result != QDialog::Accepted)
4116  return QUrl();
4117  QUrl url = dlg.url();
4118  return url;
4119 }
4120 
4121 
4122 
4123 // ---------------------
4124 
4125 
4127  : QDialog(parent)
4128 {
4130 
4131  pUi = new Ui::KLFLibOpenResourceDlg;
4132  pUi->setupUi(this);
4133  setWindowIcon(QPixmap(":/pics/klatexformula-64.png"));
4134 
4135  pUi->lblMain->setText(tr("Create New Library Resource", "[[dialog label title]]"));
4136  setWindowTitle(tr("Create New Library Resource", "[[dialog window title]]"));
4137  pUi->chkReadOnly->hide();
4138 
4139  pUi->cbxSubResource->setEnabled(true);
4140  pUi->cbxSubResource->setEditable(true);
4141  pUi->cbxSubResource->setEditText(tr("SubResource1"));
4142 
4143  pUi->btnBar->setStandardButtons(QDialogButtonBox::Save|QDialogButtonBox::Cancel);
4144  btnGo = pUi->btnBar->button(QDialogButtonBox::Save);
4145 
4146  int defaultIndex = 0;
4147  // add a widget for all supported widget-types
4149  int k;
4150  for (k = 0; k < wtypeList.size(); ++k) {
4151  KLFLibWidgetFactory *factory
4152  = KLFLibWidgetFactory::findFactoryFor(wtypeList[k]);
4153  QWidget *createResWidget =
4154  factory->createPromptCreateParametersWidget(pUi->stkOpenWidgets, wtypeList[k],
4155  Parameters());
4156  pUi->stkOpenWidgets->insertWidget(k, createResWidget);
4157  pUi->cbxType->insertItem(k, factory->widgetTypeTitle(wtypeList[k]),
4158  QVariant::fromValue(wtypeList[k]));
4159 
4160  if (wtypeList[k] == defaultWtype)
4161  defaultIndex = k;
4162 
4163  connect(createResWidget, SIGNAL(readyToCreate(bool)),
4164  this, SLOT(updateReadyToCreateFromSender(bool)));
4165  klfDbg("Added create-res-widget of type "<<wtypeList[k]) ;
4166  }
4167 
4168  pUi->cbxType->setCurrentIndex(defaultIndex);
4169  pUi->stkOpenWidgets->setCurrentIndex(defaultIndex);
4170 
4171  connect(pUi->cbxType, SIGNAL(activated(int)), this, SLOT(updateReadyToCreate()));
4173 }
4175 {
4176  delete pUi;
4177 }
4178 
4180 {
4182 
4183  int k = pUi->cbxType->currentIndex();
4184  QString wtype = pUi->cbxType->itemData(k).toString();
4185  KLFLibWidgetFactory *factory
4187  Parameters p = factory->retrieveCreateParametersFromWidget(wtype, pUi->stkOpenWidgets->widget(k));
4188  p["klfWidgetType"] = wtype;
4189  p["klfDefaultSubResource"] = pUi->cbxSubResource->currentText();
4190  p["klfDefaultSubResourceTitle"] = pUi->cbxSubResource->currentText();
4191 
4192  klfDbg("Create parameters are: "<<p) ;
4193 
4194  return p;
4195 }
4196 
4197 
4199 {
4200  const Parameters p = getCreateParameters();
4201  if (p == Parameters() || p["klfCancel"].toBool() == true) {
4202  QDialog::reject();
4203  return;
4204  }
4205  if (p["klfRetry"].toBool() == true)
4206  return; // ignore accept, reprompt user
4207 
4208  // then by default accept the event
4209  // set internal parameter cache to the given parameters, they
4210  // will be recycled by createResource() instead of being re-queried
4211  pParam = p;
4212  QDialog::accept();
4213 }
4215 {
4216  QDialog::reject();
4217 }
4218 
4220 {
4221  QObject *w = sender();
4222  w->setProperty("__klflibcreateresourcedlg_readyToCreate", isready);
4224 }
4226 {
4227  QWidget *w = pUi->stkOpenWidgets->currentWidget();
4228  if (w == NULL) return;
4229  QVariant v = w->property("__klflibcreateresourcedlg_readyToCreate");
4230  // and update button enabled. If the widget emitted no signal, then it is
4231  // assumed to be ready, as we have no way of knowing
4232  btnGo->setEnabled(!v.isValid() || v.toBool());
4233 }
4234 
4235 // static
4237  QObject *resourceParent, QWidget *parent)
4238 {
4239  KLFLibCreateResourceDlg dlg(defaultWtype, parent);
4240  int result = dlg.exec();
4241  if (result != QDialog::Accepted)
4242  return NULL;
4243 
4244  Parameters p = dlg.pParam; // we have access to this private member
4245  QString scheme = p["klfScheme"].toString();
4246 
4247  if (scheme.isEmpty()) {
4248  qWarning()<<"KLFLibCr.Res.Dlg::createRes.(): Widget Type "<<p["klfWidgetType"]
4249  <<" failed to announce what scheme it wanted in p[\"klfScheme\"]!";
4250  return NULL;
4251  }
4252 
4254  KLF_ASSERT_NOT_NULL( factory ,
4255  qPrintable(QString("Couldn't find factory for scheme %1 ?!?").arg(scheme)),
4256  return NULL )
4257  ;
4258 
4259  KLFLibResourceEngine *resource = factory->createResource(scheme, p, resourceParent);
4260  return resource;
4261 }
4262 
4263 
4264 // ---------------------
4265 
4266 
4268  : QWidget(parent)
4269 {
4270  U = new Ui::KLFLibResPropEditor;
4271  U->setupUi(this);
4272  setWindowIcon(QPixmap(":/pics/klatexformula-64.png"));
4273 
4274  QPalette pal = U->txtUrl->palette();
4275  pal.setColor(QPalette::Base, pal.color(QPalette::Window));
4276  pal.setColor(QPalette::Background, pal.color(QPalette::Window));
4277  U->txtUrl->setPalette(pal);
4278 
4279  if (res == NULL)
4280  qWarning("KLFLibResPropEditor: NULL Resource! Expect CRASH!");
4281 
4282  pResource = res;
4283 
4284  pSuppSubRes =
4286  pSuppSubResProps =
4288 
4289  connect(pResource, SIGNAL(resourcePropertyChanged(int)),
4290  this, SLOT(slotResourcePropertyChanged(int)));
4291  connect(pResource, SIGNAL(subResourcePropertyChanged(const QString&, int)),
4292  this, SLOT(slotSubResourcePropertyChanged(const QString&, int)));
4293 
4294  pPropModel = new QStandardItemModel(this);
4295  pPropModel->setColumnCount(2);
4296  pPropModel->setHorizontalHeaderLabels(QStringList() << tr("Name") << tr("Value"));
4297  U->tblProperties->setModel(pPropModel);
4298  U->tblProperties->setItemDelegate(new QItemDelegate(this));
4299 
4300  connect(pPropModel, SIGNAL(itemChanged(QStandardItem *)),
4301  this, SLOT(advPropEdited(QStandardItem *)));
4302 
4303  pSubResPropModel = new QStandardItemModel(this);
4304  pSubResPropModel->setColumnCount(2);
4305  pSubResPropModel->setHorizontalHeaderLabels(QStringList() << tr("Name") << tr("Value"));
4306  U->tblSubResProperties->setModel(pSubResPropModel);
4307  U->tblSubResProperties->setItemDelegate(new QItemDelegate(this));
4308 
4309  connect(pSubResPropModel, SIGNAL(itemChanged(QStandardItem *)),
4310  this, SLOT(advSubResPropEdited(QStandardItem *)));
4311 
4312  U->frmAdvanced->setShown(U->btnAdvanced->isChecked());
4313 
4314  // perform full refresh (resource properties)
4316  // preform full refresh (sub-resources)
4317  updateSubResources(pResource->defaultSubResource());
4318  // perform full refresh (sub-resource properties)
4320 
4321  connect(U->btnApply, SIGNAL(clicked()), this, SLOT(apply()));
4322 }
4323 
4325 {
4326  delete U;
4327 }
4328 
4330 {
4331  bool res = true;
4332 
4333  // set the default sub-resource
4335  pResource->setDefaultSubResource(curSubResource());
4336 
4337  bool srislocked = false;
4338  if (pSuppSubRes && pSuppSubResProps)
4339  srislocked = pResource->subResourceProperty(curSubResource(),
4341 
4342  bool lockmodified = (pResource->locked() != U->chkLocked->isChecked());
4343  bool srlockmodified = false;
4344  if (pSuppSubRes && pSuppSubResProps && srislocked != U->chkSubResLocked->isChecked()) {
4345  srlockmodified = true;
4346  }
4347  bool wantunlock = lockmodified && !U->chkLocked->isChecked();
4348  bool srwantunlock = srlockmodified && !U->chkSubResLocked->isChecked();
4349  bool wantlock = lockmodified && !wantunlock;
4350  bool srwantlock = srlockmodified && !srwantunlock;
4351  bool titlemodified = (pResource->title() != U->txtTitle->text());
4352  bool subrestitlemodified = false;
4353  if (pSuppSubRes && pSuppSubResProps &&
4355  != U->txtSubResTitle->text()) {
4356  subrestitlemodified = true;
4357  }
4358 
4359  klfDbg( ": lockmodif="<<lockmodified<<"; srlockmodified="<<srlockmodified
4360  <<"; wantunlock="<<wantunlock<<"; srwantunlock="<<srwantunlock<<"; wantlock="<<wantlock
4361  <<"; srwantlock="<<srwantlock<<"; titlemodif="<<titlemodified
4362  <<"; srtitlemodif="<<subrestitlemodified ) ;
4363 
4364  if ( (pResource->locked() && !lockmodified) ||
4365  (srislocked && !srlockmodified) ) {
4366  // no intent to modify locked state of locked resource
4367  if (titlemodified || subrestitlemodified) {
4368  QMessageBox::critical(this, tr("Error"), tr("Can't rename a locked resource!"));
4369  return false;
4370  } else {
4371  return true; // nothing to apply
4372  }
4373  }
4374  if (wantunlock) {
4375  if ( ! pResource->setLocked(false) ) { // unlock resource before other modifications
4376  res = false;
4377  QMessageBox::critical(this, tr("Error"), tr("Failed to unlock resource."));
4378  }
4379  }
4380  if (srwantunlock) {
4381  if ( ! pResource->setSubResourceProperty(curSubResource(), KLFLibResourceEngine::SubResPropLocked,
4382  false) ) { // unlock sub-resource before other modifications
4383  res = false;
4384  QMessageBox::critical(this, tr("Error"), tr("Failed to unlock sub-resource \"%1\".")
4385  .arg(curSubResource()));
4386  }
4387  }
4388 
4389  QString newTitle = U->txtTitle->text();
4390  QString newSubResTitle = U->txtSubResTitle->text();
4391 
4392  if ( titlemodified && ! pResource->setTitle(newTitle) ) {
4393  res = false;
4394  QMessageBox::critical(this, tr("Error"), tr("Failed to rename resource."));
4395  }
4396 
4397  if ( subrestitlemodified &&
4398  ! pResource->setSubResourceProperty(curSubResource(),
4400  newSubResTitle) ) {
4401  res = false;
4402  QMessageBox::critical(this, tr("Error"), tr("Failed to rename sub-resource \"%1\".")
4403  .arg(curSubResource()));
4404  }
4405 
4406  if (wantlock) {
4407  if ( ! pResource->setLocked(true) ) { // lock resource after other modifications
4408  res = false;
4409  QMessageBox::critical(this, tr("Error"), tr("Failed to lock resource."));
4410  }
4411  }
4412  if (srwantlock) {
4413  if ( ! pResource->setSubResourceProperty(curSubResource(), KLFLibResourceEngine::SubResPropLocked,
4414  true) ) { // lock resource after other modifications
4415  res = false;
4416  QMessageBox::critical(this, tr("Error"), tr("Failed to lock sub-resource \"%1\".")
4417  .arg(curSubResource()));
4418  }
4419  }
4420 
4421  return res;
4422 }
4423 
4425 {
4426  // show/hide advanced controls
4427  U->frmAdvanced->setShown(on);
4428  if (U->frmAdvanced->isVisible()) {
4429  // adjust size of columns
4430  int w = width() / 3;
4431  U->tblProperties->setColumnWidth(0, w);
4432  U->tblProperties->setColumnWidth(1, w);
4433  U->tblSubResProperties->setColumnWidth(0, w);
4434  U->tblSubResProperties->setColumnWidth(1, w);
4435  }
4436  update();
4437  adjustSize();
4438  if (parentWidget()) {
4439  klfDbg( "Parent widget is "<<parentWidget() ) ;
4440  parentWidget()->update();
4441  parentWidget()->adjustSize();
4442  }
4443 }
4444 
4446 {
4447  klfDbg( "KLFLibResPropEditor::updateSubResources("<<curSubRes<<")" ) ;
4448  if ( pSuppSubRes ) {
4449  U->cbxSubResource->blockSignals(true);
4450  U->cbxSubResource->clear();
4451  QStringList subResList = pResource->subResourceList();
4452  int k;
4453  int curSubResIndex = 0;
4454  for (k = 0; k < subResList.size(); ++k) {
4455  QString title;
4456  QString thissrtitle
4458  if (!thissrtitle.isEmpty())
4459  title = QString("%1 (%2)").arg(thissrtitle, subResList[k]);
4460  else
4461  title = subResList[k];
4462  U->cbxSubResource->addItem(title, subResList[k]);
4463  if (subResList[k] == curSubRes)
4464  curSubResIndex = k;
4465  }
4466  klfDbg( "KLFLibResPropEditor::updateSubResources("<<curSubRes<<") : setting cur index="<<curSubResIndex ) ;
4467  U->cbxSubResource->setCurrentIndex(curSubResIndex);
4468  U->cbxSubResource->blockSignals(false);
4469  if ( pSuppSubResProps ) {
4470  U->wSubResProps->show();
4471  U->txtSubResTitle->setEnabled(true);
4472  U->chkSubResLocked->setEnabled(true);
4473  slotSubResourcePropertyChanged(curSubResource(), -2);
4474  U->txtSubResTitle->setEnabled(pResource
4475  ->canModifySubResourceProperty(curSubResource(),
4477  U->txtSubResTitle->setText(pResource->subResourceProperty(curSubResource(),
4479  .toString());
4480  U->chkSubResLocked->setEnabled(pResource
4481  ->canModifySubResourceProperty(curSubResource(),
4483  U->chkSubResLocked->setChecked(pResource->subResourceProperty(curSubResource(),
4485  .toBool());
4486  } else {
4487  U->wSubResProps->hide();
4488  U->chkSubResLocked->setEnabled(false);
4489  U->txtSubResTitle->setText("");
4490  U->txtSubResTitle->setEnabled(false);
4491  }
4492  } else {
4493  U->cbxSubResource->clear();
4494  U->cbxSubResource->setEnabled(false);
4495  U->wSubResProps->hide();
4496  U->chkSubResLocked->setEnabled(false);
4497  U->txtSubResTitle->setText("");
4498  U->txtSubResTitle->setEnabled(false);
4499  }
4500 }
4501 
4503 {
4504  klfDbg( "advPropEdited("<<item<<")" ) ;
4505  QVariant value = item->data(Qt::EditRole);
4506  int propId = item->data(Qt::UserRole).toInt();
4507  bool r = pResource->setResourceProperty(propId, value);
4508  if ( ! r ) {
4509  QMessageBox::critical(this, tr("Error"),
4510  tr("Failed to set resource property \"%1\".")
4511  .arg(pResource->propertyNameForId(propId)));
4512  }
4513  // slotResourcePropertyChanged will be called.
4514 }
4515 
4517 {
4518  // perform full update
4521 }
4523 {
4524  pPropModel->setRowCount(0);
4525  int k;
4526  QStringList props = pResource->registeredPropertyNameList();
4527  QPalette pal = U->tblSubResProperties->palette();
4528  for (k = 0; k < props.size(); ++k) {
4529  QString prop = props[k];
4530  int propId = pResource->propertyIdForName(prop);
4531  QVariant val = pResource->resourceProperty(prop);
4532  QStandardItem *i1 = new QStandardItem(prop);
4533  i1->setEditable(false);
4534  QStandardItem *i2 = new QStandardItem(val.toString());
4535  bool editable = pResource->canModifyProp(propId);
4536  i2->setEditable(editable);
4537  QPalette::ColorGroup cg = editable ? QPalette::Active : QPalette::Disabled;
4538  i2->setForeground(pal.brush(cg, QPalette::Text));
4539  i2->setBackground(pal.brush(cg, QPalette::Base));
4540  i2->setData(val, Qt::EditRole);
4541  i2->setData(propId, Qt::UserRole); // user data is property ID
4542  pPropModel->appendRow(QList<QStandardItem*>() << i1 << i2);
4543  }
4544 
4545  U->txtTitle->setText(pResource->title());
4546  U->txtTitle->setEnabled(pResource->canModifyProp(KLFLibResourceEngine::PropTitle));
4547  QString surl = pResource->url().toString();
4548  if (surl.endsWith("?"))
4549  surl.chop(1);
4550  U->txtUrl->setText(surl);
4551  U->chkLocked->setChecked(pResource->locked());
4552  U->chkLocked->setEnabled(pResource->canModifyProp(KLFLibResourceEngine::PropLocked));
4553 }
4554 
4555 QString KLFLibResPropEditor::curSubResource() const
4556 {
4557  return U->cbxSubResource->itemData(U->cbxSubResource->currentIndex()).toString();
4558 }
4559 
4561 {
4562  klfDbg( "item="<<item<<"" ) ;
4563  QVariant value = item->data(Qt::EditRole);
4564  int propId = item->data(Qt::UserRole).toInt();
4565  bool r = pResource->setSubResourceProperty(curSubResource(), propId, value);
4566  if ( ! r ) {
4567  QMessageBox::critical(this, tr("Error"),
4568  tr("Failed to set sub-resource \"%1\"'s property \"%2\".")
4569  .arg(curSubResource(), propId));
4570  }
4571  // slotSubResourcePropertyChanged will be called.
4572 }
4574 {
4575  slotSubResourcePropertyChanged(curSubResource(), -2);
4576  U->txtSubResTitle->setText(pResource->subResourceProperty(curSubResource(),
4578  .toString());
4579  U->chkSubResLocked->setChecked(pResource->subResourceProperty(curSubResource(),
4581  .toBool());
4582 }
4583 
4584 void KLFLibResPropEditor::slotSubResourcePropertyChanged(const QString& subResource, int subResPropId)
4585 {
4586  if (subResource != curSubResource())
4587  return;
4588 
4589  if (subResPropId != -2) {
4590  // REALLY full refresh
4591  updateSubResources(curSubResource());
4592  // will call this function again, with subResPropId==-2
4593  // so return here.
4594  return;
4595  }
4596 
4597  if ( ! pSuppSubResProps )
4598  return;
4599 
4600  // perform full update of sub-res prop list
4602 }
4604 {
4605  // full update of model data
4606  pSubResPropModel->setRowCount(0);
4607  QPalette pal = U->tblSubResProperties->palette();
4608  int k;
4609  QList<int> props = pResource->subResourcePropertyIdList();
4610  for (k = 0; k < props.size(); ++k) {
4611  int propId = props[k];
4612  QVariant val = pResource->subResourceProperty(curSubResource(), propId);
4613  QStandardItem *i1 = new QStandardItem(pResource->subResourcePropertyName(propId));
4614  i1->setEditable(false);
4615  QStandardItem *i2 = new QStandardItem(val.toString());
4616  bool editable = pResource->canModifySubResourceProperty(curSubResource(), propId);
4617  i2->setEditable(editable);
4618  QPalette::ColorGroup cg = editable ? QPalette::Active : QPalette::Disabled;
4619  i2->setForeground(pal.brush(cg, QPalette::Text));
4620  i2->setBackground(pal.brush(cg, QPalette::Base));
4621  i2->setData(val, Qt::EditRole);
4622  i2->setData(propId, Qt::UserRole); // user data is property ID
4623  pSubResPropModel->appendRow(QList<QStandardItem*>() << i1 << i2);
4624  }
4625 }
4626 
4627 
4628 
4629 
4630 
4631 // -------------
4632 
4633 
4635  : QDialog(parent)
4636 {
4637  QVBoxLayout *lyt = new QVBoxLayout(this);
4638 
4639  pEditor = new KLFLibResPropEditor(resource, this);
4640  lyt->addWidget(pEditor);
4641 
4642  QDialogButtonBox *btns = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel,
4643  Qt::Horizontal, this);
4644  lyt->addWidget(btns);
4645 
4646  connect(btns->button(QDialogButtonBox::Ok), SIGNAL(clicked()),
4647  this, SLOT(applyAndClose()));
4648  // connect(btns->button(QDialogButtonBox::Apply), SIGNAL(clicked()),
4649  // pEditor, SLOT(apply()));
4650  connect(btns->button(QDialogButtonBox::Cancel), SIGNAL(clicked()),
4651  this, SLOT(cancelAndClose()));
4652 
4653  setModal(false);
4654  setWindowTitle(pEditor->windowTitle());
4655  setAttribute(Qt::WA_DeleteOnClose, true);
4656 }
4657 
4659 {
4660 }
4661 
4663 {
4664  if (pEditor->apply()) {
4665  accept();
4666  }
4667 }
4668 
4670 {
4671  reject();
4672 }
4673 
4674 
4675 // ---------------------------------------------------------------
4676 
4678  : QDialog(parent), isAutoName(true)
4679 {
4680  u = new Ui::KLFLibNewSubResDlg;
4681  u->setupUi(this);
4682  setWindowIcon(QPixmap(":/pics/klatexformula-64.png"));
4683 
4684  u->lblNoTitle->hide();
4685 
4686  uint fl = resource->supportedFeatureFlags();
4687  if ( (fl & KLFLibResourceEngine::FeatureSubResources) == 0 ) {
4688  u->lblName->setEnabled(false);
4689  u->txtName->setEnabled(false);
4690  u->lblTitle->setEnabled(false);
4691  u->txtTitle->setEnabled(false);
4692  u->btns->button(QDialogButtonBox::Ok)->setEnabled(false);
4693  } else if ( (fl & KLFLibResourceEngine::FeatureSubResourceProps) == 0) {
4694  u->lblTitle->setEnabled(false);
4695  u->txtTitle->setEnabled(false);
4696  u->lblNoTitle->show();
4697  }
4698 
4699  u->lblResource->setText(resource->title());
4700 }
4701 
4703 {
4704 }
4705 
4707 {
4708  return u->txtName->text();
4709 }
4710 
4712 {
4713  return u->txtTitle->text();
4714 }
4715 
4716 // static
4718 {
4719  QString nm = title;
4720  // replace "string of words-hello" with "stringOfWordsHello"
4721  QRegExp rx("(?:\\s|-)([a-z])");
4722  int i = 0;
4723  while ((i = rx.indexIn(nm,i+1)) >= 0) {
4724  QChar c = rx.cap(1).length() ? rx.cap(1)[0] : QChar('_');
4725  nm.replace(i, rx.matchedLength(), c.toUpper());
4726  }
4727  nm.replace(QRegExp("\\s"), "");
4728  nm.replace(QRegExp("[^A-Za-z0-9_]"), "_");
4729  return nm;
4730 }
4731 
4732 void KLFLibNewSubResDlg::on_txtTitle_textChanged(const QString& text)
4733 {
4734  if (isAutoName) {
4735  u->txtName->blockSignals(true);
4736  u->txtName->setText(makeSubResInternalName(text));
4737  u->txtName->blockSignals(false);
4738  }
4739 }
4740 
4741 void KLFLibNewSubResDlg::on_txtName_textChanged(const QString& text)
4742 {
4743  if (!text.isEmpty())
4744  isAutoName = false; // manually set name
4745  else
4746  isAutoName = true; // user erased name, so auto-name again
4747 }
4748 
4750 {
4752  qWarning("KLFLibNewSubResDlg::createSubResourceIn: can't create sub-resource in resource not "
4753  "supporting sub-resources (!) : %s", qPrintable(resource->url().toString()));
4754  return QString();
4755  }
4756  KLFLibNewSubResDlg d(resource, parent);
4757  int r = d.exec();
4758  if (r != QDialog::Accepted)
4759  return QString();
4760  QString name = d.newSubResourceName();
4761  QString title = d.newSubResourceTitle();
4762 
4763  bool result = resource->createSubResource(name, title);
4764  if (!result)
4765  return QString();
4766 
4767  return name;
4768 }
4769 
4770 // ---------------------------------------------------------------
4771 
4773 {
4775 }
4777 {
4779 }
4780 
4781 // ---------------------------------------------------------------
4782 
4784  : KLFLibWidgetFactory(parent)
4785 {
4786 }
4788 {
4789 }
4790 
4791 
4793 {
4794  return QStringList() << QLatin1String("LocalFile");
4795 }
4796 
4797 
4799 {
4800  if (wtype == QLatin1String("LocalFile"))
4801  return tr("Local File");
4802  return QString();
4803 }
4804 
4805 
4806 
4808  QUrl defaultlocation)
4809 {
4810  if (wtype == QLatin1String("LocalFile")) {
4812  w->setUrl(defaultlocation);
4813  return w;
4814  }
4815  return NULL;
4816 }
4817 
4819 {
4820  if (wtype == "LocalFile") {
4821  if (widget == NULL || !widget->inherits("KLFLibLocalFileOpenWidget")) {
4822  qWarning("KLFLibBasicWidgetFactory::retrieveUrlFromWidget(): Bad Widget provided!");
4823  return QUrl();
4824  }
4825  return qobject_cast<KLFLibLocalFileOpenWidget*>(widget)->url();
4826  } else {
4827  qWarning()<<"KLFLibB.W.Factory::retrieveUrlFromWidget(): Bad widget type: "<<wtype;
4828  return QUrl();
4829  }
4830 }
4831 
4832 
4834  const QString& wtype,
4835  const Parameters& defaultparameters)
4836 {
4837  if (wtype == QLatin1String("LocalFile")) {
4839  w->setUrl(defaultparameters["Url"].toUrl());
4840  return w;
4841  }
4842  return NULL;
4843 }
4844 
4847  QWidget *widget)
4848 {
4849  if (scheme == QLatin1String("LocalFile")) {
4850  if (widget == NULL || !widget->inherits("KLFLibLocalFileCreateWidget")) {
4851  qWarning("KLFLibBasicWidgetFactory::retrieveUrlFromWidget(): Bad Widget provided!");
4852  return Parameters();
4853  }
4854  KLFLibLocalFileCreateWidget *w = qobject_cast<KLFLibLocalFileCreateWidget*>(widget);
4855  Parameters p;
4856  QString filename = w->selectedFName();
4857  if (QFile::exists(filename) && !w->confirmedOverwrite()) {
4858  QMessageBox::StandardButton result =
4859  QMessageBox::warning(widget, tr("Overwrite?"),
4860  tr("The specified file already exists. Overwrite it?"),
4861  QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel,
4862  QMessageBox::No);
4863  if (result == QMessageBox::No) {
4864  p["klfRetry"] = true;
4865  return p;
4866  } else if (result == QMessageBox::Cancel) {
4867  return Parameters();
4868  }
4869  // remove the previous file, because otherwise KLFLib*Engine may fail on existing files.
4870  bool r = QFile::remove(filename);
4871  if ( !r ) {
4872  QMessageBox::critical(widget, tr("Error"), tr("Failed to overwrite the file %1.")
4873  .arg(filename));
4874  return Parameters();
4875  }
4876  }
4877 
4878  p["Filename"] = filename;
4879  p["klfScheme"] = w->selectedScheme();
4880  return p;
4881  }
4882 
4883  return Parameters();
4884 }
4885 
4886 // static
4888 {
4889  pLocalFileTypes << f;
4890 }
4891 
4892 // static
4894 {
4895  return pLocalFileTypes;
4896 }
4897 
4898 
4899 // static
4901 {
4902  int k;
4903  for (k = 0; k < pSchemeGuessers.size(); ++k) {
4904  QString s = pSchemeGuessers[k]->guessScheme(fileName);
4905  if (!s.isEmpty())
4906  return s;
4907  }
4908  return QString();
4909 }
4910 
4911 // static
4913 {
4914  pSchemeGuessers << schemeguesser;
4915 }
4916 
4917 // static
4919 {
4920  pSchemeGuessers.removeAll(schemeguesser);
4921 }
4922 
4923 
4924 
4925 // static
4927 // static
4929 
bool searchNodeMatches(const NodeId &nodeId, const QString &searchString, Qt::CaseSensitivity cs)
virtual void updateResourceEngine()
void updateSubResourceProperties()
KLFLibModel(KLFLibResourceEngine *resource, uint flavorFlags=LinearList|GroupSubCategories, QObject *parent=NULL)
virtual QWidget * createPromptUrlWidget(QWidget *wparent, const QString &wtype, QUrl defaultlocation=QUrl())=0
virtual KLFLibResourceEngine * resource()
Definition: klflibview.h:498
KLFAbstractLibView(QWidget *parent)
Definition: klflibview.cpp:171
void doReportProgress(int value)
virtual void setDefaultSubResource(const QString &subResource)
Set the default sub-resource.
Definition: klflib.cpp:584
void setGroupSubCategories(bool yesOrNo)
Definition: klflibview.h:836
setFontItalic(bool italic)
void slotSubResourcePropertyChanged(const QString &subResource, int propId)
virtual void setTheTreeView(QTreeView *theTreeView)
Definition: klflibview.h:682
drawContents(QPainter *p, const QRectF &rect=QRectF()
virtual uint compareUrlTo(const QUrl &other, uint interestFlags=0xfffffff) const =0
Compare this resource&#39;s URL with another&#39;s.
convertToFormat(Format format, Qt::ImageConversionFlags flags=Qt::AutoColor)
virtual QStringList categoryList() const
const QStyleOptionViewItem * option
Definition: klflibview.h:699
rowCount(const QModelIndex &parent=QModelIndex()
KLFLibWidgetFactory(QObject *parent)
Definition: klflibview.cpp:288
KLFLibEngineFactory::Parameters Parameters
Definition: klflibview.h:351
virtual void setDelay(int ms)
virtual bool canModifySubResourceProperty(const QString &subResource, int propId) const
Definition: klflib.cpp:548
setPointSize(int pointSize)
virtual bool wasUserDiscarded() const
cap(int nth=0)
static QUrl queryOpenResource(const QUrl &defaultlocation=QUrl(), QWidget *parent=0)
virtual void sort(int column, Qt::SortOrder order=Qt::AscendingOrder)
change the entrySorter accordingly and re-sort the model.
data(const QString &mimeType)
virtual bool event(QEvent *e)
Model for Item-Views displaying a library resource&#39;s contents.
Definition: klflibview.h:459
virtual QUrl url() const
index(int row, int column, const QModelIndex &parent=QModelIndex()
virtual void updateResourceEngine()=0
virtual QImage dragImage(const QModelIndexList &indexes)
bool allChildrenFetched
TRUE if all the children of this node have been fetched and stored into children, FALSE if possibly t...
Definition: klflibview_p.h:132
static float color_distinguishable_distance(QRgb a, QRgb b, bool aPremultiplied=false)
Definition: klflibview.cpp:105
contains(const Key &key)
static QStringList allSupportedViewTypeIdentifiers()
Definition: klflibview.cpp:249
static int entryItemRole(int propertyId)
Definition: klflibview.h:492
bool groupSubCategories
Definition: klfconfig.h:241
fillRect(const QRectF &rectangle, const QBrush &brush)
setCompositionMode(CompositionMode mode)
virtual bool createSubResource(const QString &subResource, const QString &subResourceTitle)
Create a new sub-resource.
Definition: klflib.cpp:599
virtual QVariant subResourceProperty(const QString &subResource, int propId) const
Definition: klflib.cpp:528
void requestRestore(const KLFLibEntry &entry, uint restoreflags=KLFLib::RestoreLatexAndStyle)
virtual void redoSort()
notify the model that the entrySorter() settings were changed, and we need to re-sort.
A structure that describes a query for query()
Definition: klflib.h:933
virtual Parameters retrieveCreateParametersFromWidget(const QString &wtype, QWidget *widget)
virtual QWidget * createPromptCreateParametersWidget(QWidget *wparent, const QString &wtype, const Parameters &defaultparameters=Parameters())
Definition: klflibview.cpp:311
toString(qlonglong i)
QList< KLFLib::entryId > entryIdList(const QModelIndexList &indexlist)
setColor(ColorGroup group, ColorRole role, const QColor &color)
A cached value of the size of value in Preview.
Definition: klflib.h:65
virtual void setOrder(Qt::SortOrder order)
Set the sort order.
Definition: klflib.cpp:230
int treePreviewSizePercent
Definition: klfconfig.h:246
friend class KLFLibModelCache
Definition: klflibview.h:604
#define klfDbgT(streamableItems)
Sub-Resources may be assigned properties and values.
Definition: klflib.h:515
KLFConfig klfconfig
Definition: klfconfig.cpp:88
bool glowEffect
Definition: klfconfig.h:197
void setIconViewFlow(QListView::Flow flow)
Sets the icon view flow, see QListView::Flow.
virtual void slotRefresh()
hasFormat(const QString &mimeType)
virtual bool func_indexHasSelectedDescendant(const QModelIndex &parent, const QTime &timer, int timeLimitMs) const
struct KLFConfig::@1 UI
setBackground(const QBrush &brush)
qint32 entryId
An entry ID.
Definition: klflib.h:156
virtual QModelIndex searchFindNext(bool forward)
KLFLibNewSubResDlg(KLFLibResourceEngine *resource, QWidget *parent=0)
split(const QString &sep, SplitBehavior behavior=KeepEmptyParts, Qt::CaseSensitivity cs=Qt::CaseSensitive)
void dumpNodeTree(NodeId node, int indent=0)
#define KLF_DEBUG_TEE(expr)
virtual bool locked() const
Is this resource is locked?
Definition: klflib.h:610
QString fullCategoryPath
The full category path of this category eg. "Physics/General Relativity".
Definition: klflibview_p.h:156
QList< NodeId > children
Definition: klflibview_p.h:129
virtual QModelIndexList findEntryIdList(const QList< KLFLib::entryId > &eidlist) const
virtual void slotRelayoutIcons()
QString categoryLabel
The last element in fullCategoryPath eg. "General Relativity".
Definition: klflibview_p.h:154
void ensureNotMinimalist(NodeId nodeId, int count=-1)
Definition: klflibview.cpp:672
virtual QUrl url() const
static KLFLibWidgetFactory * findFactoryFor(const QString &wtype)
Definition: klflibview.cpp:294
color(ColorGroup group, ColorRole role)
virtual bool searchFind(const QString &queryString, bool forward=true)
virtual uint dropFlags(QDragMoveEvent *event, QAbstractItemView *view)
IndexType cacheFindCategoryLabel(QStringList catelements, bool createIfNotExists=false, bool notifyQtApi=false, bool newlyCreatedAreChildrenFetched=true)
const char * style
removeAt(int i)
KLFLibViewFactory(const QStringList &viewTypeIdentifiers, QObject *parent=NULL)
Definition: klflibview.cpp:213
contains(const QString &str, Qt::CaseSensitivity cs=Qt::CaseSensitive)
changePersistentIndexList(const QModelIndexList &from, const QModelIndexList &to)
static NodeId rootNode()
Definition: klflibview_p.h:116
void resourceDataChanged(const QList< KLFLib::entryId > &entryIdList)
setPen(const QPen &pen)
static int entryPropIdForItemRole(int role)
Definition: klflibview.h:494
void ensureExpandedTo(const QModelIndexList &mil)
Definition: klflibview_p.h:674
indexAt(const QPoint &point)
virtual bool setSubResourceProperty(const QString &subResource, int propId, const QVariant &value)
Definition: klflib.cpp:593
#define klfDbg(streamableItems)
bottomLeft()
QColor glowEffectColor
Definition: klfconfig.h:198
#define KLF_DEBUG_BLOCK(msg)
Qt::SortOrder orderDirection
Definition: klflib.h:950
int listPreviewSizePercent
Definition: klfconfig.h:247
setMenu(QMenu *menu)
setAlpha(int alpha)
setHorizontalHeaderLabels(const QStringList &labels)
virtual QVariant resourceProperty(const QString &name) const
Get the value of a resource property.
Definition: klflib.cpp:711
void updateResourceProperties()
virtual bool hasSaveToWidget(const QString &wtype) const
Definition: klflibview.cpp:324
virtual QList< int > subResourcePropertyIdList() const
Definition: klflib.h:780
scale(int width, int height, Qt::AspectRatioMode mode)
virtual KLFLibEntry entry(const QString &subResource, entryId id)=0
query an entry in this resource
QFont preambleEditFont
Definition: klfconfig.h:181
int getNodeRow(NodeId nodeid)
Definition: klflibview.cpp:645
static bool canDecodeMimeData(const QMimeData *mimeData)
Definition: klflib.cpp:348
pixel(const QPoint &position)
CategoryLabelNode & getCategoryLabelNodeRef(NodeId nodeid)
Definition: klflibview.cpp:635
virtual bool setTitle(const QString &title)
set a new resource title for this library resource
Definition: klflib.cpp:555
join(const QString &separator)
_klf_block_progress_blocker(KLFLibResourceEngine *r)
hasQueryItem(const QString &key)
sortByColumn(int column, Qt::SortOrder order)
int propId
virtual QWidget * createPromptCreateParametersWidget(QWidget *parent, const QString &scheme, const Parameters &defaultparameters=Parameters())
void slotEntryDoubleClicked(const QModelIndex &index)
drawLine(const QLineF &line)
copy(const QRect &rectangle=QRect()
virtual void updateResourceOwnData(const QList< KLFLib::entryId > &entryIdList)
virtual KLFAbstractLibView * createLibView(const QString &viewTypeIdent, QWidget *parent, KLFLibResourceEngine *resourceEngine)
virtual void updateReadyToOpenFromSender(bool isready)
QList< KLFLib::entryId > entryIdForIndexList(const QModelIndexList &indexlist)
chop(int n)
virtual QString widgetTypeTitle(const QString &wtype) const
isEmpty()
virtual QList< KLFLib::entryId > entryIdForIndexList(const QModelIndexList &indexlist) const
toString(FormattingOptions options=None)
QString latex() const
Definition: klflib.h:82
bool canFetchMore(NodeId parentId)
Definition: klflibview.cpp:714
tr(const char *sourceText, const char *comment=0, int n=-1)
static QImage autocrop_image(const QImage &img, int alpha_threshold=0)
Definition: klflibview.cpp:84
virtual uint flavorFlags() const
virtual QString selectedScheme() const
Definition: klflibview_p.h:866
addAction(const QString &text)
QString newSubResourceTitle() const
static void removeLocalFileSchemeGuesser(KLFLibLocalFileSchemeGuesser *schemeguesser)
virtual QVariantMap saveGuiState() const
virtual void updateReadyToCreate()
static QImage transparentify_image(const QImage &img, qreal factor)
Definition: klflibview.cpp:68
isColumnHidden(int column)
QList< KLFLibEntryWithId > entryWithIdList
Definition: klflib.h:981
virtual void updateData(const QList< KLFLib::entryId > &entryIdList, int modifyType)
QListView::Flow iconViewFlow() const
static QStringList allEncodingMimeTypes()
Definition: klflib.cpp:305
virtual Parameters getCreateParameters() const
__klf_guarded_bool(bool *var)
setLeft(qreal x)
#define KLF_ASSERT_NOT_NULL(ptr, msg, failaction)
virtual int entryColumnContentsPropertyId(int column) const
setData(const QVariant &value, int role=Qt::UserRole+1)
static KLFLibViewFactory * findFactoryFor(const QString &viewTypeIdentifier)
Definition: klflibview.cpp:232
replace(int position, int n, const QString &after)
The Latex Code of the equation.
Definition: klflib.h:62
static QList< int > minimalistEntryPropIds()
Definition: klflibview_p.h:246
void fetchMore(NodeId parentId, int batchCount=-1)
Definition: klflibview.cpp:735
virtual KLFLibEntryList selectedEntries() const
indexOf(const T &value, int from=0)
virtual ~KLFLibNewSubResDlg()
QString nodeValue(NodeId node, int propId=KLFLibEntry::Latex)
matchedLength()
KlfUrlCompareEqual
indexIn(const QString &str, int offset=0, CaretMode caretMode=CaretAtZero)
static void addLocalFileType(const LocalFileType &fileType)
void sortCategory(NodeId category, KLFLibModelSorter *sorter, bool rootCall=true)
virtual QList< KLFLib::entryId > selectedEntryIds() const
virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
columnWidth(int column)
setFont(const QFont &font)
KLFLibEngineFactory::Parameters Parameters
Definition: klflibview.h:967
virtual bool compareDefaultSubResourceEquals(const QString &subResourceName) const
Compare our sub-resource name to another.
Definition: klflib.cpp:509
static QList< LocalFileType > localFileTypes()
virtual QStringList viewTypeIdentifiers()
Definition: klflibview.h:272
setColumnWidth(int column, int width)
showEvent(QShowEvent *event)
setColumnCount(int columns)
virtual void expandRootNice()
append(const T &value)
virtual void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
virtual ~KLFLibCreateResourceDlg()
virtual void showEvent(QShowEvent *event)
drawPoint(const QPointF &position)
virtual void updateResourceDefaultSubResourceChanged(const QString &newSubResource)
Definition: klflibview.cpp:190
QModelIndex createIndexFromId(NodeId nodeid, int row, int column)
Definition: klflibview.cpp:533
static KLFLibResourceEngine * createResource(const QString &defaultWtype, QObject *resourceParent, QWidget *parent=0)
property(const char *name)
virtual void setFetchBatchCount(int count)
Definition: klflibview.h:600
virtual bool selectionIntersectsIndexChildren(const QItemSelection &selection, const QModelIndex &parent) const
virtual void restore(uint restoreflags=KLFLib::RestoreLatexAndStyle)
virtual ~KLFLibResPropEditorDlg()
virtual QString viewTypeTitle(const QString &viewTypeIdent) const
brush(ColorGroup group, ColorRole role)
virtual ~KLFLibResPropEditor()
virtual ~KLFLibViewFactory()
Definition: klflibview.cpp:219
fill(uint pixelValue)
resizeColumnToContents(int column)
NodeId nextNode(NodeId n)
NodeId prevNode(NodeId n)
QString category() const
Definition: klflib.h:86
setWidth(qreal width)
EntryNode & getEntryNodeRef(NodeId nodeid, bool requireNotMinimalist=false)
Definition: klflibview.cpp:621
virtual QUrl retrieveRawUrl() const
virtual bool setLocked(bool locked)
Set the resource to be locked.
Definition: klflib.cpp:559
Qt::SortOrder order() const
The currently set sorting order.
Definition: klflib.h:296
void setSortingBy(int propId, Qt::SortOrder order)
Definition: klflibview_p.h:318
virtual bool isDesendantOf(const QModelIndex &child, const QModelIndex &ancestor)
KLFFactoryBase * findFactoryFor(const QString &objType)
insertText(const QString &text)
virtual void paintEntry(PaintPrivate *p, const QModelIndex &index) const
A known local file type for KLFLibBasicWidgetFactory-created widgets.
Definition: klflibview.h:1141
Data can be stored in separate sub-resources.
Definition: klflib.h:508
removeAll(const T &value)
virtual void setDisableUi(bool disableUi)
QModelIndex curVisibleIndex(bool firstOrLast) const
Definition: klflibview_p.h:534
setItemDelegate(QAbstractItemDelegate *delegate)
NodeId getNodeForIndex(const QModelIndex &index)
Definition: klflibview.cpp:568
int propId() const
The currently set property that will be queried in the items we&#39;re sorting.
Definition: klflib.h:294
virtual QStringList mimeTypes() const
void slotViewItemClicked(const QModelIndex &index)
virtual void paintCategoryLabel(PaintPrivate *p, const QModelIndex &index) const
virtual QUrl retrieveUrlFromWidget(const QString &wtype, QWidget *widget)=0
virtual int columnForEntryPropertyId(int entryPropertyId) const
void treeInsertEntry(const EntryNode &e, bool isRebuildingCache=false)
Definition: klflibview.cpp:963
virtual void wantMoreCategorySuggestions()
Definition: klflibview.cpp:195
virtual void updateResourceProp(int propId)
virtual void updateResourceProp(int propId)=0
drawText(const QPointF &position, const QString &text)
endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive)
virtual QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const
int propertyIdForName(const QString &propertyName) const
virtual bool setResourceProperty(int propId, const QVariant &value)
Set a resource property to the given value.
Definition: klflib.cpp:731
static EntryMatchCondition mkPropertyMatch(PropertyMatch pmatch)
Definition: klflib.cpp:781
A view widget to display a library resource&#39;s contents.
Definition: klflibview.h:82
KLFLibCreateResourceDlg(const QString &defaultWtype, QWidget *parent=0)
virtual KLFLibResourceEngine * createResource(const QString &scheme, const Parameters &parameters, QObject *parent=NULL)
Create a new resource of given type and parameters.
Definition: klflib.cpp:1178
KLFLibDefaultView(QWidget *parent, ViewType viewtype=CategoryTreeView)
The Category to which eq. belongs (path-style string)
Definition: klflib.h:66
virtual void setFlavorFlags(uint flags, uint modify_mask=0xffffffff)
void entriesSelected(const KLFLibEntryList &entries)
virtual void updateReadyToOpen()
UIDType universalId() const
Definition: klflibview_p.h:106
void operationStartReportingProgress(KLFProgressReporter *progressReporter, const QString &descriptiveText)
static bool image_is_distinguishable(const QImage &imgsrc, QColor background, float threshold)
Definition: klflibview.cpp:137
scheme()
void on_cbxSubResource_currentIndexChanged(int newSubResItemIndex)
static QString makeSubResInternalName(const QString &title)
virtual bool hasIndex(int row, int column, const QModelIndex &parent=QModelIndex()) const
virtual QString defaultSubResource() const
Definition: klflib.cpp:504
virtual Qt::ItemFlags flags(const QModelIndex &index) const
Add a query item for default sub-res. as "klfDefaultSubResource".
Definition: klflib.h:555
KLFLibBasicWidgetFactory(QObject *parent=NULL)
KLFStyle style used.
Definition: klflib.h:68
#define KLF_DEBUG_TIME_BLOCK(msg)
virtual void updateResourceData(const QString &subres, int modifyType, const QList< KLFLib::entryId > &entryIdList)=0
QSize previewSize() const
Definition: klflibview.h:771
KLFLibDefaultViewFactory(QObject *parent=NULL)
setVersion(int v)
virtual void setResource(KLFLibResourceEngine *resource)
KlfUrlCompareLessSpecific
#define klfFmtCC
virtual void prefetch(const QModelIndexList &index) const
void slotResourceModelReset()
Dialog prompting user to choose a resource and a sub-resource to open.
Definition: klflibview.h:936
virtual bool eventFilter(QObject *o, QEvent *e)
void advSubResPropEdited(QStandardItem *item)
setData(const QVariant &userData)
void setPreviewSize(const QSize &size)
Definition: klflibview.h:824
virtual uint supportedFeatureFlags() const
List of features supported by this resource engine.
Definition: klflib.h:550
virtual bool canModifyData(const QString &subResource, ModifyType modifytype) const
Definition: klflib.cpp:472
setColumnHidden(int column, bool hide)
#define KLF_FUNC_NAME
contains(const QString &str, Qt::CaseSensitivity cs=Qt::CaseSensitive)
virtual QList< entryId > insertEntries(const QString &subResource, const KLFLibEntryList &entrylist)=0
Insert new entries in this resource.
virtual QStringList subResourceList() const
Definition: klflib.h:722
virtual ~KLFLibOpenResourceDlg()
virtual void fetchMore(const QModelIndex &parent)
Tags about the equation (string)
Definition: klflib.h:67
virtual QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const
virtual void setEntrySorter(KLFLibEntrySorter *entrySorter)
virtual void searchAbort()
void setPreviewSize(const QSize &psize)
Definition: klflibview.h:693
virtual QUrl url() const
static QString guessLocalFileScheme(const QString &fileName)
virtual QModelIndex currentVisibleIndex() const
The first index that is currently visible in the current scrolling position.
Definition: klflibview.h:789
contains(const T &value)
QPointF sizeToPointF(const QSizeF &s)
Definition: klflibview_p.h:63
virtual void searchAbort()
virtual void setResourceEngine(KLFLibResourceEngine *resource)
Definition: klflibview.cpp:176
virtual QModelIndex parent(const QModelIndex &index) const
fromValue(const T &value)
virtual bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
virtual QString title() const
The human-set title of this resource.
Definition: klflib.h:599
QStringList registeredPropertyNameList() const
virtual QString selectedFName() const
Definition: klflibview_p.h:863
virtual bool canFetchMore(const QModelIndex &parent) const
static bool decodeMimeData(const QMimeData *mimeData, KLFLibEntryList *entryList, QVariantMap *metaData)
Definition: klflib.cpp:360
void blockProgressReporting(bool block)
(Un)Blocks generally progress reporting
Definition: klflib.cpp:654
setFontWeight(int weight)
QImage preview() const
Definition: klflib.h:84
static QString createSubResourceIn(KLFLibResourceEngine *resource, QWidget *parent=0)
Interface for guessing file schemes.
Definition: klflibview.h:1096
virtual ~KLFLibBasicWidgetFactory()
virtual QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const
A structure that will hold the result of a query() query.
Definition: klflib.h:970
QModelIndexList findEntryIdList(const QList< KLFLib::entryId > &eidlist)
setForeground(const QBrush &brush)
setPixel(const QPoint &position, uint index_or_rgb)
virtual QWidget * createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
NodeId lastNode(NodeId n)
virtual void updateReadyToCreateFromSender(bool isready)
virtual void setEditorData(QWidget *editor, const QModelIndex &index) const
void updateSubResources(const QString &curSubResource=QString())
Create Associated Widgets to resources for Open/Create/Save actions.
Definition: klflibview.h:339
void slotResourceDataChanged(const QModelIndex &topLeft, const QModelIndex &botRight)
QString newSubResourceName() const
virtual bool hasCreateWidget(const QString &wtype) const
Definition: klflibview.cpp:306
void slotShowColumnSenderAction(bool showCol)
virtual bool selectEntries(const QList< KLFLib::entryId > &idList)
drawImage(const QRectF &target, const QImage &image, const QRectF &source, Qt::ImageConversionFlags flags=Qt::AutoColor)
virtual QStringList getCategorySuggestions()=0
virtual KLFLibEntrySorter * entrySorter()
The current KLFLibEntrySorter that sorts our items.
Definition: klflibview.h:577
static QStringList defaultViewTypeIds
setClipRect(const QRectF &rectangle, Qt::ClipOperation operation=Qt::ReplaceClip)
mid(int position, int n=-1)
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
data(int role=Qt::DisplayRole)
bool operator()(const NodeId &a, const NodeId &b)
Definition: klflibview.cpp:387
virtual ~KLFLibDefaultView()
QStringList categoryListCache()
Definition: klflibview_p.h:359
An entry (single formula) in the library.
Definition: klflib.h:55
Node & getNodeRef(NodeId nodeid)
Definition: klflibview.cpp:598
scaled(const QSize &size, Qt::AspectRatioMode aspectRatioMode=Qt::IgnoreAspectRatio, Qt::TransformationMode transformMode=Qt::FastTransformation)
void slotResourcePropertyChanged(int propId)
QList< int > wantedEntryProperties
Definition: klflib.h:951
insert(int i, const T &value)
hasChildren(const QModelIndex &parent=QModelIndex()
virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
virtual Qt::DropActions supportedDropActions() const
virtual QUrl retrieveUrlFromWidget(const QString &scheme, QWidget *widget)
virtual KLFLib::entryId entryIdForIndex(const QModelIndex &index) const
static QList< KLFLibLocalFileSchemeGuesser * > pSchemeGuessers
Definition: klflibview.h:1193
static KLFLibEngineFactory * findFactoryFor(const QUrl &url)
Definition: klflib.cpp:1163
virtual Parameters retrieveCreateParametersFromWidget(const QString &wtype, QWidget *widget)
Definition: klflibview.cpp:318
parentWidget()
KLFLibViewDelegate(QObject *parent)
void slotPreviewSizeActionsRefreshChecked()
virtual KLFLibResourceEngine * resourceEngine() const
Definition: klflibview.h:89
QStringList allSupportedTypes()
columnCount(const QModelIndex &parent=QModelIndex()
KlfUrlCompareMoreSpecific
int iconPreviewSizePercent
Definition: klfconfig.h:248
KLFLibOpenResourceDlg(const QUrl &defaultlocation=QUrl(), QWidget *parent=0)
An Image Preview of equation (scaled down QImage)
Definition: klflib.h:64
void on_btnAdvanced_toggled(bool on)
virtual bool changeEntries(const QString &subResource, const QList< entryId > &idlist, const QList< int > &properties, const QList< QVariant > &values)=0
Change some entries in this resource.
critical(QWidget *parent, const QString &title, const QString &text, StandardButtons buttons=Ok, StandardButton defaultButton=NoButton)
mid(int pos, int length=-1)
virtual QMimeData * mimeData(const QModelIndexList &indexes) const
virtual void setUrl(const QUrl &url)
Definition: klflibview_p.h:891
static QMap< QString, QString > listSubResourcesWithTitles(const QUrl &url)
Definition: klflib.cpp:1202
KLFLibResPropEditorDlg(KLFLibResourceEngine *resource, QWidget *parent=0)
translate(const QPointF &offset)
drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget=0)
void slotPreviewSizeFromActionSender()
virtual void showColumns(int propIdColumn, bool show)
KLF_EXPORT void klfDrawGlowedImage(QPainter *p, const QImage &foreground, const QColor &glowcol, int r, bool also_draw_image)
Node getNode(NodeId nodeid)
Definition: klflibview.cpp:591
virtual void updateResourceData(const QString &subRes, int modifyType, const QList< KLFLib::entryId > &entryIdList)
virtual void completeRefresh()
void moreCategorySuggestions(const QStringList &categorylist)
addQueryItem(const QString &key, const QString &value)
button(StandardButton which)
warning(QWidget *parent, const QString &title, const QString &text, StandardButtons buttons=Ok, StandardButton defaultButton=NoButton)
indexOf(const QRegExp &rx, int from=0)
KLFLibEntrySorter * entrySorter()
Definition: klflibview_p.h:302
virtual void paintText(PaintPrivate *p, const QString &text, uint flags=PTF_HighlightSearch) const
A KLFLibEntry in combination with a KLFLib::entryId.
Definition: klflib.h:447
setProperty(const char *name, const QVariant &value)
QSizeF pointToSizeF(const QPointF &p)
Definition: klflibview_p.h:65
size(int flags, const QString &text, int tabStops=0, int *tabArray=0)
static QString defaultViewTypeIdentifier()
Definition: klflibview.cpp:225
KLF_EXPORT QDebug & operator<<(QDebug &dbg, const KLFLibModelCache::NodeId &n)
Definition: klflibview.cpp:346
virtual QModelIndex searchFind(const QString &queryString, const QModelIndex &fromIndex=QModelIndex(), bool forward=true)
isEmpty()
static void addLocalFileSchemeGuesser(KLFLibLocalFileSchemeGuesser *schemeguesser)
virtual QStringList getCategorySuggestions()
setData(const QString &mimeType, const QByteArray &data)
Utility class for sorting library entry items.
Definition: klflib.h:276
setRowCount(int rows)
virtual QUrl url(uint flags=0x0) const
query URL
Definition: klflib.cpp:457
QSize labelOutputFixedSize
Definition: klfconfig.h:183
virtual bool searchFindNext(bool forward)
expand(const QModelIndex &index)
virtual QString widgetTypeTitle(const QString &wtype) const =0
The human-readable label for this type of input.
virtual QUrl retrieveSaveToUrlFromWidget(const QString &wtype, QWidget *widget)
Definition: klflibview.cpp:335
QDateTime dateTime() const
Definition: klflib.h:83
An abstract resource engine.
Definition: klflib.h:440
virtual void slotSelectAll(bool expandItems=false)
virtual QModelIndex walkNextIndex(const QModelIndex &cur)
Call repeatedly to walk all indexes (once each exactly, first column only)
virtual QList< QAction * > addContextMenuActions(const QPoint &pos)
Definition: klflibview.cpp:200
QString propertyNameForId(int propId) const
The Date/Time at which the equation was evaluated.
Definition: klflib.h:63
static QList< LocalFileType > pLocalFileTypes
Definition: klflibview.h:1192
struct KLFConfig::@4 LibraryBrowser
virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
virtual QString correspondingWidgetType(const QString &scheme) const =0
virtual ~KLFLibViewDelegate()
virtual bool indexHasSelectedDescendant(const QModelIndex &parent) const
void slotViewSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
static QMimeData * createMimeData(const KLFLibEntryList &entryList, const QVariantMap &metaData)
Creates a QMetaData with all known registered encoding mime types.
Definition: klflib.cpp:326
KLFLib::EntryMatchCondition matchCondition
Definition: klflib.h:946
toHtml(const QByteArray &encoding=QByteArray()
void updateData(const QList< KLFLib::entryId > &entryIdList, int modifyType)
Definition: klflibview.cpp:840
virtual uint compareUrlTo(const QUrl &other, uint interestFlags=0xFFFFFFFF) const
void advPropEdited(QStandardItem *item)
#define KLF_DEBUG_ASSIGN_SAME_REF_INSTANCE(object)
event(QEvent *event)
indexOf(const QString &str, int from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive)
virtual bool canModifyProp(int propId) const
Definition: klflib.cpp:485
static QStringList allSupportedWTypes()
Definition: klflibview.cpp:300
virtual bool confirmedOverwrite() const
QString tags() const
Definition: klflib.h:87
virtual void sortBy(int propIdColumn, Qt::SortOrder sortorder)
appendRow(const QList< QStandardItem * > &items)
EntryNode treeTakeEntry(const NodeId &e, bool notifyQtApi=true)
virtual void setPropId(int propId)
Set the KLFLibEntry property id the sort will take into account.
Definition: klflib.cpp:222
data(int role=Qt::UserRole+1)
queryItemValue(const QString &key)
NodeId findEntryId(KLFLib::entryId eId)
setEditable(bool editable)
KLFLibResPropEditor(KLFLibResourceEngine *resource, QWidget *parent=0)
toEncoded(FormattingOptions options=None)
localeAwareCompare(const QString &s1, const QString &s2)
virtual QList< QAction * > addContextMenuActions(const QPoint &pos)
virtual QWidget * createPromptUrlWidget(QWidget *parent, const QString &scheme, QUrl defaultlocation=QUrl())
virtual QWidget * createPromptSaveToWidget(QWidget *wparent, const QString &wtype, KLFLibResourceEngine *resource, const QUrl &defaultUrl)
Definition: klflibview.cpp:328
virtual QModelIndex walkPrevIndex(const QModelIndex &cur)
Call repeatedly to walk all indexes in model in reverse order.
virtual QStringList supportedTypes() const
virtual bool restoreGuiState(const QVariantMap &state)
virtual QString subResourcePropertyName(int propId) const
Definition: klflib.cpp:533
virtual ~KLFLibModel()
KlfUrlCompareBaseEqual
QSize previewSize() const
Definition: klflib.h:85
virtual QModelIndex findEntryId(KLFLib::entryId eid) const
static QString normalizeCategoryPath(const QString &categoryPath)
Definition: klflib.cpp:195
int glowEffectRadius
Definition: klfconfig.h:199
KLFStyle style() const
Definition: klflib.h:88

Generated by doxygen 1.8.11