2 ******************************************************************************
4 * @file uavgadgetinstancemanager.cpp
5 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
6 * @addtogroup GCSPlugins GCS Plugins
8 * @addtogroup CorePlugin Core Plugin
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
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"
38 #include <extensionsystem/pluginmanager.h>
39 #include <QtCore/QStringList>
40 #include <QtCore/QSettings>
41 #include <QtCore/QDebug>
42 #include <QMessageBox>
47 static const UAVConfigVersion m_versionUAVGadgetConfigurations
= UAVConfigVersion("1.2.0");
49 UAVGadgetInstanceManager::UAVGadgetInstanceManager(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
);
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.
96 tr("You might want to save your old config NOW since it might be replaced by broken one when you exit the GCS!")
99 readConfigs_1_2_0(qs
);
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
);
122 configInfo
.setNameOfConfigurable(classId
+ "-" + configName
);
123 qs
->beginGroup("data");
124 IUAVGadgetConfiguration
*config
= f
->createConfiguration(qs
, &configInfo
);
126 config
->setName(configName
);
127 config
->setProvisionalName(configName
);
128 config
->setLocked(configInfo
.locked());
129 int idx
= indexForConfig(m_configurations
, classId
, configName
);
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
;
135 m_configurations
.append(config
);
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
147 config
->setName(tr("default"));
148 config
->setProvisionalName(tr("default"));
149 m_configurations
.append(config
);
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
);
175 config
->setName(configName
);
176 config
->setProvisionalName(configName
);
177 config
->setLocked(locked
);
178 int idx
= indexForConfig(m_configurations
, classId
, configName
);
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
;
184 m_configurations
.append(config
);
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
195 config
->setName(tr("default"));
196 config
->setProvisionalName(tr("default"));
197 m_configurations
.append(config
);
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
);
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
);
220 configInfo
->save(qs
);
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());
242 qWarning() << "No gadget factory for configuration " + config
->classId();
245 IOptionsPage
*p
= f
->createOptionsPage(config
);
247 IOptionsPage
*page
= new UAVGadgetOptionsPageDecorator(p
, config
, f
->isSingleConfigurationGadget());
248 page
->setIcon(f
->icon());
249 m_optionsPages
.append(page
);
250 m_pm
->addObject(page
);
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
263 IUAVGadget
*UAVGadgetInstanceManager::createGadget(QString classId
, QWidget
*parent
, bool loadDefaultConfiguration
)
265 IUAVGadgetFactory
*f
= factory(classId
);
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
*)));
285 void UAVGadgetInstanceManager::removeGadget(IUAVGadget
*gadget
)
287 if (m_gadgetInstances
.contains(gadget
)) {
288 m_gadgetInstances
.removeOne(gadget
);
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
);
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
) {
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();
375 int num
= last
.toInt(&ok
);
379 QStringList n
= name
.split(" ");
385 suggestedName
= name
+ " " + QString::number(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
);
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
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()) {
436 foreach(IUAVGadgetConfiguration
* d
, m_provisionalConfigs
) {
437 if (c
!= d
&& c
->classId() == d
->classId() && c
->provisionalName() == d
->provisionalName()) {
442 foreach(IUAVGadgetConfiguration
* c
, m_provisionalConfigs
) {
443 foreach(IUAVGadgetConfiguration
* d
, m_provisionalConfigs
) {
444 if (c
!= d
&& c
->classId() == d
->classId() && c
->provisionalName() == d
->provisionalName()) {
449 if (hasText
&& text
== "") {
452 m_settingsDialog
->disableApplyOk(disable
);
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
480 foreach(IUAVGadgetConfiguration
* config
, m_configurations
) {
481 if (config
->classId() == classId
) {
482 names
.append(config
->name());
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
) {
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
);
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
);
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
) {