~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to kcontrol/keyboard/layout_memory_persister.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  Copyright (C) 2011 Andriy Rysin (rysin@kde.org)
 
3
 *
 
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.
 
8
 *
 
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.
 
13
 *
 
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.
 
17
 */
 
18
 
 
19
#include "layout_memory_persister.h"
 
20
 
 
21
#include <kdebug.h>
 
22
#include <kconfiggroup.h>
 
23
#include <ksharedconfig.h>
 
24
#include <kstandarddirs.h>
 
25
 
 
26
#include <QtCore/QFile>
 
27
#include <QtXml/qdom.h>
 
28
#include <QtXml/qxml.h>
 
29
 
 
30
#include "keyboard_config.h"
 
31
#include "layout_memory.h"
 
32
 
 
33
 
 
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";
 
43
 
 
44
static const char* LIST_SEPARATOR = ",";
 
45
 
 
46
static const char* REL_SESSION_FILE_PATH = "/session/keyboard/layout_memory.xml";
 
47
 
 
48
QString LayoutMemoryPersister::getLayoutMapAsString()
 
49
{
 
50
        if( ! canPersist() )
 
51
                return "";
 
52
 
 
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);
 
58
 
 
59
        if( layoutMemory.keyboardConfig.switchingPolicy == KeyboardConfig::SWITCH_POLICY_GLOBAL ) {
 
60
                if( ! globalLayout.isValid() )
 
61
                        return "";
 
62
 
 
63
                QDomElement item = doc.createElement(ITEM_NODE);
 
64
                item.setAttribute(CURRENT_LAYOUT_ATTRIBUTE, globalLayout.toString());
 
65
                root.appendChild(item);
 
66
        }
 
67
        else {
 
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());
 
72
 
 
73
                        QString layoutSetString;
 
74
                        foreach(const LayoutUnit& layoutUnit, layoutMemory.layoutMap[key].layouts) {
 
75
                                if( ! layoutSetString.isEmpty() ) {
 
76
                                        layoutSetString += LIST_SEPARATOR;
 
77
                                }
 
78
                                layoutSetString += layoutUnit.toString();
 
79
                        }
 
80
                        item.setAttribute(LAYOUTS_ATTRIBUTE, layoutSetString);
 
81
                        root.appendChild(item);
 
82
                }
 
83
        }
 
84
 
 
85
        return doc.toString();
 
86
}
 
87
 
 
88
static bool isRestoreSession()
 
89
{
 
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
 
94
}
 
95
 
 
96
bool LayoutMemoryPersister::save(const QString& moduleName)
 
97
{
 
98
        if( isRestoreSession() ) {
 
99
        QString relPath = moduleName + REL_SESSION_FILE_PATH;
 
100
        QFile file(KStandardDirs::locateLocal("data", relPath));
 
101
        return saveToFile(file);
 
102
    }
 
103
    return false;
 
104
}
 
105
 
 
106
bool LayoutMemoryPersister::restore(const QString& moduleName)
 
107
{
 
108
        if( isRestoreSession() ) {
 
109
        QString relPath = moduleName + REL_SESSION_FILE_PATH;
 
110
        QFile file(KStandardDirs::locateLocal("data", relPath));
 
111
        return restoreFromFile(file);
 
112
    }
 
113
    return false;
 
114
}
 
115
 
 
116
 
 
117
bool LayoutMemoryPersister::saveToFile(const QFile& file_)
 
118
{
 
119
        QString xml = getLayoutMapAsString();
 
120
        if( xml.isEmpty() )
 
121
                return false;
 
122
 
 
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();
 
126
        return false;
 
127
    }
 
128
 
 
129
    QTextStream out(&file);
 
130
    out << xml;
 
131
    out.flush();
 
132
 
 
133
    if( file.error() != QFile::NoError ) {
 
134
        kWarning() << "Failed to store keyboard layout memory, error" << file.error();
 
135
        file.close();
 
136
        file.remove();
 
137
        return false;
 
138
    }
 
139
    else {
 
140
        kDebug() << "Keyboard layout memory stored into" << file.fileName() << "written" << file.pos();
 
141
        return true;
 
142
    }
 
143
}
 
144
 
 
145
 
 
146
class MapHandler : public QXmlDefaultHandler
 
