Commit 96d80096 authored by Tobias Hunger's avatar Tobias Hunger

Fix saving of xml files

Do not save XML config files (profiles.xml, toolchains.xml, etc.)
if the file has not changed.

Change-Id: I5f0dea374b33a05e7c428f4031d53c83d92de595
Reviewed-by: default avatarDaniel Teske <daniel.teske@nokia.com>
parent 29ec32a5
......@@ -332,10 +332,6 @@ bool PersistentSettingsReader::load(const Utils::FileName &fileName)
\sa Utils::PersistentSettingsReader
*/
PersistentSettingsWriter::PersistentSettingsWriter()
{
}
static void writeVariantValue(QXmlStreamWriter &w, const Context &ctx,
const QVariant &variant, const QString &key = QString())
{
......@@ -376,24 +372,33 @@ static void writeVariantValue(QXmlStreamWriter &w, const Context &ctx,
}
}
PersistentSettingsWriter::PersistentSettingsWriter(const FileName &fileName, const QString &docType) :
m_fileName(fileName), m_docType(docType), m_mustSave(false)
{ }
void PersistentSettingsWriter::saveValue(const QString &variable, const QVariant &value)
{
if (m_valueMap.contains(variable) && m_valueMap.value(variable) == value)
return;
m_mustSave = true;
m_valueMap.insert(variable, value);
}
bool PersistentSettingsWriter::save(const Utils::FileName &fileName, const QString &docType,
QWidget *parent) const
bool PersistentSettingsWriter::save(QWidget *parent) const
{
if (!m_mustSave)
return true;
QDir tmp;
tmp.mkpath(fileName.toFileInfo().path());
Utils::FileSaver saver(fileName.toString(), QIODevice::Text);
tmp.mkpath(m_fileName.toFileInfo().path());
Utils::FileSaver saver(m_fileName.toString(), QIODevice::Text);
if (!saver.hasError()) {
const Context ctx;
QXmlStreamWriter w(saver.file());
w.setAutoFormatting(true);
w.setAutoFormattingIndent(1); // Historical, used to be QDom.
w.writeStartDocument();
w.writeDTD(QLatin1String("<!DOCTYPE ") + docType + QLatin1Char('>'));
w.writeDTD(QLatin1String("<!DOCTYPE ") + m_docType + QLatin1Char('>'));
w.writeComment(QString::fromAscii(" Written by Qt Creator %1, %2. ").
arg(QLatin1String(Core::Constants::IDE_VERSION_LONG),
QDateTime::currentDateTime().toString(Qt::ISODate)));
......@@ -409,6 +414,13 @@ bool PersistentSettingsWriter::save(const Utils::FileName &fileName, const QStri
saver.setResult(&w);
}
return saver.finalize(parent);
bool ok = saver.finalize(parent);
if (ok)
m_mustSave = false;
return ok;
}
FileName PersistentSettingsWriter::fileName() const
{ return m_fileName; }
} // namespace Utils
......@@ -59,12 +59,17 @@ private:
class QTCREATOR_UTILS_EXPORT PersistentSettingsWriter
{
public:
PersistentSettingsWriter();
PersistentSettingsWriter(const FileName &fileName, const QString &docType);
void saveValue(const QString &variable, const QVariant &value);
bool save(const FileName &fileName, const QString &docType, QWidget *parent) const;
bool save(QWidget *parent) const;
Utils::FileName fileName() const;
private:
QMap<QString, QVariant> m_valueMap;
const Utils::FileName m_fileName;
const QString m_docType;
mutable bool m_mustSave;
};
} // namespace Utils
......
......@@ -182,7 +182,7 @@ AndroidConfig::AndroidConfig()
void AndroidConfig::save(QSettings &settings) const
{
QFileInfo fileInfo(settingsFileName().toFileInfo());
QFileInfo fileInfo = settingsFileName().toFileInfo();
if (fileInfo.exists())
settings.setValue(changeTimeStamp, fileInfo.lastModified().toMSecsSinceEpoch() / 1000);
......
......@@ -80,6 +80,8 @@ public:
QList<IDevice::Ptr> devices;
QList<IDevice::Ptr> inactiveAutoDetectedDevices;
QHash<Core::Id, Core::Id> defaultDevices;
Utils::PersistentSettingsWriter *writer;
};
DeviceManager *DeviceManagerPrivate::clonedInstance = 0;
......@@ -134,10 +136,8 @@ void DeviceManager::copy(const DeviceManager *source, DeviceManager *target, boo
void DeviceManager::save()
{
Utils::PersistentSettingsWriter writer;
writer.saveValue(QLatin1String(DeviceManagerKey), toMap());
writer.save(settingsFilePath(QLatin1String("/qtcreator/devices.xml")),
QLatin1String("QtCreatorDevices"), Core::ICore::mainWindow());
d->writer->saveValue(QLatin1String(DeviceManagerKey), toMap());
d->writer->save(Core::ICore::mainWindow());
}
void DeviceManager::load()
......@@ -332,6 +332,8 @@ const IDeviceFactory *DeviceManager::restoreFactory(const QVariantMap &map)
DeviceManager::DeviceManager(bool isInstance) : d(new DeviceManagerPrivate)
{
d->writer = new Utils::PersistentSettingsWriter(settingsFilePath(QLatin1String("/qtcreator/devices.xml")),
QLatin1String("QtCreatorDevices"));
if (isInstance) {
load();
connect(Core::ICore::instance(), SIGNAL(saveSettingsRequested()), SLOT(save()));
......@@ -340,6 +342,7 @@ DeviceManager::DeviceManager(bool isInstance) : d(new DeviceManagerPrivate)
DeviceManager::~DeviceManager()
{
delete d->writer;
delete d;
}
......
......@@ -35,6 +35,8 @@
#include <projectexplorer/projectexplorer_export.h>
#include <utils/fileutils.h>
#include <utils/fileutils.h>
#include <QObject>
namespace ProjectExplorer {
......
......@@ -86,14 +86,19 @@ public:
bool m_initialized;
QList<ProfileInformation *> m_informationList;
QList<Profile *> m_profileList;
Utils::PersistentSettingsWriter *m_writer;
};
ProfileManagerPrivate::ProfileManagerPrivate()
: m_defaultProfile(0), m_initialized(false)
: m_defaultProfile(0), m_initialized(false),
m_writer(new Utils::PersistentSettingsWriter(settingsFileName(), QLatin1String("QtCreatorProfiles")))
{ }
ProfileManagerPrivate::~ProfileManagerPrivate()
{
qDeleteAll(m_informationList);
qDeleteAll(m_profileList);
delete m_writer;
}
QList<Task> ProfileManagerPrivate::validateProfile(Profile *p) const
......@@ -213,8 +218,6 @@ void ProfileManager::restoreProfiles()
ProfileManager::~ProfileManager()
{
// Clean out profile information to avoid calling them during deregistration:
qDeleteAll(d->m_informationList);
qDeleteAll(d->m_profileList);
delete d;
m_instance = 0;
}
......@@ -224,21 +227,20 @@ void ProfileManager::saveProfiles()
if (!d->m_initialized) // ignore save requests while we are not initialized.
return;
PersistentSettingsWriter writer;
writer.saveValue(QLatin1String(PROFILE_FILE_VERSION_KEY), 1);
d->m_writer->saveValue(QLatin1String(PROFILE_FILE_VERSION_KEY), 1);
int count = 0;
foreach (Profile *p, profiles()) {
QVariantMap tmp = p->toMap();
if (tmp.isEmpty())
continue;
writer.saveValue(QString::fromLatin1(PROFILE_DATA_KEY) + QString::number(count), tmp);
d->m_writer->saveValue(QString::fromLatin1(PROFILE_DATA_KEY) + QString::number(count), tmp);
++count;
}
writer.saveValue(QLatin1String(PROFILE_COUNT_KEY), count);
writer.saveValue(QLatin1String(PROFILE_DEFAULT_KEY),
d->m_writer->saveValue(QLatin1String(PROFILE_COUNT_KEY), count);
d->m_writer->saveValue(QLatin1String(PROFILE_DEFAULT_KEY),
d->m_defaultProfile ? QString::fromLatin1(d->m_defaultProfile->id().name()) : QString());
writer.save(settingsFileName(), QLatin1String("QtCreatorProfiles"), Core::ICore::mainWindow());
d->m_writer->save(Core::ICore::mainWindow());
}
bool greaterPriority(ProfileInformation *a, ProfileInformation *b)
......
......@@ -87,23 +87,28 @@ class ProjectPrivate
{
public:
ProjectPrivate();
~ProjectPrivate();
QList<Target *> m_targets;
Target *m_activeTarget;
EditorConfiguration *m_editorConfiguration;
Core::Context m_projectContext;
Core::Context m_projectLanguage;
QVariantMap m_pluginSettings;
SettingsAccessor *m_accessor;
};
ProjectPrivate::ProjectPrivate() :
m_activeTarget(0),
m_editorConfiguration(new EditorConfiguration())
{
}
m_editorConfiguration(new EditorConfiguration()),
m_accessor(0)
{ }
ProjectPrivate::~ProjectPrivate()
{ delete m_accessor; }
Project::Project() : d(new ProjectPrivate)
{
}
{ }
Project::~Project()
{
......@@ -281,12 +286,16 @@ Target *Project::restoreTarget(const QVariantMap &data)
void Project::saveSettings()
{
emit aboutToSaveSettings();
SettingsAccessor::instance()->saveSettings(this, toMap());
if (!d->m_accessor)
d->m_accessor = new SettingsAccessor(this);
d->m_accessor->saveSettings(toMap());
}
bool Project::restoreSettings()
{
QVariantMap map(SettingsAccessor::instance()->restoreSettings(this));
if (!d->m_accessor)
d->m_accessor = new SettingsAccessor(this);
QVariantMap map(d->m_accessor->restoreSettings());
bool ok = fromMap(map);
if (ok)
emit settingsLoaded();
......
......@@ -91,7 +91,8 @@ SessionManager::SessionManager(QObject *parent)
m_sessionName(QLatin1String("default")),
m_virginSession(true),
m_loadingSession(false),
m_startupProject(0)
m_startupProject(0),
m_writer(0)
{
connect(ModeManager::instance(), SIGNAL(currentModeChanged(Core::IMode*)),
this, SLOT(saveActiveMode(Core::IMode*)));
......@@ -111,6 +112,7 @@ SessionManager::SessionManager(QObject *parent)
SessionManager::~SessionManager()
{
emit aboutToUnloadSession(m_sessionName);
delete m_writer;
}
......@@ -304,12 +306,15 @@ bool SessionManager::save()
emit aboutToSaveSession();
PersistentSettingsWriter writer;
if (!m_writer || m_writer->fileName() != sessionNameToFileName(m_sessionName)) {
delete m_writer;
m_writer = new Utils::PersistentSettingsWriter(sessionNameToFileName(m_sessionName),
QLatin1String("QtCreatorSession"));
}
// save the startup project
if (m_startupProject) {
writer.saveValue(QLatin1String("StartupProject"), m_startupProject->document()->fileName());
}
if (m_startupProject)
m_writer->saveValue(QLatin1String("StartupProject"), m_startupProject->document()->fileName());
QStringList projectFiles;
foreach (Project *pro, m_projects)
......@@ -321,7 +326,7 @@ bool SessionManager::save()
if (!projectFiles.contains(failed))
projectFiles << failed;
writer.saveValue(QLatin1String("ProjectList"), projectFiles);
m_writer->saveValue(QLatin1String("ProjectList"), projectFiles);
QMap<QString, QVariant> depMap;
QMap<QString, QStringList>::const_iterator i = m_depMap.constBegin();
......@@ -334,7 +339,7 @@ bool SessionManager::save()
depMap.insert(key, values);
++i;
}
writer.saveValue(QLatin1String("ProjectDependencies"), QVariant(depMap));
m_writer->saveValue(QLatin1String("ProjectDependencies"), QVariant(depMap));
int editorCount = 0;
QList<Core::IEditor *> editors = ICore::editorManager()->openedEditors();
......@@ -343,25 +348,24 @@ bool SessionManager::save()
if (!editor->isTemporary())
++editorCount;
}
writer.saveValue(QLatin1String("OpenEditors"), editorCount);
writer.saveValue(QLatin1String("EditorSettings"),
ICore::editorManager()->saveState().toBase64());
m_writer->saveValue(QLatin1String("OpenEditors"), editorCount);
m_writer->saveValue(QLatin1String("EditorSettings"),
ICore::editorManager()->saveState().toBase64());
QMap<QString, QVariant>::const_iterator it, end;
end = m_values.constEnd();
QStringList keys;
for (it = m_values.constBegin(); it != end; ++it) {
writer.saveValue(QLatin1String("value-") + it.key(), it.value());
m_writer->saveValue(QLatin1String("value-") + it.key(), it.value());
keys << it.key();
}
writer.saveValue(QLatin1String("valueKeys"), keys);
m_writer->saveValue(QLatin1String("valueKeys"), keys);
Utils::FileName fileName = sessionNameToFileName(m_sessionName);
bool result = writer.save(fileName, QLatin1String("QtCreatorSession"), Core::ICore::mainWindow());
bool result = m_writer->save(Core::ICore::mainWindow());
if (!result) {
QMessageBox::warning(0, tr("Error while saving session"),
tr("Could not save session to file %1").arg(fileName.toUserOutput()));
tr("Could not save session to file %1").arg(m_writer->fileName().toUserOutput()));
}
if (debug)
......
......@@ -176,6 +176,7 @@ private:
QMap<QString, QStringList> m_depMap;
QMap<QString, QVariant> m_values;
QFutureInterface<void> m_future;
Utils::PersistentSettingsWriter *m_writer;
};
} // namespace ProjectExplorer
......
......@@ -450,20 +450,25 @@ static QVariantMap processHandlerNodes(const HandlerNode &node, const QVariantMa
// -------------------------------------------------------------------------
// UserFileAccessor
// -------------------------------------------------------------------------
SettingsAccessor::SettingsAccessor() :
SettingsAccessor::SettingsAccessor(Project *project) :
m_firstVersion(-1),
m_lastVersion(-1),
m_userFileAcessor(QByteArray("qtcUserFileName"),
QLatin1String(".user"),
QString::fromLocal8Bit(qgetenv("QTC_EXTENSION")),
true,
true),
true,
this),
m_sharedFileAcessor(QByteArray("qtcSharedFileName"),
QLatin1String(".shared"),
QString::fromLocal8Bit(qgetenv("QTC_SHARED_EXTENSION")),
false,
false)
false,
this),
m_project(project)
{
QTC_CHECK(m_project);
addVersionHandler(new Version0Handler);
addVersionHandler(new Version1Handler);
addVersionHandler(new Version2Handler);
......@@ -483,11 +488,8 @@ SettingsAccessor::~SettingsAccessor()
qDeleteAll(m_handlers);
}
SettingsAccessor *SettingsAccessor::instance()
{
static SettingsAccessor acessor;
return &acessor;
}
Project *SettingsAccessor::project() const
{ return m_project; }
namespace {
......@@ -589,17 +591,21 @@ void trackUserStickySettings(QVariantMap *userMap, const QVariantMap &sharedMap)
} // Anonymous
QVariantMap SettingsAccessor::restoreSettings(Project *project) const
QVariantMap SettingsAccessor::restoreSettings() const
{
if (m_lastVersion < 0 || !project)
if (m_lastVersion < 0)
return QVariantMap();
SettingsData settings;
if (!m_userFileAcessor.readFile(project, &settings))
QString fn = project()->property(m_userFileAcessor.id()).toString();
if (fn.isEmpty())
fn = project()->document()->fileName() + m_userFileAcessor.suffix();
settings.m_fileName = Utils::FileName::fromString(fn);
if (!m_userFileAcessor.readFile(&settings))
settings.clear(); // No user settings, but there can still be shared ones.
if (settings.isValid()) {
if (settings.m_version > SettingsAccessor::instance()->m_lastVersion + 1) {
if (settings.m_version > m_lastVersion + 1) {
QMessageBox::information(
Core::ICore::mainWindow(),
QApplication::translate("ProjectExplorer::SettingsAccessor",
......@@ -652,7 +658,7 @@ QVariantMap SettingsAccessor::restoreSettings(Project *project) const
// Time to consider shared settings...
SettingsData sharedSettings;
if (m_sharedFileAcessor.readFile(project, &sharedSettings)) {
if (m_sharedFileAcessor.readFile(&sharedSettings)) {
bool useSharedSettings = true;
if (sharedSettings.m_version != settings.m_version) {
int baseFileVersion;
......@@ -692,20 +698,20 @@ QVariantMap SettingsAccessor::restoreSettings(Project *project) const
if (useSharedSettings) {
// We now update the user and shared settings so they are compatible.
for (int i = sharedSettings.m_version; i < baseFileVersion; ++i)
sharedSettings.m_map = m_handlers.value(i)->update(project, sharedSettings.m_map);
sharedSettings.m_map = m_handlers.value(i)->update(m_project, sharedSettings.m_map);
if (!settings.isValid()) {
project->setProperty(SHARED_SETTINGS, sharedSettings.m_map);
m_project->setProperty(SHARED_SETTINGS, sharedSettings.m_map);
return sharedSettings.m_map;
}
for (int i = settings.m_version; i < baseFileVersion; ++i)
settings.m_map = m_handlers.value(i)->update(project, settings.m_map);
settings.m_map = m_handlers.value(i)->update(m_project, settings.m_map);
settings.m_version = baseFileVersion;
}
}
if (useSharedSettings) {
project->setProperty(SHARED_SETTINGS, sharedSettings.m_map);
m_project->setProperty(SHARED_SETTINGS, sharedSettings.m_map);
if (!settings.isValid())
return sharedSettings.m_map;
......@@ -718,22 +724,26 @@ QVariantMap SettingsAccessor::restoreSettings(Project *project) const
// Update from the base version to Creator's version.
for (int i = settings.m_version; i <= m_lastVersion; ++i)
settings.m_map = m_handlers.value(i)->update(project, settings.m_map);
settings.m_map = m_handlers.value(i)->update(m_project, settings.m_map);
return settings.m_map;
}
bool SettingsAccessor::saveSettings(const Project *project, const QVariantMap &map) const
bool SettingsAccessor::saveSettings(const QVariantMap &map) const
{
if (!project || map.isEmpty())
if (map.isEmpty())
return false;
SettingsData settings(map);
const QVariant &shared = project->property(SHARED_SETTINGS);
QString fn = project()->property(m_userFileAcessor.id()).toString();
if (fn.isEmpty())
fn = project()->document()->fileName() + m_userFileAcessor.suffix();
settings.m_fileName = Utils::FileName::fromString(fn);
const QVariant &shared = m_project->property(SHARED_SETTINGS);
if (shared.isValid())
trackUserStickySettings(&settings.m_map, shared.toMap());
return m_userFileAcessor.writeFile(project, &settings);
return m_userFileAcessor.writeFile(&settings);
}
void SettingsAccessor::addVersionHandler(UserFileVersionHandler *handler)
......@@ -800,14 +810,21 @@ SettingsAccessor::FileAccessor::FileAccessor(const QByteArray &id,
const QString &defaultSuffix,
const QString &environmentSuffix,
bool envSpecific,
bool versionStrict)
bool versionStrict, SettingsAccessor *accessor)
: m_id(id)
, m_environmentSpecific(envSpecific)
, m_versionStrict(versionStrict)
, m_accessor(accessor)
, m_writer(0)
{
assignSuffix(defaultSuffix, environmentSuffix);
}
SettingsAccessor::FileAccessor::~FileAccessor()
{
delete m_writer;
}
void SettingsAccessor::FileAccessor::assignSuffix(const QString &defaultSuffix,
const QString &environmentSuffix)
{
......@@ -820,11 +837,6 @@ void SettingsAccessor::FileAccessor::assignSuffix(const QString &defaultSuffix,
}
}
QString SettingsAccessor::FileAccessor::assembleFileName(const Project *project) const
{
return project->document()->fileName() + m_suffix;
}
bool SettingsAccessor::FileAccessor::findNewestCompatibleSetting(SettingsData *settings) const
{
const QString baseFileName = settings->m_fileName.toString();
......@@ -833,7 +845,6 @@ bool SettingsAccessor::FileAccessor::findNewestCompatibleSetting(SettingsData *s
settings->m_version = -1;
PersistentSettingsReader reader;
SettingsAccessor *acessor = SettingsAccessor::instance();
QFileInfo fileInfo(baseFileName);
QStringList fileNameFilter(fileInfo.fileName() + QLatin1String(".*"));
......@@ -845,10 +856,10 @@ bool SettingsAccessor::FileAccessor::findNewestCompatibleSetting(SettingsData *s
const QString &suffix = file.mid(fileInfo.fileName().length() + 1);
const QString &candidateFileName = baseFileName + QLatin1String(".") + suffix;
candidates.append(candidateFileName);
for (int candidateVersion = acessor->m_lastVersion;
candidateVersion >= acessor->m_firstVersion;
for (int candidateVersion = m_accessor->m_lastVersion;
candidateVersion >= m_accessor->m_firstVersion;
--candidateVersion) {
if (suffix == acessor->m_handlers.value(candidateVersion)->displayUserFileVersion()) {
if (suffix == m_accessor->m_handlers.value(candidateVersion)->displayUserFileVersion()) {
if (candidateVersion > settings->m_version) {
settings->m_version = candidateVersion;
settings->m_fileName = Utils::FileName::fromString(candidateFileName);
......@@ -876,7 +887,7 @@ bool SettingsAccessor::FileAccessor::findNewestCompatibleSetting(SettingsData *s
if (reader.load(fn)) {
settings->m_map = reader.restoreValues();
int candidateVersion = settings->m_map.value(QLatin1String(VERSION_KEY), 0).toInt();
if (candidateVersion == acessor->m_lastVersion + 1) {
if (candidateVersion == m_accessor->m_lastVersion + 1) {
settings->m_version = candidateVersion;
settings->m_fileName = fn;
return true;
......@@ -890,11 +901,9 @@ bool SettingsAccessor::FileAccessor::findNewestCompatibleSetting(SettingsData *s
return false;
}
bool SettingsAccessor::FileAccessor::readFile(Project *project,
SettingsData *settings) const
bool SettingsAccessor::FileAccessor::readFile(SettingsData *settings) const
{
PersistentSettingsReader reader;
settings->m_fileName = Utils::FileName::fromString(assembleFileName(project));
if (!reader.load(settings->m_fileName))
return false;
......@@ -905,43 +914,41 @@ bool SettingsAccessor::FileAccessor::readFile(Project *project,
if (!m_versionStrict)
return true;
if (settings->m_version < SettingsAccessor::instance()->m_firstVersion) {
if (settings->m_version < m_accessor->m_firstVersion) {
qWarning() << "Version" << settings->m_version << "in" << m_suffix << "too old.";
return false;
}
if (settings->m_version > SettingsAccessor::instance()->m_lastVersion + 1) {
if (settings->m_version > m_accessor->m_lastVersion + 1) {
if (!findNewestCompatibleSetting(settings))
return false;
settings->m_usingBackup = true;
project->setProperty(m_id.constData(), settings->m_fileName.toString());
m_accessor->project()->setProperty(m_id.constData(), settings->m_fileName.toString());
}
return true;
}
bool SettingsAccessor::FileAccessor::writeFile(const Project *project,
const SettingsData *settings) const
bool SettingsAccessor::FileAccessor::writeFile(const SettingsData *settings) const
{
PersistentSettingsWriter writer;
if (!m_writer || m_writer->fileName() != settings->m_fileName) {
delete m_writer;
m_writer = new Utils::PersistentSettingsWriter(settings->m_fileName, QLatin1String("QtCreatorProject"));
}