1 /*
2 Copyright (c) 2020, Lukas Holecek <hluk@email.cz>
3
4 This file is part of CopyQ.
5
6 CopyQ is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 CopyQ is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with CopyQ. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "settings.h"
21
22 #include "common/common.h"
23 #include "common/config.h"
24 #include "common/log.h"
25
26 #include <QCoreApplication>
27 #include <QDateTime>
28 #include <QFileInfo>
29 #include <QStringList>
30
31 namespace {
32
needsUpdate(const Settings & newSettings,const QSettings & oldSettings)33 bool needsUpdate(const Settings &newSettings, const QSettings &oldSettings)
34 {
35 if ( Settings::isEmpty(oldSettings) )
36 return false;
37
38 const QFileInfo newFile(newSettings.fileName());
39 const QFileInfo oldFile(oldSettings.fileName());
40
41 return newFile.size() != oldFile.size()
42 || newFile.lastModified() < oldFile.lastModified();
43 }
44
copySettings(const QSettings & from,QSettings * to)45 void copySettings(const QSettings &from, QSettings *to)
46 {
47 Q_ASSERT(from.group().isEmpty());
48 Q_ASSERT(to->group().isEmpty());
49
50 to->clear();
51
52 for ( const auto &key : from.allKeys() )
53 to->setValue(key, from.value(key));
54
55 to->sync();
56 }
57
lockFileName(const QString & path)58 QString lockFileName(const QString &path)
59 {
60 if ( path.isEmpty() )
61 return getConfigurationFilePath(".bad");
62 return path + ".bad";
63 }
64
isLastSaveUnfinished(const QString & path)65 bool isLastSaveUnfinished(const QString &path)
66 {
67 return QFile::exists(lockFileName(path));
68 }
69
beginSave(const QString & path)70 void beginSave(const QString &path)
71 {
72 QFile lockFile(lockFileName(path));
73 lockFile.open(QIODevice::WriteOnly);
74 }
75
endSave(const QString & path)76 void endSave(const QString &path)
77 {
78 QFile::remove(lockFileName(path));
79 }
80
81 } // namespace
82
83 bool Settings::canModifySettings = false;
84
isEmpty(const QSettings & settings)85 bool Settings::isEmpty(const QSettings &settings)
86 {
87 return settings.childGroups().isEmpty();
88 }
89
Settings()90 Settings::Settings()
91 : m_settings(
92 QSettings::defaultFormat(),
93 QSettings::UserScope,
94 QCoreApplication::organizationName(),
95 QCoreApplication::applicationName() + "-bak" )
96 , m_changed(false)
97 {
98 }
99
Settings(const QString & path)100 Settings::Settings(const QString &path)
101 : m_settings(path + ".bak", QSettings::IniFormat)
102 , m_path(path)
103 {
104 }
105
~Settings()106 Settings::~Settings()
107 {
108 // Only main application is allowed to change settings.
109 if (canModifySettings && m_changed) {
110 m_settings.sync();
111
112 beginSave(m_path);
113
114 while ( !m_settings.group().isEmpty() )
115 m_settings.endGroup();
116
117 save();
118
119 endSave(m_path);
120 }
121 }
122
restore()123 void Settings::restore()
124 {
125 if ( isLastSaveUnfinished(m_path) ) {
126 log("Restoring application settings", LogWarning);
127
128 if ( isEmpty() )
129 log("Cannot restore application settings", LogError);
130 else
131 save();
132
133 endSave(m_path);
134 } else if ( m_path.isEmpty() ) {
135 restore( QSettings() );
136 } else {
137 restore( QSettings(m_path, QSettings::IniFormat) );
138 }
139 }
140
restore(const QSettings & settings)141 void Settings::restore(const QSettings &settings)
142 {
143 if ( needsUpdate(*this, settings) )
144 copySettings(settings, &m_settings);
145 }
146
save()147 void Settings::save()
148 {
149 if ( m_path.isEmpty() ) {
150 QSettings settings;
151 copySettings(m_settings, &settings);
152 } else {
153 QSettings settings(m_path, QSettings::IniFormat);
154 copySettings(m_settings, &settings);
155 }
156 }
157