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