/*************************************************************************** kbconfig.cpp - description ------------------- begin : Sun Jul 8 2001 copyright : (C) 2001 by Leonid Zeitlin email : lz@europe.com ***************************************************************************/ /*************************************************************************** * * * 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. * * * ***************************************************************************/ #include #include #include #include #if KDE_VERSION_MAJOR >= 3 #include #include #else #include #include #endif #include #include #include #include #include #include #include "kbconfig.h" #include "xkeyboard.h" #ifdef HAVE_X11_EXTENSIONS_XKBRULES_H #include #endif #define TOGGLE_MODE_ENTRY "toggle_mode" #define DEFAULT_GROUP_ENTRY "default_group" //#define PERWINDOW_GROUP_ENTRY "perwindow_group" #define ICON_TYPE_ENTRY "icon_type" #define AUTOSTART_ENTRY "autostart" #define USE_SHORTCUTS_ENTRY "use_shorcuts" #define GROUP_SCOPE_ENTRY "group_scope" KBConfig::KBConfig() { m_toggle_mode = false; m_groups.setAutoDelete(true); m_default_groupno = 0; //m_perwindow_group = false; m_group_scope = SCOPE_GLOBAL; m_autostart = true; m_icon_style = ICON_CODE_AND_FLAG; //m_keys = new KGlobalAccel(NULL); m_keys = NULL; } KBConfig::~KBConfig() { delete m_keys; } /** load the KBSwitch configration from the application KConfig object */ void KBConfig::load(KConfig *config){ config->setGroup(OPTIONS_SECTION); m_toggle_mode = config->readBoolEntry(TOGGLE_MODE_ENTRY); m_default_groupno = config->readNumEntry(DEFAULT_GROUP_ENTRY); //m_perwindow_group = config->readBoolEntry(PERWINDOW_GROUP_ENTRY); m_group_scope = GroupScope(config->readNumEntry(GROUP_SCOPE_ENTRY, SCOPE_GLOBAL)); m_autostart = config->readBoolEntry(AUTOSTART_ENTRY, true); m_icon_style = IconStyle(config->readNumEntry(ICON_TYPE_ENTRY, ICON_FLAG)); m_use_shortcuts = config->readBoolEntry(USE_SHORTCUTS_ENTRY, false); XKeyboard *xkb = XKeyboard::self(); QStringList list; xkb->getGroupNames(list); unsigned int i = 0; m_groups.clear(); m_groups.resize(xkb->getNumKbdGroups()); QString name; for (QStringList::Iterator iter = list.begin(); iter != list.end(); iter++, i++) { name = *iter; if (name == QString::null) name = i18n(""); m_groups.insert(i, new KBGroup(name)); } QValueVector pixlist; QStringList iconpaths; drawIcons(m_icon_style, &pixlist, &iconpaths); for (i = 0; i < m_groups.count(); i++) { m_groups[i]->setPixmap(pixlist[i]); m_groups[i]->setIconPath(iconpaths[i]); } if (m_keys) delete m_keys; m_keys = new KGlobalAccel(NULL); for (int i = 0; i < groupCount(); i++) { m_keys->insert(QString::fromLatin1("SetGroup %1").arg(i), i18n("Activate %1 keyboard layout").arg(m_groups[i]->getName()), QString::null, Qt::ALT+Qt::CTRL+Qt::Key_1 + i, KKey::QtWIN+Qt::CTRL+Qt::Key_1 + i, kapp, SLOT(slotGroupSelected(int))); } m_keys->readSettings(config); checkKeysEnabled(); } void KBConfig::save(KConfig *config) { config->setGroup(OPTIONS_SECTION); config->writeEntry(TOGGLE_MODE_ENTRY, m_toggle_mode); config->writeEntry(DEFAULT_GROUP_ENTRY, m_default_groupno); //config->writeEntry(PERWINDOW_GROUP_ENTRY, m_perwindow_group); config->writeEntry(GROUP_SCOPE_ENTRY, m_group_scope); config->writeEntry(ICON_TYPE_ENTRY, m_icon_style); config->writeEntry(AUTOSTART_ENTRY, m_autostart); config->writeEntry(USE_SHORTCUTS_ENTRY, m_use_shortcuts); m_keys->writeSettings(config); } void KBConfig::drawIcons(IconStyle icon_style, QValueVector *icons, QStringList *iconpaths) { QString path, countryCode, langCode; QStringList layouts; KGlobal::dirs()->addResourceDir("appdata", "."); KConfig map("group_names", true, true, "appdata"); KConfig *config = kapp->config(); config->setGroup(ICONS_SECTION); getXkbLayouts(layouts); icons->clear(); icons->resize(m_groups.count()); iconpaths->clear(); for (unsigned int i = 0; i < m_groups.count(); i++) { map.setGroup("Mapping"); countryCode = map.readEntry(m_groups[i]->getName()); // if the country code can't be guessed from group name, try XKB layout name if (countryCode.isEmpty() && i < layouts.count()) countryCode = layouts[i]; map.setGroup("Languages"); langCode = map.readEntry(m_groups[i]->getName()); if (langCode.isEmpty()) langCode = countryCode; QPixmap &pix = (*icons)[i]; pix.resize(0, 0); path = QString::null; if (icon_style == ICON_FLAG /*&& !countryCode.isEmpty()*/) drawFlagPixmap(pix, path, countryCode, i, config); else if (icon_style == ICON_CODE_AND_FLAG /*&& !countryCode.isEmpty()*/) drawCodeAndFlagPixmap(pix, path, countryCode, langCode, i, config); if (pix.isNull() && !langCode.isEmpty()) drawCodePixmap(pix, langCode); if (pix.isNull()) drawDefaultPixmap(pix, i); iconpaths->append(path); } } /** No descriptions */ /*void KBConfig::guessGroupPixmaps(){ KGlobal::dirs()->addResourceDir("appdata", "."); KConfig map("group_names", true, true, "appdata"); QString path, countryCode, langCode; QPixmap pix; for (unsigned int i = 0; i < m_groups.count(); i++) { if (m_groups[i]->getPixmap().isNull()) { map.setGroup("Mapping"); countryCode = map.readEntry(m_groups[i]->getName()); map.setGroup("Languages"); langCode = map.readEntry(m_groups[i]->getName()); if (langCode.isEmpty()) langCode = countryCode; pix.resize(0, 0); if (m_icon_type == ICON_FLAG && !countryCode.isEmpty()) drawFlagPixmap(pix, countryCode); else if (m_icon_type == ICON_CODE_AND_FLAG && !countryCode.isEmpty()) drawCodeAndFlagPixmap(pix, countryCode, langCode); if (pix.isNull() && !langCode.isEmpty()) drawCodePixmap(pix, langCode); if (!pix.isNull()) m_groups[i]->setPixmap(pix); } } }*/ bool KBConfig::getGroupImage(QImage &img, QString &path, const QString &code, int group, KConfig *config) { bool ret = true; bool need_to_scale = false; path = config->readEntry(m_groups[group]->getName()/*entryForGroup(group)*/); if (path.isEmpty() || !img.load(path)) { if (code.isEmpty()) ret = false; else { path = locate("locale", QString("l10n/%1/flag.png").arg(code)); if (!path.isEmpty()) ret = img.load(path); else { // I am told in Red Hat 9 standard KDE flag pixmaps are missing. // Workaround: we have to simulate them by rescaling GKB's pixmaps path = QString("/usr/share/pixmaps/gkb/%1.png").arg(code); ret = img.load(path) && !img.isNull(); need_to_scale = true; } } } if (ret) { // if need_to_scale is not already set, set it if image is too wide if (!need_to_scale) need_to_scale = img.width() > 24; if (need_to_scale) img = img.smoothScale(FLAG_ICON_WIDTH, FLAG_ICON_HEIGHT); } return ret; } void KBConfig::drawFlagPixmap(QPixmap &pix, QString &path, const QString &code, int group, KConfig *config) { QImage img; if (getGroupImage(img, path, code, group, config)) pix.convertFromImage(img); } void KBConfig::drawCodePixmap(QPixmap &pix, const QString &code) { pix.resize(19, 16); QPainter painter(&pix); QFont font("helvetica", 9, QFont::Bold); font.setPixelSize(10); painter.setFont(font); painter.setPen(KGlobalSettings::highlightedTextColor()); pix.fill(KGlobalSettings::highlightColor()); painter.drawText(1, 0, pix.width(), pix.height(), Qt::AlignHCenter | Qt::AlignVCenter, code.upper()); /*QSize size = painter.fontMetrics().size(0, code.upper()); kdDebug() << size.width() << " x " << size.height() << endl;*/ } void KBConfig::drawCodeAndFlagPixmap(QPixmap &pix, QString &path, const QString &countryCode, const QString &langCode, int group, KConfig *config) { QImage img; if (!getGroupImage(img, path, countryCode, group, config)) return; // could not find flag if (img.depth() <= 8) img = img.convertDepth(32); // the following code is taken from kdebase/kxkb/pixmap.cpp for (int y = 0; y < img.height(); y++) for(int x = 0; x < img.width(); x++) { QRgb rgb = img.pixel(x, y); img.setPixel(x, y, qRgb(qRed(rgb)*3/4, qGreen(rgb)*3/4, qBlue(rgb)*3/4)); } pix.convertFromImage(img); QPainter painter(&pix); painter.setPen(Qt::black); painter.setFont(QFont("helvetica", 10, QFont::Bold)); painter.drawText(1, 1, pix.width(), pix.height()-2, Qt::AlignCenter, langCode); painter.setPen(Qt::white); painter.drawText(0, 0, pix.width(), pix.height()-2, Qt::AlignCenter, langCode); } void KBConfig::drawDefaultPixmap(QPixmap &pix, int group) { pix.resize(FLAG_ICON_WIDTH, FLAG_ICON_HEIGHT); QPainter painter(&pix); pix.fill(); painter.drawText(0, 0, pix.width(), pix.height(), Qt::AlignHCenter | Qt::AlignVCenter, QString::number(group+1)); } void KBConfig::checkKeysEnabled() { m_keys->setEnabled(m_use_shortcuts); m_keys->updateConnections(); } /** No descriptions */ /*void KBConfig::drawDefaultPixmaps(){ QPixmap pix(16, 16); QPainter painter(&pix); for (unsigned int i = 0; i < m_groups.count(); i++) { if (m_groups[i]->getPixmap().isNull()) { pix.fill(); painter.drawText(0, 0, pix.width(), pix.height(), Qt::AlignHCenter | Qt::AlignVCenter, QString::number(i+1)); m_groups[i]->setPixmap(pix); } } }*/ /** No descriptions */ /*void KBConfig::loadConfiguredPixmaps(KConfig *config){ QString path; QPixmap pix; config->setGroup(ICONS_SECTION); for (unsigned int i = 0; i < m_groups.count(); i++) { path = config->readEntry(entryForGroup(i)); if (!path.isEmpty() && pix.load(path)) m_groups[i]->setPixmap(pix); } }*/ /** No descriptions */ /*void KBConfig::notifyChanged(){ emit changed(); }*/ /*! \fn KBConfig::getXkbLayouts(const QStringList &layouts) */ void KBConfig::getXkbLayouts(QStringList &layouts) { #if HAVE_X11_EXTENSIONS_XKBRULES_H && HAVE_LIBXKBFILE XkbRF_VarDefsRec vardefs; int i; usleep(10000); if (XkbRF_GetNamesProp(qt_xdisplay(), NULL, &vardefs)) { layouts = QStringList::split(',', vardefs.layout, true); for (QStringList::Iterator it = layouts.begin(); it != layouts.end(); ++it) { i = 0; while ((*it)[i] >= 'a' && (*it)[i] <= 'z') i++; *it = (*it).left(i); } if (vardefs.layout) XFree(vardefs.layout); if (vardefs.model) XFree(vardefs.model); if (vardefs.variant) XFree(vardefs.variant); if (vardefs.options) XFree(vardefs.options); } #endif }