~michael-sheldon/ubuntu-keyboard/fix-oxide-dismiss-test

« back to all changes in this revision

Viewing changes to src/lib/logic/keyboardloader.cpp

  • Committer: Thomas Moenicke
  • Date: 2013-07-19 12:05:07 UTC
  • Revision ID: thomas.moenicke@canonical.com-20130719120507-lzw5oq50xm567x0j
initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; c-file-offsets: ((innamespace . 0)); -*-
 
2
/*
 
3
 * This file is part of Maliit Plugins
 
4
 *
 
5
 * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.
 
6
 *
 
7
 * Contact: Mohammad Anwari <Mohammad.Anwari@nokia.com>
 
8
 *
 
9
 * Redistribution and use in source and binary forms, with or without modification,
 
10
 * are permitted provided that the following conditions are met:
 
11
 *
 
12
 * Redistributions of source code must retain the above copyright notice, this list
 
13
 * of conditions and the following disclaimer.
 
14
 * Redistributions in binary form must reproduce the above copyright notice, this list
 
15
 * of conditions and the following disclaimer in the documentation and/or other materials
 
16
 * provided with the distribution.
 
17
 * Neither the name of Nokia Corporation nor the names of its contributors may be
 
18
 * used to endorse or promote products derived from this software without specific
 
19
 * prior written permission.
 
20
 *
 
21
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
 
22
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 
23
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 
24
 * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 
25
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 
26
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 
28
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 
29
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
30
 *
 
31
 */
 
32
 
 
33
#include <QDir>
 
34
#include <QFile>
 
35
#include <QRegExp>
 
36
 
 
37
#include "parser/layoutparser.h"
 
38
#include "coreutils.h"
 
39
 
 
40
#include "keyboardloader.h"
 
