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

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;