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

src/klflibview_p.h

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   file klflibview_p.h
00003  *   This file is part of the KLatexFormula Project.
00004  *   Copyright (C) 2011 by Philippe Faist
00005  *   philippe.faist at bluewin.ch
00006  *                                                                         *
00007  *   This program is free software; you can redistribute it and/or modify  *
00008  *   it under the terms of the GNU General Public License as published by  *
00009  *   the Free Software Foundation; either version 2 of the License, or     *
00010  *   (at your option) any later version.                                   *
00011  *                                                                         *
00012  *   This program is distributed in the hope that it will be useful,       *
00013  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00014  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00015  *   GNU General Public License for more details.                          *
00016  *                                                                         *
00017  *   You should have received a copy of the GNU General Public License     *
00018  *   along with this program; if not, write to the                         *
00019  *   Free Software Foundation, Inc.,                                       *
00020  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
00021  ***************************************************************************/
00022 /* $Id: klflibview_p.h 754 2012-01-05 21:56:47Z phfaist $ */
00023 
00024 
00030 #ifndef KLFLIBVIEW_P_H
00031 #define KLFLIBVIEW_P_H
00032 
00033 #include <math.h> // abs()
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 ) // invalid index
00108         return (~0x0); // 0xFFFFFFFF
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; // no children to fetch
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         // walk the cache, and find an invalid node
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; // render invalid
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; // not initialized, not used except for return values
00209   //                              of functions aborting their call eg. getNodeRef()
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     // walk decrementally, and break once we fall back in the list of known categories
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   //  virtual void moveSelectedIconsBy(const QPoint& delta) = 0;
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     // decide whether to show drop indicator or not.
00424     bool showdropindic = (fl & KLFLibModel::DropWillCategorize);
00425     thisView()->setDropIndicatorShown(showdropindic);
00426     // decide whether to accept the drop or to ignore it
00427     if ( !(fl & KLFLibModel::DropWillAccept) && pViewType != KLFLibDefaultView::IconView ) {
00428       // pViewType != IconView  <=  don't ignore if in icon view (where user can
00429       // move the equations freely...by drag&drop)
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       // and FAKE a QDragMoveEvent to the item view.
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     // decide whether to accept the drop or to ignore it
00449     if ( !(fl & KLFLibModel::DropWillAccept) && pViewType != KLFLibDefaultView::IconView ) {
00450       // pView != IconView  <=   don't ignore if in icon view (user can move the equations
00451       //    freely...by drag&drop)
00452       de->ignore();
00453     } else {
00454       // check proposed actions
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       // and FAKE a QDragMoveEvent to the item view.
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       // internal move -> send event directly
00473       //        qobject_cast<KLFLibDefListView*>(pView)->simulateEvent(event);
00474       //        qApp->sendEvent(object, event);
00475       // move the objects ourselves because of bug (?) in Qt's handling?
00476       QPoint delta = pos - mousePressedContentsPos;
00477       klfDbg( "Delta is "<<delta ) ;
00478       // and fake a QDragLeaveEvent
00479       QDragLeaveEvent fakeevent;
00480       qApp->sendEvent(thisView()->viewport(), &fakeevent);
00481       // and manually move all selected indexes
00482       //      moveSelectedIconsBy(delta); .... IF we decide to sometime re-try supporting manual icon positioning...
00483       thisView()->viewport()->update();
00484     } else {
00485       // and FAKE a QDropEvent to the item view.
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     // largely based on Qt's QAbstractItemView source in src/gui/itemviews/qabstractitemview.cpp
00496     QModelIndexList indexes = commonSelectedIndexes();
00497 
00498     if (pViewType == KLFLibDefaultView::IconView) {
00499       // icon view -> move icons around
00500 
00501       // this is not supported. This functionality was attempted and abandoned.
00502       return;
00503     }
00504     
00505     klfDbg(  "Normal DRAG..." ) ;
00506     /*  // DEBUG:
00507         if (indexes.count() > 0)
00508         if (v->inherits("KLFLibDefListView")) {
00509         klfDbg( "Got First index' rect: "
00510         <<qobject_cast<KLFLibDefListView*>(v)->rectForIndex(indexes[0]) ) ;
00511         qobject_cast<KLFLibDefListView*>(v)->setPositionForIndex(QPoint(200,100), indexes[0]);
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     // In the future, firstOrLast will be used to search forwards or backwards from the right point
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         // first index from the beginning, that is after our scroll offset.
00544       return it;
00545       }
00546     }
00547     return pModel->walkNextIndex(QModelIndex());
00548     /*
00549       QModelIndex index;
00550       QPoint offset = scrollOffset();
00551       klfDbg( " offset="<<offset ) ;
00552       int xStart, yStart;
00553       int xStep, yStep;
00554       if (firstOrLast) {
00555       xStep = 40;
00556       yStep = 40;
00557       xStart = xStep/2;
00558       yStart = yStep/2;
00559       } else {
00560       xStep = -40;
00561       yStep = -40;
00562       xStart = thisConstView()->width() - xStep/2;
00563       yStart = thisConstView()->height() - yStep/2;
00564       }
00565       int xpos, ypos;
00566       for (xpos = xStart; xpos > 0 && xpos < thisConstView()->width(); xpos += xStep) {
00567       for (ypos = yStart; ypos > 0 && ypos < thisConstView()->height(); ypos += yStep) {
00568       if ((index = thisConstView()->indexAt(QPoint(xpos,ypos))).isValid()) {
00569       klfDbg( ": Found index = "<<index<<" at pos=("<<xpos<<","<<ypos<<"); "
00570       <<" with offset "<<offset ) ;
00571       return firstOrLast ? pModel->walkPrevIndex(index) : pModel->walkNextIndex(index);
00572       }
00573       }
00574       }
00575       return firstOrLast ? pModel->walkNextIndex(QModelIndex()) : pModel->walkPrevIndex(QModelIndex());
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   /*   virtual void preparePaintEvent(QPaintEvent *e) */
00614   /*   { */
00615   /*     KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ; */
00616   /*     klfDbg("e->rect()="<<e->rect()); */
00617   /*     const QAbstractItemView *v = thisView(); */
00618   /*     QModelIndex idx; */
00619   /*     while ((idx = pModel->walkNextIndex(idx)).isValid()) { */
00620   /*       klfDbg("Testing for prefetching item at row="<<idx.row()<<" its rect="<<v->visualRect(idx)); */
00621   /*       if (e->rect().intersects(v->visualRect(idx))) { */
00622   /*    pModel->prefetch(QModelIndexList()<<idx); */
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     //    if (object == this && event->type() == QEvent::Paint)
00655     //      preparePaintEvent((QPaintEvent*)event);
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   // reimpl. from QTreeView for debugging a segfault in fetchMore()
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     //    if (object == this && event->type() == QEvent::Paint)
00746     //      preparePaintEvent((QPaintEvent*)event);
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(); // force a re-layout
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     // fall back to guessing the scheme with the file contents
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       // test for this file type
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(); // invalid file type...
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       // ready to open state changes
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; // remember this one
00958     }
00959     if (bt == BrowseOpen) {
00960       // only when opening
00961       // NOTE: this doesn't work for save when we want to preserve 'path's extension, because
00962       //   Q(K?)FileDialog foolishly feels obliged to automatically force the first extension
00963       //   in the patterns list.
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); // this will call on_txtFile_textChanged()
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

Generated by doxygen 1.7.3