not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / kcontrol / kxkb / kcmlayout.cpp
blobfccf6f8d08c3d35d6b9c185946693bbfe7a4c758
1 /*
2 * Copyright (C) 2003-2006 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 <QLabel>
20 #include <QComboBox>
21 #include <QTabWidget>
22 #include <QGroupBox>
23 #include <QPushButton>
24 #include <QHeaderView>
25 #include <QCheckBox>
26 #include <QRadioButton>
27 #include <QLineEdit>
28 #include <QWidget>
29 #include <QtGui/QtGui>
30 #include <QKeySequence>
32 #include <kicon.h>
33 #include <kdialog.h>
34 #include <kglobalaccel.h>
35 #include <kglobalsettings.h>
36 #include <kactioncollection.h>
37 #include <kglobal.h>
38 #include <kconfig.h>
39 #include <kdebug.h>
40 #include <kapplication.h>
41 #include <kiconloader.h>
42 #include <ktoolinvocation.h>
43 #include <kkeysequencewidget.h>
45 #include "extension.h"
46 #include "kxkbconfig.h"
47 #include "rules.h"
48 #include "pixmap.h"
49 #include "ui_kcmlayoutwidget.h"
51 #include "kcmlayout.h"
52 #include <KPluginFactory>
53 #include <KPluginLoader>
54 #include "kcmlayout.moc"
56 #ifdef HAVE_XKLAVIER
57 #include "xklavier_adaptor.h"
58 #endif
61 K_PLUGIN_FACTORY(KeyboardLayoutFactory,
62 registerPlugin<LayoutConfig>("keyboard_layout");
64 K_EXPORT_PLUGIN(KeyboardLayoutFactory("kxkb"))
67 static
68 bool localeAwareLessThan(const QString &s1, const QString &s2)
70 return QString::localeAwareCompare(s1, s2) < 0;
73 // sort by locale-aware value string
74 static QList<QString> getKeysSortedByVaue(const QHash<QString, QString>& map)
76 QList<QString> outList;
78 QMap<QString, QString> reverseMap;
79 // we have to add nums as translations can be dups and them reverse map will miss items
80 int i=0;
81 QString fmt("%1%2");
82 foreach (const QString& str, map.keys())
83 reverseMap.insert(fmt.arg(map[str], QString::number(i++)), str);
85 QList<QString> values = reverseMap.keys();
86 qSort(values.begin(), values.end(), localeAwareLessThan);
88 foreach (const QString& value, values)
89 outList << reverseMap[value];
91 int diff = map.keys().count() - reverseMap.keys().count();
92 if( diff > 0 ) {
93 kDebug() << "original keys" << map.keys().count() << "reverse map" << reverseMap.keys().count()
94 << "- translation encoding must have been messed up - padding layouts...";
95 for(int i=0; i<diff; i++)
96 reverseMap.insert(QString("%1%2").arg("nocrash", i), "nocrash");
99 return outList;
102 enum {
103 LAYOUT_COLUMN_FLAG = 0,
104 LAYOUT_COLUMN_NAME = 1,
105 LAYOUT_COLUMN_MAP = 2,
106 LAYOUT_COLUMN_VARIANT = 3,
107 LAYOUT_COLUMN_DISPLAY_NAME = 4,
108 SRC_LAYOUT_COLUMN_COUNT = 3,
109 DST_LAYOUT_COLUMN_COUNT = 5
112 enum { TAB_LAYOUTS=0, TAB_OPTIONS=1, TAB_XKB=2 };
113 enum { BTN_XKB_ENABLE=0, BTN_XKB_INDICATOR=1, BTN_XKB_DISABLE=2 };
116 class SrcLayoutModel: public QAbstractTableModel {
117 public:
118 SrcLayoutModel(XkbRules* rules, QObject *parent)
119 : QAbstractTableModel(parent)
120 { setRules(rules); }
121 // bool hasChildren ( const QModelIndex & parent = QModelIndex() ) const { return false; }
122 int columnCount(const QModelIndex& parent) const { return !parent.isValid() ? SRC_LAYOUT_COLUMN_COUNT : 0; }
123 int rowCount(const QModelIndex&) const { return m_rules->layouts().keys().count(); }
124 QVariant data(const QModelIndex& index, int role) const;
125 QVariant headerData(int section, Qt::Orientation orientation, int role) const;
127 void setRules(XkbRules* rules) {
128 m_rules = rules;
129 m_layoutKeys = getKeysSortedByVaue( m_rules->layouts() );
131 QString getLayoutAt(int row) { return m_layoutKeys[row]; }
133 private:
134 XkbRules* m_rules;
135 QStringList m_layoutKeys;
138 QVariant SrcLayoutModel::headerData(int section, Qt::Orientation orientation, int role) const
140 if (role != Qt::DisplayRole)
141 return QVariant();
143 QString colNames[] = {"", i18n("Layout Name"), i18n("Map")};
144 if (orientation == Qt::Horizontal) {
145 return colNames[section];
147 return QVariant();
150 QVariant
151 SrcLayoutModel::data(const QModelIndex& index, int role) const
153 if (!index.isValid())
154 return QVariant();
156 int col = index.column();
157 int row = index.row();
158 QHash<QString, QString> layouts = m_rules->layouts();
159 QString layout = m_layoutKeys[row];
161 if (role == Qt::TextAlignmentRole) {
162 return int(Qt::AlignLeft | Qt::AlignVCenter);
163 } else if (role == Qt::DecorationRole) {
164 switch(col) {
165 case LAYOUT_COLUMN_FLAG: return LayoutIcon::getInstance().findPixmap(layout, true);
167 } else if (role == Qt::DisplayRole) {
168 switch(col) {
169 case LAYOUT_COLUMN_NAME: return layouts[layout];
170 case LAYOUT_COLUMN_MAP: return layout;
171 break;
172 default: ;
175 return QVariant();
178 class DstLayoutModel: public QAbstractTableModel {
179 public:
180 DstLayoutModel(XkbRules* rules, KxkbConfig* kxkbConfig, QObject *parent)
181 : QAbstractTableModel(parent),
182 m_kxkbConfig(kxkbConfig)
183 { setRules(rules); }
184 int columnCount(const QModelIndex& parent) const { return !parent.isValid() ? DST_LAYOUT_COLUMN_COUNT : 0; }
185 int rowCount(const QModelIndex&) const { return m_kxkbConfig->m_layouts.count(); }
186 QVariant data(const QModelIndex& index, int role) const;
187 QVariant headerData(int section, Qt::Orientation orientation, int role) const;
189 void setRules(XkbRules* rules) { m_rules = rules; }
190 void reset() { QAbstractTableModel::reset(); }
191 void emitDataChange(int row, int col) { emit dataChanged(createIndex(row,col),createIndex(row,col)); }
193 private:
194 XkbRules* m_rules;
195 KxkbConfig* m_kxkbConfig;
198 QVariant DstLayoutModel::headerData(int section, Qt::Orientation orientation, int role) const
200 if (role != Qt::DisplayRole)
201 return QVariant();
203 QString colNames[] = {"", i18n("Layout Name"), i18n("Map"), i18n("Variant"), i18n("Label")};
204 if (orientation == Qt::Horizontal) {
205 return colNames[section];
207 return QVariant();
210 QVariant
211 DstLayoutModel::data(const QModelIndex& index, int role) const
213 if (!index.isValid())
214 return QVariant();
216 int col = index.column();
217 int row = index.row();
218 QHash<QString, QString> layouts = m_rules->layouts();
219 LayoutUnit lu = m_kxkbConfig->m_layouts[row];
221 if (role == Qt::TextAlignmentRole) {
222 return int(Qt::AlignLeft | Qt::AlignVCenter);
223 } else if (role == Qt::DecorationRole) {
224 switch(col) {
225 case LAYOUT_COLUMN_FLAG:
226 return LayoutIcon::getInstance().findPixmap(lu.layout, m_kxkbConfig->m_showFlag, lu.getDisplayName());
228 } else if (role == Qt::DisplayRole) {
229 switch(col) {
230 case LAYOUT_COLUMN_NAME: return layouts[lu.layout];
231 case LAYOUT_COLUMN_MAP: return lu.layout;
232 case LAYOUT_COLUMN_VARIANT: return lu.variant;
233 case LAYOUT_COLUMN_DISPLAY_NAME: return lu.getDisplayName();
234 break;
235 default: ;
238 return QVariant();
242 class XkbOptionsModel: public QAbstractItemModel {
243 public:
244 XkbOptionsModel(XkbRules* rules, KxkbConfig* kxkbConfig, QObject *parent)
245 : QAbstractItemModel(parent),
246 m_kxkbConfig(kxkbConfig)
247 { setRules(rules); }
249 int columnCount(const QModelIndex& /*parent*/) const { return 1; }
250 int rowCount(const QModelIndex& parent) const {
251 if( ! parent.isValid() )
252 return m_rules->optionGroups().count();
253 if( ! parent.parent().isValid() )
254 return m_rules->optionGroups().values()[parent.row()].options.count();
255 return 0;
257 QModelIndex parent(const QModelIndex& index) const {
258 if (!index.isValid() )
259 return QModelIndex();
260 if( index.internalId() < 100 )
261 return QModelIndex();
262 return createIndex(((index.internalId() - index.row())/100) - 1, index.column());
264 QModelIndex index(int row, int column, const QModelIndex& parent) const {
265 if(!parent.isValid()) return createIndex(row, column);
266 return createIndex(row, column, (100 * (parent.row()+1)) + row);
268 Qt::ItemFlags flags ( const QModelIndex & index ) const {
269 if( ! index.isValid() )
270 return 0;
272 if( !index.parent().isValid() )
273 return Qt::ItemIsEnabled;
275 return Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;
277 bool setData ( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole ) {
278 int groupRow = index.parent().row();
279 if( groupRow < 0 ) return false;
281 QString xkbGroupNm = m_rules->optionGroups().keys()[groupRow];
282 const XkbOptionGroup& xkbGroup = m_rules->optionGroups()[xkbGroupNm];
283 const XkbOption& option = xkbGroup.options[index.row()];
285 if( value.toInt() == Qt::Checked ) {
286 if( xkbGroup.exclusive ) {
287 // clear if exclusive (TODO: radiobutton)
288 int idx = m_kxkbConfig->m_options.indexOf(QRegExp(xkbGroupNm+".*"));
289 if( idx >= 0 ) {
290 for(int i=0; i<xkbGroup.options.count(); i++)
291 if( xkbGroup.options[i].name == m_kxkbConfig->m_options[idx] ) {
292 setData(createIndex(i, index.column(), (quint32)index.internalId()-index.row()+i), Qt::Unchecked, role);
293 break;
295 // m_kxkbConfig->m_options.removeAt(idx);
296 // idx = m_kxkbConfig->m_options.indexOf(QRegExp(xkbGroupNm+".*"));
299 if( m_kxkbConfig->m_options.indexOf(option.name) < 0 ) {
300 m_kxkbConfig->m_options.append(option.name);
303 else {
304 m_kxkbConfig->m_options.removeAll(option.name);
306 emit dataChanged(index, index);
307 return true;
310 QVariant data(const QModelIndex& index, int role) const;
312 void setRules(XkbRules* rules) { m_rules = rules; }
313 void reset() { QAbstractItemModel::reset(); }
315 void gotoGroup(const QString& group, QTreeView* view) {
316 int index = m_rules->optionGroups().keys().indexOf(group);
317 // kDebug() << "scrolling to group" << index << "-" << group;
318 if( index != -1 ) {
319 QModelIndex modelIdx = createIndex(index,0);
320 // view->selectionModel()->setCurrentIndex(createIndex(index,0), QItemSelectionModel::NoUpdate);
321 view->setExpanded(modelIdx, true);
322 view->scrollTo(modelIdx, QAbstractItemView::PositionAtTop);
323 view->selectionModel()->setCurrentIndex(modelIdx, QItemSelectionModel::Current);
324 view->setFocus(Qt::OtherFocusReason);
325 // kDebug() << "wdg:" << view->itemDelegate(createIndex(index, 0).child(0,0));
327 else
328 kDebug() << "can't scroll to group" << group;
330 private:
331 XkbRules* m_rules;
332 KxkbConfig* m_kxkbConfig;
335 QVariant
336 XkbOptionsModel::data(const QModelIndex& index, int role) const
338 if (!index.isValid())
339 return QVariant();
341 int row = index.row();
343 if (role == Qt::DisplayRole) {
344 if( ! index.parent().isValid() )
345 return m_rules->optionGroups().values()[row].description;
346 else {
347 int groupRow = index.parent().row();
348 QString xkbGroupNm = m_rules->optionGroups().keys()[groupRow];
349 const XkbOptionGroup& xkbGroup = m_rules->optionGroups()[xkbGroupNm];
350 return xkbGroup.options[row].description;
353 else if (role==Qt::CheckStateRole && index.parent().isValid()) {
354 int groupRow = index.parent().row();
355 QString xkbGroupNm = m_rules->optionGroups().keys()[groupRow];
356 const XkbOptionGroup& xkbGroup = m_rules->optionGroups()[xkbGroupNm];
358 return m_kxkbConfig->m_options.indexOf(xkbGroup.options[row].name) == -1 ? Qt::Unchecked : Qt::Checked;
360 return QVariant();
364 //K_PLUGIN_FACTORY_DECLARATION(KeyboardLayoutFactory)
366 LayoutConfig::LayoutConfig(QWidget *parent, const QVariantList &)
367 : KCModule(KeyboardLayoutFactory::componentData(), parent),
368 DEFAULT_VARIANT_NAME(i18nc("Default variant", "Default")),
369 m_rules(NULL),
370 m_srcModel(NULL),
371 m_dstModel(NULL),
372 m_xkbOptModel(NULL)
374 //kDebug() << "Qt locale" << QLocale::system().name();
375 //kDebug() << "KDE locale" << KGlobal::locale()->language() << KGlobal::locale()->country();
376 //kDebug() << "OS locale" << setlocale(LC_ALL, NULL);
377 //Read rules - we _must_ read _before_ creating UIs
378 loadRules();
380 widget = new Ui_LayoutConfigWidget();
381 widget->setupUi(this);
382 layout()->setMargin(0);
383 // main->addWidget(widget);
385 m_srcModel = new SrcLayoutModel(m_rules, NULL);
387 widget->srcTableView->setModel(m_srcModel);
388 // widget->srcTableView->setSortingEnabled(true);
389 widget->srcTableView->setColumnWidth(LAYOUT_COLUMN_FLAG, 26);
390 widget->srcTableView->setColumnWidth(LAYOUT_COLUMN_MAP, 30);
391 //(QTableView) widget->srcTableView->verticalHeader()->hide();
392 //(QTableView) widget->srcTableView->setShowGrid(false);
393 //(QTableView) widget->srcTableView->resizeRowsToContents();
394 widget->srcTableView->setRootIsDecorated(false);
396 m_dstModel = new DstLayoutModel(m_rules, &m_kxkbConfig, NULL);
397 widget->dstTableView->setModel(m_dstModel);
398 widget->dstTableView->setColumnWidth(LAYOUT_COLUMN_FLAG, 26);
399 widget->dstTableView->setColumnWidth(LAYOUT_COLUMN_MAP, 30);
400 //(QTableView) widget->dstTableView->verticalHeader()->hide();
401 widget->dstTableView->setRootIsDecorated(false);
403 m_xkbOptModel = new XkbOptionsModel(m_rules, &m_kxkbConfig, NULL);
404 widget->xkbOptionsTreeView->setModel(m_xkbOptModel);
405 widget->xkbOptionsTreeView->header()->hide();
406 widget->xkbOptionsTreeView->expandAll();
408 connect( m_xkbOptModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)),
409 this, SLOT(xkbOptionsChanged(const QModelIndex &, const QModelIndex &)));
411 connect( widget->grpEnableKxkb, SIGNAL( clicked( int ) ), SLOT(enableChanged()));
412 connect( widget->grpEnableKxkb, SIGNAL( clicked( int ) ), SLOT(updateGroupsFromServer()));
413 // connect( widget->chkEnable, SIGNAL( toggled( bool )), this, SLOT(changed()));
414 // connect( widget->chkIndicatorOnly, SIGNAL( toggled( bool )), this, SLOT(changed()));
415 connect( widget->chkShowSingle, SIGNAL( toggled( bool )), this, SLOT(changed()));
416 // connect( widget->chkShowFlag, SIGNAL( toggled( bool )), this, SLOT(changed()));
417 connect( widget->chkShowFlag, SIGNAL(toggled(bool)), this, SLOT(showFlagChanged(bool)));
418 connect( widget->comboModel, SIGNAL(activated(int)), this, SLOT(updateLayoutCommand()));
419 connect( widget->comboModel, SIGNAL(activated(int)), this, SLOT(changed()));
421 connect( widget->srcTableView, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(add()));
422 connect( widget->dstTableView, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(remove()));
423 connect( widget->btnAdd, SIGNAL(clicked()), this, SLOT(add()));
424 connect( widget->btnRemove, SIGNAL(clicked()), this, SLOT(remove()));
426 // connect( widget->comboVariant, SIGNAL(activated(int)), this, SLOT(changed()));
427 connect( widget->comboVariant, SIGNAL(activated(int)), this, SLOT(variantChanged()));
428 connect( widget->dstTableView->selectionModel(),
429 SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
430 this, SLOT(layoutSelChanged()) );
432 connect( widget->btnXkbShortcut, SIGNAL(clicked()), this, SLOT(xkbShortcutPressed()));
433 connect( widget->btnXkbShortcut3d, SIGNAL(clicked()), this, SLOT(xkbShortcut3dPressed()));
435 connect( widget->editDisplayName, SIGNAL(textChanged(const QString&)), this, SLOT(displayNameChanged(const QString&)));
437 widget->btnUp->setIcon(KIcon("arrow-up"));
438 widget->btnDown->setIcon(KIcon("arrow-down"));
439 widget->btnAdd->setIcon( layoutDirection() == Qt::LeftToRight? KIcon("arrow-right"): KIcon("arrow-left") );
440 widget->btnRemove->setIcon( layoutDirection() == Qt::LeftToRight? KIcon("arrow-left") : KIcon("arrow-right") );
441 connect( widget->btnUp, SIGNAL(clicked()), this, SLOT(moveUp()));
442 widget->btnDown->setIcon(KIcon("arrow-down"));
443 connect( widget->btnDown, SIGNAL(clicked()), this, SLOT(moveDown()));
445 connect( widget->grpSwitching, SIGNAL( clicked( int ) ), SLOT(changed()));
446 #ifdef STICKY_SWITCHING
447 connect( widget->chkEnableSticky, SIGNAL(toggled(bool)), this, SLOT(changed()));
448 #endif
450 KIcon clearIcon = qApp->isLeftToRight() ? KIcon("edit-clear-locationbar-rtl") : KIcon("edit-clear-locationbar-ltr");
451 widget->xkbClearButton->setIcon(clearIcon);
452 widget->xkb3dClearButton->setIcon(clearIcon);
453 connect(widget->xkbClearButton, SIGNAL(clicked()), this, SLOT(clearXkbSequence()));
454 connect(widget->xkb3dClearButton, SIGNAL(clicked()), this, SLOT(clearXkb3dSequence()));
456 #ifdef STICKY_SWITCHING
457 connect( widget->spinStickyDepth, SIGNAL(valueChanged(int)), this, SLOT(changed()));
458 #endif
460 actionCollection = new KActionCollection(this, componentData());
461 // actionCollection->setConfigGlobal(true);
462 KAction* a = 0;
463 #include "kxkbbindings.cpp"
464 kDebug() << "getting shortcut" << a->globalShortcut().toString();
466 widget->kdeKeySequence->setModifierlessAllowed(false);
467 widget->kdeKeySequence->setKeySequence( a->globalShortcut().primary() );
469 connect(widget->kdeKeySequence, SIGNAL(keySequenceChanged (const QKeySequence &)), this, SLOT(changed()));
471 refreshRulesUI();
473 makeOptionsTab();
477 LayoutConfig::~LayoutConfig()
479 delete m_rules;
483 void LayoutConfig::load()
485 m_kxkbConfig.load(KxkbConfig::LOAD_ALL);
486 initUI();
489 void LayoutConfig::initUI()
491 QString modelName = m_rules->models()[m_kxkbConfig.m_model];
492 widget->comboModel->setCurrentIndex( widget->comboModel->findText(modelName) );
494 m_dstModel->reset();
495 widget->dstTableView->update();
497 // display KXKB switching options
498 widget->chkShowSingle->setChecked(m_kxkbConfig.m_showSingle);
499 widget->chkShowFlag->setChecked(m_kxkbConfig.m_showFlag);
501 //widget->chkEnableOptions->setChecked( m_kxkbConfig.m_enableXkbOptions );
502 widget->checkResetOld->setChecked(m_kxkbConfig.m_resetOldOptions);
504 widget->grpSwitching->setSelected( m_kxkbConfig.m_switchingPolicy );
506 #ifdef STICKY_SWITCHING
507 widget->chkEnableSticky->setChecked(m_kxkbConfig.m_stickySwitching);
508 widget->spinStickyDepth->setEnabled(m_kxkbConfig.m_stickySwitching);
509 widget->spinStickyDepth->setValue( m_kxkbConfig.m_stickySwitchingDepth);
510 updateStickyLimit();
511 #endif
513 int enableKxkb = BTN_XKB_DISABLE;
514 if( m_kxkbConfig.m_indicatorOnly ) enableKxkb = BTN_XKB_INDICATOR;
515 else
516 if( m_kxkbConfig.m_useKxkb ) enableKxkb = BTN_XKB_ENABLE;
517 widget->grpEnableKxkb->setSelected(enableKxkb);
518 enableChanged();
520 updateShortcutsLabels();
522 updateLayoutCommand();
523 updateOptionsCommand();
525 widget->tabWidget->setCurrentIndex(TAB_LAYOUTS);
527 emit KCModule::changed( false );
531 void LayoutConfig::save()
533 KCModule::save();
535 QString model = widget->comboModel->itemData(widget->comboModel->currentIndex()).toString();
536 m_kxkbConfig.m_model = model;
538 // m_kxkbConfig.m_enableXkbOptions = widget->chkEnableOptions->isChecked();
539 m_kxkbConfig.m_resetOldOptions = widget->checkResetOld->isChecked();
541 if( m_kxkbConfig.m_layouts.count() == 0 ) {
542 m_kxkbConfig.m_layouts.append(LayoutUnit(DEFAULT_LAYOUT_UNIT));
543 widget->grpEnableKxkb->setSelected(BTN_XKB_DISABLE);
546 m_kxkbConfig.m_useKxkb = widget->grpEnableKxkb->selected() <= BTN_XKB_INDICATOR;
547 m_kxkbConfig.m_indicatorOnly = widget->grpEnableKxkb->selected() == BTN_XKB_INDICATOR;
548 m_kxkbConfig.m_showSingle = widget->chkShowSingle->isChecked();
549 m_kxkbConfig.m_showFlag = widget->chkShowFlag->isChecked();
551 int modeId = widget->grpSwitching->selected();
552 m_kxkbConfig.m_switchingPolicy = (SwitchingPolicy)modeId;
554 #ifdef STICKY_SWITCHING
555 m_kxkbConfig.m_stickySwitching = widget->chkEnableSticky->isChecked();
556 m_kxkbConfig.m_stickySwitchingDepth = widget->spinStickyDepth->value();
557 #endif
558 m_kxkbConfig.save();
560 KAction* action = static_cast<KAction*>(actionCollection->action(0));
561 KShortcut shortcut(widget->kdeKeySequence->keySequence());
562 action->setGlobalShortcut(shortcut, KAction::ActiveShortcut, KAction::NoAutoloading);
563 kDebug() << "saving kxkb shortcut" << shortcut.toString();
564 // actionCollection->writeSettings();
566 KGlobalSettings::emitChange(KGlobalSettings::SettingsChanged, KGlobalSettings::SETTINGS_SHORTCUTS);
568 KToolInvocation::kdeinitExec("kxkb");
569 emit KCModule::changed( false );
572 void LayoutConfig::xkbOptionsChanged(const QModelIndex & /*topLeft*/, const QModelIndex & /*bottomRight*/)
574 updateOptionsCommand();
575 updateShortcutsLabels();
576 changed();
577 // widget->xkbOptionsTreeView->update(topLeft);
581 static QStringList getGroupOptionList(const QStringList& options, const QString& grp)
583 QRegExp grpRegExp("^" + grp + ".*");
584 return options.filter(grpRegExp);
587 void LayoutConfig::clearXkbSequence()
589 QStringList grpOptions = getGroupOptionList(m_kxkbConfig.m_options, "grp");
590 foreach(const QString& opt, grpOptions)
591 m_kxkbConfig.m_options.removeAll(opt);
592 m_xkbOptModel->reset();
593 widget->xkbOptionsTreeView->update();
594 updateShortcutsLabels();
595 changed();
598 void LayoutConfig::clearXkb3dSequence()
600 QStringList grpOptions = getGroupOptionList(m_kxkbConfig.m_options, "lv3");
601 foreach(const QString& opt, grpOptions)
602 m_kxkbConfig.m_options.removeAll(opt);
603 m_xkbOptModel->reset();
604 widget->xkbOptionsTreeView->update();
605 updateShortcutsLabels();
606 changed();
609 void LayoutConfig::xkbShortcutPressed()
611 widget->tabWidget->setCurrentIndex(TAB_XKB);
612 m_xkbOptModel->gotoGroup("grp", widget->xkbOptionsTreeView);
615 void LayoutConfig::xkbShortcut3dPressed()
617 widget->tabWidget->setCurrentIndex(TAB_XKB);
618 m_xkbOptModel->gotoGroup("lv3", widget->xkbOptionsTreeView);
621 static QString getShortcutText(const QStringList& options, const QString& grp)
623 QStringList grpOptions = getGroupOptionList(options, grp);
625 if( grpOptions.count() > 1 )
626 return i18n("Multiple keys");
627 else
628 if( grpOptions.count() == 1 )
629 return i18n("Defined"); //TODO: show shortcut
630 else
631 return i18n("None");
634 void LayoutConfig::updateShortcutsLabels()
636 QString txt = getShortcutText( m_kxkbConfig.m_options, "grp" );
637 widget->btnXkbShortcut->setText(txt);
638 widget->btnXkbShortcut->setToolTip("");
639 txt = getShortcutText( m_kxkbConfig.m_options, "lv3" );
640 widget->btnXkbShortcut3d->setText(txt);
641 widget->btnXkbShortcut3d->setToolTip("");
644 void LayoutConfig::showFlagChanged(bool on)
646 m_kxkbConfig.m_showFlag = on;
647 m_dstModel->reset();
648 widget->dstTableView->update();
650 changed();
653 void LayoutConfig::updateStickyLimit()
655 #ifdef STICKY_SWITCHING
656 int layoutsCnt = m_kxkbConfig.m_layouts.count();
657 int maxDepth = layoutsCnt - 1;
659 if( maxDepth < 2 ) {
660 maxDepth = 2;
663 widget->spinStickyDepth->setMaximum(maxDepth);
664 /* if( value > maxDepth )
665 setValue(maxDepth);*/
666 #endif
670 void LayoutConfig::updateGroupsFromServer()
672 bool enabled = widget->grpEnableKxkb->selected() == BTN_XKB_ENABLE;
673 //kDebug() << "enabled:" << enabled << m_kxkbConfig.m_layouts.count();
674 if( enabled ) {
675 #ifdef HAVE_XKLAVIER
676 XkbConfig xkbConfig = XKlavierAdaptor::getInstance(QX11Info::display())->getGroupNames();
677 #else
678 XkbConfig xkbConfig = X11Helper::getGroupNames(QX11Info::display());
679 #endif
680 xkbConfig.model = m_kxkbConfig.m_model;
681 //TODO: update model
682 if( m_kxkbConfig.m_layouts.count() > 1 || xkbConfig.layouts.count() == 0 ) {
683 xkbConfig.layouts = m_kxkbConfig.m_layouts;
685 kDebug() << m_kxkbConfig.m_options.join(",") << xkbConfig.options.join(",");
686 if( !m_kxkbConfig.m_resetOldOptions || m_kxkbConfig.m_options.count() > 0 || xkbConfig.options.count() == 0 ) {
687 xkbConfig.options = m_kxkbConfig.m_options;
690 m_kxkbConfig.setConfiguredLayouts(xkbConfig);
692 m_dstModel->reset();
693 widget->dstTableView->update();
694 updateLayoutCommand();
696 m_xkbOptModel->reset();
697 widget->xkbOptionsTreeView->update();
698 updateOptionsCommand();
702 void LayoutConfig::enableChanged()
704 bool enabled = widget->grpEnableKxkb->selected() == BTN_XKB_ENABLE;
705 bool indicatorEnabled = widget->grpEnableKxkb->selected() <= BTN_XKB_INDICATOR;
707 widget->grpLayouts->setEnabled(enabled);
708 widget->tabWidget->widget(TAB_OPTIONS)->setEnabled(enabled);
709 widget->tabWidget->widget(TAB_XKB)->setEnabled(enabled);
710 widget->grpIndicatorOptions->setEnabled(indicatorEnabled);
712 changed();
715 void LayoutConfig::add()
717 QItemSelectionModel* selectionModel = widget->srcTableView->selectionModel();
718 if( selectionModel == NULL || !selectionModel->hasSelection()
719 || m_kxkbConfig.m_layouts.count() >= GROUP_LIMIT )
720 return;
722 QModelIndexList selected = selectionModel->selectedRows();
723 QHash<QString, QString> layouts = m_rules->layouts();
724 QString layout = m_srcModel->getLayoutAt(selected[0].row());
725 // kDebug() << "selected to add" << layout;
726 LayoutUnit lu(layout, "");
727 m_kxkbConfig.m_layouts << lu;
729 m_dstModel->reset();
730 widget->dstTableView->update();
732 updateAddButton();
733 updateLayoutCommand();
735 updateStickyLimit();
736 changed();
739 void LayoutConfig::updateAddButton()
741 bool aboveLimit = m_kxkbConfig.m_layouts.count() >= GROUP_LIMIT;
742 widget->btnAdd->setEnabled( !aboveLimit );
745 void LayoutConfig::remove()
747 QItemSelectionModel* selectionModel = widget->dstTableView->selectionModel();
748 if( selectionModel == NULL || !selectionModel->hasSelection() )
749 return;
751 int row = getSelectedDstLayout();
752 if( row == -1 )
753 return;
755 m_kxkbConfig.m_layouts.removeAt(row);
757 m_dstModel->reset();
758 widget->dstTableView->update();
760 layoutSelChanged();
761 updateAddButton();
762 updateLayoutCommand();
763 updateStickyLimit();
765 changed();
768 void LayoutConfig::moveSelected(int shift)
770 QItemSelectionModel* selectionModel = widget->dstTableView->selectionModel();
771 if( selectionModel == NULL || !selectionModel->hasSelection() )
772 return;
774 QModelIndexList selected = selectionModel->selectedRows();
775 if( selected.count() < 1 )
776 return;
778 int row = selected[0].row();
779 int new_row = row + shift;
781 if( new_row >= 0 && new_row <= m_kxkbConfig.m_layouts.count()-1 ) {
782 m_kxkbConfig.m_layouts.move(row, new_row);
783 m_dstModel->reset();
784 widget->dstTableView->update();
788 void LayoutConfig::moveUp()
790 moveSelected(-1);
791 updateLayoutCommand();
792 changed();
795 void LayoutConfig::moveDown()
797 moveSelected(1);
798 updateLayoutCommand();
799 changed();
802 void LayoutConfig::variantChanged()
804 int row = getSelectedDstLayout();
806 if( row == -1 ) {
807 widget->comboVariant->clear();
808 widget->comboVariant->setEnabled(false);
809 return;
812 QString selectedVariant = widget->comboVariant->itemData( widget->comboVariant->currentIndex() ).toString();
813 // if( selectedVariant == DEFAULT_VARIANT_NAME )
814 // selectedVariant = "";
816 m_kxkbConfig.m_layouts[row].variant = selectedVariant;
817 m_dstModel->emitDataChange(row, LAYOUT_COLUMN_VARIANT);
819 updateLayoutCommand();
820 changed();
823 void LayoutConfig::displayNameChanged(const QString& newDisplayName)
825 int row = getSelectedDstLayout();
826 if( row == -1 )
827 return;
829 LayoutUnit& layoutUnit = m_kxkbConfig.m_layouts[row];
831 QString oldName = layoutUnit.getDisplayName();
833 if( oldName != newDisplayName ) {
834 layoutUnit.setDisplayName(newDisplayName);
836 m_dstModel->emitDataChange(row, LAYOUT_COLUMN_DISPLAY_NAME);
837 m_dstModel->emitDataChange(row, LAYOUT_COLUMN_FLAG);
839 changed();
843 int LayoutConfig::getSelectedDstLayout()
845 QItemSelectionModel* selectionModel = widget->dstTableView->selectionModel();
846 if( selectionModel == NULL || !selectionModel->hasSelection() )
847 return -1;
849 QModelIndexList selected = selectionModel->selectedRows();
850 int row = selected.count() > 0 ? selected[0].row() : -1;
851 return row;
854 void LayoutConfig::layoutSelChanged()
856 int row = getSelectedDstLayout();
858 widget->comboVariant->clear();
859 widget->comboVariant->setEnabled( row != -1 );
860 if( row == -1 ) {
861 return;
864 QString kbdLayout = m_kxkbConfig.m_layouts[row].layout;
866 QList<XkbVariant> vars = m_rules->getAvailableVariants(kbdLayout);
867 kDebug() << "layout " << kbdLayout << " has " << vars.count() << " variants";
869 if( vars.count() > 0 ) {
870 // vars.prepend(DEFAULT_VARIANT_NAME);
871 // widget->comboVariant->addItems(vars);
872 widget->comboVariant->addItem(DEFAULT_VARIANT_NAME, "");
873 for(int ii=0; ii<vars.count(); ii++) {
874 widget->comboVariant->addItem(vars[ii].description, vars[ii].name);
875 widget->comboVariant->setItemData(widget->comboVariant->count()-1, vars[ii].description, Qt::ToolTipRole );
877 QString variant = m_kxkbConfig.m_layouts[row].variant;
878 if( variant != NULL && variant.isEmpty() == false ) {
879 int idx = widget->comboVariant->findData(variant);
880 widget->comboVariant->setCurrentIndex(idx);
882 else {
883 widget->comboVariant->setCurrentIndex(0);
886 updateDisplayName();
889 void LayoutConfig::makeOptionsTab()
891 // connect(widget->chkEnableOptions, SIGNAL(toggled(bool)), SLOT(changed()));
892 connect(widget->checkResetOld, SIGNAL(toggled(bool)), SLOT(changed()));
893 connect(widget->checkResetOld, SIGNAL(toggled(bool)), SLOT(updateOptionsCommand()));
896 void LayoutConfig::updateOptionsCommand()
898 widget->editCmdLineOpt->setText(createOptionString());
901 void LayoutConfig::updateLayoutCommand()
903 QStringList layouts;
904 QStringList variants;
906 QList<LayoutUnit> layoutUnits = m_kxkbConfig.m_layouts;
907 for(int i=0; i<layoutUnits.count(); i++) {
908 QString layout = layoutUnits[i].layout;
909 QString variant = layoutUnits[i].variant;
910 //QString displayName = layoutUnits[i].displayName;
912 if( variant == DEFAULT_VARIANT_NAME )
913 variant = "";
915 layouts << layout;
916 variants << variant;
919 QString model = widget->comboModel->itemData(widget->comboModel->currentIndex()).toString();
920 QString setxkbmap = XKBExtension::getLayoutGroupsCommand(model, layouts, variants);
922 widget->editCmdLine->setText(setxkbmap);
926 void LayoutConfig::updateDisplayName()
928 int row = getSelectedDstLayout();
930 widget->editDisplayName->setEnabled( row != -1 );
931 if( row == -1 ) {
932 widget->editDisplayName->clear();
933 return;
936 widget->editDisplayName->setText( m_kxkbConfig.m_layouts[row].getDisplayName() );
939 void LayoutConfig::changed()
941 emit KCModule::changed( true );
945 void LayoutConfig::loadRules()
947 // TODO: do we need this ?
948 // this could obly be used if rules are changed and 'Defaults' is pressed
949 delete m_rules;
950 m_rules = new XkbRules();
951 if( m_srcModel )
952 m_srcModel->setRules(m_rules);
953 if( m_dstModel )
954 m_dstModel->setRules(m_rules);
955 if( m_xkbOptModel )
956 m_xkbOptModel->setRules(m_rules);
959 void LayoutConfig::refreshRulesUI()
961 widget->comboModel->clear();
962 QList<QString> sortedModels = getKeysSortedByVaue( m_rules->models() );
963 foreach( const QString& model, sortedModels ) {
964 widget->comboModel->addItem( m_rules->models()[model], model);
965 widget->comboModel->setItemData( widget->comboModel->count()-1, m_rules->models()[model], Qt::ToolTipRole );
967 widget->comboModel->setCurrentIndex(0);
968 //TODO: reset options and xkb options
972 QString LayoutConfig::createOptionString()
974 bool reset = widget->checkResetOld->isChecked();
975 return XKBExtension::getXkbOptionsCommand(m_kxkbConfig.m_options, reset);
979 void LayoutConfig::defaults()
981 loadRules();
982 refreshRulesUI();
983 m_kxkbConfig.setDefaults();
985 initUI();
987 emit KCModule::changed( true );
990 extern "C"
992 KDE_EXPORT void kcminit_keyboard_layout()
994 KxkbConfig m_kxkbConfig;
995 m_kxkbConfig.load(KxkbConfig::LOAD_ACTIVE_OPTIONS);
997 if( m_kxkbConfig.m_useKxkb ) {
998 KToolInvocation::kdeinitExec("kxkb");