147
{
 
148
public:
 
149
        MapHandler(const KeyboardConfig::SwitchingPolicy& switchingPolicy_):
 
150
                verified(false),
 
151
                switchingPolicy(switchingPolicy_) {}
 
152
 
 
153
    bool startElement(const QString &/*namespaceURI*/, const QString &/*localName*/,
 
154
                      const QString &qName, const QXmlAttributes &attributes) {
 
155
 
 
156
        if( qName == ROOT_NODE ) {
 
157
                if( attributes.value(VERSION_ATTRIBUTE) != VERSION )
 
158
                        return false;
 
159
                if( attributes.value(SWITCH_MODE_ATTRIBUTE) != KeyboardConfig::getSwitchingPolicyString(switchingPolicy) )
 
160
                        return false;
 
161
 
 
162
                verified = true;
 
163
        }
 
164
        if( qName == ITEM_NODE ) {
 
165
                if( ! verified )
 
166
                        return false;
 
167
 
 
168
                if( switchingPolicy == KeyboardConfig::SWITCH_POLICY_GLOBAL ) {
 
169
                        globalLayout = LayoutUnit(attributes.value(CURRENT_LAYOUT_ATTRIBUTE));
 
170
                }
 
171
                else {
 
172
                    QStringList layoutStrings = attributes.value(LAYOUTS_ATTRIBUTE).split(LIST_SEPARATOR);
 
173
                        LayoutSet layoutSet;
 
174
                    foreach(const QString& layoutString, layoutStrings) {
 
175
                        layoutSet.layouts.append(LayoutUnit(layoutString));
 
176
                    }
 
177
                        layoutSet.currentLayout = LayoutUnit(attributes.value(CURRENT_LAYOUT_ATTRIBUTE));
 
178
                        QString ownerKey = attributes.value(OWNER_KEY_ATTRIBUTE);
 
179
 
 
180
                        if( ownerKey.trimmed().isEmpty() || ! layoutSet.isValid() )
 
181
                                return false;
 
182
 
 
183
                        layoutMap[ownerKey] = layoutSet;
 
184
                }
 
185
        }
 
186
        return verified;
 
187
    }
 
188
 
 
189
    bool verified;
 
190
    QMap<QString, LayoutSet> layoutMap;
 
191
    LayoutUnit globalLayout;
 
192
 
 
193
private:
 
194
    const KeyboardConfig::SwitchingPolicy& switchingPolicy;
 
195
};
 
196
 
 
197
template <typename T>
 
198
static
 
199
bool containsAll(QList<T> set1, QList<T> set2)
 
200
{
 
201
        foreach(const T& t, set2) {
 
202
                if( ! set1.contains(t) )
 
203
                        return false;
 
204
        }
 
205
        return true;
 
206
}
 
207
 
 
208
bool LayoutMemoryPersister::restoreFromFile(const QFile& file_)
 
209
{
 
210
        globalLayout = LayoutUnit();
 
211
 
 
212
        if( ! canPersist() )
 
213
                return false;
 
214
 
 
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();
 
218
        return false;
 
219
    }
 
220
 
 
221
        MapHandler mapHandler(layoutMemory.keyboardConfig.switchingPolicy);
 
222
 
 
223
        QXmlSimpleReader reader;
 
224
        reader.setContentHandler(&mapHandler);
 
225
        reader.setErrorHandler(&mapHandler);
 
226
 
 
227
        QXmlInputSource xmlInputSource(&file);
 
228
        kDebug() << "Restoring keyboard layout map from" << file.fileName();
 
229
 
 
230
        if( ! reader.parse(xmlInputSource) ) {
 
231
                kWarning() << "Failed to parse the layout memory file" << file.fileName();
 
232
                return false;
 
233
        }
 
234
 
 
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();
 
239
                }
 
240
        }
 
241
        else {
 
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]);
 
246
                        }
 
247
                }
 
248
                kDebug() << "Restored layouts for" << layoutMemory.layoutMap.size() << "containers";
 
249
        }
 
250
        return true;
 
251
}
 
252
 
 
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;
 
256
        if( windowMode ) {
 
257
                kDebug() << "Not saving session for window mode";
 
258
        }
 
259
        return !windowMode;
 
260
}