2
* Copyright (C) 2011 Andriy Rysin (rysin@kde.org)
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; either version 2 of the License, or
7
* (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
#include "layout_memory_persister.h"
22
#include <kconfiggroup.h>
23
#include <ksharedconfig.h>
24
#include <kstandarddirs.h>
26
#include <QtCore/QFile>
27
#include <QtXml/qdom.h>
28
#include <QtXml/qxml.h>
30
#include "keyboard_config.h"
31
#include "layout_memory.h"
34
static const char* VERSION = "1.0";
35
static const char* DOC_NAME = "LayoutMap";
36
static const char* ROOT_NODE = "LayoutMap";
37
static const char* VERSION_ATTRIBUTE = "version";
38
static const char* SWITCH_MODE_ATTRIBUTE = "SwitchMode";
39
static const char* ITEM_NODE = "item";
40
static const QString CURRENT_LAYOUT_ATTRIBUTE("currentLayout");
41
static const char* OWNER_KEY_ATTRIBUTE = "ownerKey";
42
static const char* LAYOUTS_ATTRIBUTE = "layouts";
44
static const char* LIST_SEPARATOR = ",";
46
static const char* REL_SESSION_FILE_PATH = "/session/keyboard/layout_memory.xml";
48
QString LayoutMemoryPersister::getLayoutMapAsString()
53
QDomDocument doc(DOC_NAME);
54
QDomElement root = doc.createElement(ROOT_NODE);
55
root.setAttribute(VERSION_ATTRIBUTE, VERSION);
56
root.setAttribute(SWITCH_MODE_ATTRIBUTE, KeyboardConfig::getSwitchingPolicyString(layoutMemory.keyboardConfig.switchingPolicy));
57
doc.appendChild(root);
59
if( layoutMemory.keyboardConfig.switchingPolicy == KeyboardConfig::SWITCH_POLICY_GLOBAL ) {
60
if( ! globalLayout.isValid() )
63
QDomElement item = doc.createElement(ITEM_NODE);
64
item.setAttribute(CURRENT_LAYOUT_ATTRIBUTE, globalLayout.toString());
65
root.appendChild(item);
68
foreach(const QString& key , layoutMemory.layoutMap.keys()) {
69
QDomElement item = doc.createElement(ITEM_NODE);
70
item.setAttribute(OWNER_KEY_ATTRIBUTE, key);
71
item.setAttribute(CURRENT_LAYOUT_ATTRIBUTE, layoutMemory.layoutMap[key].currentLayout.toString());
73
QString layoutSetString;
74
foreach(const LayoutUnit& layoutUnit, layoutMemory.layoutMap[key].layouts) {
75
if( ! layoutSetString.isEmpty() ) {
76
layoutSetString += LIST_SEPARATOR;
78
layoutSetString += layoutUnit.toString();
80
item.setAttribute(LAYOUTS_ATTRIBUTE, layoutSetString);
81
root.appendChild(item);
85
return doc.toString();
88
static bool isRestoreSession()
90
KConfigGroup c(KSharedConfig::openConfig("ksmserverrc", KConfig::NoGlobals), "General");
91
kDebug() << "loginMode:" << c.readEntry("loginMode");
92
QString loginMode = c.readEntry("loginMode");
93
return loginMode != "default" && loginMode != "restoreSavedSession"; // we don't know how to restore saved session - only previous one
96
bool LayoutMemoryPersister::save(const QString& moduleName)
98
if( isRestoreSession() ) {
99
QString relPath = moduleName + REL_SESSION_FILE_PATH;
100
QFile file(KStandardDirs::locateLocal("data", relPath));
101
return saveToFile(file);
106
bool LayoutMemoryPersister::restore(const QString& moduleName)
108
if( isRestoreSession() ) {
109
QString relPath = moduleName + REL_SESSION_FILE_PATH;
110
QFile file(KStandardDirs::locateLocal("data", relPath));
111
return restoreFromFile(file);
117
bool LayoutMemoryPersister::saveToFile(const QFile& file_)
119
QString xml = getLayoutMapAsString();
123
QFile file(file_.fileName()); // so we don't expose the file we open/close to the caller
124
if( ! file.open( QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text) ) {
125
kWarning() << "Failed to open layout memory xml file for writing" << file.fileName();
129
QTextStream out(&file);
133
if( file.error() != QFile::NoError ) {
134
kWarning() << "Failed to store keyboard layout memory, error" << file.error();
140
kDebug() << "Keyboard layout memory stored into" << file.fileName() << "written" << file.pos();
146
class MapHandler : public QXmlDefaultHandler
149
MapHandler(const KeyboardConfig::SwitchingPolicy& switchingPolicy_):
151
switchingPolicy(switchingPolicy_) {}
153
bool startElement(const QString &/*namespaceURI*/, const QString &/*localName*/,
154
const QString &qName, const QXmlAttributes &attributes) {
156
if( qName == ROOT_NODE ) {
157
if( attributes.value(VERSION_ATTRIBUTE) != VERSION )
159
if( attributes.value(SWITCH_MODE_ATTRIBUTE) != KeyboardConfig::getSwitchingPolicyString(switchingPolicy) )
164
if( qName == ITEM_NODE ) {
168
if( switchingPolicy == KeyboardConfig::SWITCH_POLICY_GLOBAL ) {
169
globalLayout = LayoutUnit(attributes.value(CURRENT_LAYOUT_ATTRIBUTE));
172
QStringList layoutStrings = attributes.value(LAYOUTS_ATTRIBUTE).split(LIST_SEPARATOR);
174
foreach(const QString& layoutString, layoutStrings) {
175
layoutSet.layouts.append(LayoutUnit(layoutString));
177
layoutSet.currentLayout = LayoutUnit(attributes.value(CURRENT_LAYOUT_ATTRIBUTE));
178
QString ownerKey = attributes.value(OWNER_KEY_ATTRIBUTE);
180
if( ownerKey.trimmed().isEmpty() || ! layoutSet.isValid() )
183
layoutMap[ownerKey] = layoutSet;
190
QMap<QString, LayoutSet> layoutMap;
191
LayoutUnit globalLayout;
194
const KeyboardConfig::SwitchingPolicy& switchingPolicy;
197
template <typename T>
199
bool containsAll(QList<T> set1, QList<T> set2)
201
foreach(const T& t, set2) {
202
if( ! set1.contains(t) )
208
bool LayoutMemoryPersister::restoreFromFile(const QFile& file_)
210
globalLayout = LayoutUnit();
215
QFile file(file_.fileName()); // so we don't expose the file we open/close to the caller
216
if( ! file.open( QIODevice::ReadOnly | QIODevice::Text ) ) {
217
kWarning() << "Failed to open layout memory xml file for reading" << file.fileName() << "error:" << file.error();
221
MapHandler mapHandler(layoutMemory.keyboardConfig.switchingPolicy);
223
QXmlSimpleReader reader;
224
reader.setContentHandler(&mapHandler);
225
reader.setErrorHandler(&mapHandler);
227
QXmlInputSource xmlInputSource(&file);
228
kDebug() << "Restoring keyboard layout map from" << file.fileName();
230
if( ! reader.parse(xmlInputSource) ) {
231
kWarning() << "Failed to parse the layout memory file" << file.fileName();
235
if( layoutMemory.keyboardConfig.switchingPolicy == KeyboardConfig::SWITCH_POLICY_GLOBAL ) {
236
if( mapHandler.globalLayout.isValid() && layoutMemory.keyboardConfig.layouts.contains(mapHandler.globalLayout)) {
237
globalLayout = mapHandler.globalLayout;
238
kDebug() << "Restored global layout" << globalLayout.toString();
242
layoutMemory.layoutMap.clear();
243
foreach(const QString& key, mapHandler.layoutMap.keys()) {
244
if( containsAll(layoutMemory.keyboardConfig.layouts, mapHandler.layoutMap[key].layouts) ) {
245
layoutMemory.layoutMap.insert(key, mapHandler.layoutMap[key]);
248
kDebug() << "Restored layouts for" << layoutMemory.layoutMap.size() << "containers";
253
bool LayoutMemoryPersister::canPersist() {
254
// we can't persist per window - as we're using window id which is not preserved between sessions
255
bool windowMode = layoutMemory.keyboardConfig.switchingPolicy == KeyboardConfig::SWITCH_POLICY_WINDOW;
257
kDebug() << "Not saving session for window mode";