Kstars

guimanager.cpp
1/*
2 SPDX-FileCopyrightText: 2012 Jasem Mutlaq
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#include "guimanager.h"
8
9#include "clientmanager.h"
10#include "deviceinfo.h"
11#include "indidevice.h"
12#include "kstars.h"
13#include "Options.h"
14#include "fitsviewer/fitsviewer.h"
15#include "ksnotification.h"
16
17#include <KActionCollection>
18#include <KMessageBox>
19
20#include <QApplication>
21#include <QSplitter>
22#include <QTextEdit>
23#include <QPushButton>
24#include <QThread>
25#include <QAction>
26
27extern const char *libindi_strings_context;
28
29GUIManager *GUIManager::_GUIManager = nullptr;
30
31GUIManager *GUIManager::Instance()
32{
33 if (_GUIManager == nullptr)
34 {
35 _GUIManager = new GUIManager(
36 Options::independentWindowINDI() ? nullptr : KStars::Instance());
37 }
38
39 return _GUIManager;
40}
41
42void GUIManager::release()
43{
44 delete _GUIManager;
45 _GUIManager = nullptr;
46}
47
48GUIManager::GUIManager(QWidget *parent) : QWidget(parent, Qt::Window)
49{
50#ifdef Q_OS_MACOS
51 if (Options::independentWindowINDI())
52 setWindowFlags(Qt::Window);
53 else
54 {
55 setWindowFlags(Qt::Window | Qt::WindowStaysOnTopHint);
57 SIGNAL(applicationStateChanged(Qt::ApplicationState)), this,
58 SLOT(changeAlwaysOnTop(Qt::ApplicationState)));
59 }
60#endif
61
62 mainLayout = new QVBoxLayout(this);
63 mainLayout->setContentsMargins(10, 10, 10, 10);
64 mainLayout->setSpacing(10);
65
66 mainTabWidget = new QTabWidget(this);
67
68 mainLayout->addWidget(mainTabWidget);
69
70 setWindowIcon(QIcon::fromTheme("kstars_indi"));
71
72 setWindowTitle(i18nc("@title:window", "INDI Control Panel"));
73 setAttribute(Qt::WA_ShowModal, false);
74
75 clearB = new QPushButton(i18n("Clear"));
76 closeB = new QPushButton(i18n("Close"));
77
78 QHBoxLayout *buttonLayout = new QHBoxLayout;
79 buttonLayout->insertStretch(0);
80 buttonLayout->addWidget(clearB, 0, Qt::AlignRight);
81 buttonLayout->addWidget(closeB, 0, Qt::AlignRight);
82
83 mainLayout->addLayout(buttonLayout);
84
85 connect(closeB, SIGNAL(clicked()), this, SLOT(close()));
86 connect(clearB, SIGNAL(clicked()), this, SLOT(clearLog()));
87
88 resize(Options::iNDIWindowWidth(), Options::iNDIWindowHeight());
89
90 QAction *showINDIPanel =
91 KStars::Instance()->actionCollection()->action("show_control_panel");
92 showINDIPanel->setChecked(Options::showINDIwindowInitially());
93}
94
95GUIManager::~GUIManager()
96{
97 for (auto oneClient : qAsConst(clients))
98 oneClient->disconnect(this);
99}
100
101void GUIManager::changeAlwaysOnTop(Qt::ApplicationState state)
102{
103 if (isVisible())
104 {
105 if (state == Qt::ApplicationActive)
107 else
109 show();
110 }
111}
112
113void GUIManager::closeEvent(QCloseEvent * /*event*/)
114{
115 KStars *ks = KStars::Instance();
116
117 if (ks)
118 {
119 QAction *showINDIPanel =
120 KStars::Instance()->actionCollection()->action("show_control_panel");
121 showINDIPanel->setChecked(false);
122 }
123
124 Options::setINDIWindowWidth(width());
125 Options::setINDIWindowHeight(height());
126}
127
128void GUIManager::hideEvent(QHideEvent * /*event*/)
129{
130 KStars *ks = KStars::Instance();
131
132 if (ks)
133 {
134 QAction *a = KStars::Instance()->actionCollection()->action("show_control_panel");
135 a->setChecked(false);
136 }
137}
138
139void GUIManager::showEvent(QShowEvent * /*event*/)
140{
141 QAction *a = KStars::Instance()->actionCollection()->action("show_control_panel");
142 a->setChecked(true);
143}
144
145/*********************************************************************
146** Traverse the drivers list, check for updated drivers and take
147** appropriate action
148*********************************************************************/
149void GUIManager::updateStatus(bool toggle_behavior)
150{
151 QAction *showINDIPanel =
152 KStars::Instance()->actionCollection()->action("show_control_panel");
153
154 if (guidevices.count() == 0)
155 {
156 KSNotification::error(i18n("No INDI devices currently running. To run devices, "
157 "please select devices from the "
158 "Device Manager in the devices menu."));
159 showINDIPanel->setChecked(false);
160 showINDIPanel->setEnabled(false);
161 return;
162 }
163
164 // enable the INDI button if at least one device has been recognized
165 showINDIPanel->setEnabled(getDevices().size() > 0);
166
167 if (toggle_behavior)
168 showINDIPanel->setChecked(! showINDIPanel->isChecked());
169
170 if (showINDIPanel->isChecked())
171 {
172 raise();
174 showNormal();
175 }
176 else
177 {
178 hide();
179 }
180}
181
182INDI_D *GUIManager::findGUIDevice(const QString &deviceName)
183{
184 for (auto oneGUIDevice : guidevices)
185 {
186 if (oneGUIDevice->name() == deviceName)
187 return oneGUIDevice;
188 }
189
190 return nullptr;
191}
192
193void GUIManager::clearLog()
194{
195 INDI_D *dev = findGUIDevice(
196 mainTabWidget->tabText(mainTabWidget->currentIndex()).remove(QChar('&')));
197
198 if (dev)
199 dev->clearMessageLog();
200}
201
202void GUIManager::addClient(ClientManager *cm)
203{
204 clients.append(cm);
205 connect(cm, &ClientManager::newINDIDevice, this, &GUIManager::buildDevice);
206 connect(cm, &ClientManager::removeINDIDevice, this, &GUIManager::removeDevice);
207}
208
209void GUIManager::removeClient(ClientManager *cm)
210{
211 clients.removeOne(cm);
212
213 QMutableListIterator<INDI_D *> it(guidevices);
214 while (it.hasNext())
215 {
216 INDI_D *gdv = it.next();
217
218 if (gdv->getClientManager() == cm)
219 {
220 for (int i = 0; i < mainTabWidget->count(); i++)
221 {
222 if (mainTabWidget->tabText(i).remove('&') == QString(gdv->name()))
223 {
224 mainTabWidget->removeTab(i);
225 break;
226 }
227 }
228
229 it.remove();
230 gdv->deleteLater();
231 }
232 }
233
234 if (clients.size() == 0)
235 hide();
236}
237
238void GUIManager::removeDevice(const QString &name)
239{
240 INDI_D *dp = findGUIDevice(name);
241
242 if (dp == nullptr)
243 return;
244
245 if (dp->getClientManager())
246 dp->getClientManager()->disconnect(dp);
247 dp->disconnect();
248
249 // Hack to give mainTabWidget sometime to remove its item as these calls are coming from a different thread
250 // the clientmanager thread. Sometimes removeTab() requires sometime to be removed properly and hence the wait.
251 if (mainTabWidget->count() != guidevices.count())
252 QThread::msleep(100);
253
254 for (int i = 0; i < mainTabWidget->count(); i++)
255 {
256 if (mainTabWidget->tabText(i).remove('&') == name)
257 {
258 mainTabWidget->removeTab(i);
259 break;
260 }
261 }
262
263 guidevices.removeOne(dp);
264 dp->deleteLater();
265
266 if (guidevices.isEmpty())
267 {
268 QAction *showINDIPanel =
269 KStars::Instance()->actionCollection()->action("show_control_panel");
270 showINDIPanel->setEnabled(false);
271 }
272}
273
274void GUIManager::buildDevice(DeviceInfo *di)
275{
277 Q_ASSERT_X(cm, __FUNCTION__, "Client manager is not valid.");
278
279 INDI_D *gdm = new INDI_D(mainTabWidget, di->getBaseDevice(), cm);
280
281 connect(cm, &ClientManager::newINDIProperty, gdm, &INDI_D::buildProperty);
282 connect(cm, &ClientManager::removeINDIProperty, gdm, &INDI_D::removeProperty);
283 connect(cm, &ClientManager::updateINDIProperty, gdm, &INDI_D::updateProperty);
284 connect(cm, &ClientManager::newINDIMessage, gdm, &INDI_D::updateMessageLog);
285
286 // Build existing properties.
287 for (auto &oneProperty : di->getBaseDevice().getProperties())
288 gdm->buildProperty(oneProperty);
289
290 auto deviceName = di->getDeviceName();
291 auto index = mainTabWidget->count();
292 for (int i = 0; i < mainTabWidget->count(); i++)
293 {
294 if (mainTabWidget->tabText(i) > deviceName)
295 {
296 index = i;
297 break;
298 }
299 }
300
301 mainTabWidget->insertTab(index, gdm, di->getDeviceName());
302 guidevices.insert(index, gdm);
303
304 updateStatus(false);
305}
ClientManager manages connection to INDI server, creation of devices, and receiving/sending propertie...
DeviceInfo is simple class to hold DriverInfo and INDI::BaseDevice associated with a particular devic...
Definition deviceinfo.h:21
GUIManager creates the INDI Control Panel upon receiving a new device.
Definition guimanager.h:34
INDI_D represents an INDI GUI Device.
Definition indidevice.h:35
Q_INVOKABLE QAction * action(const QString &name) const
This is the main window for KStars.
Definition kstars.h:89
static KStars * Instance()
Definition kstars.h:121
virtual KActionCollection * actionCollection() const
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
KGuiItem close()
void setChecked(bool)
void setEnabled(bool)
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
void insertStretch(int index, int stretch)
QCoreApplication * instance()
QIcon fromTheme(const QString &name)
void append(QList< T > &&value)
qsizetype count() const const
bool removeOne(const AT &t)
qsizetype size() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void deleteLater()
bool disconnect(const QMetaObject::Connection &connection)
T qobject_cast(QObject *object)
QObject * sender() const const
QString & remove(QChar ch, Qt::CaseSensitivity cs)
AlignRight
ApplicationState
WA_ShowModal
int insertTab(int index, QWidget *page, const QIcon &icon, const QString &label)
void removeTab(int index)
QString tabText(int index) const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
void msleep(unsigned long msecs)
void activateWindow()
void hide()
void raise()
void show()
void showNormal()
bool isVisible() const const
void setWindowFlags(Qt::WindowFlags type)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 4 2024 16:38:43 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.