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.
23 #include <QPushButton>
24 #include <QHeaderView>
26 #include <QRadioButton>
29 #include <QtGui/QtGui>
30 #include <QKeySequence>
34 #include <kglobalaccel.h>
35 #include <kglobalsettings.h>
36 #include <kactioncollection.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"
49 #include "ui_kcmlayoutwidget.h"
51 #include "kcmlayout.h"
52 #include <KPluginFactory>
53 #include <KPluginLoader>
54 #include "kcmlayout.moc"
57 #include "xklavier_adaptor.h"
61 K_PLUGIN_FACTORY(KeyboardLayoutFactory
,
62 registerPlugin
<LayoutConfig
>("keyboard_layout");
64 K_EXPORT_PLUGIN(KeyboardLayoutFactory("kxkb"))
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
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();
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");
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
{
118 SrcLayoutModel(XkbRules
* rules
, QObject
*parent
)
119 : QAbstractTableModel(parent
)
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
) {
129 m_layoutKeys
= getKeysSortedByVaue( m_rules
->layouts() );
131 QString
getLayoutAt(int row
) { return m_layoutKeys
[row
]; }
135 QStringList m_layoutKeys
;
138 QVariant
SrcLayoutModel::headerData(int section
, Qt::Orientation orientation
, int role
) const
140 if (role
!= Qt::DisplayRole
)
143 QString colNames
[] = {"", i18n("Layout Name"), i18n("Map")};
144 if (orientation
== Qt::Horizontal
) {
145 return colNames
[section
];
151 SrcLayoutModel::data(const QModelIndex
& index
, int role
) const
153 if (!index
.isValid())
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
) {
165 case LAYOUT_COLUMN_FLAG
: return LayoutIcon::getInstance().findPixmap(layout
, true);
167 } else if (role
== Qt::DisplayRole
) {
169 case LAYOUT_COLUMN_NAME
: return layouts
[layout
];
170 case LAYOUT_COLUMN_MAP
: return layout
;
178 class DstLayoutModel
: public QAbstractTableModel
{
180 DstLayoutModel(XkbRules
* rules
, KxkbConfig
* kxkbConfig
, QObject
*parent
)
181 : QAbstractTableModel(parent
),
182 m_kxkbConfig(kxkbConfig
)
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
)); }
195 KxkbConfig
* m_kxkbConfig
;
198 QVariant
DstLayoutModel::headerData(int section
, Qt::Orientation orientation
, int role
) const
200 if (role
!= Qt::DisplayRole
)
203 QString colNames
[] = {"", i18n("Layout Name"), i18n("Map"), i18n("Variant"), i18n("Label")};
204 if (orientation
== Qt::Horizontal
) {
205 return colNames
[section
];
211 DstLayoutModel::data(const QModelIndex
& index
, int role
) const
213 if (!index
.isValid())
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
) {
225 case LAYOUT_COLUMN_FLAG
:
226 return LayoutIcon::getInstance().findPixmap(lu
.layout
, m_kxkbConfig
->m_showFlag
, lu
.getDisplayName());
228 } else if (role
== Qt::DisplayRole
) {
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();
242 class XkbOptionsModel
: public QAbstractItemModel
{
244 XkbOptionsModel(XkbRules
* rules
, KxkbConfig
* kxkbConfig
, QObject
*parent
)
245 : QAbstractItemModel(parent
),
246 m_kxkbConfig(kxkbConfig
)
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();
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() )
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
+".*"));
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
);
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
);
304 m_kxkbConfig
->m_options
.removeAll(option
.name
);
306 emit
dataChanged(index
, index
);
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;
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));
328 kDebug() << "can't scroll to group" << group
;
332 KxkbConfig
* m_kxkbConfig
;
336 XkbOptionsModel::data(const QModelIndex
& index
, int role
) const
338 if (!index
.isValid())
341 int row
= index
.row();
343 if (role
== Qt::DisplayRole
) {
344 if( ! index
.parent().isValid() )
345 return m_rules
->optionGroups().values()[row
].description
;
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
;
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")),
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
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()));
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()));
460 actionCollection
= new KActionCollection(this, componentData());
461 // actionCollection->setConfigGlobal(true);
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()));
477 LayoutConfig::~LayoutConfig()
483 void LayoutConfig::load()
485 m_kxkbConfig
.load(KxkbConfig::LOAD_ALL
);
489 void LayoutConfig::initUI()
491 QString modelName
= m_rules
->models()[m_kxkbConfig
.m_model
];
492 widget
->comboModel
->setCurrentIndex( widget
->comboModel
->findText(modelName
) );
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
);
513 int enableKxkb
= BTN_XKB_DISABLE
;
514 if( m_kxkbConfig
.m_indicatorOnly
) enableKxkb
= BTN_XKB_INDICATOR
;
516 if( m_kxkbConfig
.m_useKxkb
) enableKxkb
= BTN_XKB_ENABLE
;
517 widget
->grpEnableKxkb
->setSelected(enableKxkb
);
520 updateShortcutsLabels();
522 updateLayoutCommand();
523 updateOptionsCommand();
525 widget
->tabWidget
->setCurrentIndex(TAB_LAYOUTS
);
527 emit
KCModule::changed( false );
531 void LayoutConfig::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();
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();
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();
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();
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");
628 if( grpOptions
.count() == 1 )
629 return i18n("Defined"); //TODO: show shortcut
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
;
648 widget
->dstTableView
->update();
653 void LayoutConfig::updateStickyLimit()
655 #ifdef STICKY_SWITCHING
656 int layoutsCnt
= m_kxkbConfig
.m_layouts
.count();
657 int maxDepth
= layoutsCnt
- 1;
663 widget
->spinStickyDepth
->setMaximum(maxDepth
);
664 /* if( value > maxDepth )
665 setValue(maxDepth);*/
670 void LayoutConfig::updateGroupsFromServer()
672 bool enabled
= widget
->grpEnableKxkb
->selected() == BTN_XKB_ENABLE
;
673 //kDebug() << "enabled:" << enabled << m_kxkbConfig.m_layouts.count();
676 XkbConfig xkbConfig
= XKlavierAdaptor::getInstance(QX11Info::display())->getGroupNames();
678 XkbConfig xkbConfig
= X11Helper::getGroupNames(QX11Info::display());
680 xkbConfig
.model
= m_kxkbConfig
.m_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
);
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
);
715 void LayoutConfig::add()
717 QItemSelectionModel
* selectionModel
= widget
->srcTableView
->selectionModel();
718 if( selectionModel
== NULL
|| !selectionModel
->hasSelection()
719 || m_kxkbConfig
.m_layouts
.count() >= GROUP_LIMIT
)
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
;
730 widget
->dstTableView
->update();
733 updateLayoutCommand();
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() )
751 int row
= getSelectedDstLayout();
755 m_kxkbConfig
.m_layouts
.removeAt(row
);
758 widget
->dstTableView
->update();
762 updateLayoutCommand();
768 void LayoutConfig::moveSelected(int shift
)
770 QItemSelectionModel
* selectionModel
= widget
->dstTableView
->selectionModel();
771 if( selectionModel
== NULL
|| !selectionModel
->hasSelection() )
774 QModelIndexList selected
= selectionModel
->selectedRows();
775 if( selected
.count() < 1 )
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
);
784 widget
->dstTableView
->update();
788 void LayoutConfig::moveUp()
791 updateLayoutCommand();
795 void LayoutConfig::moveDown()
798 updateLayoutCommand();
802 void LayoutConfig::variantChanged()
804 int row
= getSelectedDstLayout();
807 widget
->comboVariant
->clear();
808 widget
->comboVariant
->setEnabled(false);
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();
823 void LayoutConfig::displayNameChanged(const QString
& newDisplayName
)
825 int row
= getSelectedDstLayout();
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
);
843 int LayoutConfig::getSelectedDstLayout()
845 QItemSelectionModel
* selectionModel
= widget
->dstTableView
->selectionModel();
846 if( selectionModel
== NULL
|| !selectionModel
->hasSelection() )
849 QModelIndexList selected
= selectionModel
->selectedRows();
850 int row
= selected
.count() > 0 ? selected
[0].row() : -1;
854 void LayoutConfig::layoutSelChanged()
856 int row
= getSelectedDstLayout();
858 widget
->comboVariant
->clear();
859 widget
->comboVariant
->setEnabled( row
!= -1 );
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
);
883 widget
->comboVariant
->setCurrentIndex(0);
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()
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
)
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 );
932 widget
->editDisplayName
->clear();
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
950 m_rules
= new XkbRules();
952 m_srcModel
->setRules(m_rules
);
954 m_dstModel
->setRules(m_rules
);
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()
983 m_kxkbConfig
.setDefaults();
987 emit
KCModule::changed( true );
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");