00001 /* This file is part of WarpTree 00002 * 00003 * Copyright (C) 2007 Jos van den Oever <jos@vandenoever.info> 00004 * 00005 * This library is free software; you can redistribute it and/or 00006 * modify it under the terms of the GNU Library General Public 00007 * License as published by the Free Software Foundation; either 00008 * version 2 of the License, or (at your option) any later version. 00009 * 00010 * This library is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 * Library General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU Library General Public License 00016 * along with this library; see the file COPYING.LIB. If not, write to 00017 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00018 * Boston, MA 02110-1301, USA. 00019 */ 00020 #include "warptreeview.h" 00021 #include "modelnode.h" 00022 #include "labelfitter.h" 00023 #include <QtCore/QTime> 00024 #include <QtCore/QTimer> 00025 #include <QtCore/QTimeLine> 00026 00027 /* 00028 * Private class that does the actual work of displaying the WarpTree 00029 */ 00030 class WarpTree : public QWidget { 00031 Q_OBJECT 00032 public: 00033 // data members 00034 00035 // reference to the public and private classes of WarpTreeView 00036 WarpTreeView& view; 00037 WarpTreeView::Private& viewp; 00038 // pointer to the nodepainter that paints background, nodes and lines 00039 WarpNodePainter* nodepainter; 00040 // timer used for loading incomplete nodes in the main thread 00041 // (it must be done in the main thread because models are not threadsafe 00042 // in general) 00043 QTimer loadTimer; 00044 // timeline for the animation 00045 QTimeLine animationTimeLine; 00046 // start- and endpoint of the animation 00047 WarpCoord start, end; 00048 // boolean that determines if the widget is drawn antialiased 00049 bool antialias; 00050 00051 WarpTree(WarpTreeView& v, WarpTreeView::Private& p) 00052 :view(v), viewp(p), antialias(true) { 00053 // construct a default painter that fits with the palette 00054 nodepainter = new WarpNodePainter(this); 00055 00056 // initialize the load timer to load more data in intervals of 100 ms 00057 loadTimer.setSingleShot(true); 00058 loadTimer.setInterval(100); 00059 connect(&loadTimer, SIGNAL(timeout()), this, SLOT(loadMore())); 00060 00061 // initialize the animation timer 00062 animationTimeLine.setDuration(500); 00063 connect(&animationTimeLine, SIGNAL(valueChanged(qreal)), 00064 this, SLOT(step(qreal))); 00065 } 00066 00067 // paint the widget 00068 void paintEvent(QPaintEvent*); 00069 // paint one node by calling the node painter 00070 void paintNode(QPainter&, const ModelNode*); 00071 // paint the line connecting this node to its parent, if one of the two 00072 // is visible 00073 void paintParentLine(QPainter& painter, const ModelNode* node); 00074 // descent into the hierarchy and draw lines that connect to all visible 00075 // nodes 00076 void paintChildLines(QPainter& painter, const ParentModelNode* node, 00077 const ModelNode* notnode); 00078 // perform a smooth animation starting from the current position to t 00079 void animateTo(const WarpCoord& t); 00080 public slots: 00081 // when not all visible nodes have been completely loaded this slot is 00082 // called 00083 void loadMore(); 00084 // perform one step in the animation 00085 void step(qreal value); 00086 }; 00087 class WarpTreeView::Private { 00088 public: 00089 // the tree widget that does the drawing 00090 WarpTree tree; 00091 // all the nodes that have been loaded 00092 QHash<QModelIndex, ModelNode*> nodes; 00093 // a subset of all nodes, namely all nodes that have their center visible 00094 QList<ModelNode*> visibleNodes; 00095 // a subset of all nodes that are connected to visible nodes 00096 QList<ModelNode*> showLineNodes; 00097 // the list of nodes that are currently visible and need to be loaded 00098 QList<ParentModelNode*> todo; 00099 // the helper class that fits the labels into the view 00100 LabelFitter labelfitter; 00101 // a reference to the public part 00102 WarpTreeView& view; 00103 // the root of the model 00104 QPersistentModelIndex root; 00105 // the point on the unit square that corresponds to the current position 00106 WarpCoord origin; 00107 // the start from where the user started a drag action 00108 WarpCoord dragStart; 00109 // the origin corresponding to the position from which the drag started 00110 WarpCoord dragStartOrigin; 00111 // a pointer to the node that is currently being hovered by the mouse 00112 ModelNode* hoverNode; 00113 // a pointer to the previous node that was hovered by the mouse 00114 ModelNode* lastHoverNode; 00115 // a pointer to the active node, the node closest to the center of the view 00116 ModelNode* activeNode; 00117 // the zoomfactor of the view 00118 double zoomFactor; 00119 // a boolean that is set when we are in a drag action 00120 bool movedSinceClick; 00121 00122 Private(WarpTreeView& v) :tree(v, *this), view(v), hoverNode(0), 00123 lastHoverNode(0), activeNode(0), zoomFactor(1), movedSinceClick(false) { 00124 } 00125 ~Private() { 00126 foreach(ModelNode* n, nodes) { 00127 delete n; 00128 } 00129 } 00130 /* equivalents to the public functions in WarpTreeView that 00131 contain the actual implementation */ 00132 void setModel(QAbstractItemModel* model); 00133 void mouseMoveEvent(QMouseEvent* event); 00134 void mousePressEvent(QMouseEvent* event); 00135 void mouseReleaseEvent(QMouseEvent* event); 00136 00137 /* functions for moving the view */ 00138 // change the origin of the view and translate all the points in the graph 00139 void setOrigin(const WarpCoord& o); 00140 // update the screen coordinates and determine which labels to display 00141 void updateScreenCoords(); 00142 // two functions that will later help speedup the view 00143 void translateParent(ModelNode* node); 00144 void translateChildren(ParentModelNode* node, const ModelNode* notnode); 00145 // start dragging the view at the given screen coordinates 00146 void startDrag(int x, int y); 00147 // drag the view to the given screen coordinates 00148 void drag(int x, int y); 00149 // change the zoom factor with a factor f 00150 void zoom(double f); 00151 // animate the view from the current positions to the position given in 00152 // screen coordinates 00153 void animateTo(int x, int y); 00154 // move the view by the distance given in screen coordinates 00155 void move(int x, int y); 00156 // find the node that displays a label at position pos 00157 ModelNode* findNode(const QPoint& pos); 00158 00159 /* functions for loading the nodes */ 00160 // load the nodes from the todo list 00161 void loadMore(); 00162 // load the children of a node and layout the node 00163 void completeNode(ParentModelNode* n); 00164 // add one node and determine the size of its label, 00165 // but do not yet layout or load the children 00166 ModelNode* addNode(const QModelIndex& index, 00167 ParentModelNode* parent, int depth); 00168 // determine which of the labels of the dynamically loaded nodes to show 00169 void filterChildrenVisible(const QVector<ModelNode*>& nodes); 00170 };