41
 
 
42
namespace {
 
43
 
 
44
using namespace MaliitKeyboard;
 
45
 
 
46
// For getting languages directory we use a function instead of global constant
 
47
// because global constants are initialized before main runs. In this case that
 
48
// would mean that CoreUtils::pluginDataDirectory is ran before any code in main
 
49
// and it sets its static variable once. We want to be able to set the
 
50
// environment variable altering behaviour of pluginDataDirectory for testing
 
51
// purposes.
 
52
QString getLanguagesDir()
 
53
{
 
54
    static QString languages_dir;
 
55
 
 
56
    if (languages_dir.isEmpty()) {
 
57
        // From http://doc.qt.nokia.com/4.7/qdir.html#separator: If you always
 
58
        // use "/", Qt will translate your paths to conform to the underlying
 
59
        // operating system.
 
60
        languages_dir = CoreUtils::pluginDataDirectory() + "/languages";
 
61
    }
 
62
 
 
63
    return languages_dir;
 
64
}
 
65
 
 
66
typedef const QStringList (LayoutParser::*ParserFunc)() const;
 
67
 
 
68
TagKeyboardPtr getTagKeyboard(const QString &id)
 
69
{
 
70
    if (id.isEmpty()) {
 
71
        return TagKeyboardPtr();
 
72
    }
 
73
 
 
74
    const QString path(getLanguagesDir() + "/" + id + ".xml");
 
75
    QFile file(path);
 
76
 
 
77
    if (file.exists()) {
 
78
        file.open(QIODevice::ReadOnly);
 
79
 
 
80
        LayoutParser parser(&file);
 
81
        const bool result(parser.parse());
 
82
 
 
83
        file.close();
 
84
        if (result) {
 
85
            return parser.keyboard();
 
86
        } else {
 
87
            qWarning() << __PRETTY_FUNCTION__ << "Could not parse file:" << path << ", error:" << parser.errorString();
 
88
        }
 
89
    } else {
 
90
        qWarning() << __PRETTY_FUNCTION__ << "File not found:" << path;
 
91
    }
 
92
 
 
93
    return TagKeyboardPtr();
 
94
}
 
95
 
 
96
QPair<Key, KeyDescription> keyAndDescFromTags(const TagKeyPtr &key,
 
97
                                              const TagBindingPtr &binding,
 
98
                                              int row)
 
99
{
 
100
    Key skey;
 
101
    KeyDescription skey_description;
 
102
 
 
103
    skey.setExtendedKeysEnabled(key->extended());
 
104
    skey.rLabel().setText(binding->label());
 
105
 
 
106
    if (binding->dead()) {
 
107
        // TODO: document it.
 
108
        skey.setAction(Key::ActionDead);
 
109
    } else {
 
110
        skey.setAction(static_cast<Key::Action>(binding->action()));
 
111
    }
 
112
 
 
113
    skey.setCommandSequence(binding->sequence());
 
114
    skey.setIcon(binding->icon().toUtf8());
 
115
    skey.setStyle(static_cast<Key::Style>(key->style()));
 
116
 
 
117
    skey_description.row = row;
 
118
    skey_description.use_rtl_icon = key->rtl();
 
119
    skey_description.left_spacer = false;
 
120
    skey_description.right_spacer = false;
 
121
    skey_description.width = static_cast<KeyDescription::Width>(key->width());
 
122
 
 
123
    switch (skey.action()) {
 
124
    case Key::ActionBackspace:
 
125
        skey_description.icon = KeyDescription::BackspaceIcon;
 
126
        break;
 
127
    case Key::ActionReturn:
 
128
        skey_description.icon = KeyDescription::ReturnIcon;
 
129
        break;
 
130
    case Key::ActionShift:
 
131
        skey_description.icon = KeyDescription::ShiftIcon;
 
132
        break;
 
133
    case Key::ActionClose:
 
134
        skey_description.icon = KeyDescription::CloseIcon;
 
135
        break;
 
136
    case Key::ActionLeftLayout:
 
137
        skey_description.icon = KeyDescription::LeftLayoutIcon;
 
138
        break;
 
139
    case Key::ActionRightLayout:
 
140
        skey_description.icon = KeyDescription::RightLayoutIcon;
 
141
        break;
 
142
    default:
 
143
        if (skey.icon().isEmpty()) {
 
144
            skey_description.icon = KeyDescription::NoIcon;
 
145
        } else {
 
146
            skey_description.icon = KeyDescription::CustomIcon;
 
147
        }
 
148
        break;
 
149
    }
 
150
 
 
151
    skey_description.font_group = KeyDescription::NormalFontGroup;
 
152
 
 
153
    return qMakePair(skey, skey_description);
 
154
}
 
155
 
 
156
Keyboard getKeyboard(const TagKeyboardPtr &keyboard,
 
157
                     bool shifted = false,
 
158
                     int page = 0,
 
159
                     const QString &dead_label = "")
 
160
{
 
161
    Keyboard skeyboard;
 
162
    const QChar dead_key((dead_label.size() == 1) ? dead_label[0] : QChar::Null);
 
163
 
 
164
    if (keyboard) {
 
165
        TagLayoutPtrs layouts(keyboard->layouts());
 
166
 
 
167
        if (not layouts.isEmpty()) {
 
168
            const TagSectionPtrs sections(layouts.first()->sections());
 
169
            // sections cannot be empty - parser does not allow that.
 
170
            const TagSectionPtr section(sections[page % sections.size()]);
 
171
            const TagRowPtrs rows(section->rows());
 
172
            int row_num(0);
 
173
            QString section_style(section->style());
 
174
            int key_count(0);
 
175
 
 
176
            Q_FOREACH (const TagRowPtr &row, rows) {
 
177
                const TagRowElementPtrs elements(row->elements());
 
178
                bool spacer_met(false);
 
179
 
 
180
                Q_FOREACH (const TagRowElementPtr &element, elements) {
 
181
                    if (element->element_type() == TagRowElement::Key) {
 
182
                        const TagKeyPtr key(element.staticCast<TagKey>());
 
183
                        const TagBindingPtr binding(key->binding());
 
184
                        TagBindingPtr the_binding;
 
185
                        const TagModifiersPtrs all_modifiers(binding->modifiers());
 
186
 
 
187
                        ++key_count;
 
188
 
 
189
                        if (not shifted or all_modifiers.isEmpty()) {
 
190
                            the_binding = binding;
 
191
                        } else {
 
192
                            Q_FOREACH (const TagModifiersPtr &modifiers, all_modifiers) {
 
193
                                if (modifiers->keys() == TagModifiers::Shift) {
 
194
                                    the_binding = modifiers->binding();
 
195
                                }
 
196
                            }
 
197
                            if (not the_binding) {
 
198
                                the_binding = binding;
 
199
                            }
 
200
                        }
 
201
 
 
202
                        const int index(dead_key.isNull() ? -1 : the_binding->accents().indexOf(dead_key));
 
203
                        QPair<Key, KeyDescription> key_and_desc(keyAndDescFromTags(key, the_binding, row_num));
 
204
 
 
205
                        key_and_desc.first.rLabel().setText(index < 0 ? the_binding->label()
 
206
                                                                      : the_binding->accented_labels().at(index));
 
207
                        key_and_desc.second.left_spacer = spacer_met;
 
208
                        key_and_desc.second.right_spacer = false;
 
209
 
 
210
                        skeyboard.keys.append(key_and_desc.first);
 
211
                        skeyboard.key_descriptions.append(key_and_desc.second);
 
212
                        spacer_met = false;
 
213
                    } else { // spacer
 
214
                        if (not skeyboard.key_descriptions.isEmpty()) {
 
215
                            KeyDescription &previous_skey_description(skeyboard.key_descriptions.last());
 
216
 
 
217
                            if (previous_skey_description.row == row_num) {
 
218
                                previous_skey_description.right_spacer = true;
 
219
                            }
 
220
                        }
 
221
                        spacer_met = true;
 
222
                    }
 
223
                }
 
224
                ++row_num;
 
225
            }
 
226
            if (section_style.isEmpty()) {
 
227
                section_style = "keys" + QString::number(key_count);
 
228
            }
 
229
            skeyboard.style_name = section_style;
 
230
        }
 
231
    }
 
232
    return skeyboard;
 
233
}
 
234
 
 
235
QPair<TagKeyPtr, TagBindingPtr> getTagKeyAndBinding(const TagKeyboardPtr &keyboard,
 
236
                                                    const QString &label,
 
237
                                                    bool *shifted)
 
238
{
 
239
    QPair<TagKeyPtr, TagBindingPtr> pair;
 
240
 
 
241
    if (keyboard) {
 
242
        TagLayoutPtrs layouts(keyboard->layouts());
 
243
 
 
244
        if (not layouts.isEmpty()) {
 
245
            // sections cannot be empty - parser does not allow that.
 
246
            TagRowPtrs rows(layouts.first()->sections().first()->rows());
 
247
 
 
248
            Q_FOREACH (const TagRowPtr &row, rows) {
 
249
                TagRowElementPtrs elements(row->elements());
 
250
 
 
251
                Q_FOREACH (const TagRowElementPtr &element, elements) {
 
252
                    if (element->element_type() == TagRowElement::Key) {
 
253
                        TagKeyPtr key(element.staticCast<TagKey>());
 
254
                        TagBindingPtr the_binding;
 
255
                        TagBindingPtr binding(key->binding());
 
256
 
 
257
                        // Hotfix for suppressing long-press on space bringing
 
258
                        // up extended keys if another key has empty label, in
 
259
                        // given layout.
 
260
                        // FIXME: Make extended keyboard/keyarea part of key
 
261
                        // model instead, to avoid wrong lookups.
 
262
                        if (binding->action() == TagBinding::Space) {
 
263
                            continue;
 
264
                        }
 
265
                        if (binding->label() == label) {
 
266
                            the_binding = binding;
 
267
                            *shifted = false;
 
268
                        } else {
 
269
                            const TagModifiersPtrs all_modifiers(binding->modifiers());
 
270
 
 
271
                            Q_FOREACH (const TagModifiersPtr &modifiers, all_modifiers) {
 
272
                                const TagBindingPtr mod_binding(modifiers->binding());
 
273
 
 
274
                                if (mod_binding->label() == label) {
 
275
                                    the_binding = mod_binding;
 
276
                                    *shifted = (modifiers->keys() == TagModifiers::Shift);
 
277
                                    break;
 
278
                                }
 
279
                            }
 
280
                        }
 
281
 
 
282
                        if (the_binding) {
 
283
                            pair.first = key;
 
284
                            pair.second = the_binding;
 
285
                            return pair;
 
286
                        }
 
287
                    }
 
288
                }
 
289
            }
 
290
        }
 
291
    }
 
292
    return pair;
 
293
}
 
294
 
 
295
Keyboard getImportedKeyboard(const QString &id,
 
296
                             ParserFunc func,
 
297
                             const QString &file_prefix,
 
298
                             const QString &default_file,
 
299
                             int page = 0)
 
300
{
 
301
    QString path(getLanguagesDir() + "/" + id + ".xml");
 
302
    QFile file(path);
 
303
 
 
304
    if (file.exists()) {
 
305
        file.open(QIODevice::ReadOnly);
 
306
 
 
307
        LayoutParser parser(&file);
 
308
        const bool result(parser.parse());
 
309
 
 
310
        file.close();
 
311
        if (result) {
 
312
            const QStringList f_results((parser.*func)());
 
313
 
 
314
            Q_FOREACH (const QString &f_result, f_results) {
 
315
                const QFileInfo file_info(getLanguagesDir() + "/" + f_result);
 
316
 
 
317
                if (file_info.exists() and file_info.isFile()) {
 
318
                    const TagKeyboardPtr keyboard(getTagKeyboard(file_info.baseName()));
 
319
                    return getKeyboard(keyboard, false, page);
 
320
                }
 
321
            }
 
322
 
 
323
            // If we got there then it means that we got xml layout file that does not use
 
324
            // new <import> syntax or just does not specify explicitly which file to import.
 
325
            // In this case we have to search imports list for entry with filename beginning
 
326
            // with file_prefix.
 
327
            const QStringList imports(parser.imports());
 
328
            const QRegExp file_regexp("^(" + file_prefix + ".*).xml$");
 
329
 
 
330
            Q_FOREACH (const QString &import, imports) {
 
331
                if (file_regexp.exactMatch(import)) {
 
332
                    QFileInfo file_info(getLanguagesDir() + "/" + import);
 
333
 
 
334
                    if (file_info.exists() and file_info.isFile()) {
 
335
                        const TagKeyboardPtr keyboard(getTagKeyboard(file_regexp.cap(1)));
 
336
                        return getKeyboard(keyboard, false, page);
 
337
                    }
 
338
                }
 
339
            }
 
340
 
 
341
            // If we got there then we try to just load a file with name in default_file.
 
342
            QFileInfo file_info(getLanguagesDir() + "/" + default_file);
 
343
 
 
344
            if (file_info.exists() and file_info.isFile()) {
 
345
                const TagKeyboardPtr keyboard(getTagKeyboard(file_info.baseName()));
 
346
                return getKeyboard(keyboard, false);
 
347
            }
 
348
        } else {
 
349
            qWarning() << __PRETTY_FUNCTION__ << "Could not parse file:" << path << ", error:" << parser.errorString();
 
350
        }
 
351
    } else {
 
352
        qWarning() << __PRETTY_FUNCTION__ << "File not found:" << path;
 
353
    }
 
354
    return Keyboard();
 
355
}
 
356
 
 
357
} // anonymous namespace
 
