1 /**********************************************************************************************
2     Copyright (C) 2014 Oliver Eichler <oliver.eichler@gmx.de>
3     Copyright (C) 2017 Norbert Truchsess <norbert.truchsess@t-online.de>
4 
5     This program is free software: you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation, either version 3 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 
18 **********************************************************************************************/
19 
20 #ifndef CGISWORKSPACE_H
21 #define CGISWORKSPACE_H
22 
23 #include "ui_IGisWorkspace.h"
24 #include <QEvent>
25 #include <QSqlDatabase>
26 #include <QWidget>
27 
28 #include "db/IDBFolder.h"
29 #include "gis/IGisItem.h"
30 #include "gis/rte/router/IRouter.h"
31 #include "gis/search/CSearchLineEdit.h"
32 #include "helpers/Tristate.h"
33 
34 
35 class CGisDraw;
36 class IGisProject;
37 class CSearchExplanationDialog;
38 struct poi_t;
39 
40 enum event_types_e
41 {
42     eEvtD2WReqInfo     = QEvent::User + 1
43     , eEvtD2WShowFolder  = QEvent::User + 2
44     , eEvtD2WHideFolder  = QEvent::User + 3
45     , eEvtD2WShowItems   = QEvent::User + 4
46     , eEvtD2WHideItems   = QEvent::User + 5
47     , eEvtD2WUpdateLnF   = QEvent::User + 6
48     , eEvtD2WUpdateItems = QEvent::User + 7
49     , eEvtD2WReload      = QEvent::User + 8
50 
51     , eEvtW2DAckInfo     = QEvent::User + 100
52     , eEvtW2DCreate      = QEvent::User + 101
53 
54     , eEvtA2WCutTrk      = QEvent::User + 200
55     , eEvtA2WSave        = QEvent::User + 201
56     , eEvtA2WSync        = QEvent::User + 202
57 };
58 
59 struct evt_item_t
60 {
evt_item_tevt_item_t61     evt_item_t(quint64 id, quint32 type) : id(id), type(type)
62     {
63     }
64     quint64 id;
65     quint32 type;
66 };
67 
68 class CEvtD2WReqInfo : public QEvent
69 {
70 public:
CEvtD2WReqInfo(quint64 id,const QString & db)71     CEvtD2WReqInfo(quint64 id, const QString& db) : QEvent(QEvent::Type(eEvtD2WReqInfo)), id(id), db(db)
72     {
73     }
74 
75     quint64 id;
76     QString db;
77 };
78 
79 class CEvtD2WShowFolder : public QEvent
80 {
81 public:
CEvtD2WShowFolder(quint64 id,const QString & db)82     CEvtD2WShowFolder(quint64 id, const QString& db) : QEvent(QEvent::Type(eEvtD2WShowFolder)), id(id), db(db)
83     {
84     }
85 
86     quint64 id;
87     QString db;
88 };
89 
90 class CEvtD2WHideFolder : public QEvent
91 {
92 public:
CEvtD2WHideFolder(quint64 id,const QString & db)93     CEvtD2WHideFolder(quint64 id, const QString& db) : QEvent(QEvent::Type(eEvtD2WHideFolder)), id(id), db(db)
94     {
95     }
96 
97     quint64 id;
98     QString db;
99 };
100 
101 class CEvtD2WShowItems : public QEvent
102 {
103 public:
CEvtD2WShowItems(quint64 id,const QString & db)104     CEvtD2WShowItems(quint64 id, const QString& db) : QEvent(QEvent::Type(eEvtD2WShowItems)), id(id), db(db)
105     {
106     }
107 
108     /// if true only the items in the list are loaded. Any other item loaded but not part of the list will be removed.
109     bool addItemsExclusively = false;
110     quint64 id;
111     QString db;
112     QList<evt_item_t> items;
113 };
114 
115 class CEvtD2WHideItems : public QEvent
116 {
117 public:
CEvtD2WHideItems(quint64 id,const QString & db)118     CEvtD2WHideItems(quint64 id, const QString& db) : QEvent(QEvent::Type(eEvtD2WHideItems)), id(id), db(db)
119     {
120     }
121 
122     quint64 id;
123     QString db;
124     QSet<QString> keys;
125 };
126 
127 class CEvtW2DAckInfo : public QEvent
128 {
129 public:
CEvtW2DAckInfo(Qt::CheckState checkState,quint64 id,const QString & db,const QString & host)130     CEvtW2DAckInfo(Qt::CheckState checkState, quint64 id, const QString& db, const QString& host)
131         : QEvent(QEvent::Type(eEvtW2DAckInfo))
132         , checkState(checkState)
133         , id(id)
134         , db(db)
135         , host(host)
136     {
137     }
138 
CEvtW2DAckInfo(quint64 id,const QString & db,const QString & host)139     CEvtW2DAckInfo(quint64 id, const QString& db, const QString& host)
140         : QEvent(QEvent::Type(eEvtW2DAckInfo))
141         , id(id)
142         , db(db)
143         , host(host)
144     {
145     }
146 
147     Qt::CheckState checkState = Qt::Unchecked;
148     bool updateLostFound = false;
149     quint64 id;
150     QString db;
151     QString host;
152     QSet<QString> keysChildren;
153 };
154 
155 class CEvtD2WUpdateLnF : public QEvent
156 {
157 public:
CEvtD2WUpdateLnF(quint64 id,const QString & db)158     CEvtD2WUpdateLnF(quint64 id, const QString& db) : QEvent(QEvent::Type(eEvtD2WUpdateLnF)), id(id), db(db)
159     {
160     }
161 
162     quint64 id;
163     QString db;
164 };
165 
166 class CEvtW2DCreate : public QEvent
167 {
168 public:
CEvtW2DCreate(const QString & name,IDBFolder::type_e type,quint64 id,const QString & db,const QString & host)169     CEvtW2DCreate(const QString& name, IDBFolder::type_e type, quint64 id, const QString& db, const QString& host)
170         : QEvent(QEvent::Type(eEvtW2DCreate))
171         , name(name)
172         , type(type)
173         , idParent(id)
174         , db(db)
175         , host(host)
176     {
177     }
178 
179     QString name;
180     IDBFolder::type_e type;
181     quint64 idParent;
182     quint64 idChild = 0;
183     QString db;
184     QString host;
185 };
186 
187 class CEvtD2WUpdateItems : public QEvent
188 {
189 public:
CEvtD2WUpdateItems(quint64 id,const QString & db)190     CEvtD2WUpdateItems(quint64 id, const QString& db) : QEvent(QEvent::Type(eEvtD2WUpdateItems)), id(id), db(db)
191     {
192     }
193 
194     quint64 id;
195     QString db;
196 };
197 
198 class CEvtD2WReload : public QEvent
199 {
200 public:
CEvtD2WReload(const QString & db)201     CEvtD2WReload(const QString& db) : QEvent(QEvent::Type(eEvtD2WReload)), db(db)
202     {
203     }
204 
205     QString db;
206 };
207 
208 
209 class CEvtA2WCutTrk : public QEvent
210 {
211 public:
CEvtA2WCutTrk(const IGisItem::key_t & key)212     CEvtA2WCutTrk(const IGisItem::key_t& key) : QEvent(QEvent::Type(eEvtA2WCutTrk)), key(key)
213     {
214     }
215 
216     const IGisItem::key_t key;
217 };
218 
219 class CEvtA2WSave : public QEvent
220 {
221 public:
CEvtA2WSave(const QString & key)222     CEvtA2WSave(const QString& key) : QEvent(QEvent::Type(eEvtA2WSave)), key(key)
223     {
224     }
225 
226     const QString key;
227 };
228 
229 class CEvtA2WSync : public QEvent
230 {
231 public:
CEvtA2WSync(const QString & key)232     CEvtA2WSync(const QString& key) : QEvent(QEvent::Type(eEvtA2WSync)), key(key)
233     {
234     }
235 
236     const QString key;
237 };
238 
239 
240 class CGisWorkspace : public QWidget, private Ui::IGisWorkspace
241 {
242     Q_OBJECT
243 public:
self()244     static CGisWorkspace& self()
245     {
246         return *pSelf;
247     }
248     virtual ~CGisWorkspace();
249 
250     void loadGisProject(const QString& filename);
251     /**
252        @brief Draw all loaded data in the workspace that is visible
253 
254        This method is called from The CGisDraw thread. The thread has to make sure
255        that everything is thread safe.
256 
257        @param p         the painter to be used
258        @param viewport  the viewport in units of rad
259        @param gis       the draw context to be used
260      */
261     void draw(QPainter& p, const QPolygonF& viewport, CGisDraw* gis);
262 
263     /**
264        @brief Receive the current mouse position
265 
266        Iterate over all projects and pass the position
267 
268        @param pos   the mouse position on the screen in pixel
269      */
270     void mouseMove(const QPointF& pos);
271     /**
272        @brief Draw all data that is time variant and can't wait for a full update
273 
274        This method is called directly from the main thread's paintEvent() method.
275 
276        @param p         the painter to be used
277        @param viewport  the viewport in units of rad
278        @param gis       the draw context to be used
279      */
280     void fastDraw(QPainter& p, const QRectF& viewport, CGisDraw* gis);
281 
282     /**
283        @brief Get items close to the given point
284 
285        Note: Do not store the pointers of items permanently as they can become invalid
286        once you reach the main event loop again. Store the key instead.
287 
288        @param pos       the position in pixel
289        @param items     an empty item list that will get filled with temporary pointers
290      */
291     void getItemsByPos(const QPointF& pos, QList<IGisItem*>& items);
292 
293     /**
294        @brief Get items matching the given area
295 
296        @param area      a rectangle in screen pixel coordinates
297        @param flags     flag field with IGisItem::selection_e flags set
298        @param items     a list to receive the temporary pointers to the found items
299      */
300     void getItemsByArea(const QRectF& area, IGisItem::selflags_t flags, QList<IGisItem*>& items);
301 
302     /**
303        @brief Find first item with matching key
304        @param key       the item's key as it is returned from IGisItem::getKey()
305        @return If no item is found 0 is returned.
306      */
307     IGisItem* getItemByKey(const IGisItem::key_t& key);
308 
309     void getItemsByKeys(const QList<IGisItem::key_t>& keys, QList<IGisItem*>& items);
310 
311     void getNogoAreas(QList<IGisItem*>& nogos);
312 
313     /**
314        @brief Delete all items with matching key from workspace
315 
316        @param key       the item's key as it is returned from IGisItem::getKey()
317      */
318     void delItemByKey(const IGisItem::key_t& key);
319 
320     void delItemsByKey(const QList<IGisItem::key_t>& keys);
321 
322     /**
323        @brief Edit / view item details
324        @param key       the item's key as it is returned from IGisItem::getKey()
325      */
326     void editItemByKey(const IGisItem::key_t& key);
327 
328     /**
329        @brief Select a project and add a copy of the item to the project
330        @param key       the item's key as it is returned from IGisItem::getKey()
331      */
332     void copyItemByKey(const IGisItem::key_t& key);
333 
334     /**
335        @brief Select a project and add a copy of all items in the list
336        @param keys      a list of item keys to copy
337      */
338     IGisProject* copyItemsByKey(const QList<IGisItem::key_t>& keys);
339 
340     /**
341        @brief Clone waypoint and move clone
342        @param key       the item's key as it is returned from IGisItem::getKey()
343      */
344     void projWptByKey(const IGisItem::key_t& key);
345 
346     /**
347        @brief Move waypoint via mouse
348        @param key       the item's key as it is returned from IGisItem::getKey()
349      */
350     void moveWptByKey(const IGisItem::key_t& key);
351 
352     /**
353        @brief Add a new waypoint by Position
354        @param pt    the position in degrees
355      */
356     void addWptByPos(const QPointF& pt, const QString& name = QString::Null(), const QString& desc = QString::Null()) const;
357 
358     void addPoisAsWpt(const QSet<poi_t>& pois, IGisProject* project = nullptr) const;
359     void addPoiAsWpt(const poi_t& poi, IGisProject* project = nullptr) const;
360     void addPoiAsWpt(const poi_t& poi, tristate_e& openEditWindow, IGisProject* project = nullptr) const;
361 
362     void toggleWptBubble(const IGisItem::key_t& key);
363 
364     void deleteWptRadius(const IGisItem::key_t& key);
365 
366     void toggleNogoItem(const IGisItem::key_t& key);
367 
368     void editWptRadius(const IGisItem::key_t& key);
369 
370     void copyWptCoordByKey(const IGisItem::key_t& key);
371 
372     /**
373        @brief Set user focus to track
374        @param yes       true if focus is set
375        @param key       the item's key as it is returned from IGisItem::getKey()
376      */
377     void focusTrkByKey(bool yes, const IGisItem::key_t& key);
378 
379     void focusRteByKey(bool yes, const IGisItem::key_t& key);
380 
381     void convertRouteToTrack(const IGisItem::key_t& key);
382 
383     void convertTrackToRoute(const IGisItem::key_t& key);
384 
385     void cutTrkByKey(const IGisItem::key_t& key);
386 
387     void addTrkInfoByKey(const IGisItem::key_t& key);
388 
389     void editTrkByKey(const IGisItem::key_t& key);
390 
391     void reverseTrkByKey(const IGisItem::key_t& key);
392 
393     /**
394        @brief Combine all tracks in a given track's project
395 
396        This will collect all tracks in a project and pass them
397        to the track combine dialog.
398 
399        @param keyTrk    the key of the first track
400      */
401     void combineTrkByKey(const IGisItem::key_t& keyTrk);
402 
403     /**
404        @brief Combine al tracks in the given list of keys.
405 
406        @param keys  a list of GIS item keys
407      */
408     void combineTrkByKey(const QList<IGisItem::key_t>& keys, const QList<IGisItem::key_t>& keysPreSel);
409 
410     void colorTrkByKey(const QList<IGisItem::key_t>& keys);
411 
412     void rangeTrkByKey(const IGisItem::key_t& key);
413 
414     void copyTrkWithWptByKey(const IGisItem::key_t& key);
415 
416     void editRteByKey(const IGisItem::key_t& key);
417 
418     void reverseRteByKey(const IGisItem::key_t& key);
419 
420     void calcRteByKey(const IGisItem::key_t& key);
421 
422     void resetRteByKey(const IGisItem::key_t& key);
423 
424     void editAreaByKey(const IGisItem::key_t& key);
425 
426     void makeRteFromWpt(const QList<IGisItem::key_t>& keys);
427 
428     void editPrxWpt(const QList<IGisItem::key_t>& keys);
429 
430     void changeWptSymByKey(const QList<IGisItem::key_t>& keys, const QString& sym);
431 
432     void addEleToWptTrkByKey(const QList<IGisItem::key_t>& keys);
433 
434     void searchWebByKey(const IGisItem::key_t& key);
435 
436     /**
437        @brief Select a project via dialog
438 
439        If a new project name is entered a new project is created. Else the pointer
440        to an existing project is passed back.
441 
442        @return 0 if no project was selected.
443      */
444     IGisProject* selectProject(bool forceSelect);
445 
446     void postEventForWks(QEvent* event);
447 
448     void setOpacity(qreal val);
449 
450     bool findPolylineCloseBy(const QPointF& pt1, const QPointF& pt2, qint32 threshold, QPolygonF& polyline);
451 
452     bool areTagsHidden() const;
453     void setTagsHidden(bool hidden);
454 
455     void tagItemsByKey(const QList<IGisItem::key_t>& keys);
456 
getCurrentSearch()457     const CSearch& getCurrentSearch() const
458     {
459         return currentSearch;
460     }
461 
462 signals:
463     void sigChanged();
464 
465 public slots:
466     void slotLateInit();
467     void slotSaveAll();
468     void slotWksItemSelectionReset();
469     void slotActivityTrkByKey(const QList<IGisItem::key_t>& keys, trkact_t act);
470 
471 private slots:
472     void slotSetGisLayerOpacity(int val);
473     void slotSearch(const CSearch& currentSearch);
474 
475     void slotWksItemSelectionChanged();
476     void slotWksItemPressed(QTreeWidgetItem* item);
477 
478 private:
479     friend class CMainWindow;
480     CGisWorkspace(QMenu* menuProject, QWidget* parent);
481 
482     static CGisWorkspace* pSelf;
483 
484     /**
485         The item key of last item pressed in the workspace list.
486         The key will be reset by getItemsByPos() which is used by
487         the mouse object to find items close by for highlight.
488      */
489     IGisItem::key_t keyWksSelection;
490     CSearch currentSearch;
491 
492     enum tags_hidden_e
493     {
494         eTagsHiddenTrue,
495         eTagsHiddenFalse,
496         eTagsHiddenUnknown
497     };
498 };
499 
500 #endif //CGISWORKSPACE_H
501 
502