1 /**********************************************************************************************
2     Copyright (C) 2018 Oliver Eichler <oliver.eichler@gmx.de>
3 
4     This program is free software: you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation, either version 3 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License
15     along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 
17 **********************************************************************************************/
18 
19 #include "helpers/CSettings.h"
20 #include "realtime/CRtDraw.h"
21 #include "realtime/CRtSelectSource.h"
22 #include "realtime/CRtWorkspace.h"
23 #include "realtime/opensky/CRtOpenSky.h"
24 
25 #include <QtWidgets>
26 
27 CRtWorkspace* CRtWorkspace::pSelf = nullptr;
28 
CRtWorkspace(QWidget * parent)29 CRtWorkspace::CRtWorkspace(QWidget* parent)
30     : QWidget(parent)
31 {
32     pSelf = this;
33     setupUi(this);
34     connect(this, &CRtWorkspace::sigChanged, this, &CRtWorkspace::slotChanged);
35 
36     menu = new QMenu(treeWidget);
37     menu->addAction(actionAddSource);
38     menu->addAction(actionDeleteSource);
39 
40     connect(treeWidget, &QTreeWidget::itemChanged, this, &CRtWorkspace::slotItemChanged);
41     connect(treeWidget, &QTreeWidget::customContextMenuRequested, this, &CRtWorkspace::slotContextMenu);
42     connect(treeWidget, &QTreeWidget::itemClicked, this, &CRtWorkspace::slotItemClicked);
43     connect(actionAddSource, &QAction::triggered, this, &CRtWorkspace::slotAddSource);
44     connect(actionDeleteSource, &QAction::triggered, this, &CRtWorkspace::slotDeleteSource);
45 
46     SETTINGS;
47     cfg.beginGroup("Realtime");
48     treeWidget->header()->restoreState(cfg.value("treeWks/state", treeWidget->header()->saveState()).toByteArray());
49     const int N = cfg.value("numberOfSources", 0).toInt();
50     for(int n = 0; n < N; n++)
51     {
52         cfg.beginGroup(QString("source%1").arg(n));
53         IRtSource* source = IRtSource::create(cfg.value("type", IRtSource::eTypeNone).toInt(), treeWidget);
54         if(source != nullptr)
55         {
56             connect(source, &IRtSource::sigChanged, this, &CRtWorkspace::sigChanged);
57             source->loadSettings(cfg);
58         }
59 
60         cfg.endGroup();
61     }
62 
63     treeWidget->expandAll();
64 
65     cfg.endGroup();
66 
67     labelHelp->setText(tr("To add a realtime source do a right click on the list above. "));
68     slotChanged();
69 }
70 
~CRtWorkspace()71 CRtWorkspace::~CRtWorkspace()
72 {
73     SETTINGS;
74     cfg.beginGroup("Realtime");
75     cfg.remove("");
76     cfg.setValue("treeWks/state", treeWidget->header()->saveState());
77 
78     const int N = treeWidget->topLevelItemCount();
79     cfg.setValue("numberOfSources", N);
80     for(int n = 0; n < N; n++)
81     {
82         IRtSource* source = dynamic_cast<IRtSource*>(treeWidget->topLevelItem(n));
83         if(source == nullptr)
84         {
85             continue;
86         }
87         cfg.beginGroup(QString("source%1").arg(n));
88         cfg.setValue("type", source->type);
89         source->saveSettings(cfg);
90         cfg.endGroup();
91     }
92 
93     cfg.endGroup();
94 }
95 
draw(QPainter & p,const QPolygonF & viewport,CRtDraw * rt) const96 void CRtWorkspace::draw(QPainter& p, const QPolygonF& viewport, CRtDraw* rt) const
97 {
98     QMutexLocker lock(&IRtSource::mutex);
99     QList<QRectF> blockedAreas;
100 
101     const int N = treeWidget->topLevelItemCount();
102     for(int n = 0; n < N; n++)
103     {
104         IRtSource* item = dynamic_cast<IRtSource*>(treeWidget->topLevelItem(n));
105         if(item == nullptr)
106         {
107             continue;
108         }
109 
110         item->drawItem(p, viewport, blockedAreas, rt);
111     }
112 }
113 
fastDraw(QPainter & p,const QRectF & viewport,CRtDraw * rt) const114 void CRtWorkspace::fastDraw(QPainter& p, const QRectF& viewport, CRtDraw* rt) const
115 {
116     QMutexLocker lock(&IRtSource::mutex);
117     const int N = treeWidget->topLevelItemCount();
118     for(int n = 0; n < N; n++)
119     {
120         IRtSource* item = dynamic_cast<IRtSource*>(treeWidget->topLevelItem(n));
121         if(item == nullptr)
122         {
123             continue;
124         }
125 
126         item->fastDraw(p, viewport, rt);
127     }
128 }
129 
addSource(IRtSource * source)130 void CRtWorkspace::addSource(IRtSource* source)
131 {
132     QMutexLocker lock(&IRtSource::mutex);
133     treeWidget->insertTopLevelItem(treeWidget->topLevelItemCount(), source);
134     source->registerWithTreeWidget();
135     connect(source, &IRtSource::sigChanged, this, &CRtWorkspace::sigChanged);
136     emit sigChanged();
137 }
138 
hasSourceOfType(int type) const139 bool CRtWorkspace::hasSourceOfType(int type) const
140 {
141     QMutexLocker lock(&IRtSource::mutex);
142 
143     const int N = treeWidget->topLevelItemCount();
144     for(int n = 0; n < N; n++)
145     {
146         IRtSource* item = dynamic_cast<IRtSource*>(treeWidget->topLevelItem(n));
147         if(item == nullptr)
148         {
149             continue;
150         }
151 
152         if(item->type == type)
153         {
154             return true;
155         }
156     }
157 
158     return false;
159 }
160 
mouseMove(const QPointF & pos)161 void CRtWorkspace::mouseMove(const QPointF& pos)
162 {
163     QMutexLocker lock(&IRtSource::mutex);
164     const int N = treeWidget->topLevelItemCount();
165     for(int n = 0; n < N; n++)
166     {
167         IRtSource* item = dynamic_cast<IRtSource*>(treeWidget->topLevelItem(n));
168         if(item == nullptr)
169         {
170             continue;
171         }
172         item->mouseMove(pos);
173     }
174 }
175 
slotItemChanged(QTreeWidgetItem * item,int column)176 void CRtWorkspace::slotItemChanged(QTreeWidgetItem* item, int column)
177 {
178     QMutexLocker lock(&IRtSource::mutex);
179 
180     if(column == IRtSource::eColumnCheckBox)
181     {
182         IRtSource* source = dynamic_cast<IRtSource*>(item);
183         if(source != nullptr)
184         {
185             source->blockSignals(source->checkState(IRtSource::eColumnCheckBox) == Qt::Unchecked);
186         }
187 
188         emit sigChanged();
189     }
190 }
191 
slotContextMenu(const QPoint & point)192 void CRtWorkspace::slotContextMenu(const QPoint& point)
193 {
194     actionDeleteSource->setEnabled(false);
195     QTreeWidgetItem* item = treeWidget->currentItem();
196 
197     if(item != nullptr)
198     {
199         IRtSource* source = dynamic_cast<IRtSource*>(item);
200         if(source != nullptr)
201         {
202             actionDeleteSource->setEnabled(true);
203             source->contextMenu(menu);
204         }
205         else
206         {
207             QTreeWidgetItem* child = item;
208             item = item->parent();
209             while(item != nullptr)
210             {
211                 IRtSource* source = dynamic_cast<IRtSource*>(item);
212                 if(source != nullptr)
213                 {
214                     source->contextMenuChild(child, menu);
215                     break;
216                 }
217                 item = item->parent();
218             }
219         }
220     }
221 
222     QPoint p = mapToGlobal(point);
223     menu->exec(p);
224 }
225 
slotItemClicked(QTreeWidgetItem * item,int column)226 void CRtWorkspace::slotItemClicked(QTreeWidgetItem* item, int column)
227 {
228     if(item == nullptr)
229     {
230         return;
231     }
232     IRtSource* source = dynamic_cast<IRtSource*>(item);
233     if(source != nullptr)
234     {
235         source->itemClicked(column);
236     }
237     else
238     {
239         QTreeWidgetItem* child = item;
240         item = item->parent();
241         while(item != nullptr)
242         {
243             IRtSource* source = dynamic_cast<IRtSource*>(item);
244             if(source != nullptr)
245             {
246                 source->itemClicked(child, column);
247                 break;
248             }
249             item = item->parent();
250         }
251     }
252 }
253 
slotAddSource()254 void CRtWorkspace::slotAddSource()
255 {
256     CRtSelectSource dlg(*this);
257     dlg.exec();
258 }
259 
slotDeleteSource()260 void CRtWorkspace::slotDeleteSource()
261 {
262     int res = QMessageBox::question(this, tr("Delete Source..."), tr("Do you really want to remove the realtime source?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
263     if(res != QMessageBox::Yes)
264     {
265         return;
266     }
267 
268     QMutexLocker lock(&IRtSource::mutex);
269 
270     IRtSource* source = dynamic_cast<IRtSource*>(treeWidget->currentItem());
271     if(source == nullptr)
272     {
273         return;
274     }
275 
276     delete source;
277     emit sigChanged();
278 }
279 
slotChanged()280 void CRtWorkspace::slotChanged()
281 {
282     frame->setVisible(treeWidget->topLevelItemCount() == 0);
283 }
284