[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) 2010 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 580 2010-12-02 18:55:28Z philippe $ */
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         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() const {
00535     /*
00536       int off_y = scrollOffset().y();
00537       klfDbg( "curVisibleIndex: offset y is "<<off_y ) ;
00538       QModelIndex it = QModelIndex();
00539       while ((it = pModel->walkNextIndex(it)).isValid()) {
00540       klfDbg( "\texploring item it="<<it<<"; bottom="<<thisConstView()->visualRect(it).bottom() ) ;
00541       if (thisConstView()->visualRect(it).bottom() >= 0) {
00542       // first index from the beginning, that is after our scroll offset.
00543       return it;
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   /*   virtual void preparePaintEvent(QPaintEvent *e) */
00600   /*   { */
00601   /*     KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ; */
00602   /*     klfDbg("e->rect()="<<e->rect()); */
00603   /*     const QAbstractItemView *v = thisView(); */
00604   /*     QModelIndex idx; */
00605   /*     while ((idx = pModel->walkNextIndex(idx)).isValid()) { */
00606   /*       klfDbg("Testing for prefetching item at row="<<idx.row()<<" its rect="<<v->visualRect(idx)); */
00607   /*       if (e->rect().intersects(v->visualRect(idx))) { */
00608   /*    pModel->prefetch(QModelIndexList()<<idx); */
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     //    if (object == this && event->type() == QEvent::Paint)
00641     //      preparePaintEvent((QPaintEvent*)event);
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   // reimpl. from QTreeView for debugging a segfault in fetchMore()
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     //    if (object == this && event->type() == QEvent::Paint)
00732     //      preparePaintEvent((QPaintEvent*)event);
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(); // force a re-layout
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     // fall back to guessing the scheme with the file contents
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       // test for this file type
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(); // invalid file type...
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       // ready to open state changes
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; // remember this one
00944     }
00945     if (bt == BrowseOpen) {
00946       // only when opening
00947       // NOTE: this doesn't work for save when we want to preserve 'path's extension, because
00948       //   Q(K?)FileDialog foolishly feels obliged to automatically force the first extension
00949       //   in the patterns list.
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); // this will call on_txtFile_textChanged()
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

Generated by doxygen 1.7.3