00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00030 #ifndef KLFLIBVIEW_P_H
00031 #define KLFLIBVIEW_P_H
00032
00033 #include <math.h>
00034
00035 #include <QApplication>
00036 #include <QStringList>
00037 #include <QAbstractItemView>
00038 #include <QTreeView>
00039 #include <QListView>
00040 #include <QMimeData>
00041 #include <QDrag>
00042 #include <QDragEnterEvent>
00043 #include <QDragMoveEvent>
00044 #include <QDropEvent>
00045 #include <QWidget>
00046 #include <QFileInfo>
00047 #include <QFileDialog>
00048 #include <QDir>
00049 #include <QDesktopServices>
00050 #include <QDirModel>
00051 #include <QCompleter>
00052
00053 #include <ui_klfliblocalfilewidget.h>
00054
00055 #include "klflib.h"
00056 #include "klflibview.h"
00057 #include "klfconfig.h"
00058
00059 class KLFLibDefTreeView;
00060
00061
00063 inline QPointF sizeToPointF(const QSizeF& s) { return QPointF(s.width(), s.height()); }
00065 inline QSizeF pointToSizeF(const QPointF& p) { return QSizeF(p.x(), p.y()); }
00066
00067
00068
00069
00070
00072 class KLFLibModelCache
00073 {
00074 public:
00075 typedef qint32 IndexType;
00083 typedef quint32 UIDType;
00084 static const quint8 UIDKindShift = 30;
00085 static const UIDType UIDKindMask = 0xC0000000;
00086 static const UIDType UIDIndexMask = 0x3FFFFFFF;
00087 static const UIDType UIDInvalid = 0xFFFFFFFF;
00088
00089 enum ItemKind {
00090 EntryKind = KLFLibModel::EntryKind,
00091 CategoryLabelKind = KLFLibModel::CategoryLabelKind
00092 };
00093
00094 struct NodeId {
00095 NodeId(ItemKind k = ItemKind(EntryKind), IndexType i = -1) : kind(k), index(i) { }
00096 bool valid() const { return index >= 0; }
00097 bool isRoot() const { return kind == CategoryLabelKind && index == 0; }
00098 ItemKind kind;
00099 IndexType index;
00100 bool operator==(const NodeId& other) const {
00101 return kind == other.kind && index == other.index;
00102 }
00103 bool operator!=(const NodeId& other) const {
00104 return !(operator==(other));
00105 }
00106 UIDType universalId() const {
00107 if ( index < 0 )
00108 return (~0x0);
00109 UIDType uid = (UIDType)index;
00110 uid |= (kind << UIDKindShift);
00111 return uid;
00112 }
00113 static NodeId fromUID(UIDType uid) {
00114 return NodeId((ItemKind)((uid&UIDKindMask)>>UIDKindShift), uid&UIDIndexMask);
00115 }
00116 static NodeId rootNode() { return NodeId(CategoryLabelKind, 0); }
00117 };
00118 struct Node {
00119 Node() : allocated(false) { }
00120 Node(ItemKind k) : allocated(true), kind(k), parent(NodeId()), children(QList<NodeId>()),
00121 allChildrenFetched(false) { }
00122 Node(const Node& other) : allocated(other.allocated), kind(other.kind), parent(other.parent),
00123 children(other.children), allChildrenFetched(other.allChildrenFetched) { }
00124 virtual ~Node() { }
00126 bool allocated;
00127 ItemKind kind;
00128 NodeId parent;
00129 QList<NodeId> children;
00132 bool allChildrenFetched;
00133 };
00134 struct EntryNode : public Node {
00135 EntryNode() : Node(EntryKind), entryid(-1), minimalist(false), entry()
00136 {
00137 allChildrenFetched = true;
00138 }
00139 EntryNode(const EntryNode& copy)
00140 : Node(copy), entryid(copy.entryid), minimalist(copy.minimalist), entry(copy.entry) { }
00141
00142 inline bool entryIsValid() const { return allocated && parent != NodeId() && entryid >= 0; }
00143
00144 KLFLib::entryId entryid;
00146 bool minimalist;
00147 KLFLibEntry entry;
00148 };
00149 struct CategoryLabelNode : public Node {
00150 CategoryLabelNode() : Node(CategoryLabelKind), categoryLabel(), fullCategoryPath() { }
00151 CategoryLabelNode(const CategoryLabelNode& copy)
00152 : Node(copy), categoryLabel(copy.categoryLabel), fullCategoryPath(copy.fullCategoryPath) { }
00154 QString categoryLabel;
00156 QString fullCategoryPath;
00157 };
00158
00159 template<class N>
00160 class NodeCache : public QList<N> {
00161 public:
00162 NodeCache() : QList<N>(), pContainsNonAllocated(false) { }
00163
00164 inline bool isAllocated(IndexType i) { return QList<N>::at(i).allocated; }
00165
00166 IndexType insertNewNode(const N& n) {
00167 IndexType insertPos = QList<N>::size();
00168 if (pContainsNonAllocated) {
00169
00170 for (insertPos = 0; insertPos < QList<N>::size() && QList<N>::at(insertPos).allocated; ++insertPos)
00171 ;
00172 }
00173 if (insertPos == QList<N>::size()) {
00174 pContainsNonAllocated = false;
00175 append(n);
00176 return insertPos;
00177 }
00178 QList<N>::operator[](insertPos) = n;
00179 return insertPos;
00180 }
00181
00183 inline void unlinkNode(const NodeId& nid) { unlinkNode(nid.index); }
00184 void unlinkNode(IndexType index) {
00185 N& node = QList<N>::operator[](index);
00186 node.allocated = false;
00187 pContainsNonAllocated = true;
00188 }
00189
00191 inline N takeNode(const NodeId& nid) { return takeNode(nid.index); }
00192 N takeNode(IndexType index) {
00193 if (index < 0 || index >= QList<N>::size()) {
00194 qWarning()<<KLF_FUNC_NAME<<": invalid index="<<index;
00195 return N();
00196 }
00197 N node = QList<N>::at(index);
00198 unlinkNode(index);
00199 return node;
00200 }
00201 private:
00202 bool pContainsNonAllocated;
00203 };
00204
00205 typedef NodeCache<EntryNode> EntryCache;
00206 typedef NodeCache<CategoryLabelNode> CategoryLabelCache;
00207
00208 EntryNode pInvalidEntryNode;
00209
00210
00211
00212 KLFLibModelCache(KLFLibModel * model)
00213 : pModel(model)
00214 {
00215 pIsFetchingMore = false;
00216
00217 pLastSortPropId = KLFLibEntry::DateTime;
00218 pLastSortOrder = Qt::DescendingOrder;
00219 }
00220
00221 virtual ~KLFLibModelCache() { }
00222
00223 KLFLibModel *pModel;
00224
00225 void rebuildCache();
00226
00229 QModelIndex createIndexFromId(NodeId nodeid, int row, int column);
00230
00232 NodeId getNodeForIndex(const QModelIndex& index);
00234 Node getNode(NodeId nodeid);
00235 Node& getNodeRef(NodeId nodeid);
00236 EntryNode& getEntryNodeRef(NodeId nodeid, bool requireNotMinimalist = false);
00237 CategoryLabelNode& getCategoryLabelNodeRef(NodeId nodeid);
00238
00240 int getNodeRow(NodeId nodeid);
00241
00246 static inline QList<int> minimalistEntryPropIds() {
00247 return QList<int>() << KLFLibEntry::Category << KLFLibEntry::Tags
00248 << KLFLibEntry::DateTime << KLFLibEntry::Latex
00249 << KLFLibEntry::PreviewSize;
00250 }
00251
00256 void ensureNotMinimalist(NodeId nodeId, int count = -1);
00257
00258 bool canFetchMore(NodeId parentId);
00259 void fetchMore(NodeId parentId, int batchCount = -1);
00260
00261 void updateData(const QList<KLFLib::entryId>& entryIdList, int modifyType);
00262
00274 void treeInsertEntry(const EntryNode& e, bool isRebuildingCache = false);
00275
00280 EntryNode treeTakeEntry(const NodeId& e, bool notifyQtApi = true);
00281
00289 IndexType cacheFindCategoryLabel(QStringList catelements, bool createIfNotExists = false,
00290 bool notifyQtApi = false, bool newlyCreatedAreChildrenFetched = true);
00291
00292 class KLF_EXPORT KLFLibModelSorter
00293 {
00294 public:
00295 KLFLibModelSorter(KLFLibModelCache *c, KLFLibEntrySorter *es, bool groupcategories)
00296 : cache(c), entrysorter(es), groupCategories(groupcategories)
00297 {
00298 }
00300 bool operator()(const NodeId& a, const NodeId& b);
00301
00302 KLFLibEntrySorter *entrySorter() { return entrysorter; }
00303
00304 private:
00305 KLFLibModelCache *cache;
00306 KLFLibEntrySorter *entrysorter;
00307 bool groupCategories;
00308 };
00309
00311 QString nodeValue(NodeId node, int propId = KLFLibEntry::Latex);
00312
00315 bool searchNodeMatches(const NodeId& nodeId, const QString& searchString, Qt::CaseSensitivity cs);
00316
00318 void setSortingBy(int propId, Qt::SortOrder order)
00319 {
00320 pLastSortPropId = propId;
00321 pLastSortOrder = order;
00322 }
00323
00325 void sortCategory(NodeId category, KLFLibModelSorter *sorter, bool rootCall = true);
00326
00334 NodeId nextNode(NodeId n);
00339 NodeId prevNode(NodeId n);
00346 NodeId lastNode(NodeId n);
00347
00350 QList<KLFLib::entryId> entryIdList(const QModelIndexList& indexlist);
00351
00354 QList<KLFLib::entryId> entryIdForIndexList(const QModelIndexList& indexlist);
00355 QModelIndexList findEntryIdList(const QList<KLFLib::entryId>& eidlist);
00356
00357 NodeId findEntryId(KLFLib::entryId eId);
00358
00359 QStringList categoryListCache() { return pCatListCache; }
00360
00361 void fullDump();
00362 void dumpNodeTree(NodeId node, int indent = 0);
00363
00364 private:
00365 EntryCache pEntryCache;
00366 CategoryLabelCache pCategoryLabelCache;
00367
00368 QStringList pCatListCache;
00369
00372 void insertCategoryStringInSuggestionCache(const QString& category)
00373 {
00374 insertCategoryStringInSuggestionCache(category.split('/', QString::SkipEmptyParts));
00375 }
00378 void insertCategoryStringInSuggestionCache(const QStringList& catelements)
00379 {
00380
00381 for (int kl = catelements.size()-1; kl >= 0; --kl) {
00382 QString c = QStringList(catelements.mid(0,kl+1)).join("/");
00383 if (pCatListCache.contains(c))
00384 break;
00385 pCatListCache.insert(qLowerBound(pCatListCache.begin(), pCatListCache.end(), c), c);
00386 }
00387 }
00388
00389 bool pIsFetchingMore;
00390
00391 int pLastSortPropId;
00392 Qt::SortOrder pLastSortOrder;
00393
00394 KLF_DEBUG_DECLARE_ASSIGNABLE_REF_INSTANCE() ;
00395 };
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00408 class KLFLibDefViewCommon
00409 {
00410 public:
00411 KLFLibDefViewCommon(KLFLibDefaultView *dview)
00412 : pDView(dview), pViewType(dview->viewType())
00413 {
00414 }
00415 virtual ~KLFLibDefViewCommon() { }
00416
00417
00418
00420 virtual bool evDragEnter(QDragEnterEvent *de, const QPoint& pos) {
00421 uint fl = pModel->dropFlags(de, thisView());
00422 klfDbg( "KLFLibDefViewCommon::evDragEnter: drop flags are "<<fl<<"; this viewtype="<<pViewType ) ;
00423
00424 bool showdropindic = (fl & KLFLibModel::DropWillCategorize);
00425 thisView()->setDropIndicatorShown(showdropindic);
00426
00427 if ( !(fl & KLFLibModel::DropWillAccept) && pViewType != KLFLibDefaultView::IconView ) {
00428
00429
00430 de->ignore();
00431 qDebug("Ignored drag enter event.");
00432 } else {
00433 mousePressedContentsPos = pos;
00434 de->accept();
00435 klfDbg( "Accepted drag enter event issued at pos="<<pos ) ;
00436
00437 QDragEnterEvent fakeevent(de->pos(), de->dropAction(), de->mimeData(), de->mouseButtons(),
00438 de->keyboardModifiers());
00439 qApp->sendEvent(thisView()->viewport(), &fakeevent);
00440 }
00441 return true;
00442 }
00443
00445 virtual bool evDragMove(QDragMoveEvent *de, const QPoint& pos) {
00446 uint fl = pModel->dropFlags(de, thisView());
00447 klfDbg( "KLFLibDefViewCommon::evDragMove: flags are "<<fl<<"; pos is "<<pos ) ;
00448
00449 if ( !(fl & KLFLibModel::DropWillAccept) && pViewType != KLFLibDefaultView::IconView ) {
00450
00451
00452 de->ignore();
00453 } else {
00454
00455 if ( (fl & KLFLibModel::DropWillMove) || pViewType == KLFLibDefaultView::IconView ) {
00456 de->setDropAction(Qt::MoveAction);
00457 } else {
00458 de->setDropAction(Qt::CopyAction);
00459 }
00460 de->accept();
00461
00462 QDragMoveEvent fakeevent(de->pos(), de->dropAction(), de->mimeData(), de->mouseButtons(),
00463 de->keyboardModifiers());
00464 qApp->sendEvent(thisView()->viewport(), &fakeevent);
00465 }
00466 return true;
00467 }
00468
00470 virtual bool evDrop(QDropEvent *de, const QPoint& pos) {
00471 if ( pViewType == KLFLibDefaultView::IconView && de->source() == thisView() ) {
00472
00473
00474
00475
00476 QPoint delta = pos - mousePressedContentsPos;
00477 klfDbg( "Delta is "<<delta ) ;
00478
00479 QDragLeaveEvent fakeevent;
00480 qApp->sendEvent(thisView()->viewport(), &fakeevent);
00481
00482
00483 thisView()->viewport()->update();
00484 } else {
00485
00486 klfDbg( "Drop event at position="<<de->pos() ) ;
00487 QDropEvent fakeevent(de->pos(), de->dropAction(), de->mimeData(), de->mouseButtons(),
00488 de->keyboardModifiers());
00489 qApp->sendEvent(thisView()->viewport(), &fakeevent);
00490 }
00491 return true;
00492 }
00493
00494 virtual void commonStartDrag(Qt::DropActions supportedActions) {
00495
00496 QModelIndexList indexes = commonSelectedIndexes();
00497
00498 if (pViewType == KLFLibDefaultView::IconView) {
00499
00500
00501
00502 return;
00503 }
00504
00505 klfDbg( "Normal DRAG..." ) ;
00506
00507
00508
00509
00510
00511
00512
00513
00514 if (indexes.count() == 0)
00515 return;
00516 QMimeData *data = pModel->mimeData(indexes);
00517 if (data == NULL)
00518 return;
00519 QDrag *drag = new QDrag(thisView());
00520 drag->setMimeData(data);
00521 QPixmap pix = QPixmap::fromImage(pModel->dragImage(indexes));
00522 drag->setPixmap(pix);
00523 drag->setHotSpot(QPoint(0,0));
00524 Qt::DropAction defaultDropAction = Qt::IgnoreAction;
00525
00526 if (supportedActions & Qt::CopyAction &&
00527 thisView()->dragDropMode() != QAbstractItemView::InternalMove)
00528 defaultDropAction = Qt::CopyAction;
00529
00530 drag->exec(supportedActions, defaultDropAction);
00531 }
00532
00533
00534 QModelIndex curVisibleIndex() const {
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547 QModelIndex index;
00548 QPoint offset = scrollOffset();
00549 klfDbg( " offset="<<offset ) ;
00550 int xStep = 40;
00551 int yStep = 40;
00552 int xpos, ypos;
00553 for (xpos = xStep/2; xpos < thisConstView()->width(); xpos += xStep) {
00554 for (ypos = yStep/2; ypos < thisConstView()->height(); ypos += yStep) {
00555 if ((index = thisConstView()->indexAt(QPoint(xpos,ypos))).isValid()) {
00556 klfDbg( ": Found index = "<<index<<" at pos=("<<xpos<<","<<ypos<<"); "
00557 <<" with offset "<<offset ) ;
00558 return index;
00559 }
00560 }
00561 }
00562 return pModel->walkNextIndex(QModelIndex());
00563 }
00564
00565 virtual void modelInitialized() { }
00566
00567 protected:
00568 KLFLibModel *pModel;
00569 KLFLibDefaultView *pDView;
00570 KLFLibDefaultView::ViewType pViewType;
00571 QPoint mousePressedContentsPos;
00572
00573 virtual QModelIndexList commonSelectedIndexes() const = 0;
00574 virtual void commonInternalDrag(Qt::DropActions a) = 0;
00575 virtual QAbstractItemView *thisView() = 0;
00576 virtual const QAbstractItemView *thisConstView() const = 0;
00577 virtual QPoint scrollOffset() const = 0;
00578
00580 virtual QPoint eventPos(QObject *object, QDragEnterEvent *event, int horoffset, int veroffset) {
00581 if (object == thisView()->viewport())
00582 return event->pos() + QPoint(horoffset, veroffset);
00583 if (object == thisView())
00584 return thisView()->viewport()->mapFromGlobal(thisView()->mapToGlobal(event->pos()))
00585 + QPoint(horoffset, veroffset);
00586 return event->pos() + QPoint(horoffset, veroffset);
00587 }
00588
00589 virtual bool setTheModel(QAbstractItemModel *m) {
00590 KLFLibModel *model = qobject_cast<KLFLibModel*>(m);
00591 if (model == NULL) {
00592 qWarning()<<"KLFLibDefViewCommon::setTheModel: model is NULL or not a KLFLibModel :"<<model<<" !";
00593 return false;
00594 }
00595 pModel = model;
00596 return true;
00597 }
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613 };
00614
00615
00617 class KLFLibDefTreeView : public QTreeView, public KLFLibDefViewCommon
00618 {
00619 Q_OBJECT
00620 public:
00621 KLFLibDefTreeView(KLFLibDefaultView *parent)
00622 : QTreeView(parent), KLFLibDefViewCommon(parent), inPaintEvent(false), pInEventFilter(false)
00623 {
00624 installEventFilter(this);
00625 viewport()->installEventFilter(this);
00626 }
00627
00628 virtual bool eventFilter(QObject *object, QEvent *event) {
00629 if (pInEventFilter)
00630 return QTreeView::eventFilter(object, event);
00631 pInEventFilter = true;
00632 bool eat = false;
00633 if (event->type() == QEvent::DragEnter) {
00634 eat = evDragEnter((QDragEnterEvent*)event, eventPos(object, (QDragEnterEvent*)event));
00635 } else if (event->type() == QEvent::DragMove) {
00636 eat = evDragMove((QDragMoveEvent*)event, eventPos(object, (QDragEnterEvent*)event));
00637 } else if (event->type() == QEvent::Drop) {
00638 eat = evDrop((QDropEvent*)event, eventPos(object, (QDragEnterEvent*)event));
00639 }
00640
00641
00642 pInEventFilter = false;
00643 if (eat)
00644 return eat;
00645 return QTreeView::eventFilter(object, event);
00646 }
00647 virtual void setModel(QAbstractItemModel *model) {
00648 if ( setTheModel(model) ) {
00649 QTreeView::setModel(model);
00650 }
00651 }
00652
00653
00654 public slots:
00655
00656 virtual void selectAll() {
00657 pDView->slotSelectAll();
00658 }
00659
00660 void ensureExpandedTo(const QModelIndexList& mil)
00661 {
00662 int k;
00663 for (k = 0; k < mil.size(); ++k) {
00664 QModelIndex idx = mil[k];
00665 if (!idx.isValid())
00666 continue;
00667 while (idx.parent().isValid()) {
00668 klfDbg("expanding index "<<idx.parent()) ;
00669 expand(idx.parent());
00670 idx = idx.parent();
00671 }
00672 }
00673 }
00674
00675
00676 protected:
00677 QModelIndexList commonSelectedIndexes() const { return selectedIndexes(); }
00678 void commonInternalDrag(Qt::DropActions) { }
00679 QAbstractItemView *thisView() { return this; }
00680 const QAbstractItemView *thisConstView() const { return this; }
00681 QPoint scrollOffset() const { return QPoint(horizontalOffset(), verticalOffset()); }
00682
00683 QPoint eventPos(QObject *object, QDragEnterEvent *event) {
00684 return KLFLibDefViewCommon::eventPos(object, event, horizontalOffset(), verticalOffset());
00685 }
00686
00687 void startDrag(Qt::DropActions supportedActions) {
00688 commonStartDrag(supportedActions);
00689 }
00690
00691 bool inPaintEvent;
00692 virtual void paintEvent(QPaintEvent *event) {
00693 QTreeView::paintEvent(event);
00694 }
00695
00696
00697 virtual void rowsInserted(const QModelIndex& parent, int start, int end)
00698 {
00699 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
00700 QTreeView::rowsInserted(parent, start, end);
00701 }
00702
00703 bool pInEventFilter;
00704 };
00705
00707 class KLFLibDefListView : public QListView, public KLFLibDefViewCommon
00708 {
00709 Q_OBJECT
00710 public:
00711 KLFLibDefListView(KLFLibDefaultView *parent)
00712 : QListView(parent), KLFLibDefViewCommon(parent), inPaintEvent(false), pInEventFilter(false),
00713 pInitialLayoutDone(false), pWantRelayout(true)
00714 {
00715 installEventFilter(this);
00716 viewport()->installEventFilter(this);
00717 }
00718
00719 virtual bool eventFilter(QObject *object, QEvent *event) {
00720 if (pInEventFilter)
00721 return false;
00722 pInEventFilter = true;
00723 bool eat = false;
00724 if (event->type() == QEvent::DragEnter) {
00725 eat = evDragEnter((QDragEnterEvent*)event, eventPos(object, (QDragEnterEvent*)event));
00726 } else if (event->type() == QEvent::DragMove) {
00727 eat = evDragMove((QDragMoveEvent*)event, eventPos(object, (QDragEnterEvent*)event));
00728 } else if (event->type() == QEvent::Drop) {
00729 eat = evDrop((QDropEvent*)event, eventPos(object, (QDragEnterEvent*)event));
00730 }
00731
00732
00733 pInEventFilter = false;
00734 if (eat)
00735 return eat;
00736 return QListView::eventFilter(object, event);
00737 }
00738 virtual void setModel(QAbstractItemModel *model) {
00739 if ( setTheModel(model) ) {
00740 QListView::setModel(model);
00741 }
00742 }
00743
00744
00745 void forceRelayout() {
00746 scheduleDelayedItemsLayout();
00747 }
00748
00749 virtual void modelInitialized() {
00750 klfDbg("scheduling an items layout...");
00751 if (isVisible()) {
00752 scheduleDelayedItemsLayout();
00753 pInitialLayoutDone = true;
00754 } else {
00755 pInitialLayoutDone = false;
00756 }
00757 }
00758
00759 protected:
00760 virtual QModelIndexList commonSelectedIndexes() const { return selectedIndexes(); }
00761 virtual void commonInternalDrag(Qt::DropActions a) { internalDrag(a); }
00762 virtual QAbstractItemView *thisView() { return this; }
00763 virtual const QAbstractItemView *thisConstView() const { return this; }
00764 virtual QPoint scrollOffset() const { return QPoint(horizontalOffset(), verticalOffset()); }
00765
00766 virtual QPoint eventPos(QObject *object, QDragEnterEvent *event) {
00767 return KLFLibDefViewCommon::eventPos(object, event, horizontalOffset(), verticalOffset());
00768 }
00769
00770 bool inPaintEvent;
00771 virtual void paintEvent(QPaintEvent *event) {
00772 QListView::paintEvent(event);
00773 }
00774
00775 bool pInEventFilter;
00776 bool pInitialLayoutDone;
00777
00778 virtual void startDrag(Qt::DropActions supportedActions) {
00779 commonStartDrag(supportedActions);
00780 }
00781
00782 virtual void showEvent(QShowEvent *event) {
00783 if (!event->spontaneous()) {
00784 klfDbg("Show event! initialLayoutDone="<<pInitialLayoutDone<<"; size hint="<<sizeHint());
00785 if (!pInitialLayoutDone) {
00786 scheduleDelayedItemsLayout();
00787 pInitialLayoutDone = true;
00788 }
00789 }
00790 QListView::showEvent(event);
00791 }
00792
00793 bool pWantRelayout;
00794
00795 };
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00814 class KLFLibLocalFileOpenWidget : public QWidget, protected Ui::KLFLibLocalFileWidget
00815 {
00816 Q_OBJECT
00817
00818 Q_PROPERTY(bool readyToOpen READ isReadyToOpen)
00819 public:
00820 typedef KLFLibBasicWidgetFactory::LocalFileType LocalFileType;
00821
00822 KLFLibLocalFileOpenWidget(QWidget *parent,
00823 const QList<LocalFileType>& fileTypes)
00824 : QWidget(parent)
00825 {
00826 pReadyToOpen = false;
00827 pReadyToOpenUrl = QUrl();
00828 pFileTypes = fileTypes;
00829 setupUi(this);
00830
00831 QStringList namefilters;
00832 int k;
00833 for (k = 0; k < pFileTypes.size(); ++k)
00834 namefilters << pFileTypes[k].filepattern;
00835 QDirModel *dirModel = new QDirModel(namefilters,
00836 QDir::AllEntries|QDir::AllDirs|QDir::NoDotAndDotDot,
00837 QDir::DirsFirst|QDir::IgnoreCase, this);
00838
00839 QCompleter *fileNameCompleter = new QCompleter(this);
00840 fileNameCompleter->setModel(dirModel);
00841 txtFile->setCompleter(fileNameCompleter);
00842
00843 setUrl(QUrl());
00844 }
00845 virtual ~KLFLibLocalFileOpenWidget() { }
00846
00847 virtual bool isReadyToOpen() const { return pReadyToOpen; }
00848
00849 virtual QString selectedFName() const {
00850 return QDir::fromNativeSeparators(txtFile->text());
00851 }
00852 virtual QString selectedScheme() const
00853 {
00854 QString filename = selectedFName();
00855 LocalFileType ft = fileTypeForFileName(filename);
00856 if (!ft.scheme.isEmpty())
00857 return ft.scheme;
00858
00859 return KLFLibBasicWidgetFactory::guessLocalFileScheme(filename);
00860 }
00861
00862 LocalFileType fileTypeForFileName(const QString& filename) const
00863 {
00864 QString fname = QFileInfo(filename).fileName();
00865 int k;
00866 for (k = 0; k < pFileTypes.size(); ++k) {
00867
00868 QRegExp rgx(pFileTypes[k].filepattern, Qt::CaseInsensitive, QRegExp::Wildcard);
00869 if (rgx.exactMatch(fname))
00870 return pFileTypes[k];
00871 }
00872 if (!pFileTypes.size())
00873 return LocalFileType();
00874 return pFileTypes[0];
00875 }
00876
00877 virtual void setUrl(const QUrl& url) {
00878 if (url.isValid() && url.path().length()>0)
00879 txtFile->setText(QDir::toNativeSeparators(url.path()));
00880 else
00881 txtFile->setText(QDir::toNativeSeparators(klfconfig.LibraryBrowser.lastFileDialogPath+"/"));
00882 }
00883 virtual QUrl url() const {
00884 QString fname = selectedFName();
00885 QString scheme = selectedScheme();
00886 if (scheme.isEmpty())
00887 return QUrl();
00888
00889 QUrl url = QUrl::fromLocalFile(fname);
00890 url.setScheme(scheme);
00891 return url;
00892 }
00893
00894 signals:
00895 void readyToOpen(bool ready);
00896
00897 public slots:
00898 void setReadyToOpen(bool ready, const QUrl& url) {
00899 if (ready != pReadyToOpen || url != pReadyToOpenUrl) {
00900
00901 pReadyToOpen = ready;
00902 pReadyToOpenUrl = url;
00903 emit readyToOpen(ready);
00904 }
00905 }
00906
00907 protected:
00908 QList<LocalFileType> pFileTypes;
00909 bool pReadyToOpen;
00910 QUrl pReadyToOpenUrl;
00911 enum BrowseType { BrowseOpen, BrowseSave };
00912
00913 virtual bool checkIsReadyToOpen(const QString& text = QString()) const
00914 {
00915 QString t = text.isNull() ? txtFile->text() : text;
00916 return QFileInfo(t).isFile();
00917 }
00918
00919
00920 protected slots:
00921 virtual bool browseFileName(BrowseType bt)
00922 {
00923 static QString selectedFilter;
00924
00925 QString path = txtFile->text();
00926 if (path.isEmpty())
00927 path = klfconfig.LibraryBrowser.lastFileDialogPath;
00928 QString pathfilter;
00929 if (!QFileInfo(path).isDir()) {
00930 LocalFileType pathft = fileTypeForFileName(path);
00931 if (!pathft.filter.isEmpty())
00932 pathfilter = pathft.filter;
00933 }
00934
00935 QStringList filters;
00936 QStringList fpatterns;
00937 int k;
00938 int pathfilterN = -1;
00939 for (k = 0; k < pFileTypes.size(); ++k) {
00940 filters << pFileTypes[k].filter;
00941 fpatterns << pFileTypes[k].filepattern;
00942 if (pFileTypes[k].filter == pathfilter)
00943 pathfilterN = k;
00944 }
00945 if (bt == BrowseOpen) {
00946
00947
00948
00949
00950 if (pathfilterN >= 0)
00951 filters.removeAt(pathfilterN);
00952 filters.prepend(tr("All Known Files (%1)").arg(fpatterns.join(" ")));
00953 if (pathfilterN >= 0)
00954 filters.prepend(pathfilter);
00955 } else {
00956 if (pathfilterN >= 0) {
00957 filters.removeAt(pathfilterN);
00958 filters.prepend(pathfilter);
00959 }
00960 }
00961 filters.append(tr("All Files (*)"));
00962 QString filter = filters.join(";;");
00963 QString title = tr("Select Library Resource File");
00964 QString name;
00965 if (bt == BrowseOpen) {
00966 name = QFileDialog::getOpenFileName(this, title, path, filter, &selectedFilter);
00967 } else if (bt == BrowseSave) {
00968 name = QFileDialog::getSaveFileName(this, title, path, filter, &selectedFilter);
00969 } else {
00970 qWarning()<<"KLFLibLocalFileOpenWidget::browseFileName: bad bt="<<bt;
00971 name = QFileDialog::getSaveFileName(this, title, path, filter, &selectedFilter);
00972 }
00973 if ( name.isEmpty() )
00974 return false;
00975
00976 klfconfig.LibraryBrowser.lastFileDialogPath = QFileInfo(name).absolutePath();
00977
00978 txtFile->setText(name);
00979 return true;
00980 }
00981 virtual void on_btnBrowse_clicked()
00982 {
00983 browseFileName(BrowseOpen);
00984 }
00985 virtual void on_txtFile_textChanged(const QString& text)
00986 {
00987 setReadyToOpen(checkIsReadyToOpen(text), url());
00988 }
00989 };
00990
00991
00992
00994 class KLFLibLocalFileCreateWidget : public KLFLibLocalFileOpenWidget
00995 {
00996 Q_OBJECT
00997
00998 Q_PROPERTY(bool readyToCreate READ isReadyToCreate WRITE setReadyToCreate)
00999 public:
01000 KLFLibLocalFileCreateWidget(QWidget *parent,
01001 const QList<LocalFileType>& fileTypes)
01002 : KLFLibLocalFileOpenWidget(parent, fileTypes)
01003 {
01004 pConfirmedOverwrite = false;
01005 pReadyToCreate = false;
01006 }
01007 virtual ~KLFLibLocalFileCreateWidget() { }
01008
01009 QString fileName() const {
01010 return txtFile->text();
01011 }
01012
01013 virtual bool isReadyToCreate() const { return pReadyToCreate; }
01014
01015 virtual bool confirmedOverwrite() const { return pConfirmedOverwrite; }
01016
01017 signals:
01018 void readyToCreate(bool ready);
01019
01020 public slots:
01021 void setReadyToCreate(bool ready) {
01022 if (ready != pReadyToCreate) {
01023 pReadyToCreate = ready;
01024 emit readyToCreate(pReadyToCreate);
01025 }
01026 }
01027
01028 protected slots:
01029 virtual void on_btnBrowse_clicked()
01030 {
01031 if ( browseFileName(BrowseSave) )
01032 pConfirmedOverwrite = true;
01033 }
01034 virtual void on_txtFile_textChanged(const QString& text)
01035 {
01036 pConfirmedOverwrite = false;
01037 setReadyToCreate(QFileInfo(text).absoluteDir().exists());
01038 }
01039
01040 protected:
01041 bool pConfirmedOverwrite;
01042 bool pReadyToCreate;
01043 };
01044
01045
01046
01047 #ifdef KLF_DEBUG
01048 #include <QDebug>
01049 KLF_EXPORT QDebug& operator<<(QDebug& dbg, const KLFLibModelCache::NodeId& n);
01050 KLF_EXPORT QDebug& operator<<(QDebug& dbg, const KLFLibModelCache::Node& n);
01051 KLF_EXPORT QDebug& operator<<(QDebug& dbg, const KLFLibModelCache::EntryNode& en);
01052 KLF_EXPORT QDebug& operator<<(QDebug& dbg, const KLFLibModelCache::CategoryLabelNode& cn);
01053 #endif
01054
01055 #endif