LP-56 - Better txpid option namings, fix tabs-spaces, tooltips. headers, variable...
[librepilot.git] / ground / openpilotgcs / src / plugins / coreplugin / uavgadgetinstancemanager.cpp
blob17bf5a18756b653d305063f248892c84f0f36003
1 /**
2 ******************************************************************************
4 * @file uavgadgetinstancemanager.cpp
5 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
6 * @addtogroup GCSPlugins GCS Plugins
7 * @{
8 * @addtogroup CorePlugin Core Plugin
9 * @{
10 * @brief The Core GCS plugin
11 *****************************************************************************/
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 3 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 * for more details.
23 * You should have received a copy of the GNU General Public License along
24 * with this program; if not, write to the Free Software Foundation, Inc.,
25 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include "uavgadgetinstancemanager.h"
29 #include "iuavgadget.h"
30 #include "uavgadgetdecorator.h"
31 #include "iuavgadgetfactory.h"
32 #include "iuavgadgetconfiguration.h"
33 #include "uavgadgetoptionspagedecorator.h"
34 #include "coreplugin/dialogs/ioptionspage.h"
35 #include "coreplugin/dialogs/settingsdialog.h"
36 #include "icore.h"
38 #include <extensionsystem/pluginmanager.h>
39 #include <QtCore/QStringList>
40 #include <QtCore/QSettings>
41 #include <QtCore/QDebug>
42 #include <QMessageBox>
45 using namespace Core;
47 static const UAVConfigVersion m_versionUAVGadgetConfigurations = UAVConfigVersion("1.2.0");
49 UAVGadgetInstanceManager::UAVGadgetInstanceManager(QObject *parent) :
50 QObject(parent)
52 m_pm = ExtensionSystem::PluginManager::instance();
53 QList<IUAVGadgetFactory *> factories = m_pm->getObjects<IUAVGadgetFactory>();
54 foreach(IUAVGadgetFactory * f, factories) {
55 if (!m_factories.contains(f)) {
56 m_factories.append(f);
57 QString classId = f->classId();
58 QString name = f->name();
59 QIcon icon = f->icon();
60 m_classIdNameMap.insert(classId, name);
61 m_classIdIconMap.insert(classId, icon);
66 UAVGadgetInstanceManager::~UAVGadgetInstanceManager()
68 foreach(IOptionsPage * page, m_optionsPages) {
69 m_pm->removeObject(page);
70 delete page;
74 void UAVGadgetInstanceManager::readSettings(QSettings *qs)
76 while (!m_configurations.isEmpty()) {
77 emit configurationToBeDeleted(m_configurations.takeLast());
79 qs->beginGroup("UAVGadgetConfigurations");
80 UAVConfigInfo configInfo(qs);
81 configInfo.setNameOfConfigurable("UAVGadgetConfigurations");
82 if (configInfo.version() == UAVConfigVersion()) {
83 // If version is not set, assume its a old version before readable config (1.0.0).
84 // however compatibility to 1.0.0 is broken.
85 configInfo.setVersion("1.0.0");
88 if (configInfo.version() == UAVConfigVersion("1.1.0")) {
89 configInfo.notify(tr("Migrating UAVGadgetConfigurations from version 1.1.0 to ")
90 + m_versionUAVGadgetConfigurations.toString());
91 readConfigs_1_1_0(qs); // this is fully compatible with 1.2.0
92 } else if (!configInfo.standardVersionHandlingOK(m_versionUAVGadgetConfigurations)) {
93 // We are in trouble now. User wants us to quit the import, but when he saves
94 // the GCS, his old config will be lost.
95 configInfo.notify(
96 tr("You might want to save your old config NOW since it might be replaced by broken one when you exit the GCS!")
98 } else {
99 readConfigs_1_2_0(qs);
102 qs->endGroup();
103 createOptionsPages();
106 void UAVGadgetInstanceManager::readConfigs_1_2_0(QSettings *qs)
108 UAVConfigInfo configInfo;
110 foreach(QString classId, m_classIdNameMap.keys()) {
111 IUAVGadgetFactory *f = factory(classId);
113 qs->beginGroup(classId);
115 QStringList configs = QStringList();
117 configs = qs->childGroups();
118 foreach(QString configName, configs) {
119 qDebug() << "Loading config: " << classId << "," << configName;
120 qs->beginGroup(configName);
121 configInfo.read(qs);
122 configInfo.setNameOfConfigurable(classId + "-" + configName);
123 qs->beginGroup("data");
124 IUAVGadgetConfiguration *config = f->createConfiguration(qs, &configInfo);
125 if (config) {
126 config->setName(configName);
127 config->setProvisionalName(configName);
128 config->setLocked(configInfo.locked());
129 int idx = indexForConfig(m_configurations, classId, configName);
130 if (idx >= 0) {
131 // We should replace the config, but it might be used, so just
132 // throw it out of the list. The GCS should be reinitialised soon.
133 m_configurations[idx] = config;
134 } else {
135 m_configurations.append(config);
138 qs->endGroup();
139 qs->endGroup();
142 if (configs.count() == 0) {
143 IUAVGadgetConfiguration *config = f->createConfiguration(0, 0);
144 // it is not mandatory for uavgadgets to have any configurations (settings)
145 // and therefore we have to check for that
146 if (config) {
147 config->setName(tr("default"));
148 config->setProvisionalName(tr("default"));
149 m_configurations.append(config);
152 qs->endGroup();
156 void UAVGadgetInstanceManager::readConfigs_1_1_0(QSettings *qs)
158 UAVConfigInfo configInfo;
160 foreach(QString classId, m_classIdNameMap.keys()) {
161 IUAVGadgetFactory *f = factory(classId);
163 qs->beginGroup(classId);
165 QStringList configs = QStringList();
167 configs = qs->childGroups();
168 foreach(QString configName, configs) {
169 qDebug().nospace() << "Loading config: " << classId << ", " << configName;
170 qs->beginGroup(configName);
171 bool locked = qs->value("config.locked").toBool();
172 configInfo.setNameOfConfigurable(classId + "-" + configName);
173 IUAVGadgetConfiguration *config = f->createConfiguration(qs, &configInfo);
174 if (config) {
175 config->setName(configName);
176 config->setProvisionalName(configName);
177 config->setLocked(locked);
178 int idx = indexForConfig(m_configurations, classId, configName);
179 if (idx >= 0) {
180 // We should replace the config, but it might be used, so just
181 // throw it out of the list. The GCS should be reinitialised soon.
182 m_configurations[idx] = config;
183 } else {
184 m_configurations.append(config);
187 qs->endGroup();
190 if (configs.count() == 0) {
191 IUAVGadgetConfiguration *config = f->createConfiguration(0, 0);
192 // it is not mandatory for uavgadgets to have any configurations (settings)
193 // and therefore we have to check for that
194 if (config) {
195 config->setName(tr("default"));
196 config->setProvisionalName(tr("default"));
197 m_configurations.append(config);
200 qs->endGroup();
204 void UAVGadgetInstanceManager::saveSettings(QSettings *qs)
206 UAVConfigInfo *configInfo;
208 qs->beginGroup("UAVGadgetConfigurations");
209 qs->remove(""); // Remove existing configurations
210 configInfo = new UAVConfigInfo(m_versionUAVGadgetConfigurations, "UAVGadgetConfigurations");
211 configInfo->save(qs);
212 delete configInfo;
213 foreach(IUAVGadgetConfiguration * config, m_configurations) {
214 configInfo = new UAVConfigInfo(config);
215 qs->beginGroup(config->classId());
216 qs->beginGroup(config->name());
217 qs->beginGroup("data");
218 config->saveConfig(qs, configInfo);
219 qs->endGroup();
220 configInfo->save(qs);
221 qs->endGroup();
222 qs->endGroup();
223 delete configInfo;
225 qs->endGroup();
228 void UAVGadgetInstanceManager::createOptionsPages()
230 // In case there are pages (import a configuration), remove them.
231 // Maybe they should be deleted as well (memory-leak),
232 // but this might lead to NULL-pointers?
233 while (!m_optionsPages.isEmpty()) {
234 m_pm->removeObject(m_optionsPages.takeLast());
237 QMutableListIterator<IUAVGadgetConfiguration *> ite(m_configurations);
238 while (ite.hasNext()) {
239 IUAVGadgetConfiguration *config = ite.next();
240 IUAVGadgetFactory *f = factory(config->classId());
241 if (!f) {
242 qWarning() << "No gadget factory for configuration " + config->classId();
243 continue;
245 IOptionsPage *p = f->createOptionsPage(config);
246 if (p) {
247 IOptionsPage *page = new UAVGadgetOptionsPageDecorator(p, config, f->isSingleConfigurationGadget());
248 page->setIcon(f->icon());
249 m_optionsPages.append(page);
250 m_pm->addObject(page);
251 } else {
252 qWarning()
253 << "UAVGadgetInstanceManager::createOptionsPages - failed to create options page for configuration "
254 + config->classId() + ":" + config->name() + ", configuration will be removed.";
255 // The m_optionsPages list and m_configurations list must be in synch otherwise nasty issues happen later
256 // so if we fail to create an options page we must remove the associated configuration
257 ite.remove();
263 IUAVGadget *UAVGadgetInstanceManager::createGadget(QString classId, QWidget *parent, bool loadDefaultConfiguration)
265 IUAVGadgetFactory *f = factory(classId);
267 if (f) {
268 QList<IUAVGadgetConfiguration *> *configs = configurations(classId);
269 IUAVGadget *g = f->createGadget(parent);
270 UAVGadgetDecorator *gadget = new UAVGadgetDecorator(g, configs);
271 if ((loadDefaultConfiguration && configs && configs->count()) > 0) {
272 gadget->loadConfiguration(configs->at(0));
275 m_gadgetInstances.append(gadget);
276 connect(this, SIGNAL(configurationAdded(IUAVGadgetConfiguration *)), gadget, SLOT(configurationAdded(IUAVGadgetConfiguration *)));
277 connect(this, SIGNAL(configurationChanged(IUAVGadgetConfiguration *)), gadget, SLOT(configurationChanged(IUAVGadgetConfiguration *)));
278 connect(this, SIGNAL(configurationNameChanged(IUAVGadgetConfiguration *, QString, QString)), gadget, SLOT(configurationNameChanged(IUAVGadgetConfiguration *, QString, QString)));
279 connect(this, SIGNAL(configurationToBeDeleted(IUAVGadgetConfiguration *)), gadget, SLOT(configurationToBeDeleted(IUAVGadgetConfiguration *)));
280 return gadget;
282 return 0;
285 void UAVGadgetInstanceManager::removeGadget(IUAVGadget *gadget)
287 if (m_gadgetInstances.contains(gadget)) {
288 m_gadgetInstances.removeOne(gadget);
289 delete gadget;
290 gadget = 0;
295 * Removes all the gadgets. This is called by the core plugin when
296 * shutting down: this ensures that all registered gadget factory destructors are
297 * indeed called when the GCS is shutting down. We can't destroy them at the end
298 * (coreplugin is deleted last), because the gadgets sometimes depend on other
299 * plugins, like uavobjects...
301 void UAVGadgetInstanceManager::removeAllGadgets()
303 foreach(IUAVGadget * gadget, m_gadgetInstances) {
304 m_gadgetInstances.removeOne(gadget);
305 delete gadget;
310 bool UAVGadgetInstanceManager::isConfigurationActive(IUAVGadgetConfiguration *config)
312 // check if there is gadget currently using the configuration
313 foreach(IUAVGadget * gadget, m_gadgetInstances) {
314 if (gadget->activeConfiguration() == config) {
315 return true;
318 return false;
321 UAVGadgetInstanceManager::DeleteStatus UAVGadgetInstanceManager::canDeleteConfiguration(IUAVGadgetConfiguration *config)
323 // to be able to delete a configuration, no instance must be using it
324 if (isConfigurationActive(config)) {
325 return UAVGadgetInstanceManager::KO_ACTIVE;
327 // and it cannot be the only configuration
328 QList<IUAVGadgetConfiguration *> *configs = provisionalConfigurations(config->classId());
329 if (configs->count() <= 1) {
330 return UAVGadgetInstanceManager::KO_LONE;
332 return UAVGadgetInstanceManager::OK;
335 void UAVGadgetInstanceManager::deleteConfiguration(IUAVGadgetConfiguration *config)
337 m_provisionalDeletes.append(config);
338 if (m_provisionalConfigs.contains(config)) {
339 int i = m_provisionalConfigs.indexOf(config);
340 m_provisionalConfigs.removeAt(i);
341 m_provisionalOptionsPages.removeAt(i);
342 int j = m_takenNames[config->classId()].indexOf(config->name());
343 m_takenNames[config->classId()].removeAt(j);
344 m_settingsDialog->deletePage();
345 } else if (m_configurations.contains(config)) {
346 m_settingsDialog->deletePage();
348 configurationNameEdited("", false);
351 void UAVGadgetInstanceManager::cloneConfiguration(IUAVGadgetConfiguration *configToClone)
353 QString name = suggestName(configToClone->classId(), configToClone->name());
355 IUAVGadgetConfiguration *config = configToClone->clone();
357 config->setName(name);
358 config->setProvisionalName(name);
359 IUAVGadgetFactory *f = factory(config->classId());
360 IOptionsPage *p = f->createOptionsPage(config);
361 IOptionsPage *page = new UAVGadgetOptionsPageDecorator(p, config);
362 page->setIcon(f->icon());
363 m_provisionalConfigs.append(config);
364 m_provisionalOptionsPages.append(page);
365 m_settingsDialog->insertPage(page);
368 // "name" => "name 1", "Name 3" => "Name 4", "Name1" => "Name1 1"
369 QString UAVGadgetInstanceManager::suggestName(QString classId, QString name)
371 QString suggestedName;
373 QString last = name.split(" ").last();
374 bool ok;
375 int num = last.toInt(&ok);
376 int i = 1;
378 if (ok) {
379 QStringList n = name.split(" ");
380 n.removeLast();
381 name = n.join(" ");
382 i = num + 1;
384 do {
385 suggestedName = name + " " + QString::number(i);
386 ++i;
387 } while (m_takenNames[classId].contains(suggestedName));
389 m_takenNames[classId].append(suggestedName);
390 return suggestedName;
393 void UAVGadgetInstanceManager::applyChanges(IUAVGadgetConfiguration *config)
395 if (m_provisionalDeletes.contains(config)) {
396 m_provisionalDeletes.removeAt(m_provisionalDeletes.indexOf(config));
397 int i = m_configurations.indexOf(config);
398 if (i >= 0) {
399 emit configurationToBeDeleted(config);
400 int j = m_takenNames[config->classId()].indexOf(config->name());
401 m_takenNames[config->classId()].removeAt(j);
402 m_pm->removeObject(m_optionsPages.at(i));
403 m_configurations.removeAt(i);
404 m_optionsPages.removeAt(i); // TODO delete
406 return;
408 if (config->provisionalName() != config->name()) {
409 emit configurationNameChanged(config, config->name(), config->provisionalName());
410 config->setName(config->provisionalName());
412 if (m_configurations.contains(config)) {
413 emit configurationChanged(config);
414 } else if (m_provisionalConfigs.contains(config)) {
415 emit configurationAdded(config);
416 int i = m_provisionalConfigs.indexOf(config);
417 IOptionsPage *page = m_provisionalOptionsPages.at(i);
418 m_configurations.append(config);
419 m_optionsPages.append(page);
420 m_provisionalConfigs.removeAt(i);
421 m_provisionalOptionsPages.removeAt(i);
422 m_pm->addObject(page);
426 void UAVGadgetInstanceManager::configurationNameEdited(QString text, bool hasText)
428 bool disable = false;
430 foreach(IUAVGadgetConfiguration * c, m_configurations) {
431 foreach(IUAVGadgetConfiguration * d, m_configurations) {
432 if (c != d && c->classId() == d->classId() && c->provisionalName() == d->provisionalName()) {
433 disable = true;
436 foreach(IUAVGadgetConfiguration * d, m_provisionalConfigs) {
437 if (c != d && c->classId() == d->classId() && c->provisionalName() == d->provisionalName()) {
438 disable = true;
442 foreach(IUAVGadgetConfiguration * c, m_provisionalConfigs) {
443 foreach(IUAVGadgetConfiguration * d, m_provisionalConfigs) {
444 if (c != d && c->classId() == d->classId() && c->provisionalName() == d->provisionalName()) {
445 disable = true;
449 if (hasText && text == "") {
450 disable = true;
452 m_settingsDialog->disableApplyOk(disable);
453 if (hasText) {
454 m_settingsDialog->updateText(text);
458 void UAVGadgetInstanceManager::settingsDialogShown(Core::Internal::SettingsDialog *settingsDialog)
460 foreach(QString classId, classIds())
461 m_takenNames.insert(classId, configurationNames(classId));
462 m_settingsDialog = settingsDialog;
465 void UAVGadgetInstanceManager::settingsDialogRemoved()
467 m_takenNames.clear();
468 m_provisionalConfigs.clear();
469 m_provisionalDeletes.clear();
470 m_provisionalOptionsPages.clear(); // TODO delete
471 foreach(IUAVGadgetConfiguration * config, m_configurations)
472 config->setProvisionalName(config->name());
473 m_settingsDialog = 0;
476 QStringList UAVGadgetInstanceManager::configurationNames(QString classId) const
478 QStringList names;
480 foreach(IUAVGadgetConfiguration * config, m_configurations) {
481 if (config->classId() == classId) {
482 names.append(config->name());
485 return names;
488 QString UAVGadgetInstanceManager::gadgetName(QString classId) const
490 return m_classIdNameMap.value(classId);
493 QIcon UAVGadgetInstanceManager::gadgetIcon(QString classId) const
495 return m_classIdIconMap.value(classId);
498 IUAVGadgetFactory *UAVGadgetInstanceManager::factory(QString classId) const
500 foreach(IUAVGadgetFactory * f, m_factories) {
501 if (f->classId() == classId) {
502 return f;
505 return 0;
508 QList<IUAVGadgetConfiguration *> *UAVGadgetInstanceManager::configurations(QString classId) const
510 QList<IUAVGadgetConfiguration *> *configs = new QList<IUAVGadgetConfiguration *>;
511 foreach(IUAVGadgetConfiguration * config, m_configurations) {
512 if (config->classId() == classId) {
513 configs->append(config);
516 return configs;
519 QList<IUAVGadgetConfiguration *> *UAVGadgetInstanceManager::provisionalConfigurations(QString classId) const
521 QList<IUAVGadgetConfiguration *> *configs = new QList<IUAVGadgetConfiguration *>;
522 // add current configurations
523 foreach(IUAVGadgetConfiguration * config, m_configurations) {
524 if (config->classId() == classId) {
525 configs->append(config);
528 // add provisional configurations
529 foreach(IUAVGadgetConfiguration * config, m_provisionalConfigs) {
530 if (config->classId() == classId) {
531 configs->append(config);
534 // remove provisional configurations
535 foreach(IUAVGadgetConfiguration * config, m_provisionalDeletes) {
536 if (config->classId() == classId) {
537 configs->removeOne(config);
540 return configs;
543 int UAVGadgetInstanceManager::indexForConfig(QList<IUAVGadgetConfiguration *> configurations,
544 QString classId, QString configName)
546 for (int i = 0; i < configurations.length(); ++i) {
547 if (configurations.at(i)->classId() == classId
548 && configurations.at(i)->name() == configName) {
549 return i;
552 return -1;