Files
qmltermwidget/lib/KeyboardTranslator.cpp
T
2010-10-01 16:08:14 +02:00

917 lines
27 KiB
C++

/*
This source file was part of Konsole, a terminal emulator.
Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
*/
// Own
#include "KeyboardTranslator.h"
// System
#include <ctype.h>
#include <stdio.h>
// Qt
#include <QtCore/QBuffer>
//#include <KDebug>
#include <QtCore/QFile>
#include <QtCore/QFileInfo>
#include <QtCore>
#include <QtGui>
// KDE
//#include <KDebug>
//#include <KLocale>
//#include <KStandardDirs>
using namespace Konsole;
//this is for default REALLY fallback translator.
//const char* KeyboardTranslatorManager::defaultTranslatorText =
//#include "DefaultTranslatorText.h"
//;
//and this is default now translator - default.keytab from original Konsole
const char * KeyboardTranslatorManager::defaultTranslatorText =
#include "ExtendedDefaultTranslator.h"
;
KeyboardTranslatorManager::KeyboardTranslatorManager()
: _haveLoadedAll(false)
{
}
KeyboardTranslatorManager::~KeyboardTranslatorManager()
{
qDeleteAll(_translators.values());
}
QString KeyboardTranslatorManager::findTranslatorPath(const QString & name)
{
return QString("kb-layouts/" + name + ".keytab");
}
void KeyboardTranslatorManager::findTranslators()
{
QDir dir("kb-layouts/");
QStringList filters;
filters << "*.keytab";
dir.setNameFilters(filters);
QStringList list = dir.entryList(filters); //(".keytab"); // = KGlobal::dirs()->findAllResources("data",
// "konsole/*.keytab",
// KStandardDirs::NoDuplicates);
list = dir.entryList(filters);
// add the name of each translator to the list and associated
// the name with a null pointer to indicate that the translator
// has not yet been loaded from disk
QStringListIterator listIter(list);
while (listIter.hasNext()) {
QString translatorPath = listIter.next();
QString name = QFileInfo(translatorPath).baseName();
if ( !_translators.contains(name) ) {
_translators.insert(name,0);
}
}
_haveLoadedAll = true;
}
const KeyboardTranslator * KeyboardTranslatorManager::findTranslator(const QString & name)
{
if ( name.isEmpty() ) {
return defaultTranslator();
}
//here was smth wrong in original Konsole source
findTranslators();
if ( _translators.contains(name) && _translators[name] != 0 ) {
return _translators[name];
}
KeyboardTranslator * translator = loadTranslator(name);
if ( translator != 0 ) {
_translators[name] = translator;
} else if ( !name.isEmpty() ) {
qWarning() << "Unable to load translator" << name;
}
return translator;
}
bool KeyboardTranslatorManager::saveTranslator(const KeyboardTranslator * translator)
{
const QString path = ".keytab";// = KGlobal::dirs()->saveLocation("data","konsole/")+translator->name()
// +".keytab";
qDebug() << "Saving translator to" << path;
QFile destination(path);
if (!destination.open(QIODevice::WriteOnly | QIODevice::Text)) {
qWarning() << "Unable to save keyboard translation:"
<< destination.errorString();
return false;
}
{
KeyboardTranslatorWriter writer(&destination);
writer.writeHeader(translator->description());
QListIterator<KeyboardTranslator::Entry> iter(translator->entries());
while ( iter.hasNext() ) {
writer.writeEntry(iter.next());
}
}
destination.close();
return true;
}
KeyboardTranslator * KeyboardTranslatorManager::loadTranslator(const QString & name)
{
const QString & path = findTranslatorPath(name);
QFile source(path);
if (name.isEmpty() || !source.open(QIODevice::ReadOnly | QIODevice::Text)) {
return 0;
}
return loadTranslator(&source,name);
}
const KeyboardTranslator * KeyboardTranslatorManager::defaultTranslator()
{
qDebug() << "Loading default translator from text";
QBuffer textBuffer;
textBuffer.setData(defaultTranslatorText,strlen(defaultTranslatorText));
if (!textBuffer.open(QIODevice::ReadOnly)) {
return 0;
}
return loadTranslator(&textBuffer,"fallback");
}
KeyboardTranslator * KeyboardTranslatorManager::loadTranslator(QIODevice * source,const QString & name)
{
KeyboardTranslator * translator = new KeyboardTranslator(name);
KeyboardTranslatorReader reader(source);
translator->setDescription( reader.description() );
while ( reader.hasNextEntry() ) {
translator->addEntry(reader.nextEntry());
}
source->close();
if ( !reader.parseError() ) {
return translator;
} else {
delete translator;
return 0;
}
}
KeyboardTranslatorWriter::KeyboardTranslatorWriter(QIODevice * destination)
: _destination(destination)
{
Q_ASSERT( destination && destination->isWritable() );
_writer = new QTextStream(_destination);
}
KeyboardTranslatorWriter::~KeyboardTranslatorWriter()
{
delete _writer;
}
void KeyboardTranslatorWriter::writeHeader( const QString & description )
{
*_writer << "keyboard \"" << description << '\"' << '\n';
}
void KeyboardTranslatorWriter::writeEntry( const KeyboardTranslator::Entry & entry )
{
QString result;
if ( entry.command() != KeyboardTranslator::NoCommand ) {
result = entry.resultToString();
} else {
result = '\"' + entry.resultToString() + '\"';
}
*_writer << "key " << entry.conditionToString() << " : " << result << '\n';
}
// each line of the keyboard translation file is one of:
//
// - keyboard "name"
// - key KeySequence : "characters"
// - key KeySequence : CommandName
//
// KeySequence begins with the name of the key ( taken from the Qt::Key enum )
// and is followed by the keyboard modifiers and state flags ( with + or - in front
// of each modifier or flag to indicate whether it is required ). All keyboard modifiers
// and flags are optional, if a particular modifier or state is not specified it is
// assumed not to be a part of the sequence. The key sequence may contain whitespace
//
// eg: "key Up+Shift : scrollLineUp"
// "key Next-Shift : "\E[6~"
//
// (lines containing only whitespace are ignored, parseLine assumes that comments have
// already been removed)
//
KeyboardTranslatorReader::KeyboardTranslatorReader( QIODevice * source )
: _source(source)
, _hasNext(false)
{
// read input until we find the description
while ( _description.isEmpty() && !source->atEnd() ) {
const QList<Token>& tokens = tokenize( QString(source->readLine()) );
if ( !tokens.isEmpty() && tokens.first().type == Token::TitleKeyword ) {
_description = (tokens[1].text.toUtf8());
}
}
readNext();
}
void KeyboardTranslatorReader::readNext()
{
// find next entry
while ( !_source->atEnd() ) {
const QList<Token>& tokens = tokenize( QString(_source->readLine()) );
if ( !tokens.isEmpty() && tokens.first().type == Token::KeyKeyword ) {
KeyboardTranslator::States flags = KeyboardTranslator::NoState;
KeyboardTranslator::States flagMask = KeyboardTranslator::NoState;
Qt::KeyboardModifiers modifiers = Qt::NoModifier;
Qt::KeyboardModifiers modifierMask = Qt::NoModifier;
int keyCode = Qt::Key_unknown;
decodeSequence(tokens[1].text.toLower(),
keyCode,
modifiers,
modifierMask,
flags,
flagMask);
KeyboardTranslator::Command command = KeyboardTranslator::NoCommand;
QByteArray text;
// get text or command
if ( tokens[2].type == Token::OutputText ) {
text = tokens[2].text.toLocal8Bit();
} else if ( tokens[2].type == Token::Command ) {
// identify command
if (!parseAsCommand(tokens[2].text,command)) {
qWarning() << "Command" << tokens[2].text << "not understood.";
}
}
KeyboardTranslator::Entry newEntry;
newEntry.setKeyCode( keyCode );
newEntry.setState( flags );
newEntry.setStateMask( flagMask );
newEntry.setModifiers( modifiers );
newEntry.setModifierMask( modifierMask );
newEntry.setText( text );
newEntry.setCommand( command );
_nextEntry = newEntry;
_hasNext = true;
return;
}
}
_hasNext = false;
}
bool KeyboardTranslatorReader::parseAsCommand(const QString & text,KeyboardTranslator::Command & command)
{
if ( text.compare("erase",Qt::CaseInsensitive) == 0 ) {
command = KeyboardTranslator::EraseCommand;
} else if ( text.compare("scrollpageup",Qt::CaseInsensitive) == 0 ) {
command = KeyboardTranslator::ScrollPageUpCommand;
} else if ( text.compare("scrollpagedown",Qt::CaseInsensitive) == 0 ) {
command = KeyboardTranslator::ScrollPageDownCommand;
} else if ( text.compare("scrolllineup",Qt::CaseInsensitive) == 0 ) {
command = KeyboardTranslator::ScrollLineUpCommand;
} else if ( text.compare("scrolllinedown",Qt::CaseInsensitive) == 0 ) {
command = KeyboardTranslator::ScrollLineDownCommand;
} else if ( text.compare("scrolllock",Qt::CaseInsensitive) == 0 ) {
command = KeyboardTranslator::ScrollLockCommand;
} else {
return false;
}
return true;
}
bool KeyboardTranslatorReader::decodeSequence(const QString & text,
int & keyCode,
Qt::KeyboardModifiers & modifiers,
Qt::KeyboardModifiers & modifierMask,
KeyboardTranslator::States & flags,
KeyboardTranslator::States & flagMask)
{
bool isWanted = true;
bool endOfItem = false;
QString buffer;
Qt::KeyboardModifiers tempModifiers = modifiers;
Qt::KeyboardModifiers tempModifierMask = modifierMask;
KeyboardTranslator::States tempFlags = flags;
KeyboardTranslator::States tempFlagMask = flagMask;
for ( int i = 0 ; i < text.count() ; i++ ) {
const QChar & ch = text[i];
bool isLastLetter = ( i == text.count()-1 );
endOfItem = true;
if ( ch.isLetterOrNumber() ) {
endOfItem = false;
buffer.append(ch);
}
if ( (endOfItem || isLastLetter) && !buffer.isEmpty() ) {
Qt::KeyboardModifier itemModifier = Qt::NoModifier;
int itemKeyCode = 0;
KeyboardTranslator::State itemFlag = KeyboardTranslator::NoState;
if ( parseAsModifier(buffer,itemModifier) ) {
tempModifierMask |= itemModifier;
if ( isWanted ) {
tempModifiers |= itemModifier;
}
} else if ( parseAsStateFlag(buffer,itemFlag) ) {
tempFlagMask |= itemFlag;
if ( isWanted ) {
tempFlags |= itemFlag;
}
} else if ( parseAsKeyCode(buffer,itemKeyCode) ) {
keyCode = itemKeyCode;
} else {
qDebug() << "Unable to parse key binding item:" << buffer;
}
buffer.clear();
}
// check if this is a wanted / not-wanted flag and update the
// state ready for the next item
if ( ch == '+' ) {
isWanted = true;
} else if ( ch == '-' ) {
isWanted = false;
}
}
modifiers = tempModifiers;
modifierMask = tempModifierMask;
flags = tempFlags;
flagMask = tempFlagMask;
return true;
}
bool KeyboardTranslatorReader::parseAsModifier(const QString & item , Qt::KeyboardModifier & modifier)
{
if ( item == "shift" ) {
modifier = Qt::ShiftModifier;
} else if ( item == "ctrl" || item == "control" ) {
modifier = Qt::ControlModifier;
} else if ( item == "alt" ) {
modifier = Qt::AltModifier;
} else if ( item == "meta" ) {
modifier = Qt::MetaModifier;
} else if ( item == "keypad" ) {
modifier = Qt::KeypadModifier;
} else {
return false;
}
return true;
}
bool KeyboardTranslatorReader::parseAsStateFlag(const QString & item , KeyboardTranslator::State & flag)
{
if ( item == "appcukeys" ) {
flag = KeyboardTranslator::CursorKeysState;
} else if ( item == "ansi" ) {
flag = KeyboardTranslator::AnsiState;
} else if ( item == "newline" ) {
flag = KeyboardTranslator::NewLineState;
} else if ( item == "appscreen" ) {
flag = KeyboardTranslator::AlternateScreenState;
} else if ( item == "anymod" ) {
flag = KeyboardTranslator::AnyModifierState;
} else {
return false;
}
return true;
}
bool KeyboardTranslatorReader::parseAsKeyCode(const QString & item , int & keyCode)
{
QKeySequence sequence = QKeySequence::fromString(item);
if ( !sequence.isEmpty() ) {
keyCode = sequence[0];
if ( sequence.count() > 1 ) {
qDebug() << "Unhandled key codes in sequence: " << item;
}
}
// additional cases implemented for backwards compatibility with KDE 3
else if ( item == "prior" ) {
keyCode = Qt::Key_PageUp;
} else if ( item == "next" ) {
keyCode = Qt::Key_PageDown;
} else {
return false;
}
return true;
}
QString KeyboardTranslatorReader::description() const
{
return _description;
}
bool KeyboardTranslatorReader::hasNextEntry()
{
return _hasNext;
}
KeyboardTranslator::Entry KeyboardTranslatorReader::createEntry( const QString & condition ,
const QString & result )
{
QString entryString("keyboard \"temporary\"\nkey ");
entryString.append(condition);
entryString.append(" : ");
// if 'result' is the name of a command then the entry result will be that command,
// otherwise the result will be treated as a string to echo when the key sequence
// specified by 'condition' is pressed
KeyboardTranslator::Command command;
if (parseAsCommand(result,command)) {
entryString.append(result);
} else {
entryString.append('\"' + result + '\"');
}
QByteArray array = entryString.toUtf8();
KeyboardTranslator::Entry entry;
QBuffer buffer(&array);
buffer.open(QIODevice::ReadOnly);
KeyboardTranslatorReader reader(&buffer);
if ( reader.hasNextEntry() ) {
entry = reader.nextEntry();
}
return entry;
}
KeyboardTranslator::Entry KeyboardTranslatorReader::nextEntry()
{
Q_ASSERT( _hasNext );
KeyboardTranslator::Entry entry = _nextEntry;
readNext();
return entry;
}
bool KeyboardTranslatorReader::parseError()
{
return false;
}
QList<KeyboardTranslatorReader::Token> KeyboardTranslatorReader::tokenize(const QString & line)
{
QString text = line.simplified();
// comment line: # comment
static QRegExp comment("\\#.*");
// title line: keyboard "title"
static QRegExp title("keyboard\\s+\"(.*)\"");
// key line: key KeySequence : "output"
// key line: key KeySequence : command
static QRegExp key("key\\s+([\\w\\+\\s\\-]+)\\s*:\\s*(\"(.*)\"|\\w+)");
QList<Token> list;
if ( text.isEmpty() || comment.exactMatch(text) ) {
return list;
}
if ( title.exactMatch(text) ) {
Token titleToken = { Token::TitleKeyword , QString() };
Token textToken = { Token::TitleText , title.capturedTexts()[1] };
list << titleToken << textToken;
} else if ( key.exactMatch(text) ) {
Token keyToken = { Token::KeyKeyword , QString() };
Token sequenceToken = { Token::KeySequence , key.capturedTexts()[1].remove(' ') };
list << keyToken << sequenceToken;
if ( key.capturedTexts()[3].isEmpty() ) {
// capturedTexts()[2] is a command
Token commandToken = { Token::Command , key.capturedTexts()[2] };
list << commandToken;
} else {
// capturedTexts()[3] is the output string
Token outputToken = { Token::OutputText , key.capturedTexts()[3] };
list << outputToken;
}
} else {
qWarning() << "Line in keyboard translator file could not be understood:" << text;
}
return list;
}
QList<QString> KeyboardTranslatorManager::allTranslators()
{
if ( !_haveLoadedAll ) {
findTranslators();
}
return _translators.keys();
}
KeyboardTranslator::Entry::Entry()
: _keyCode(0)
, _modifiers(Qt::NoModifier)
, _modifierMask(Qt::NoModifier)
, _state(NoState)
, _stateMask(NoState)
, _command(NoCommand)
{
}
bool KeyboardTranslator::Entry::operator==(const Entry & rhs) const
{
return _keyCode == rhs._keyCode &&
_modifiers == rhs._modifiers &&
_modifierMask == rhs._modifierMask &&
_state == rhs._state &&
_stateMask == rhs._stateMask &&
_command == rhs._command &&
_text == rhs._text;
}
bool KeyboardTranslator::Entry::matches(int keyCode ,
Qt::KeyboardModifiers modifiers,
States state) const
{
if ( _keyCode != keyCode ) {
return false;
}
if ( (modifiers & _modifierMask) != (_modifiers & _modifierMask) ) {
return false;
}
// if modifiers is non-zero, the 'any modifier' state is implicit
if ( modifiers != 0 ) {
state |= AnyModifierState;
}
if ( (state & _stateMask) != (_state & _stateMask) ) {
return false;
}
// special handling for the 'Any Modifier' state, which checks for the presence of
// any or no modifiers. In this context, the 'keypad' modifier does not count.
bool anyModifiersSet = modifiers != 0 && modifiers != Qt::KeypadModifier;
if ( _stateMask & KeyboardTranslator::AnyModifierState ) {
// test fails if any modifier is required but none are set
if ( (_state & KeyboardTranslator::AnyModifierState) && !anyModifiersSet ) {
return false;
}
// test fails if no modifier is allowed but one or more are set
if ( !(_state & KeyboardTranslator::AnyModifierState) && anyModifiersSet ) {
return false;
}
}
return true;
}
QByteArray KeyboardTranslator::Entry::escapedText(bool expandWildCards,Qt::KeyboardModifiers modifiers) const
{
QByteArray result(text(expandWildCards,modifiers));
for ( int i = 0 ; i < result.count() ; i++ ) {
char ch = result[i];
char replacement = 0;
switch ( ch ) {
case 27 :
replacement = 'E';
break;
case 8 :
replacement = 'b';
break;
case 12 :
replacement = 'f';
break;
case 9 :
replacement = 't';
break;
case 13 :
replacement = 'r';
break;
case 10 :
replacement = 'n';
break;
default:
// any character which is not printable is replaced by an equivalent
// \xhh escape sequence (where 'hh' are the corresponding hex digits)
if ( !QChar(ch).isPrint() ) {
replacement = 'x';
}
}
if ( replacement == 'x' ) {
result.replace(i,1,"\\x"+QByteArray(1,ch).toInt(0, 16));
} else if ( replacement != 0 ) {
result.remove(i,1);
result.insert(i,'\\');
result.insert(i+1,replacement);
}
}
return result;
}
QByteArray KeyboardTranslator::Entry::unescape(const QByteArray & input) const
{
QByteArray result(input);
for ( int i = 0 ; i < result.count()-1 ; i++ ) {
QByteRef ch = result[i];
if ( ch == '\\' ) {
char replacement[2] = {0,0};
int charsToRemove = 2;
bool escapedChar = true;
switch ( result[i+1] ) {
case 'E' :
replacement[0] = 27;
break;
case 'b' :
replacement[0] = 8 ;
break;
case 'f' :
replacement[0] = 12;
break;
case 't' :
replacement[0] = 9 ;
break;
case 'r' :
replacement[0] = 13;
break;
case 'n' :
replacement[0] = 10;
break;
case 'x' : {
// format is \xh or \xhh where 'h' is a hexadecimal
// digit from 0-9 or A-F which should be replaced
// with the corresponding character value
char hexDigits[3] = {0};
if ( (i < result.count()-2) && isxdigit(result[i+2]) ) {
hexDigits[0] = result[i+2];
}
if ( (i < result.count()-3) && isxdigit(result[i+3]) ) {
hexDigits[1] = result[i+3];
}
int charValue = 0;
sscanf(hexDigits,"%x",&charValue);
replacement[0] = (char)charValue;
charsToRemove = 2 + strlen(hexDigits);
}
break;
default:
escapedChar = false;
}
if ( escapedChar ) {
result.replace(i,charsToRemove,replacement);
}
}
}
return result;
}
void KeyboardTranslator::Entry::insertModifier( QString & item , int modifier ) const
{
if ( !(modifier & _modifierMask) ) {
return;
}
if ( modifier & _modifiers ) {
item += '+';
} else {
item += '-';
}
if ( modifier == Qt::ShiftModifier ) {
item += "Shift";
} else if ( modifier == Qt::ControlModifier ) {
item += "Ctrl";
} else if ( modifier == Qt::AltModifier ) {
item += "Alt";
} else if ( modifier == Qt::MetaModifier ) {
item += "Meta";
} else if ( modifier == Qt::KeypadModifier ) {
item += "KeyPad";
}
}
void KeyboardTranslator::Entry::insertState( QString & item , int state ) const
{
if ( !(state & _stateMask) ) {
return;
}
if ( state & _state ) {
item += '+' ;
} else {
item += '-' ;
}
if ( state == KeyboardTranslator::AlternateScreenState ) {
item += "AppScreen";
} else if ( state == KeyboardTranslator::NewLineState ) {
item += "NewLine";
} else if ( state == KeyboardTranslator::AnsiState ) {
item += "Ansi";
} else if ( state == KeyboardTranslator::CursorKeysState ) {
item += "AppCuKeys";
} else if ( state == KeyboardTranslator::AnyModifierState ) {
item += "AnyMod";
}
}
QString KeyboardTranslator::Entry::resultToString(bool expandWildCards,Qt::KeyboardModifiers modifiers) const
{
if ( !_text.isEmpty() ) {
return escapedText(expandWildCards,modifiers);
} else if ( _command == EraseCommand ) {
return "Erase";
} else if ( _command == ScrollPageUpCommand ) {
return "ScrollPageUp";
} else if ( _command == ScrollPageDownCommand ) {
return "ScrollPageDown";
} else if ( _command == ScrollLineUpCommand ) {
return "ScrollLineUp";
} else if ( _command == ScrollLineDownCommand ) {
return "ScrollLineDown";
} else if ( _command == ScrollLockCommand ) {
return "ScrollLock";
}
return QString();
}
QString KeyboardTranslator::Entry::conditionToString() const
{
QString result = QKeySequence(_keyCode).toString();
// add modifiers
insertModifier( result , Qt::ShiftModifier );
insertModifier( result , Qt::ControlModifier );
insertModifier( result , Qt::AltModifier );
insertModifier( result , Qt::MetaModifier );
// add states
insertState( result , KeyboardTranslator::AlternateScreenState );
insertState( result , KeyboardTranslator::NewLineState );
insertState( result , KeyboardTranslator::AnsiState );
insertState( result , KeyboardTranslator::CursorKeysState );
insertState( result , KeyboardTranslator::AnyModifierState );
return result;
}
KeyboardTranslator::KeyboardTranslator(const QString & name)
: _name(name)
{
}
void KeyboardTranslator::setDescription(const QString & description)
{
_description = description;
}
QString KeyboardTranslator::description() const
{
return _description;
}
void KeyboardTranslator::setName(const QString & name)
{
_name = name;
}
QString KeyboardTranslator::name() const
{
return _name;
}
QList<KeyboardTranslator::Entry> KeyboardTranslator::entries() const
{
return _entries.values();
}
void KeyboardTranslator::addEntry(const Entry & entry)
{
const int keyCode = entry.keyCode();
_entries.insertMulti(keyCode,entry);
}
void KeyboardTranslator::replaceEntry(const Entry & existing , const Entry & replacement)
{
if ( !existing.isNull() ) {
_entries.remove(existing.keyCode());
}
_entries.insertMulti(replacement.keyCode(),replacement);
}
void KeyboardTranslator::removeEntry(const Entry & entry)
{
_entries.remove(entry.keyCode());
}
KeyboardTranslator::Entry KeyboardTranslator::findEntry(int keyCode, Qt::KeyboardModifiers modifiers, States state) const
{
if ( _entries.contains(keyCode) ) {
QList<Entry> entriesForKey = _entries.values(keyCode);
QListIterator<Entry> iter(entriesForKey);
while (iter.hasNext()) {
const Entry & next = iter.next();
if ( next.matches(keyCode,modifiers,state) ) {
return next;
}
}
return Entry(); // entry not found
} else {
return Entry();
}
}
void KeyboardTranslatorManager::addTranslator(KeyboardTranslator * translator)
{
_translators.insert(translator->name(),translator);
if ( !saveTranslator(translator) )
qWarning() << "Unable to save translator" << translator->name()
<< "to disk.";
}
bool KeyboardTranslatorManager::deleteTranslator(const QString & name)
{
Q_ASSERT( _translators.contains(name) );
// locate and delete
QString path = findTranslatorPath(name);
if ( QFile::remove(path) ) {
_translators.remove(name);
return true;
} else {
qWarning() << "Failed to remove translator - " << path;
return false;
}
}
K_GLOBAL_STATIC( KeyboardTranslatorManager , theKeyboardTranslatorManager )
KeyboardTranslatorManager * KeyboardTranslatorManager::instance()
{
return theKeyboardTranslatorManager;
}