1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-01-18 03:52:11 +01:00

OP-99 Ground Import/Export Plugin: Add version-number to plugin configuration.

git-svn-id: svn://svn.openpilot.org/OpenPilot/trunk@1771 ebee16cc-31ac-478f-84a7-5cbb03baadba
This commit is contained in:
erhard 2010-09-26 17:34:23 +00:00 committed by erhard
parent a46b46f939
commit 9d5f82727f
15 changed files with 267 additions and 80 deletions

View File

@ -29,11 +29,14 @@
#define IUAVGADGETCONFIGURATION_H
#include <coreplugin/core_global.h>
#include <coreplugin/uavconfiginfo.h>
#include <QObject>
#include <QSettings>
namespace Core {
class UAVConfigInfo;
class CORE_EXPORT IUAVGadgetConfiguration : public QObject
{
Q_OBJECT
@ -47,7 +50,8 @@ public:
bool locked() const { return m_locked; }
void setLocked(bool locked) { m_locked = locked; }
virtual void saveConfig(QSettings* settings) const = 0;
virtual void saveConfig(QSettings* /*settings*/) const {};
virtual void saveConfig(QSettings* settings, UAVConfigInfo* /*configInfo*/) const { saveConfig(settings); }
virtual IUAVGadgetConfiguration *clone() = 0;

View File

@ -32,6 +32,7 @@
#include <QtCore/QObject>
#include <QSettings>
#include "uavconfiginfo.h"
QT_BEGIN_NAMESPACE
class QStringList;
@ -55,6 +56,7 @@ public:
virtual IUAVGadget *createGadget(QWidget *parent) = 0;
virtual IUAVGadgetConfiguration *createConfiguration(QSettings* /*qSettings*/) { return 0; }
virtual IUAVGadgetConfiguration *createConfiguration(QSettings* qs, UAVConfigInfo */*configInfo*/) { return createConfiguration(qs); }
virtual IOptionsPage *createOptionsPage(IUAVGadgetConfiguration */*config*/) { return 0; }
QString classId() const { return m_classId; }
QString name() const { return m_name; }

View File

@ -24,6 +24,85 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*!
\class Core::UAVConfigInfo
\mainclass
\brief The Config Info is a helper-class to handle version changes in GCS
configuration files.
The UAVConfigInfo provides version-information for the configuration-data
and callback functions to ask the user how to handle incompatble
(old or newer) configurations.
When the config is created from a \l{QSettings} instance, an UAVConfigInfo
object is passed to the factory-method. With the version-data it can decide whether
the presented config-data is compatible to the current implementation. It may
migrate old data to the current format or abort the import.
When the config is written to the \l{QSettings} instance, an UAVConfigInfo object
is passed to the writer-function. The version of the config-format should
be written to the UAVConfigInfo object. This version will be passed to
factory-method when creating the config-object from this configuration.
Typically a plugin can handle version-changes like this:
\code
MyGadgetConfiguration::MyGadgetConfiguration(QString classId, QSettings* qSettings, UAVConfigInfo *configInfo, QObject *parent) :
IUAVGadgetConfiguration(classId, parent)
{
if ( ! qSettings )
return;
if ( configInfo->version() == UAVConfigVersion() )
configInfo->setVersion("1.0.0");
if ( !configInfo->standardVersionHandlingOK(CURRENT_VERSION))
return;
... read the config ...
}
void MyGadgetConfiguration::saveConfig(QSettings* qSettings, Core::UAVConfigInfo *configInfo) const {
configInfo->setVersion(CURRENT_VERSION);
... write the config ...
}
\endcode
\section1 Version Conventions
The Version numbers are in the form "major.minor.patch" (e.g. "3.1.4") with the
following meaning:
\list
\o major: Differences in this number indicate completely incompatible formats. The
config can't be imported.
\o minor: Differences in this number indicate backwards compatible formats. Old
configs can be imported or will be automatically migrated by the new program
but configs written by this plugin can't be reasonably read by old versions of
the plugin.
\o patch: Differences in this number indicate backwards and forward compatible formats.
Configs written by this plugin can be read by old versions of the plugin. Old configs
are extended by defaults by the new plugin.
\endlist
All parts (major, minor, patch) must be numeric values.
\section1 Utility Functions
\fn bool UAVConfigInfo::standardVersionHandlingOK(UAVConfigVersion programVersion)
\brief Default version handling.
With this function the plugin can test compatiblility of the current version
with the imported version. If there are differences, the user is asked whether
he or she wants to import the settings or abort the import.
Returns true when the import should be done, false otherwise.
*/
#include "uavconfiginfo.h"
#include <QMessageBox>
@ -47,27 +126,51 @@ by your version of the plugin. You should upgrade the plugin to import these set
using namespace Core;
UAVConfigInfo::UAVConfigInfo(QObject *parent) :
QObject(parent),
m_version(VERSION_DEFAULT),
m_locked(false),
m_nameOfConfigurable("")
{
}
UAVConfigInfo::UAVConfigInfo(QSettings *qs, QObject *parent) :
QObject(parent),
m_version(VERSION_DEFAULT)
{
qs->beginGroup("configInfo");
m_version = UAVConfigVersion( qs->value("version", VERSION_DEFAULT ).toString());
qs->endGroup();
read(qs);
}
UAVConfigInfo::UAVConfigInfo(UAVConfigVersion version, QString nameOfConfigurable, QObject *parent) :
QObject(parent),
m_version(version),
m_locked(false),
m_nameOfConfigurable(nameOfConfigurable)
{
}
UAVConfigInfo::UAVConfigInfo(IUAVGadgetConfiguration *config, QObject *parent) :
QObject(parent)
{
m_locked = config->locked();
m_nameOfConfigurable = config->classId() + "-" + config->name();
}
void UAVConfigInfo::save(QSettings *qs)
{
qs->beginGroup("configInfo");
qs->setValue("version", m_version.toString());
qs->setValue("locked", m_locked);
qs->endGroup();
}
void UAVConfigInfo::read(QSettings *qs)
{
qs->beginGroup("configInfo");
m_version = UAVConfigVersion( qs->value("version", VERSION_DEFAULT ).toString());
m_locked = qs->value("locked", false ).toBool();
qs->endGroup();
}
@ -104,6 +207,7 @@ bool UAVConfigInfo::askToAbort(int compat, QString message)
case NotCompatible:
msgBox.setText("ERROR: " + message + TEXT_NOT_COMPATIBLE);
msgBox.setInformativeText(tr(""));
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.exec();
return true;
@ -118,7 +222,7 @@ bool UAVConfigInfo::askToAbort(int compat, QString message)
}
void UAVConfigInfo::notifyAbort(QString message)
void UAVConfigInfo::notify(QString message)
{
QMessageBox msgBox;
msgBox.setText(message);
@ -139,9 +243,9 @@ int UAVConfigInfo::checkCompatibilityWith(UAVConfigVersion programVersion)
return FullyCompatible;
}
bool UAVConfigInfo::standardVersionHandlingIsNotOK(UAVConfigVersion programVersion)
bool UAVConfigInfo::standardVersionHandlingOK(UAVConfigVersion programVersion)
{
return askToAbort(
return !askToAbort(
checkCompatibilityWith(programVersion),
"("+m_nameOfConfigurable+")");
}

View File

@ -30,11 +30,15 @@
#include <QObject>
#include <QString>
#include <QSettings>
#include "iuavgadgetconfiguration.h"
#include "core_global.h"
namespace Core
{
class UAVConfigVersion{
class IUAVGadgetConfiguration;
class CORE_EXPORT UAVConfigVersion{
public:
UAVConfigVersion(QString versionString = "0.0.0");
UAVConfigVersion(int major, int minor, int patch);
@ -47,26 +51,34 @@ public:
bool operator==(const UAVConfigVersion &other);
};
class UAVConfigInfo : public QObject
class CORE_EXPORT UAVConfigInfo : public QObject
{
Q_OBJECT
public:
UAVConfigInfo(QSettings *qs, QObject *parent = 0);
explicit UAVConfigInfo(QObject *parent = 0);
explicit UAVConfigInfo(QSettings *qs, QObject *parent = 0);
explicit UAVConfigInfo(IUAVGadgetConfiguration* config, QObject *parent = 0);
UAVConfigInfo(UAVConfigVersion version, QString nameOfConfigurable, QObject *parent = 0);
enum Compatibility { FullyCompatible, MinorLossOfConfiguration, MissingConfiguration, MajorLossOfConfiguration, NotCompatible };
void setNameOfConfigurable(const QString nameOfConfigurable){m_nameOfConfigurable = nameOfConfigurable;}
void save(QSettings *qs);
void read(QSettings *qs);
void setVersion(int major, int minor, int patch){m_version = UAVConfigVersion(major, minor, patch);}
void setVersion(const QString version){m_version = UAVConfigVersion(version);}
void setVersion(const UAVConfigVersion version){m_version = version;}
UAVConfigVersion version(){ return m_version;}
bool locked(){ return m_locked; }
void setLocked(bool locked){ m_locked = locked; }
int checkCompatibilityWith(UAVConfigVersion programVersion);
bool askToAbort(int compat, QString message);
void notifyAbort(QString message);
bool standardVersionHandlingIsNotOK(UAVConfigVersion programVersion);
void notify(QString message);
bool standardVersionHandlingOK(UAVConfigVersion programVersion);
bool standardVersionHandlingOK(QString programVersion){ return standardVersionHandlingOK(UAVConfigVersion(programVersion));}
signals:
@ -74,6 +86,7 @@ public slots:
private:
UAVConfigVersion m_version;
bool m_locked;
QString m_nameOfConfigurable;
};

View File

@ -44,9 +44,10 @@
using namespace Core;
static const UAVConfigVersion m_versionUAVGadgetConfigurations = UAVConfigVersion("1.2.0");
UAVGadgetInstanceManager::UAVGadgetInstanceManager(QObject *parent) :
QObject(parent),
m_versionUAVGadgetConfigurations("1.1.0")
QObject(parent)
{
m_pm = ExtensionSystem::PluginManager::instance();
QList<IUAVGadgetFactory*> factories = m_pm->getObjects<IUAVGadgetFactory>();
@ -77,23 +78,86 @@ void UAVGadgetInstanceManager::readConfigurations(QSettings *qs)
UAVConfigInfo configInfo(qs);
configInfo.setNameOfConfigurable("UAVGadgetConfigurations");
if ( configInfo.version() == UAVConfigVersion() ){
// If version is not set, assume its a old version before readable config.
// If version is not set, assume its a old version before readable config (1.0.0).
// however compatibility to 1.0.0 is broken.
configInfo.setVersion("1.0.0");
}
/*
if ( configInfo.standardVersionHandlingIsNotOK(m_versionUAVGadgetConfigurations) ){
// We are in trouble now. User wants us to quit the import.
qs->endGroup();
return;
if ( configInfo.version() == UAVConfigVersion("1.1.0") ){
configInfo.notify(tr("Migrating UAVGadgetConfigurations from version 1.1.0 to ")
+ m_versionUAVGadgetConfigurations.toString());
readConfigs_1_1_0(qs); // this is fully compatible with 1.2.0
}
*/
readConfigs_1_0_0(qs);
else if ( !configInfo.standardVersionHandlingOK(m_versionUAVGadgetConfigurations) ){
// We are in trouble now. User wants us to quit the import, but when he saves
// the GCS, his old config will be lost.
configInfo.notify(
tr("You might want to save your old config NOW since it might be replaced by broken one when you exit the GCS!")
);
}
else{
readConfigs_1_2_0(qs);
}
qs->endGroup();
createOptionsPages();
}
void UAVGadgetInstanceManager::readConfigs_1_0_0(QSettings *qs)
void UAVGadgetInstanceManager::readConfigs_1_2_0(QSettings *qs)
{
UAVConfigInfo configInfo;
foreach (QString classId, m_classIds.keys())
{
IUAVGadgetFactory *f = factory(classId);
qs->beginGroup(classId);
QStringList configs = QStringList();
configs = qs->childGroups();
foreach (QString configName, configs) {
qDebug() << "Loading config: " << classId << "," << configName;
qs->beginGroup(configName);
configInfo.read(qs);
configInfo.setNameOfConfigurable(classId+"-"+configName);
qs->beginGroup("data");
IUAVGadgetConfiguration *config = f->createConfiguration(qs, &configInfo);
if (config){
config->setName(configName);
config->setProvisionalName(configName);
config->setLocked(configInfo.locked());
int idx = indexForConfig(m_configurations, classId, configName);
if ( idx >= 0 ){
// We should replace the config, but it might be used, so just
// throw it out of the list. The GCS should be reinitialised soon.
m_configurations[idx] = config;
}
else{
m_configurations.append(config);
}
}
qs->endGroup();
qs->endGroup();
}
if (configs.count() == 0) {
IUAVGadgetConfiguration *config = f->createConfiguration(0, 0);
// it is not mandatory for uavgadgets to have any configurations (settings)
// and therefore we have to check for that
if (config) {
config->setName(tr("default"));
config->setProvisionalName(tr("default"));
m_configurations.append(config);
}
}
qs->endGroup();
}
}
void UAVGadgetInstanceManager::readConfigs_1_1_0(QSettings *qs)
{
UAVConfigInfo configInfo;
foreach (QString classId, m_classIds.keys())
{
IUAVGadgetFactory *f = factory(classId);
@ -106,7 +170,8 @@ void UAVGadgetInstanceManager::readConfigs_1_0_0(QSettings *qs)
qDebug() << "Loading config: " << classId << "," << configName;
qs->beginGroup(configName);
bool locked = qs->value("config.locked").toBool();
IUAVGadgetConfiguration *config = f->createConfiguration(qs);
configInfo.setNameOfConfigurable(classId+"-"+configName);
IUAVGadgetConfiguration *config = f->createConfiguration(qs, &configInfo);
if (config){
config->setName(configName);
config->setProvisionalName(configName);
@ -125,7 +190,7 @@ void UAVGadgetInstanceManager::readConfigs_1_0_0(QSettings *qs)
}
if (configs.count() == 0) {
IUAVGadgetConfiguration *config = f->createConfiguration(0);
IUAVGadgetConfiguration *config = f->createConfiguration(0, 0);
// it is not mandatory for uavgadgets to have any configurations (settings)
// and therefore we have to check for that
if (config) {
@ -140,19 +205,24 @@ void UAVGadgetInstanceManager::readConfigs_1_0_0(QSettings *qs)
void UAVGadgetInstanceManager::writeConfigurations(QSettings *qs)
{
UAVConfigInfo *configInfo;
qs->beginGroup("UAVGadgetConfigurations");
qs->remove(""); // Remove existing configurations
UAVConfigInfo configInfo(m_versionUAVGadgetConfigurations, "UAVGadgetConfigurations");
configInfo.save(qs);
configInfo = new UAVConfigInfo(m_versionUAVGadgetConfigurations, "UAVGadgetConfigurations");
configInfo->save(qs);
delete configInfo;
foreach (IUAVGadgetConfiguration *config, m_configurations)
{
configInfo = new UAVConfigInfo(config);
qs->beginGroup(config->classId());
qs->beginGroup(config->name());
// TODO: Someone could accidentially use the same name?
qs->setValue("config.locked", config->locked());
config->saveConfig(qs);
qs->beginGroup("data");
config->saveConfig(qs, configInfo);
qs->endGroup();
configInfo->save(qs);
qs->endGroup();
qs->endGroup();
delete configInfo;
}
qs->endGroup();
}

View File

@ -97,10 +97,10 @@ private:
QList<IOptionsPage*> m_provisionalOptionsPages;
Core::Internal::SettingsDialog *m_settingsDialog;
ExtensionSystem::PluginManager *m_pm;
UAVConfigVersion m_versionUAVGadgetConfigurations;
int indexForConfig(QList<IUAVGadgetConfiguration*> configurations,
QString classId, QString configName);
void readConfigs_1_0_0(QSettings *qs);
void readConfigs_1_1_0(QSettings *qs);
void readConfigs_1_2_0(QSettings *qs);
};
} // namespace Core

View File

@ -29,18 +29,26 @@
#include "importexportgadgetconfiguration.h"
static const QString VERSION = "1.0.1";
/**
* Loads a saved configuration or defaults if non exist.
*
*/
ImportExportGadgetConfiguration::ImportExportGadgetConfiguration(QString classId, QSettings* qSettings, QObject *parent) :
IUAVGadgetConfiguration(classId, parent),
dialFile("gcs.ini")
ImportExportGadgetConfiguration::ImportExportGadgetConfiguration(QString classId, QSettings* qSettings, UAVConfigInfo *configInfo, QObject *parent) :
IUAVGadgetConfiguration(classId, parent)
{
//if a saved configuration exists load it
if(qSettings != 0) {
dialFile = qSettings->value("dialFile").toString();
}
if ( ! qSettings )
return;
if ( configInfo->version() == UAVConfigVersion() )
configInfo->setVersion("1.0.0");
if ( !configInfo->standardVersionHandlingOK(VERSION))
return;
iniFile = qSettings->value("dialFile", "gcs.ini").toString(); // TODO Delete with next minor version.
iniFile = qSettings->value("iniFile", iniFile).toString();
}
/**
@ -50,7 +58,7 @@ ImportExportGadgetConfiguration::ImportExportGadgetConfiguration(QString classId
IUAVGadgetConfiguration *ImportExportGadgetConfiguration::clone()
{
ImportExportGadgetConfiguration *m = new ImportExportGadgetConfiguration(this->classId());
m->dialFile = dialFile;
m->iniFile = iniFile;
return m;
}
@ -58,8 +66,10 @@ IUAVGadgetConfiguration *ImportExportGadgetConfiguration::clone()
* Saves a configuration.
*
*/
void ImportExportGadgetConfiguration::saveConfig(QSettings* qSettings) const {
qSettings->setValue("dialFile", dialFile);
void ImportExportGadgetConfiguration::saveConfig(QSettings* qSettings, Core::UAVConfigInfo *configInfo) const {
configInfo->setVersion(VERSION);
qSettings->setValue("dialFile", iniFile);
qSettings->setValue("iniFile", iniFile);
}
/**

View File

@ -39,23 +39,23 @@ class IMPORTEXPORT_EXPORT ImportExportGadgetConfiguration : public IUAVGadgetCon
{
Q_OBJECT
public:
explicit ImportExportGadgetConfiguration(QString classId, QSettings* qSettings = 0, QObject *parent = 0);
ImportExportGadgetConfiguration(QString classId, QSettings* qSettings = 0, UAVConfigInfo *configInfo = 0, QObject *parent = 0);
//set dial configuration functions
void setDialFile(QString filename) {
dialFile = filename;
void setIniFile(QString filename) {
iniFile = filename;
}
//get dial configuration functions
QString getDialFile() const{
return dialFile;
QString getIniFile() const{
return iniFile;
}
void saveConfig(QSettings* settings) const;
void saveConfig(QSettings* settings, Core::UAVConfigInfo *configInfo) const;
IUAVGadgetConfiguration *clone();
private:
QString dialFile;
QString iniFile;
};
#endif // IMPORTEXPORTGADGETCONFIGURATION_H

View File

@ -50,9 +50,9 @@ Core::IUAVGadget* ImportExportGadgetFactory::createGadget(QWidget *parent)
return new ImportExportGadget(QString("ImportExportGadget"), gadgetWidget, parent);
}
IUAVGadgetConfiguration *ImportExportGadgetFactory::createConfiguration(QSettings* qSettings)
IUAVGadgetConfiguration *ImportExportGadgetFactory::createConfiguration(QSettings* qSettings, UAVConfigInfo *configInfo)
{
lastConfig = new ImportExportGadgetConfiguration(QString("ImportExportGadget"), qSettings);
lastConfig = new ImportExportGadgetConfiguration(QString("ImportExportGadget"), qSettings, configInfo);
return lastConfig;
}

View File

@ -47,7 +47,7 @@ public:
ImportExportGadgetConfiguration *getLastConfig(){ return lastConfig;}
Core::IUAVGadget *createGadget(QWidget *parent);
IUAVGadgetConfiguration *createConfiguration(QSettings* qSettings);
IUAVGadgetConfiguration *createConfiguration(QSettings *qSettings, UAVConfigInfo *configInfo);
IOptionsPage *createOptionsPage(IUAVGadgetConfiguration *config);
private:

View File

@ -51,10 +51,10 @@ QWidget *ImportExportGadgetOptionsPage::createPage(QWidget *parent)
options_page->setupUi(optionsPageWidget);
// Restore the contents from the settings:
options_page->svgSourceFile->setExpectedKind(Utils::PathChooser::File);
options_page->svgSourceFile->setPromptDialogFilter(tr("INI file (*.ini)"));
options_page->svgSourceFile->setPromptDialogTitle(tr("Choose configuration file"));
options_page->svgSourceFile->setPath(m_config->getDialFile());
options_page->iniFile->setExpectedKind(Utils::PathChooser::File);
options_page->iniFile->setPromptDialogFilter(tr("INI file (*.ini)"));
options_page->iniFile->setPromptDialogTitle(tr("Choose configuration file"));
options_page->iniFile->setPath(m_config->getIniFile());
return optionsPageWidget;
}
@ -67,7 +67,7 @@ QWidget *ImportExportGadgetOptionsPage::createPage(QWidget *parent)
*/
void ImportExportGadgetOptionsPage::apply()
{
m_config->setDialFile(options_page->svgSourceFile->path());
m_config->setIniFile(options_page->iniFile->path());
}

View File

@ -63,7 +63,7 @@
</widget>
</item>
<item>
<widget class="Utils::PathChooser" name="svgSourceFile" native="true">
<widget class="Utils::PathChooser" name="iniFile" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>

View File

@ -67,7 +67,7 @@ void ImportExportGadgetWidget::loadConfiguration(const ImportExportGadgetConfigu
if ( !config )
return;
ui->configFile->setText(config->getDialFile());
ui->configFile->setText(config->getIniFile());
}
void ImportExportGadgetWidget::on_exportButton_clicked()

View File

@ -14,24 +14,6 @@
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>This is experimental. Use at own risk.</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Please report bugs!</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>

View File

@ -69,9 +69,11 @@ bool ImportExportPlugin::initialize(const QStringList& args, QString *errMsg)
cmd->setDefaultKeySequence(QKeySequence("Ctrl+I"));
cmd->action()->setText("Import/Export...");
ac->menu()->addSeparator();
ac->appendGroup("ImportExport");
ac->addAction(cmd, "ImportExport");
// ac->menu()->addSeparator();
// ac->appendGroup("ImportExport");
// ac->addAction(cmd, "ImportExport");
ac->addAction(cmd, Core::Constants::G_FILE_SAVE);
connect(cmd->action(), SIGNAL(triggered(bool)), this, SLOT(importExport()));