358
 
 
359
namespace MaliitKeyboard {
 
360
 
 
361
class KeyboardLoaderPrivate
 
362
{
 
363
public:
 
364
 
 
365
    QString active_id;
 
366
};
 
367
 
 
368
KeyboardLoader::KeyboardLoader(QObject *parent)
 
369
    : QObject(parent)
 
370
    , d_ptr(new KeyboardLoaderPrivate)
 
371
{}
 
372
 
 
373
KeyboardLoader::~KeyboardLoader()
 
374
{}
 
375
 
 
376
QStringList KeyboardLoader::ids() const
 
377
{
 
378
    QStringList ids;
 
379
    QDir dir(getLanguagesDir(),
 
380
             "*.xml",
 
381
             QDir::Name | QDir::IgnoreCase,
 
382
             QDir::Files | QDir::NoSymLinks | QDir::Readable);
 
383
 
 
384
    if (dir.exists()) {
 
385
        QFileInfoList file_infos(dir.entryInfoList());
 
386
 
 
387
        Q_FOREACH (const QFileInfo &file_info, file_infos) {
 
388
            QFile file(file_info.filePath());
 
389
            file.open(QIODevice::ReadOnly);
 
390
            LayoutParser parser(&file);
 
391
 
 
392
            if (parser.isLanguageFile()) {
 
393
                ids.append(file_info.baseName());
 
394
            }
 
395
        }
 
396
    }
 
397
    return ids;
 
398
}
 
399
 
 
400
QString KeyboardLoader::activeId() const
 
401
{
 
402
    Q_D(const KeyboardLoader);
 
403
    return d->active_id;
 
404
}
 
405
 
 
406
void KeyboardLoader::setActiveId(const QString &id)
 
407
{
 
408
    Q_D(KeyboardLoader);
 
409
 
 
410
    if (d->active_id != id) {
 
411
        d->active_id = id;
 
412
 
 
413
        // FIXME: Emit only after parsing new keyboard.
 
414
        Q_EMIT keyboardsChanged();
 
415
    }
 
416
}
 
417
 
 
418
QString KeyboardLoader::title(const QString &id) const
 
419
{
 
420
    const TagKeyboardPtr keyboard(getTagKeyboard(id));
 
421
 
 
422
    if (keyboard) {
 
423
        return keyboard->title();
 
424
    }
 
425
 
 
426
    return QString();
 
427
}
 
428
 
 
429
Keyboard KeyboardLoader::keyboard() const
 
430
{
 
431
    Q_D(const KeyboardLoader);
 
432
    TagKeyboardPtr keyboard(getTagKeyboard(d->active_id));
 
433
 
 
434
    return getKeyboard(keyboard);
 
435
}
 
436
 
 
437
Keyboard KeyboardLoader::nextKeyboard() const
 
438
{
 
439
    Q_D(const KeyboardLoader);
 
440
 
 
441
    const QStringList all_ids(ids());
 
442
 
 
443
    if (all_ids.isEmpty()) {
 
444
        return Keyboard();
 
445
    }
 
446
 
 
447
    int next_index(all_ids.indexOf(d->active_id) + 1);
 
448
 
 
449
    if (next_index >= all_ids.size()) {
 
450
        next_index = 0;
 
451
    }
 
452
 
 
453
    TagKeyboardPtr keyboard(getTagKeyboard(all_ids[next_index]));
 
454
 
 
455
    return getKeyboard(keyboard);
 
456
}
 
457
 
 
458
Keyboard KeyboardLoader::previousKeyboard() const
 
459
{
 
460
    Q_D(const KeyboardLoader);
 
461
 
 
462
    const QStringList all_ids(ids());
 
463
 
 
464
    if (all_ids.isEmpty()) {
 
465
        return Keyboard();
 
466
    }
 
467
 
 
468
    int previous_index(all_ids.indexOf(d->active_id) - 1);
 
469
 
 
470
    if (previous_index < 0) {
 
471
        previous_index = 0;
 
472
    }
 
473
 
 
474
    TagKeyboardPtr keyboard(getTagKeyboard(all_ids[previous_index]));
 
475
 
 
476
    return getKeyboard(keyboard);
 
477
}
 
478
 
 
479
Keyboard KeyboardLoader::shiftedKeyboard() const
 
480
{
 
481
    Q_D(const KeyboardLoader);
 
482
    TagKeyboardPtr keyboard(getTagKeyboard(d->active_id));
 
483
 
 
484
    return getKeyboard(keyboard, true);
 
485
}
 
486
 
 
487
Keyboard KeyboardLoader::symbolsKeyboard(int page) const
 
488
{
 
489
    Q_D(const KeyboardLoader);
 
490
 
 
491
    return getImportedKeyboard(d->active_id, &LayoutParser::symviews, "symbols", "symbols_en.xml", page);
 
492
}
 
493
 
 
494
Keyboard KeyboardLoader::deadKeyboard(const Key &dead) const
 
495
{
 
496
    Q_D(const KeyboardLoader);
 
497
    TagKeyboardPtr keyboard(getTagKeyboard(d->active_id));
 
498
 
 
499
    return getKeyboard(keyboard, false, 0, dead.label().text());
 
500
}
 
501
 
 
502
Keyboard KeyboardLoader::shiftedDeadKeyboard(const Key &dead) const
 
503
{
 
504
    Q_D(const KeyboardLoader);
 
505
    TagKeyboardPtr keyboard(getTagKeyboard(d->active_id));
 
506
 
 
507
    return getKeyboard(keyboard, true, 0, dead.label().text());
 
508
}
 
509
 
 
510
Keyboard KeyboardLoader::extendedKeyboard(const Key &key) const
 
511
{
 
512
    // Hotfix for suppressing long-press on space bringing up extended keys if
 
513
    // another key has empty label, in given layout.
 
514
    // FIXME: Make extended keyboard/keyarea part of key model instead, to
 
515
    // avoid wrong lookups.
 
516
    if (key.action() == Key::ActionSpace) {
 
517
        return Keyboard();
 
518
    }
 
519
 
 
520
    Q_D(const KeyboardLoader);
 
521
    const TagKeyboardPtr keyboard(getTagKeyboard(d->active_id));
 
522
    bool shifted(false);
 
523
    const QPair<TagKeyPtr, TagBindingPtr> pair(getTagKeyAndBinding(keyboard, key.label().text(), &shifted));
 
524
    Keyboard skeyboard;
 
525
 
 
526
    if (pair.first and pair.second) {
 
527
        const TagExtendedPtr extended(pair.first->extended());
 
528
 
 
529
        if (extended) {
 
530
            const TagRowPtrs rows(extended->rows());
 
531
            int row_index(0);
 
532
 
 
533
            Q_FOREACH (const TagRowPtr &row, rows) {
 
534
                const TagRowElementPtrs elements(row->elements());
 
535
 
 
536
                Q_FOREACH (const TagRowElementPtr &element, elements) {
 
537
                    switch (element->element_type()) {
 
538
                    case TagRowElement::Key: {
 
539
                        const TagKeyPtr key(element.staticCast<TagKey>());
 
540
                        const TagBindingPtr binding(key->binding());
 
541
                        TagBindingPtr the_binding;
 
542
 
 
543
                        if (shifted) {
 
544
                            const TagModifiersPtrs all_modifiers(binding->modifiers());
 
545
 
 
546
                            Q_FOREACH(const TagModifiersPtr &modifiers, all_modifiers) {
 
547
                                if (modifiers->keys() == TagModifiers::Shift) {
 
548
                                    the_binding = modifiers->binding();
 
549
                                }
 
550
                            }
 
551
                        }
 
552
                        if (not the_binding) {
 
553
                            the_binding = binding;
 
554
                        }
 
555
 
 
556
                        QPair<Key, KeyDescription> key_and_desc(keyAndDescFromTags(key, the_binding, row_index));
 
557
 
 
558
                        skeyboard.keys.append(key_and_desc.first);
 
559
                        skeyboard.key_descriptions.append(key_and_desc.second);
 
560
                    } break;
 
561
 
 
562
                    case TagRowElement::Spacer:
 
563
                        break;
 
564
                    }
 
565
                }
 
566
                ++row_index;
 
567
            }
 
568
            // I don't like this prepending source key idea - it should be done
 
569
            // in language layout file.
 
570
            if (row_index == 1
 
571
                and not key.label().text().isEmpty()
 
572
                and key.action() == Key::ActionInsert) {
 
573
                Key first_key(skeyboard.keys.first());
 
574
                KeyDescription first_desc(skeyboard.key_descriptions.first());
 
575
 
 
576
                first_key.rLabel().setText(key.label().text());
 
577
                first_key.setIcon(key.icon());
 
578
                skeyboard.keys.prepend(first_key);
 
579
                skeyboard.key_descriptions.prepend(first_desc);
 
580
            }
 
581
        }
 
582
    }
 
583
    return skeyboard;
 
584
}
 
585
 
 
586
Keyboard KeyboardLoader::numberKeyboard() const
 
587
{
 
588
    Q_D(const KeyboardLoader);
 
589
 
 
590
    return getImportedKeyboard(d->active_id, &LayoutParser::numbers, "number", "number.xml");
 
591
}
 
592
 
 
593
Keyboard KeyboardLoader::phoneNumberKeyboard() const
 
594
{
 
595
    Q_D(const KeyboardLoader);
 
596
 
 
597
    return getImportedKeyboard(d->active_id, &LayoutParser::phonenumbers, "phonenumber", "phonenumber.xml");
 
598
}
 
599
 
 
600
} // namespace MaliitKeyboard