1 /*
2  mind_navigator.h     MindForger thinking notebook
3 
4  Copyright (C) 2016-2020 Martin Dvorak <martin.dvorak@mindforger.com>
5 
6  This program is free software; you can redistribute it and/or
7  modify it under the terms of the GNU General Public License
8  as published by the Free Software Foundation; either version 2
9  of the License, or (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>.
18 
19  ****************************************************************************
20  **
21  ** Copyright (C) 2016 The Qt Company Ltd.
22  ** Contact: https://www.qt.io/licensing/
23  **
24  ** This file is part of the examples of the Qt Toolkit.
25  **
26  ** $QT_BEGIN_LICENSE:BSD$
27  ** Commercial License Usage
28  ** Licensees holding valid commercial Qt licenses may use this file in
29  ** accordance with the commercial license agreement provided with the
30  ** Software or, alternatively, in accordance with the terms contained in
31  ** a written agreement between you and The Qt Company. For licensing terms
32  ** and conditions see https://www.qt.io/terms-conditions. For further
33  ** information use the contact form at https://www.qt.io/contact-us.
34  **
35  ** BSD License Usage
36  ** Alternatively, you may use this file under the terms of the BSD license
37  ** as follows:
38  **
39  ** "Redistribution and use in source and binary forms, with or without
40  ** modification, are permitted provided that the following conditions are
41  ** met:
42  **   * Redistributions of source code must retain the above copyright
43  **     notice, this list of conditions and the following disclaimer.
44  **   * Redistributions in binary form must reproduce the above copyright
45  **     notice, this list of conditions and the following disclaimer in
46  **     the documentation and/or other materials provided with the
47  **     distribution.
48  **   * Neither the name of The Qt Company Ltd nor the names of its
49  **     contributors may be used to endorse or promote products derived
50  **     from this software without specific prior written permission.
51  **
52  **
53  ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
54  ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
55  ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
56  ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
57  ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
58  ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
59  ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
60  ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
61  ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
62  ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
63  ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
64  **
65  ** $QT_END_LICENSE$
66  **
67  ****************************************************************************/
68 
69 #ifndef M8R_NAVIGATOR_VIEW_H
70 #define M8R_NAVIGATOR_VIEW_H
71 
72 #include <mutex>
73 
74 #include <QGraphicsView>
75 
76 #include "../../../../lib/src/mind/knowledge_graph.h"
77 #include "../../../../lib/src/model/outline.h"
78 #include "../look_n_feel.h"
79 
80 namespace m8r {
81 
82 class NavigatorNode;
83 
84 // IMPROVE enjoy improving this class to achieve maximum rendering performance, there
85 //         is a lot of space for improvement
86 
87 /**
88  * @brief Knowledge graph navigator view.
89  *
90  * Knowledge graph is based on force-directed graph based (FDB) - magnets and rubber bands.
91  *
92  * Synchronization & UI threads: selected node sets subgraph, timerEvent()
93  * then refreshes view which avoids the need for extra synchronization.
94  *
95  * @see http://doc.qt.io/qt-5/qtwidgets-graphicsview-elasticnodes-example.html
96  */
97 class NavigatorView : public QGraphicsView
98 {
99     Q_OBJECT
100 
101     static constexpr qreal EDGE_LENGTH_DEFAULT = 300.0;
102     static constexpr qreal EDGE_LENGTH_DELTA = 30.0;
103     static constexpr qreal EDGE_LENGTH_MAX = 5000.0;
104     static constexpr qreal EDGE_LENGTH_MIN = EDGE_LENGTH_DELTA*2.0;
105 
106 private:
107     QGraphicsScene* navigatorScene;
108 
109     // IMPROVE is mutex still needed?
110     std::mutex refreshMutex;
111 
112     int timerId, w, h;
113 
114     // stupid and ugly: multi-threading & weak Qt API
115     std::vector<QGraphicsItem*> garbageItems;
116 
117     // subgraph to be rendered
118     KnowledgeSubGraph* subgraph;
119 
120     qreal initialEdgeLenght;
121 
122     bool isDashboardlet;
123 
124 public:
125     NavigatorView(QWidget* parent, bool isDashboardlet=false);
126     ~NavigatorView();
127 
getInitialEdgeLenght()128     qreal getInitialEdgeLenght() const { return initialEdgeLenght; }
129     void checkAndFixInitialEdgeLength(qreal& l);
130 
131     void itemMoved();
132 
133     void iWasSelected(NavigatorNode* selectedNode);
refreshOnNextTimerTick(KnowledgeSubGraph * subgraph)134     void refreshOnNextTimerTick(KnowledgeSubGraph* subgraph) {
135         std::lock_guard<std::mutex> criticalSection{refreshMutex};
136 
137         updateNavigatorView();
138         this->subgraph = subgraph;
139         itemMoved(); // kick timer if not running
140     }
refreshOnNextTimerTick()141     void refreshOnNextTimerTick() {
142         refreshOnNextTimerTick(subgraph);
143     }
144 
145     void cleanupBeforeHide();
146 
147 protected:
148     void scaleView(qreal scaleFactor);
149 
150     void resizeEvent(QResizeEvent *event) override;
151     void keyPressEvent(QKeyEvent *event) override;
152     void timerEvent(QTimerEvent *event) override;
153 #ifndef QT_NO_WHEELEVENT
154     void wheelEvent(QWheelEvent *event) override;
155 #endif
156     void mousePressEvent(QMouseEvent* mouseEvent) override;
157 
158 private:
159     void updateNavigatorView();
160     void clearGarbageItems();
161 
162 signals:
163     void nodeSelectedSignal(NavigatorNode* selectedNode);
164     void clickToSwitchFacet();
165 
166 public slots:
167     void shuffle();
168     void zoomIn();
169     void zoomOut();
170 };
171 
172 }
173 #endif // M8R_NAVIGATOR_VIEW_H
174