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 this->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(bool firstOrLast) const {
00535 Q_UNUSED(firstOrLast)
00536
00537
00538 klfDbg( "curVisibleIndex: offset y is "<<scrollOffset().y() ) ;
00539 QModelIndex it = QModelIndex();
00540 while ((it = pModel->walkNextIndex(it)).isValid()) {
00541 klfDbg( "\texploring item it="<<it<<"; bottom="<<thisConstView()->visualRect(it).bottom() ) ;
00542 if (thisConstView()->visualRect(it).bottom() >= 0) {
00543
00544 return it;
00545 }
00546 }
00547 return pModel->walkNextIndex(QModelIndex());
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577 }
00578
00579 virtual void modelInitialized() { }
00580
00581 protected:
00582 KLFLibModel *pModel;
00583 KLFLibDefaultView *pDView;
00584 KLFLibDefaultView::ViewType pViewType;
00585 QPoint mousePressedContentsPos;
00586
00587 virtual QModelIndexList commonSelectedIndexes() const = 0;
00588 virtual void commonInternalDrag(Qt::DropActions a) = 0;
00589 virtual QAbstractItemView *thisView() = 0;
00590 virtual const QAbstractItemView *thisConstView() const = 0;
00591 virtual QPoint scrollOffset() const = 0;
00592
00594 virtual QPoint eventPos(QObject *object, QDragEnterEvent *event, int horoffset, int veroffset) {
00595 if (object == thisView()->viewport())
00596 return event->pos() + QPoint(horoffset, veroffset);
00597 if (object == thisView())
00598 return thisView()->viewport()->mapFromGlobal(thisView()->mapToGlobal(event->pos()))
00599 + QPoint(horoffset, veroffset);
00600 return event->pos() + QPoint(horoffset, veroffset);
00601 }
00602
00603 virtual bool setTheModel(QAbstractItemModel *m) {
00604 KLFLibModel *model = qobject_cast<KLFLibModel*>(m);
00605 if (model == NULL) {
00606 qWarning()<<"KLFLibDefViewCommon::setTheModel: model is NULL or not a KLFLibModel :"<<model<<" !";
00607 return false;
00608 }
00609 pModel = model;
00610 return true;
00611 }
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627 };
00628
00629
00631 class KLFLibDefTreeView : public QTreeView, public KLFLibDefViewCommon
00632 {
00633 Q_OBJECT
00634 public:
00635 KLFLibDefTreeView(KLFLibDefaultView *parent)
00636 : QTreeView(parent), KLFLibDefViewCommon(parent), inPaintEvent(false), pInEventFilter(false)
00637 {
00638 installEventFilter(this);
00639 viewport()->installEventFilter(this);
00640 }
00641
00642 virtual bool eventFilter(QObject *object, QEvent *event) {
00643 if (pInEventFilter)
00644 return QTreeView::eventFilter(object, event);
00645 pInEventFilter = true;
00646 bool eat = false;
00647 if (event->type() == QEvent::DragEnter) {
00648 eat = evDragEnter((QDragEnterEvent*)event, eventPos(object, (QDragEnterEvent*)event));
00649 } else if (event->type() == QEvent::DragMove) {
00650 eat = evDragMove((QDragMoveEvent*)event, eventPos(object, (QDragEnterEvent*)event));
00651 } else if (event->type() == QEvent::Drop) {
00652 eat = evDrop((QDropEvent*)event, eventPos(object, (QDragEnterEvent*)event));
00653 }
00654
00655
00656 pInEventFilter = false;
00657 if (eat)
00658 return eat;
00659 return QTreeView::eventFilter(object, event);
00660 }
00661 virtual void setModel(QAbstractItemModel *model) {
00662 if ( setTheModel(model) ) {
00663 QTreeView::setModel(model);
00664 }
00665 }
00666
00667
00668 public slots:
00669
00670 virtual void selectAll() {
00671 pDView->slotSelectAll();
00672 }
00673
00674 void ensureExpandedTo(const QModelIndexList& mil)
00675 {
00676 int k;
00677 for (k = 0; k < mil.size(); ++k) {
00678 QModelIndex idx = mil[k];
00679 if (!idx.isValid())
00680 continue;
00681 while (idx.parent().isValid()) {
00682 klfDbg("expanding index "<<idx.parent()) ;
00683 expand(idx.parent());
00684 idx = idx.parent();
00685 }
00686 }
00687 }
00688
00689
00690 protected:
00691 QModelIndexList commonSelectedIndexes() const { return selectedIndexes(); }
00692 void commonInternalDrag(Qt::DropActions) { }
00693 QAbstractItemView *thisView() { return this; }
00694 const QAbstractItemView *thisConstView() const { return this; }
00695 QPoint scrollOffset() const { return QPoint(horizontalOffset(), verticalOffset()); }
00696
00697 QPoint eventPos(QObject *object, QDragEnterEvent *event) {
00698 return KLFLibDefViewCommon::eventPos(object, event, horizontalOffset(), verticalOffset());
00699 }
00700
00701 void startDrag(Qt::DropActions supportedActions) {
00702 commonStartDrag(supportedActions);
00703 }
00704
00705 bool inPaintEvent;
00706 virtual void paintEvent(QPaintEvent *event) {
00707 QTreeView::paintEvent(event);
00708 }
00709
00710
00711 virtual void rowsInserted(const QModelIndex& parent, int start, int end)
00712 {
00713 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
00714 QTreeView::rowsInserted(parent, start, end);
00715 }
00716
00717 bool pInEventFilter;
00718 };
00719
00721 class KLFLibDefListView : public QListView, public KLFLibDefViewCommon
00722 {
00723 Q_OBJECT
00724 public:
00725 KLFLibDefListView(KLFLibDefaultView *parent)
00726 : QListView(parent), KLFLibDefViewCommon(parent), inPaintEvent(false), pInEventFilter(false),
00727 pInitialLayoutDone(false), pWantRelayout(true)
00728 {
00729 installEventFilter(this);
00730 viewport()->installEventFilter(this);
00731 }
00732
00733 virtual bool eventFilter(QObject *object, QEvent *event) {
00734 if (pInEventFilter)
00735 return false;
00736 pInEventFilter = true;
00737 bool eat = false;
00738 if (event->type() == QEvent::DragEnter) {
00739 eat = evDragEnter((QDragEnterEvent*)event, eventPos(object, (QDragEnterEvent*)event));
00740 } else if (event->type() == QEvent::DragMove) {
00741 eat = evDragMove((QDragMoveEvent*)event, eventPos(object, (QDragEnterEvent*)event));
00742 } else if (event->type() == QEvent::Drop) {
00743 eat = evDrop((QDropEvent*)event, eventPos(object, (QDragEnterEvent*)event));
00744 }
00745
00746
00747 pInEventFilter = false;
00748 if (eat)
00749 return eat;
00750 return QListView::eventFilter(object, event);
00751 }
00752 virtual void setModel(QAbstractItemModel *model) {
00753 if ( setTheModel(model) ) {
00754 QListView::setModel(model);
00755 }
00756 }
00757
00758
00759 void forceRelayout() {
00760 scheduleDelayedItemsLayout();
00761 }
00762
00763 virtual void modelInitialized() {
00764 klfDbg("scheduling an items layout...");
00765 if (isVisible()) {
00766 scheduleDelayedItemsLayout();
00767 pInitialLayoutDone = true;
00768 } else {
00769 pInitialLayoutDone = false;
00770 }
00771 }
00772
00773 protected:
00774 virtual QModelIndexList commonSelectedIndexes() const { return selectedIndexes(); }
00775 virtual void commonInternalDrag(Qt::DropActions a) { internalDrag(a); }
00776 virtual QAbstractItemView *thisView() { return this; }
00777 virtual const QAbstractItemView *thisConstView() const { return this; }
00778 virtual QPoint scrollOffset() const { return QPoint(horizontalOffset(), verticalOffset()); }
00779
00780 virtual QPoint eventPos(QObject *object, QDragEnterEvent *event) {
00781 return KLFLibDefViewCommon::eventPos(object, event, horizontalOffset(), verticalOffset());
00782 }
00783
00784 bool inPaintEvent;
00785 virtual void paintEvent(QPaintEvent *event) {
00786 QListView::paintEvent(event);
00787 }
00788
00789 bool pInEventFilter;
00790 bool pInitialLayoutDone;
00791
00792 virtual void startDrag(Qt::DropActions supportedActions) {
00793 commonStartDrag(supportedActions);
00794 }
00795
00796 virtual void showEvent(QShowEvent *event) {
00797 if (!event->spontaneous()) {
00798 klfDbg("Show event! initialLayoutDone="<<pInitialLayoutDone<<"; size hint="<<sizeHint());
00799 if (!pInitialLayoutDone) {
00800 scheduleDelayedItemsLayout();
00801 pInitialLayoutDone = true;
00802 }
00803 }
00804 QListView::showEvent(event);
00805 }
00806
00807 bool pWantRelayout;
00808
00809 };
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00828 class KLFLibLocalFileOpenWidget : public QWidget, protected Ui::KLFLibLocalFileWidget
00829 {
00830 Q_OBJECT
00831
00832 Q_PROPERTY(bool readyToOpen READ isReadyToOpen)
00833 public:
00834 typedef KLFLibBasicWidgetFactory::LocalFileType LocalFileType;
00835
00836 KLFLibLocalFileOpenWidget(QWidget *parent,
00837 const QList<LocalFileType>& fileTypes)
00838 : QWidget(parent)
00839 {
00840 pReadyToOpen = false;
00841 pReadyToOpenUrl = QUrl();
00842 pFileTypes = fileTypes;
00843 setupUi(this);
00844
00845 QStringList namefilters;
00846 int k;
00847 for (k = 0; k < pFileTypes.size(); ++k)
00848 namefilters << pFileTypes[k].filepattern;
00849 QDirModel *dirModel = new QDirModel(namefilters,
00850 QDir::AllEntries|QDir::AllDirs|QDir::NoDotAndDotDot,
00851 QDir::DirsFirst|QDir::IgnoreCase, this);
00852
00853 QCompleter *fileNameCompleter = new QCompleter(this);
00854 fileNameCompleter->setModel(dirModel);
00855 txtFile->setCompleter(fileNameCompleter);
00856
00857 setUrl(QUrl());
00858 }
00859 virtual ~KLFLibLocalFileOpenWidget() { }
00860
00861 virtual bool isReadyToOpen() const { return pReadyToOpen; }
00862
00863 virtual QString selectedFName() const {
00864 return QDir::fromNativeSeparators(txtFile->text());
00865 }
00866 virtual QString selectedScheme() const
00867 {
00868 QString filename = selectedFName();
00869 LocalFileType ft = fileTypeForFileName(filename);
00870 if (!ft.scheme.isEmpty())
00871 return ft.scheme;
00872
00873 return KLFLibBasicWidgetFactory::guessLocalFileScheme(filename);
00874 }
00875
00876 LocalFileType fileTypeForFileName(const QString& filename) const
00877 {
00878 QString fname = QFileInfo(filename).fileName();
00879 int k;
00880 for (k = 0; k < pFileTypes.size(); ++k) {
00881
00882 QRegExp rgx(pFileTypes[k].filepattern, Qt::CaseInsensitive, QRegExp::Wildcard);
00883 if (rgx.exactMatch(fname))
00884 return pFileTypes[k];
00885 }
00886 if (!pFileTypes.size())
00887 return LocalFileType();
00888 return pFileTypes[0];
00889 }
00890
00891 virtual void setUrl(const QUrl& url) {
00892 if (url.isValid() && url.path().length()>0)
00893 txtFile->setText(QDir::toNativeSeparators(url.path()));
00894 else
00895 txtFile->setText(QDir::toNativeSeparators(klfconfig.LibraryBrowser.lastFileDialogPath+"/"));
00896 }
00897 virtual QUrl url() const {
00898 QString fname = selectedFName();
00899 QString scheme = selectedScheme();
00900 if (scheme.isEmpty())
00901 return QUrl();
00902
00903 QUrl url = QUrl::fromLocalFile(fname);
00904 url.setScheme(scheme);
00905 return url;
00906 }
00907
00908 signals:
00909 void readyToOpen(bool ready);
00910
00911 public slots:
00912 void setReadyToOpen(bool ready, const QUrl& url) {
00913 if (ready != pReadyToOpen || url != pReadyToOpenUrl) {
00914
00915 pReadyToOpen = ready;
00916 pReadyToOpenUrl = url;
00917 emit readyToOpen(ready);
00918 }
00919 }
00920
00921 protected:
00922 QList<LocalFileType> pFileTypes;
00923 bool pReadyToOpen;
00924 QUrl pReadyToOpenUrl;
00925 enum BrowseType { BrowseOpen, BrowseSave };
00926
00927 virtual bool checkIsReadyToOpen(const QString& text = QString()) const
00928 {
00929 QString t = text.isNull() ? txtFile->text() : text;
00930 return QFileInfo(t).isFile();
00931 }
00932
00933
00934 protected slots:
00935 virtual bool browseFileName(BrowseType bt)
00936 {
00937 static QString selectedFilter;
00938
00939 QString path = txtFile->text();
00940 if (path.isEmpty())
00941 path = klfconfig.LibraryBrowser.lastFileDialogPath;
00942 QString pathfilter;
00943 if (!QFileInfo(path).isDir()) {
00944 LocalFileType pathft = fileTypeForFileName(path);
00945 if (!pathft.filter.isEmpty())
00946 pathfilter = pathft.filter;
00947 }
00948
00949 QStringList filters;
00950 QStringList fpatterns;
00951 int k;
00952 int pathfilterN = -1;
00953 for (k = 0; k < pFileTypes.size(); ++k) {
00954 filters << pFileTypes[k].filter;
00955 fpatterns << pFileTypes[k].filepattern;
00956 if (pFileTypes[k].filter == pathfilter)
00957 pathfilterN = k;
00958 }
00959 if (bt == BrowseOpen) {
00960
00961
00962
00963
00964 if (pathfilterN >= 0)
00965 filters.removeAt(pathfilterN);
00966 filters.prepend(tr("All Known Files (%1)").arg(fpatterns.join(" ")));
00967 if (pathfilterN >= 0)
00968 filters.prepend(pathfilter);
00969 } else {
00970 if (pathfilterN >= 0) {
00971 filters.removeAt(pathfilterN);
00972 filters.prepend(pathfilter);
00973 }
00974 }
00975 filters.append(tr("All Files (*)"));
00976 QString filter = filters.join(";;");
00977 QString title = tr("Select Library Resource File");
00978 QString name;
00979 if (bt == BrowseOpen) {
00980 name = QFileDialog::getOpenFileName(this, title, path, filter, &selectedFilter);
00981 } else if (bt == BrowseSave) {
00982 name = QFileDialog::getSaveFileName(this, title, path, filter, &selectedFilter);
00983 } else {
00984 qWarning()<<"KLFLibLocalFileOpenWidget::browseFileName: bad bt="<<bt;
00985 name = QFileDialog::getSaveFileName(this, title, path, filter, &selectedFilter);
00986 }
00987 if ( name.isEmpty() )
00988 return false;
00989
00990 klfconfig.LibraryBrowser.lastFileDialogPath = QFileInfo(name).absolutePath();
00991
00992 txtFile->setText(name);
00993 return true;
00994 }
00995 virtual void on_btnBrowse_clicked()
00996 {
00997 browseFileName(BrowseOpen);
00998 }
00999 virtual void on_txtFile_textChanged(const QString& text)
01000 {
01001 setReadyToOpen(checkIsReadyToOpen(text), url());
01002 }
01003 };
01004
01005
01006
01008 class KLFLibLocalFileCreateWidget : public KLFLibLocalFileOpenWidget
01009 {
01010 Q_OBJECT
01011
01012 Q_PROPERTY(bool readyToCreate READ isReadyToCreate WRITE setReadyToCreate)
01013 public:
01014 KLFLibLocalFileCreateWidget(QWidget *parent,
01015 const QList<LocalFileType>& fileTypes)
01016 : KLFLibLocalFileOpenWidget(parent, fileTypes)
01017 {
01018 pConfirmedOverwrite = false;
01019 pReadyToCreate = false;
01020 }
01021 virtual ~KLFLibLocalFileCreateWidget() { }
01022
01023 QString fileName() const {
01024 return txtFile->text();
01025 }
01026
01027 virtual bool isReadyToCreate() const { return pReadyToCreate; }
01028
01029 virtual bool confirmedOverwrite() const { return pConfirmedOverwrite; }
01030
01031 signals:
01032 void readyToCreate(bool ready);
01033
01034 public slots:
01035 void setReadyToCreate(bool ready) {
01036 if (ready != pReadyToCreate) {
01037 pReadyToCreate = ready;
01038 emit readyToCreate(pReadyToCreate);
01039 }
01040 }
01041
01042 protected slots:
01043 virtual void on_btnBrowse_clicked()
01044 {
01045 if ( browseFileName(BrowseSave) )
01046 pConfirmedOverwrite = true;
01047 }
01048 virtual void on_txtFile_textChanged(const QString& text)
01049 {
01050 pConfirmedOverwrite = false;
01051 setReadyToCreate(QFileInfo(text).absoluteDir().exists());
01052 }
01053
01054 protected:
01055 bool pConfirmedOverwrite;
01056 bool pReadyToCreate;
01057 };
01058
01059
01060
01061 #ifdef KLF_DEBUG
01062 #include <QDebug>
01063 KLF_EXPORT QDebug& operator<<(QDebug& dbg, const KLFLibModelCache::NodeId& n);
01064 KLF_EXPORT QDebug& operator<<(QDebug& dbg, const KLFLibModelCache::Node& n);
01065 KLF_EXPORT QDebug& operator<<(QDebug& dbg, const KLFLibModelCache::EntryNode& en);
01066 KLF_EXPORT QDebug& operator<<(QDebug& dbg, const KLFLibModelCache::CategoryLabelNode& cn);
01067 #endif
01068
01069 #endif