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 
27 extern const char *libindi_strings_context;
28 
29 GUIManager *GUIManager::_GUIManager = nullptr;
30 
31 GUIManager *GUIManager::Instance()
32 {
33  if (_GUIManager == nullptr)
34  _GUIManager = new GUIManager(
35  Options::independentWindowINDI() ? nullptr : KStars::Instance());
36 
37  return _GUIManager;
38 }
39 
40 void GUIManager::release()
41 {
42  delete _GUIManager;
43 }
44 
45 GUIManager::GUIManager(QWidget *parent) : QWidget(parent, Qt::Window)
46 {
47 #ifdef Q_OS_OSX
48  if (Options::independentWindowINDI())
50  else
51  {
54  SIGNAL(applicationStateChanged(Qt::ApplicationState)), this,
55  SLOT(changeAlwaysOnTop(Qt::ApplicationState)));
56  }
57 #endif
58 
59  mainLayout = new QVBoxLayout(this);
60  mainLayout->setContentsMargins(10, 10, 10, 10);
61  mainLayout->setSpacing(10);
62 
63  mainTabWidget = new QTabWidget(this);
64 
65  mainLayout->addWidget(mainTabWidget);
66 
67  setWindowIcon(QIcon::fromTheme("kstars_indi"));
68 
69  setWindowTitle(i18nc("@title:window", "INDI Control Panel"));
71 
72  clearB = new QPushButton(i18n("Clear"));
73  closeB = new QPushButton(i18n("Close"));
74 
75  QHBoxLayout *buttonLayout = new QHBoxLayout;
76  buttonLayout->insertStretch(0);
77  buttonLayout->addWidget(clearB, 0, Qt::AlignRight);
78  buttonLayout->addWidget(closeB, 0, Qt::AlignRight);
79 
80  mainLayout->addLayout(buttonLayout);
81 
82  connect(closeB, SIGNAL(clicked()), this, SLOT(close()));
83  connect(clearB, SIGNAL(clicked()), this, SLOT(clearLog()));
84 
85  resize(Options::iNDIWindowWidth(), Options::iNDIWindowHeight());
86 }
87 
88 GUIManager::~GUIManager()
89 {
90  for (auto oneClient : qAsConst(clients))
91  oneClient->disconnect(this);
92 }
93 
94 void GUIManager::changeAlwaysOnTop(Qt::ApplicationState state)
95 {
96  if (isVisible())
97  {
98  if (state == Qt::ApplicationActive)
100  else
102  show();
103  }
104 }
105 
106 void GUIManager::closeEvent(QCloseEvent * /*event*/)
107 {
108  KStars *ks = KStars::Instance();
109 
110  if (ks)
111  {
112  QAction *showINDIPanel =
113  KStars::Instance()->actionCollection()->action("show_control_panel");
114  showINDIPanel->setChecked(false);
115  }
116 
117  Options::setINDIWindowWidth(width());
118  Options::setINDIWindowHeight(height());
119 }
120 
121 void GUIManager::hideEvent(QHideEvent * /*event*/)
122 {
123  KStars *ks = KStars::Instance();
124 
125  if (ks)
126  {
127  QAction *a = KStars::Instance()->actionCollection()->action("show_control_panel");
128  a->setChecked(false);
129  }
130 }
131 
132 void GUIManager::showEvent(QShowEvent * /*event*/)
133 {
134  QAction *a = KStars::Instance()->actionCollection()->action("show_control_panel");
135  a->setEnabled(true);
136  a->setChecked(true);
137 }
138 
139 /*********************************************************************
140 ** Traverse the drivers list, check for updated drivers and take
141 ** appropriate action
142 *********************************************************************/
143 void GUIManager::updateStatus(bool toggle_behavior)
144 {
145  QAction *showINDIPanel =
146  KStars::Instance()->actionCollection()->action("show_control_panel");
147 
148  if (guidevices.count() == 0)
149  {
150  KSNotification::error(i18n("No INDI devices currently running. To run devices, "
151  "please select devices from the "
152  "Device Manager in the devices menu."));
153  showINDIPanel->setChecked(false);
154  showINDIPanel->setEnabled(false);
155  return;
156  }
157 
158  showINDIPanel->setChecked(true);
159 
160  if (isVisible() && isActiveWindow() && toggle_behavior)
161  {
162  hide();
163  }
164  else
165  {
166  raise();
167  activateWindow();
168  showNormal();
169  }
170 }
171 
172 INDI_D *GUIManager::findGUIDevice(const QString &deviceName)
173 {
174  for (auto oneGUIDevice : guidevices)
175  {
176  if (oneGUIDevice->name() == deviceName)
177  return oneGUIDevice;
178  }
179 
180  return nullptr;
181 }
182 
183 void GUIManager::clearLog()
184 {
185  INDI_D *dev = findGUIDevice(
186  mainTabWidget->tabText(mainTabWidget->currentIndex()).remove(QChar('&')));
187 
188  if (dev)
189  dev->clearMessageLog();
190 }
191 
192 void GUIManager::addClient(ClientManager *cm)
193 {
194  clients.append(cm);
195  connect(cm, &ClientManager::newINDIDevice, this, &GUIManager::buildDevice);
196  connect(cm, &ClientManager::removeINDIDevice, this, &GUIManager::removeDevice);
197 }
198 
199 void GUIManager::removeClient(ClientManager *cm)
200 {
201  clients.removeOne(cm);
202 
203  QMutableListIterator<INDI_D *> it(guidevices);
204  while (it.hasNext())
205  {
206  INDI_D *gdv = it.next();
207 
208  if (gdv->getClientManager() == cm)
209  {
210  for (int i = 0; i < mainTabWidget->count(); i++)
211  {
212  if (mainTabWidget->tabText(i).remove('&') == QString(gdv->name()))
213  {
214  mainTabWidget->removeTab(i);
215  break;
216  }
217  }
218 
219  it.remove();
220  gdv->deleteLater();
221  }
222  }
223 
224  if (clients.size() == 0)
225  hide();
226 }
227 
228 void GUIManager::removeDevice(const QString &name)
229 {
230  INDI_D *dp = findGUIDevice(name);
231 
232  if (dp == nullptr)
233  return;
234 
235  if (dp->getClientManager())
236  dp->getClientManager()->disconnect(dp);
237  dp->disconnect();
238 
239  // Hack to give mainTabWidget sometime to remove its item as these calls are coming from a different thread
240  // the clientmanager thread. Sometimes removeTab() requires sometime to be removed properly and hence the wait.
241  if (mainTabWidget->count() != guidevices.count())
242  QThread::msleep(100);
243 
244  for (int i = 0; i < mainTabWidget->count(); i++)
245  {
246  if (mainTabWidget->tabText(i).remove('&') == name)
247  {
248  mainTabWidget->removeTab(i);
249  break;
250  }
251  }
252 
253  guidevices.removeOne(dp);
254  dp->deleteLater();
255 
256  if (guidevices.isEmpty())
257  {
258  QAction *showINDIPanel =
259  KStars::Instance()->actionCollection()->action("show_control_panel");
260  showINDIPanel->setEnabled(false);
261  }
262 }
263 
264 void GUIManager::buildDevice(DeviceInfo *di)
265 {
266  ClientManager *cm = qobject_cast<ClientManager *>(sender());
267  Q_ASSERT_X(cm, __FUNCTION__, "Client manager is not valid.");
268 
269  INDI_D *gdm = new INDI_D(mainTabWidget, di->getBaseDevice(), cm);
270 
271  connect(cm, &ClientManager::newINDIProperty, gdm, &INDI_D::buildProperty);
272  connect(cm, &ClientManager::removeINDIProperty, gdm, &INDI_D::removeProperty);
273  connect(cm, &ClientManager::newINDISwitch, gdm, &INDI_D::updateSwitchGUI);
274  connect(cm, &ClientManager::newINDIText, gdm, &INDI_D::updateTextGUI);
275  connect(cm, &ClientManager::newINDINumber, gdm, &INDI_D::updateNumberGUI);
276  connect(cm, &ClientManager::newINDILight, gdm, &INDI_D::updateLightGUI);
277  connect(cm, &ClientManager::newINDIBLOB, gdm, &INDI_D::updateBLOBGUI);
278  connect(cm, &ClientManager::newINDIMessage, gdm, &INDI_D::updateMessageLog);
279 
280  // Build existing properties.
281  for (const auto &oneProperty : di->getBaseDevice()->getProperties())
282  gdm->buildProperty(oneProperty);
283 
284  QString deviceName = di->getDeviceName();
285  int index = mainTabWidget->count();
286  for (int i = 0; i < mainTabWidget->count(); i++)
287  {
288  if (mainTabWidget->tabText(i) > deviceName)
289  {
290  index = i;
291  break;
292  }
293  }
294 
295  mainTabWidget->insertTab(index, gdm, di->getDeviceName());
296  guidevices.insert(index, gdm);
297 
298  updateStatus(false);
299 }
void append(const T &value)
void setWindowIcon(const QIcon &icon)
void msleep(unsigned long msecs)
AlignRight
QAction * action(const QString &name) const
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
int count(const T &value) const const
QIcon fromTheme(const QString &name)
QObject * sender() const const
void setAttribute(Qt::WidgetAttribute attribute, bool on)
bool close()
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void hide()
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
static KStars * Instance()
Definition: kstars.h:125
bool isVisible() const const
int size() const const
void deleteLater()
QString i18n(const char *text, const TYPE &arg...)
void setWindowFlags(Qt::WindowFlags type)
bool removeOne(const T &value)
void showNormal()
void setWindowTitle(const QString &)
QCoreApplication * instance()
void activateWindow()
This is the main window for KStars. In addition to the GUI elements, the class contains the program c...
Definition: kstars.h:92
QString & remove(int position, int n)
void show()
void resize(int w, int h)
int insertTab(int index, QWidget *page, const QString &label)
virtual KActionCollection * actionCollection() const
void setEnabled(bool)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
void removeTab(int index)
void setChecked(bool)
ApplicationState
WA_ShowModal
QString tabText(int index) const const
void insertStretch(int index, int stretch)
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Fri Aug 19 2022 03:57:51 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.