Fix crash if key bindings specified in profile cannot be found. Improve
[personal-kdebase.git] / apps / konsole / src / KeyboardTranslator.cpp
blob61d9b46c49b7289d9e0a677093fbbf8cb06408bf
1 /*
2 This source file is part of Konsole, a terminal emulator.
4 Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
22 // Own
23 #include "KeyboardTranslator.h"
25 // System
26 #include <ctype.h>
27 #include <stdio.h>
29 // Qt
30 #include <QtCore/QBuffer>
31 #include <QtCore/QFile>
32 #include <QtCore/QFileInfo>
33 #include <QtCore/QTextStream>
34 #include <QtGui/QKeySequence>
36 // KDE
37 #include <KDebug>
38 #include <KLocale>
39 #include <KStandardDirs>
41 using namespace Konsole;
44 const char* KeyboardTranslatorManager::defaultTranslatorText =
45 #include <DefaultTranslatorText.h>
48 KeyboardTranslatorManager::KeyboardTranslatorManager()
49 : _haveLoadedAll(false)
52 KeyboardTranslatorManager::~KeyboardTranslatorManager()
54 qDeleteAll(_translators);
56 QString KeyboardTranslatorManager::findTranslatorPath(const QString& name)
58 return KGlobal::dirs()->findResource("data","konsole/"+name+".keytab");
60 void KeyboardTranslatorManager::findTranslators()
62 QStringList list = KGlobal::dirs()->findAllResources("data",
63 "konsole/*.keytab",
64 KStandardDirs::NoDuplicates);
66 // add the name of each translator to the list and associated
67 // the name with a null pointer to indicate that the translator
68 // has not yet been loaded from disk
69 QStringListIterator listIter(list);
70 while (listIter.hasNext())
72 QString translatorPath = listIter.next();
74 QString name = QFileInfo(translatorPath).baseName();
76 if ( !_translators.contains(name) )
77 _translators.insert(name,0);
80 _haveLoadedAll = true;
83 const KeyboardTranslator* KeyboardTranslatorManager::findTranslator(const QString& name)
85 if ( name.isEmpty() )
86 return defaultTranslator();
88 if ( _translators.contains(name) && _translators[name] != 0 )
89 return _translators[name];
91 KeyboardTranslator* translator = loadTranslator(name);
93 if ( translator != 0 )
94 _translators[name] = translator;
95 else if ( !name.isEmpty() )
96 kWarning() << "Unable to load translator" << name;
98 return translator;
101 bool KeyboardTranslatorManager::saveTranslator(const KeyboardTranslator* translator)
103 const QString path = KGlobal::dirs()->saveLocation("data","konsole/")+translator->name()
104 +".keytab";
106 kDebug() << "Saving translator to" << path;
108 QFile destination(path);
109 if (!destination.open(QIODevice::WriteOnly | QIODevice::Text))
111 kWarning() << "Unable to save keyboard translation:"
112 << destination.errorString();
113 return false;
117 KeyboardTranslatorWriter writer(&destination);
118 writer.writeHeader(translator->description());
120 QListIterator<KeyboardTranslator::Entry> iter(translator->entries());
121 while ( iter.hasNext() )
122 writer.writeEntry(iter.next());
125 destination.close();
127 return true;
130 KeyboardTranslator* KeyboardTranslatorManager::loadTranslator(const QString& name)
132 const QString& path = findTranslatorPath(name);
134 QFile source(path);
135 if (name.isEmpty() || !source.open(QIODevice::ReadOnly | QIODevice::Text))
136 return 0;
138 return loadTranslator(&source,name);
141 const KeyboardTranslator* KeyboardTranslatorManager::defaultTranslator()
143 // Try to find the default.keytab file if it exists, otherwise
144 // fall back to the hard-coded one
145 const KeyboardTranslator* translator = findTranslator("default");
146 if (!translator)
148 QBuffer textBuffer;
149 textBuffer.setData(defaultTranslatorText,strlen(defaultTranslatorText));
150 translator = loadTranslator(&textBuffer,"fallback");
152 return translator;
155 KeyboardTranslator* KeyboardTranslatorManager::loadTranslator(QIODevice* source,const QString& name)
157 KeyboardTranslator* translator = new KeyboardTranslator(name);
158 KeyboardTranslatorReader reader(source);
159 translator->setDescription( reader.description() );
160 while ( reader.hasNextEntry() )
161 translator->addEntry(reader.nextEntry());
163 source->close();
165 if ( !reader.parseError() )
167 return translator;
169 else
171 delete translator;
172 return 0;
176 KeyboardTranslatorWriter::KeyboardTranslatorWriter(QIODevice* destination)
177 : _destination(destination)
179 Q_ASSERT( destination && destination->isWritable() );
181 _writer = new QTextStream(_destination);
183 KeyboardTranslatorWriter::~KeyboardTranslatorWriter()
185 delete _writer;
187 void KeyboardTranslatorWriter::writeHeader( const QString& description )
189 *_writer << "keyboard \"" << description << '\"' << '\n';
191 void KeyboardTranslatorWriter::writeEntry( const KeyboardTranslator::Entry& entry )
193 QString result;
194 if ( entry.command() != KeyboardTranslator::NoCommand )
195 result = entry.resultToString();
196 else
197 result = '\"' + entry.resultToString() + '\"';
199 *_writer << "key " << entry.conditionToString() << " : " << result << '\n';
203 // each line of the keyboard translation file is one of:
205 // - keyboard "name"
206 // - key KeySequence : "characters"
207 // - key KeySequence : CommandName
209 // KeySequence begins with the name of the key ( taken from the Qt::Key enum )
210 // and is followed by the keyboard modifiers and state flags ( with + or - in front
211 // of each modifier or flag to indicate whether it is required ). All keyboard modifiers
212 // and flags are optional, if a particular modifier or state is not specified it is
213 // assumed not to be a part of the sequence. The key sequence may contain whitespace
215 // eg: "key Up+Shift : scrollLineUp"
216 // "key Next-Shift : "\E[6~"
218 // (lines containing only whitespace are ignored, parseLine assumes that comments have
219 // already been removed)
222 KeyboardTranslatorReader::KeyboardTranslatorReader( QIODevice* source )
223 : _source(source)
224 , _hasNext(false)
226 // read input until we find the description
227 while ( _description.isEmpty() && !source->atEnd() )
229 QList<Token> tokens = tokenize( QString(source->readLine()) );
230 if ( !tokens.isEmpty() && tokens.first().type == Token::TitleKeyword )
231 _description = i18n(tokens[1].text.toUtf8());
233 // read first entry (if any)
234 readNext();
236 void KeyboardTranslatorReader::readNext()
238 // find next entry
239 while ( !_source->atEnd() )
241 const QList<Token>& tokens = tokenize( QString(_source->readLine()) );
242 if ( !tokens.isEmpty() && tokens.first().type == Token::KeyKeyword )
244 KeyboardTranslator::States flags = KeyboardTranslator::NoState;
245 KeyboardTranslator::States flagMask = KeyboardTranslator::NoState;
246 Qt::KeyboardModifiers modifiers = Qt::NoModifier;
247 Qt::KeyboardModifiers modifierMask = Qt::NoModifier;
249 int keyCode = Qt::Key_unknown;
251 decodeSequence(tokens[1].text.toLower(),
252 keyCode,
253 modifiers,
254 modifierMask,
255 flags,
256 flagMask);
258 KeyboardTranslator::Command command = KeyboardTranslator::NoCommand;
259 QByteArray text;
261 // get text or command
262 if ( tokens[2].type == Token::OutputText )
264 text = tokens[2].text.toLocal8Bit();
266 else if ( tokens[2].type == Token::Command )
268 // identify command
269 if (!parseAsCommand(tokens[2].text,command))
270 kWarning() << "Command" << tokens[2].text << "not understood.";
273 KeyboardTranslator::Entry newEntry;
274 newEntry.setKeyCode( keyCode );
275 newEntry.setState( flags );
276 newEntry.setStateMask( flagMask );
277 newEntry.setModifiers( modifiers );
278 newEntry.setModifierMask( modifierMask );
279 newEntry.setText( text );
280 newEntry.setCommand( command );
282 _nextEntry = newEntry;
284 _hasNext = true;
286 return;
290 _hasNext = false;
293 bool KeyboardTranslatorReader::parseAsCommand(const QString& text,KeyboardTranslator::Command& command)
295 if ( text.compare("erase",Qt::CaseInsensitive) == 0 )
296 command = KeyboardTranslator::EraseCommand;
297 else if ( text.compare("scrollpageup",Qt::CaseInsensitive) == 0 )
298 command = KeyboardTranslator::ScrollPageUpCommand;
299 else if ( text.compare("scrollpagedown",Qt::CaseInsensitive) == 0 )
300 command = KeyboardTranslator::ScrollPageDownCommand;
301 else if ( text.compare("scrolllineup",Qt::CaseInsensitive) == 0 )
302 command = KeyboardTranslator::ScrollLineUpCommand;
303 else if ( text.compare("scrolllinedown",Qt::CaseInsensitive) == 0 )
304 command = KeyboardTranslator::ScrollLineDownCommand;
305 else if ( text.compare("scrolllock",Qt::CaseInsensitive) == 0 )
306 command = KeyboardTranslator::ScrollLockCommand;
307 else
308 return false;
310 return true;
313 bool KeyboardTranslatorReader::decodeSequence(const QString& text,
314 int& keyCode,
315 Qt::KeyboardModifiers& modifiers,
316 Qt::KeyboardModifiers& modifierMask,
317 KeyboardTranslator::States& flags,
318 KeyboardTranslator::States& flagMask)
320 bool isWanted = true;
321 bool endOfItem = false;
322 QString buffer;
324 Qt::KeyboardModifiers tempModifiers = modifiers;
325 Qt::KeyboardModifiers tempModifierMask = modifierMask;
326 KeyboardTranslator::States tempFlags = flags;
327 KeyboardTranslator::States tempFlagMask = flagMask;
329 for ( int i = 0 ; i < text.count() ; i++ )
331 const QChar& ch = text[i];
332 bool isFirstLetter = i == 0;
333 bool isLastLetter = ( i == text.count()-1 );
334 endOfItem = true;
335 if ( ch.isLetterOrNumber() )
337 endOfItem = false;
338 buffer.append(ch);
339 } else if ( isFirstLetter )
341 buffer.append(ch);
344 if ( (endOfItem || isLastLetter) && !buffer.isEmpty() )
346 Qt::KeyboardModifier itemModifier = Qt::NoModifier;
347 int itemKeyCode = 0;
348 KeyboardTranslator::State itemFlag = KeyboardTranslator::NoState;
350 if ( parseAsModifier(buffer,itemModifier) )
352 tempModifierMask |= itemModifier;
354 if ( isWanted )
355 tempModifiers |= itemModifier;
357 else if ( parseAsStateFlag(buffer,itemFlag) )
359 tempFlagMask |= itemFlag;
361 if ( isWanted )
362 tempFlags |= itemFlag;
364 else if ( parseAsKeyCode(buffer,itemKeyCode) )
365 keyCode = itemKeyCode;
366 else
367 kDebug() << "Unable to parse key binding item:" << buffer;
369 buffer.clear();
372 // check if this is a wanted / not-wanted flag and update the
373 // state ready for the next item
374 if ( ch == '+' )
375 isWanted = true;
376 else if ( ch == '-' )
377 isWanted = false;
380 modifiers = tempModifiers;
381 modifierMask = tempModifierMask;
382 flags = tempFlags;
383 flagMask = tempFlagMask;
385 return true;
388 bool KeyboardTranslatorReader::parseAsModifier(const QString& item , Qt::KeyboardModifier& modifier)
390 if ( item == "shift" )
391 modifier = Qt::ShiftModifier;
392 else if ( item == "ctrl" || item == "control" )
393 modifier = Qt::ControlModifier;
394 else if ( item == "alt" )
395 modifier = Qt::AltModifier;
396 else if ( item == "meta" )
397 modifier = Qt::MetaModifier;
398 else if ( item == "keypad" )
399 modifier = Qt::KeypadModifier;
400 else
401 return false;
403 return true;
405 bool KeyboardTranslatorReader::parseAsStateFlag(const QString& item , KeyboardTranslator::State& flag)
407 if ( item == "appcukeys" || item == "appcursorkeys" )
408 flag = KeyboardTranslator::CursorKeysState;
409 else if ( item == "ansi" )
410 flag = KeyboardTranslator::AnsiState;
411 else if ( item == "newline" )
412 flag = KeyboardTranslator::NewLineState;
413 else if ( item == "appscreen" )
414 flag = KeyboardTranslator::AlternateScreenState;
415 else if ( item == "anymod" || item == "anymodifier" )
416 flag = KeyboardTranslator::AnyModifierState;
417 else if ( item == "appkeypad" )
418 flag = KeyboardTranslator::ApplicationKeypadState;
419 else
420 return false;
422 return true;
424 bool KeyboardTranslatorReader::parseAsKeyCode(const QString& item , int& keyCode)
426 QKeySequence sequence = QKeySequence::fromString(item);
427 if ( !sequence.isEmpty() )
429 keyCode = sequence[0];
431 if ( sequence.count() > 1 )
433 kDebug() << "Unhandled key codes in sequence: " << item;
436 // additional cases implemented for backwards compatibility with KDE 3
437 else if ( item == "prior" )
438 keyCode = Qt::Key_PageUp;
439 else if ( item == "next" )
440 keyCode = Qt::Key_PageDown;
441 else
442 return false;
444 return true;
447 QString KeyboardTranslatorReader::description() const
449 return _description;
451 bool KeyboardTranslatorReader::hasNextEntry()
453 return _hasNext;
455 KeyboardTranslator::Entry KeyboardTranslatorReader::createEntry( const QString& condition ,
456 const QString& result )
458 QString entryString("keyboard \"temporary\"\nkey ");
459 entryString.append(condition);
460 entryString.append(" : ");
462 // if 'result' is the name of a command then the entry result will be that command,
463 // otherwise the result will be treated as a string to echo when the key sequence
464 // specified by 'condition' is pressed
465 KeyboardTranslator::Command command;
466 if (parseAsCommand(result,command))
467 entryString.append(result);
468 else
469 entryString.append('\"' + result + '\"');
471 QByteArray array = entryString.toUtf8();
472 QBuffer buffer(&array);
473 buffer.open(QIODevice::ReadOnly);
474 KeyboardTranslatorReader reader(&buffer);
476 KeyboardTranslator::Entry entry;
477 if ( reader.hasNextEntry() )
478 entry = reader.nextEntry();
480 return entry;
483 KeyboardTranslator::Entry KeyboardTranslatorReader::nextEntry()
485 Q_ASSERT( _hasNext );
486 KeyboardTranslator::Entry entry = _nextEntry;
487 readNext();
488 return entry;
490 bool KeyboardTranslatorReader::parseError()
492 return false;
494 QList<KeyboardTranslatorReader::Token> KeyboardTranslatorReader::tokenize(const QString& line)
496 QString text = line;
498 // remove comments
499 bool inQuotes = false;
500 int commentPos = -1;
501 for (int i=text.length()-1;i>=0;i--)
503 QChar ch = text[i];
504 if (ch == '\"')
505 inQuotes = !inQuotes;
506 else if (ch == '#' && !inQuotes)
507 commentPos = i;
509 if (commentPos != -1)
510 text.remove(commentPos,text.length());
512 text = text.simplified();
514 // title line: keyboard "title"
515 static QRegExp title("keyboard\\s+\"(.*)\"");
516 // key line: key KeySequence : "output"
517 // key line: key KeySequence : command
518 static QRegExp key("key\\s+([\\w\\+\\s\\-\\*\\.]+)\\s*:\\s*(\"(.*)\"|\\w+)");
520 QList<Token> list;
521 if ( text.isEmpty() )
523 return list;
526 if ( title.exactMatch(text) )
528 Token titleToken = { Token::TitleKeyword , QString() };
529 Token textToken = { Token::TitleText , title.capturedTexts()[1] };
531 list << titleToken << textToken;
533 else if ( key.exactMatch(text) )
535 Token keyToken = { Token::KeyKeyword , QString() };
536 Token sequenceToken = { Token::KeySequence , key.capturedTexts()[1].remove(' ') };
538 list << keyToken << sequenceToken;
540 if ( key.capturedTexts()[3].isEmpty() )
542 // capturedTexts()[2] is a command
543 Token commandToken = { Token::Command , key.capturedTexts()[2] };
544 list << commandToken;
546 else
548 // capturedTexts()[3] is the output string
549 Token outputToken = { Token::OutputText , key.capturedTexts()[3] };
550 list << outputToken;
553 else
555 kWarning() << "Line in keyboard translator file could not be understood:" << text;
558 return list;
561 QList<QString> KeyboardTranslatorManager::allTranslators()
563 if ( !_haveLoadedAll )
565 findTranslators();
568 return _translators.keys();
571 KeyboardTranslator::Entry::Entry()
572 : _keyCode(0)
573 , _modifiers(Qt::NoModifier)
574 , _modifierMask(Qt::NoModifier)
575 , _state(NoState)
576 , _stateMask(NoState)
577 , _command(NoCommand)
581 bool KeyboardTranslator::Entry::operator==(const Entry& rhs) const
583 return _keyCode == rhs._keyCode &&
584 _modifiers == rhs._modifiers &&
585 _modifierMask == rhs._modifierMask &&
586 _state == rhs._state &&
587 _stateMask == rhs._stateMask &&
588 _command == rhs._command &&
589 _text == rhs._text;
592 bool KeyboardTranslator::Entry::matches(int keyCode ,
593 Qt::KeyboardModifiers modifiers,
594 States testState) const
596 if ( _keyCode != keyCode )
597 return false;
599 if ( (modifiers & _modifierMask) != (_modifiers & _modifierMask) )
600 return false;
602 // if modifiers is non-zero, the 'any modifier' state is implicit
603 if ( modifiers != 0 )
604 testState |= AnyModifierState;
606 if ( (testState & _stateMask) != (_state & _stateMask) )
607 return false;
609 // special handling for the 'Any Modifier' state, which checks for the presence of
610 // any or no modifiers. In this context, the 'keypad' modifier does not count.
611 bool anyModifiersSet = modifiers != 0 && modifiers != Qt::KeypadModifier;
612 bool wantAnyModifier = _state & KeyboardTranslator::AnyModifierState;
613 if ( _stateMask & KeyboardTranslator::AnyModifierState )
615 if ( wantAnyModifier != anyModifiersSet )
616 return false;
619 return true;
621 QByteArray KeyboardTranslator::Entry::escapedText(bool expandWildCards,Qt::KeyboardModifiers modifiers) const
623 QByteArray result(text(expandWildCards,modifiers));
625 for ( int i = 0 ; i < result.count() ; i++ )
627 char ch = result[i];
628 char replacement = 0;
630 switch ( ch )
632 case 27 : replacement = 'E'; break;
633 case 8 : replacement = 'b'; break;
634 case 12 : replacement = 'f'; break;
635 case 9 : replacement = 't'; break;
636 case 13 : replacement = 'r'; break;
637 case 10 : replacement = 'n'; break;
638 default:
639 // any character which is not printable is replaced by an equivalent
640 // \xhh escape sequence (where 'hh' are the corresponding hex digits)
641 if ( !QChar(ch).isPrint() )
642 replacement = 'x';
645 if ( replacement == 'x' )
647 result.replace(i,1,"\\x"+QByteArray(1,ch).toHex());
648 } else if ( replacement != 0 )
650 result.remove(i,1);
651 result.insert(i,'\\');
652 result.insert(i+1,replacement);
656 return result;
658 QByteArray KeyboardTranslator::Entry::unescape(const QByteArray& input) const
660 QByteArray result(input);
662 for ( int i = 0 ; i < result.count()-1 ; i++ )
665 QByteRef ch = result[i];
666 if ( ch == '\\' )
668 char replacement[2] = {0,0};
669 int charsToRemove = 2;
670 bool escapedChar = true;
672 switch ( result[i+1] )
674 case 'E' : replacement[0] = 27; break;
675 case 'b' : replacement[0] = 8 ; break;
676 case 'f' : replacement[0] = 12; break;
677 case 't' : replacement[0] = 9 ; break;
678 case 'r' : replacement[0] = 13; break;
679 case 'n' : replacement[0] = 10; break;
680 case 'x' :
682 // format is \xh or \xhh where 'h' is a hexadecimal
683 // digit from 0-9 or A-F which should be replaced
684 // with the corresponding character value
685 char hexDigits[3] = {0};
687 if ( (i < result.count()-2) && isxdigit(result[i+2]) )
688 hexDigits[0] = result[i+2];
689 if ( (i < result.count()-3) && isxdigit(result[i+3]) )
690 hexDigits[1] = result[i+3];
692 unsigned charValue = 0;
693 sscanf(hexDigits,"%x",&charValue);
695 replacement[0] = (char)charValue;
696 charsToRemove = 2 + strlen(hexDigits);
698 break;
699 default:
700 escapedChar = false;
703 if ( escapedChar )
704 result.replace(i,charsToRemove,replacement);
708 return result;
711 void KeyboardTranslator::Entry::insertModifier( QString& item , int modifier ) const
713 if ( !(modifier & _modifierMask) )
714 return;
716 if ( modifier & _modifiers )
717 item += '+';
718 else
719 item += '-';
721 if ( modifier == Qt::ShiftModifier )
722 item += "Shift";
723 else if ( modifier == Qt::ControlModifier )
724 item += "Ctrl";
725 else if ( modifier == Qt::AltModifier )
726 item += "Alt";
727 else if ( modifier == Qt::MetaModifier )
728 item += "Meta";
729 else if ( modifier == Qt::KeypadModifier )
730 item += "KeyPad";
732 void KeyboardTranslator::Entry::insertState( QString& item , int state ) const
734 if ( !(state & _stateMask) )
735 return;
737 if ( state & _state )
738 item += '+' ;
739 else
740 item += '-' ;
742 if ( state == KeyboardTranslator::AlternateScreenState )
743 item += "AppScreen";
744 else if ( state == KeyboardTranslator::NewLineState )
745 item += "NewLine";
746 else if ( state == KeyboardTranslator::AnsiState )
747 item += "Ansi";
748 else if ( state == KeyboardTranslator::CursorKeysState )
749 item += "AppCursorKeys";
750 else if ( state == KeyboardTranslator::AnyModifierState )
751 item += "AnyModifier";
752 else if ( state == KeyboardTranslator::ApplicationKeypadState )
753 item += "AppKeypad";
755 QString KeyboardTranslator::Entry::resultToString(bool expandWildCards,Qt::KeyboardModifiers modifiers) const
757 if ( !_text.isEmpty() )
758 return escapedText(expandWildCards,modifiers);
759 else if ( _command == EraseCommand )
760 return "Erase";
761 else if ( _command == ScrollPageUpCommand )
762 return "ScrollPageUp";
763 else if ( _command == ScrollPageDownCommand )
764 return "ScrollPageDown";
765 else if ( _command == ScrollLineUpCommand )
766 return "ScrollLineUp";
767 else if ( _command == ScrollLineDownCommand )
768 return "ScrollLineDown";
769 else if ( _command == ScrollLockCommand )
770 return "ScrollLock";
772 return QString();
774 QString KeyboardTranslator::Entry::conditionToString() const
776 QString result = QKeySequence(_keyCode).toString();
778 insertModifier( result , Qt::ShiftModifier );
779 insertModifier( result , Qt::ControlModifier );
780 insertModifier( result , Qt::AltModifier );
781 insertModifier( result , Qt::MetaModifier );
782 insertModifier( result , Qt::KeypadModifier );
784 insertState( result , KeyboardTranslator::AlternateScreenState );
785 insertState( result , KeyboardTranslator::NewLineState );
786 insertState( result , KeyboardTranslator::AnsiState );
787 insertState( result , KeyboardTranslator::CursorKeysState );
788 insertState( result , KeyboardTranslator::AnyModifierState );
789 insertState( result , KeyboardTranslator::ApplicationKeypadState );
791 return result;
794 KeyboardTranslator::KeyboardTranslator(const QString& name)
795 : _name(name)
799 void KeyboardTranslator::setDescription(const QString& description)
801 _description = description;
803 QString KeyboardTranslator::description() const
805 return _description;
807 void KeyboardTranslator::setName(const QString& name)
809 _name = name;
811 QString KeyboardTranslator::name() const
813 return _name;
816 QList<KeyboardTranslator::Entry> KeyboardTranslator::entries() const
818 return _entries.values();
821 void KeyboardTranslator::addEntry(const Entry& entry)
823 const int keyCode = entry.keyCode();
824 _entries.insert(keyCode,entry);
826 void KeyboardTranslator::replaceEntry(const Entry& existing , const Entry& replacement)
828 if ( !existing.isNull() )
829 _entries.remove(existing.keyCode(),existing);
830 _entries.insert(replacement.keyCode(),replacement);
832 void KeyboardTranslator::removeEntry(const Entry& entry)
834 _entries.remove(entry.keyCode(),entry);
836 KeyboardTranslator::Entry KeyboardTranslator::findEntry(int keyCode, Qt::KeyboardModifiers modifiers, States state) const
838 foreach(const Entry& entry, _entries.values(keyCode))
840 if ( entry.matches(keyCode,modifiers,state) )
841 return entry;
843 return Entry(); // entry not found
845 void KeyboardTranslatorManager::addTranslator(KeyboardTranslator* translator)
847 _translators.insert(translator->name(),translator);
849 if ( !saveTranslator(translator) )
850 kWarning() << "Unable to save translator" << translator->name()
851 << "to disk.";
853 bool KeyboardTranslatorManager::deleteTranslator(const QString& name)
855 Q_ASSERT( _translators.contains(name) );
857 // locate and delete
858 QString path = findTranslatorPath(name);
859 if ( QFile::remove(path) )
861 _translators.remove(name);
862 return true;
864 else
866 kWarning() << "Failed to remove translator - " << path;
867 return false;
870 K_GLOBAL_STATIC( KeyboardTranslatorManager , theKeyboardTranslatorManager )
871 KeyboardTranslatorManager* KeyboardTranslatorManager::instance()
873 return theKeyboardTranslatorManager;