src/hbcore/inputfw/hbinputmodecache.cpp
changeset 34 ed14f46c0e55
parent 7 923ff622b8b9
equal deleted inserted replaced
31:7516d6d86cf5 34:ed14f46c0e55
    21 ** If you have questions regarding the use of this file, please contact
    21 ** If you have questions regarding the use of this file, please contact
    22 ** Nokia at developer.feedback@nokia.com.
    22 ** Nokia at developer.feedback@nokia.com.
    23 **
    23 **
    24 ****************************************************************************/
    24 ****************************************************************************/
    25 #include "hbinputmodecache_p.h"
    25 #include "hbinputmodecache_p.h"
       
    26 #include "hbinputmodecache_p_p.h"
    26 
    27 
    27 #include <QInputContextPlugin>
    28 #include <QInputContextPlugin>
    28 #include <QLocale>
    29 #include <QLocale>
    29 #include <QFileSystemWatcher>
    30 #include <QFileSystemWatcher>
    30 #include <QLibrary>
    31 #include <QLibrary>
    31 #include <QPluginLoader>
    32 #include <QPluginLoader>
    32 #include <QDir>
    33 #include <QDir>
       
    34 #include <QSharedMemory>
       
    35 #include <QDataStream>
       
    36 #include <QBuffer>
    33 
    37 
    34 #include "hbinpututils.h"
    38 #include "hbinpututils.h"
    35 #include "hbinputmethod.h"
    39 #include "hbinputmethod.h"
    36 #include "hbinputcontextplugin.h"
    40 #include "hbinputcontextplugin.h"
    37 #include "hbinputsettingproxy.h"
    41 #include "hbinputsettingproxy.h"
    40 #include "hbinputmethod_p.h"
    44 #include "hbinputmethod_p.h"
    41 #include "hbinputmethodnull_p.h"
    45 #include "hbinputmethodnull_p.h"
    42 
    46 
    43 /*!
    47 /*!
    44 @alpha
    48 @alpha
    45 @hbcore
       
    46 \class HbInputModeCache
    49 \class HbInputModeCache
    47 \brief Input framework's internal input mode resolver class.
    50 \brief Input framework's internal input mode resolver class.
    48 */
    51 */
    49 
    52 
    50 /// @cond
    53 /// @cond
    51 
    54 
    52 class HbInputMethodListItem
    55 void HbInputMethodListItem::setValues(QInputContextPlugin *plugin, const QString &key)
    53 {
    56 {
    54 public:
    57     if (plugin) {
    55     HbInputMethodListItem() : cached(0), toBeRemoved(false) {}
    58         descriptor.setKey(key);
    56     bool operator==(const HbInputMethodListItem &item) const {
    59         descriptor.setDisplayName(plugin->displayName(key));
    57         return (descriptor.pluginNameAndPath() == item.descriptor.pluginNameAndPath() &&
    60 
    58                 descriptor.key() == item.descriptor.key());
    61         HbInputContextPlugin *extension = qobject_cast<HbInputContextPlugin *>(plugin);
    59     }
    62         if (extension) {
    60 
    63             descriptor.setDisplayNames(extension->displayNames(key));
    61 public:
    64             descriptor.setIcon(extension->icon(key));
    62     HbInputMethodDescriptor descriptor;
    65             descriptor.setIcons(extension->icons(key));
    63     QStringList languages;
    66         }
    64     HbInputMethod *cached;
    67     }
    65     bool toBeRemoved;
    68 }
    66 };
    69 
    67 
    70 QDataStream &operator<<(QDataStream &out, const HbInputMethodListItem &item)
    68 class HbInputModeCachePrivate
    71 {
    69 {
    72     out << item.descriptor;
    70 public:
    73     out << item.languages;
    71     HbInputModeCachePrivate() : mWatcher(new QFileSystemWatcher()), mShuttingDown(false) {}
    74     return out;
    72     ~HbInputModeCachePrivate() {}
    75 }
    73     void refresh(const QString &directory = QString());
    76 
    74     QInputContextPlugin *pluginInstance(const QString &pluginFileName) const;
    77 QDataStream &operator>>(QDataStream &in, HbInputMethodListItem &item)
    75     HbInputMethod *methodInstance(const QString &pluginFileName, const QString &key) const;
    78 {
    76     HbInputModeProperties propertiesFromString(const QString &entry) const;
    79     in >> item.descriptor;
    77     HbInputModeProperties propertiesFromState(const HbInputState &state) const;
    80     in >> item.languages;
    78     HbInputMethod *cachedMethod(HbInputMethodListItem &item);
    81     item.cached = 0;
    79     void updateMonitoredPaths();
    82     item.toBeRemoved = false;
    80     bool isMappedLanguage(const HbInputLanguage &language) const;
    83     return in;
    81 
    84 }
    82 public:
    85 
    83     QFileSystemWatcher *mWatcher;
    86 HbInputModeCachePrivate::HbInputModeCachePrivate()
    84     QList<HbInputMethodListItem> mMethods;
    87   : mSharedMethodList(0),
    85     bool mShuttingDown;
    88     mMethodListModTime(0),
    86 };
    89     mMethodListLastUpdate(0),
    87 
    90     mMethodsFetchedFromDisk(false),
    88 QInputContextPlugin *HbInputModeCachePrivate::pluginInstance(const QString &pluginFileName) const
    91     mShuttingDown(false)
       
    92 {
       
    93     mSharedMethodList = new QSharedMemory(HbInputMethodListKey);
       
    94     // sharedMethodList is only attached when the list is updated
       
    95     mMethodListModTime = new QSharedMemory(HbInputMethodListModTimeKey);
       
    96     mMethodListModTime->attach();
       
    97 }
       
    98 
       
    99 HbInputModeCachePrivate::~HbInputModeCachePrivate()
       
   100 {
       
   101     delete mSharedMethodList;
       
   102     delete mMethodListModTime;
       
   103 }
       
   104 
       
   105 void HbInputModeCachePrivate::refresh()
       
   106 {
       
   107     // Shared memory data is used if available (checked every time we refresh)
       
   108     // Otherwise the methods are read from disk, but just once during modecache lifetime
       
   109     if (!readInputMethodDataFromSharedMemory() && !mMethodsFetchedFromDisk) {
       
   110         readInputMethodDataFromDisk(&mMethods);
       
   111         pruneRemovedMethods();
       
   112         mMethodsFetchedFromDisk = true;
       
   113     }
       
   114 }
       
   115 
       
   116 void HbInputModeCachePrivate::readInputMethodDataFromDisk(QList<HbInputMethodListItem>* methodList, const QDir &readPath)
       
   117 {
       
   118     bool readFromSinglePath = (readPath != QDir());
       
   119     // First go through all the previously found entries and
       
   120     // tag them not refreshed. In case a directory is defined, only marks entries
       
   121     // in that directory
       
   122     for (int i = 0; i < methodList->size(); ++i) {
       
   123         if (readFromSinglePath) {
       
   124             if (methodList->at(i).descriptor.pluginNameAndPath().left(methodList->at(i).descriptor.pluginNameAndPath().lastIndexOf(QDir::separator()))
       
   125                 == readPath.absolutePath()) {
       
   126                 (*methodList)[i].toBeRemoved = true;
       
   127             }
       
   128         } else {
       
   129             (*methodList)[i].toBeRemoved = true;
       
   130         }
       
   131     }
       
   132 
       
   133     // Query plugin paths and scan the folders.
       
   134     QStringList folders = HbInputSettingProxy::instance()->inputMethodPluginPaths();
       
   135     foreach(const QString &folder, folders) {
       
   136         QDir dir(folder);
       
   137         if (!readFromSinglePath || readPath == dir) {
       
   138             for (unsigned int i = 0; i < dir.count(); i++) {
       
   139                 QString path = QString(dir.absolutePath());
       
   140                 if (path.right(1) != "\\" && path.right(1) != "/") {
       
   141                     path += QDir::separator();
       
   142                 }
       
   143                 path += dir[i];
       
   144                 QInputContextPlugin *inputContextPlugin = pluginInstance(path);
       
   145                 if (inputContextPlugin) {
       
   146                     HbInputMethodListItem listItem;
       
   147                     listItem.descriptor.setPluginNameAndPath(dir.absolutePath() + QDir::separator() + dir[i]);
       
   148 
       
   149                     // For each found plugin, check if there is already a list item for it.
       
   150                     // If not, then add one.
       
   151                     QStringList contextKeys = inputContextPlugin->keys();
       
   152                     foreach(const QString &key, contextKeys) {
       
   153                         listItem.setValues(inputContextPlugin, key);
       
   154 
       
   155                         int index = methodList->indexOf(listItem);
       
   156                         if (index >= 0) {
       
   157                             // The method is already in the list, the situation hasn't changed.
       
   158                             // just tag it not to be removed.
       
   159                             (*methodList)[index].toBeRemoved = false;
       
   160                         } else {
       
   161                             listItem.languages = inputContextPlugin->languages(key);
       
   162                             methodList->append(listItem);
       
   163                         }
       
   164                     }
       
   165                 }
       
   166             }
       
   167         }
       
   168     }
       
   169 }
       
   170 
       
   171 bool HbInputModeCachePrivate::readInputMethodDataFromSharedMemory()
       
   172 {
       
   173     // Check if the shared list has been modified
       
   174     if (!mMethodListModTime->isAttached()) {
       
   175         // Shared memory is not attached
       
   176         // Revert to in-process handling
       
   177         return false;
       
   178     }
       
   179     // No locking, since in case the value is corrupt we just need to read the list again
       
   180     // on the next run
       
   181     uint *newModTime = static_cast<uint *>(mMethodListModTime->data());
       
   182     if (*newModTime == mMethodListLastUpdate) {
       
   183         // The internal list is still in sync with the one in shared memory
       
   184         return true;
       
   185     }
       
   186     // Modifications done since last update, try to attach the method list
       
   187     // Revert to in-process handling if not successful
       
   188     if (!mSharedMethodList->attach()) {
       
   189         return false;
       
   190     }
       
   191     // Attached successfully, update the modification time
       
   192     mMethodListLastUpdate = *newModTime;
       
   193 
       
   194     // To start updating the list, first mark all methods for removal
       
   195     for (int k = 0; k < mMethods.count(); k++) {
       
   196         mMethods[k].toBeRemoved = true;
       
   197     }
       
   198 
       
   199     // Get a copy of the list from shared memory
       
   200     mSharedMethodList->lock();
       
   201     QByteArray array(static_cast<const char *>(mSharedMethodList->data())+sizeof(int), *static_cast<int *>(mSharedMethodList->data()));
       
   202     // array now has a copy of the data, so we can unlock and detach
       
   203     mSharedMethodList->unlock();
       
   204     mSharedMethodList->detach();
       
   205 
       
   206     // Next read the entries from the array to a temporary list
       
   207     QDataStream in(&array, QIODevice::ReadOnly);
       
   208     QList<HbInputMethodListItem> newMethodList;
       
   209     in >> newMethodList;
       
   210 
       
   211     // Go through the temporary list and append new methods to internal list
       
   212     // Duplicates are marked as not to be removed, the rest will be removed by pruneRemovedMethods
       
   213     foreach (const HbInputMethodListItem& item, newMethodList) {
       
   214         int index = mMethods.indexOf(item);
       
   215         if (index >= 0) {
       
   216             mMethods[index].toBeRemoved = false;
       
   217         } else {
       
   218             mMethods.append(item);
       
   219         }
       
   220     }
       
   221     pruneRemovedMethods();
       
   222     return true;
       
   223 }
       
   224 
       
   225 void HbInputModeCachePrivate::pruneRemovedMethods()
       
   226 {
       
   227     // Go through the cache list and find out if some of the previous items need to be
       
   228     // removed after the refresh.
       
   229     for (int i = 0; i < mMethods.count(); i++) {
       
   230         if (mMethods.at(i).toBeRemoved) {
       
   231             if (mMethods.at(i).cached && mMethods.at(i).cached->isActiveMethod()) {
       
   232                 // If the item to be removed happens to be the active one,
       
   233                 // try to deal with the situation.
       
   234                 mMethods.at(i).cached->forceUnfocus();
       
   235                 // The active custom method is being removed.
       
   236                 // Clear out related setting proxy values.
       
   237                 if (mMethods.at(i).descriptor.pluginNameAndPath() == HbInputSettingProxy::instance()->preferredInputMethod(Qt::Horizontal).pluginNameAndPath()) {
       
   238                     HbInputSettingProxy::instance()->setPreferredInputMethod(Qt::Horizontal, HbInputMethodDescriptor());
       
   239                 }
       
   240                 if (mMethods.at(i).descriptor.pluginNameAndPath() == HbInputSettingProxy::instance()->preferredInputMethod(Qt::Vertical).pluginNameAndPath()) {
       
   241                     HbInputSettingProxy::instance()->setPreferredInputMethod(Qt::Vertical, HbInputMethodDescriptor());
       
   242                 }
       
   243 
       
   244                 // Replace it with null input context.
       
   245                 HbInputMethod *master = HbInputMethodNull::Instance();
       
   246                 master->d_ptr->mIsActive = true;
       
   247                 QInputContext *proxy = master->d_ptr->proxy();
       
   248                 if (proxy != qApp->inputContext()) {
       
   249                     qApp->setInputContext(proxy);
       
   250                 }
       
   251             }
       
   252             delete mMethods[i].cached;
       
   253             mMethods.removeAt(i);
       
   254             i--;
       
   255         }
       
   256     }
       
   257 }
       
   258 
       
   259 QInputContextPlugin *HbInputModeCachePrivate::pluginInstance(const QString &pluginFileName)
    89 {
   260 {
    90     if (QLibrary::isLibrary(pluginFileName)) {
   261     if (QLibrary::isLibrary(pluginFileName)) {
    91         QPluginLoader loader(pluginFileName);
   262         QPluginLoader loader(pluginFileName);
    92         QObject *plugin = loader.instance();
   263         QObject *plugin = loader.instance();
    93         if (plugin) {
   264         if (plugin) {
   106         HbInputMethod *result = qobject_cast<HbInputMethod *>(instance);
   277         HbInputMethod *result = qobject_cast<HbInputMethod *>(instance);
   107         if (result) {
   278         if (result) {
   108             QStringList languages = plugin->languages(key);
   279             QStringList languages = plugin->languages(key);
   109             QList<HbInputModeProperties> modeList;
   280             QList<HbInputModeProperties> modeList;
   110             foreach(const QString &language, languages) {
   281             foreach(const QString &language, languages) {
   111                 modeList.append(propertiesFromString(language));
   282                 modeList.append(HbInputModeProperties::fromString(language));
   112             }
   283             }
   113             result->d_ptr->mInputModes = modeList;
   284             result->d_ptr->mInputModes = modeList;
   114         }
   285         }
   115         return result;
   286         return result;
   116     }
   287     }
   117 
   288 
   118     return 0;
   289     return 0;
   119 }
       
   120 
       
   121 void HbInputModeCachePrivate::refresh(const QString &directory)
       
   122 {
       
   123     Q_UNUSED(directory);
       
   124     // optimize later so that if the directory is given, only changes concerning
       
   125     // it are taken into account.
       
   126 
       
   127     // First go through all the previously found entries and
       
   128     // tag them not refreshed.
       
   129     for (int k = 0; k < mMethods.count(); k++) {
       
   130         mMethods[k].toBeRemoved = true;
       
   131     }
       
   132 
       
   133     // Query plugin paths and scan the folders.
       
   134     QStringList folders = HbInputSettingProxy::instance()->inputMethodPluginPaths();
       
   135     foreach(const QString &folder, folders) {
       
   136         QDir dir(folder);
       
   137         for (unsigned int i = 0; i < dir.count(); i++) {
       
   138             QString path = QString(dir.absolutePath());
       
   139             if (path.right(1) != "\\" && path.right(1) != "/") {
       
   140                 path += QDir::separator();
       
   141             }
       
   142             path += dir[i];
       
   143             QInputContextPlugin *inputContextPlugin = pluginInstance(path);
       
   144             if (inputContextPlugin) {
       
   145                 HbInputMethodListItem listItem;
       
   146                 listItem.descriptor.setPluginNameAndPath(dir.absolutePath() + QDir::separator() + dir[i]);
       
   147 
       
   148                 // For each found plugin, check if there is already a list item for it.
       
   149                 // If not, then add one.
       
   150                 QStringList contextKeys = inputContextPlugin->keys();
       
   151                 foreach(const QString &key, contextKeys) {
       
   152                     listItem.descriptor.setKey(key);
       
   153                     listItem.descriptor.setDisplayName(inputContextPlugin->displayName(key));
       
   154 
       
   155                     HbInputContextPlugin *extension = qobject_cast<HbInputContextPlugin *>(inputContextPlugin);
       
   156                     if (extension) {
       
   157                         listItem.descriptor.setDisplayNames(extension->displayNames(key));
       
   158                         listItem.descriptor.setIcon(extension->icon(key));
       
   159                         listItem.descriptor.setIcons(extension->icons(key));
       
   160                     }
       
   161 
       
   162                     int index = mMethods.indexOf(listItem);
       
   163                     if (index >= 0) {
       
   164                         // The method is already in the list, the situation hasn't changed.
       
   165                         // just tag it not to be removed.
       
   166                         mMethods[index].toBeRemoved = false;
       
   167                     } else {
       
   168                         listItem.languages = inputContextPlugin->languages(key);
       
   169                         mMethods.append(listItem);
       
   170                     }
       
   171                 }
       
   172             }
       
   173         }
       
   174     }
       
   175 
       
   176     // Go through the cache list and find out if some of the previous items need to be
       
   177     // removed after the refresh.
       
   178     for (int i = 0; i < mMethods.count(); i++) {
       
   179         if (mMethods[i].toBeRemoved) {
       
   180             if (mMethods[i].cached && mMethods[i].cached->isActiveMethod()) {
       
   181                 // If the item to be removed happens to be the active one,
       
   182                 // try to deal with the situation.
       
   183                 mMethods[i].cached->forceUnfocus();
       
   184                 // The active custom method is being removed.
       
   185                 // Clear out related setting proxy values.
       
   186                 if (mMethods[i].descriptor.pluginNameAndPath() == HbInputSettingProxy::instance()->preferredInputMethod(Qt::Horizontal).pluginNameAndPath()) {
       
   187                     HbInputSettingProxy::instance()->setPreferredInputMethod(Qt::Horizontal, HbInputMethodDescriptor());
       
   188                 }
       
   189                 if (mMethods[i].descriptor.pluginNameAndPath() == HbInputSettingProxy::instance()->preferredInputMethod(Qt::Vertical).pluginNameAndPath()) {
       
   190                     HbInputSettingProxy::instance()->setPreferredInputMethod(Qt::Vertical, HbInputMethodDescriptor());
       
   191                 }
       
   192 
       
   193                 // Replace it with null input context.
       
   194                 HbInputMethod *master = HbInputMethodNull::Instance();
       
   195                 master->d_ptr->mIsActive = true;
       
   196                 QInputContext *proxy = master->d_ptr->proxy();
       
   197                 if (proxy != qApp->inputContext()) {
       
   198                     qApp->setInputContext(proxy);
       
   199                 }
       
   200             }
       
   201             delete mMethods[i].cached;
       
   202             mMethods.removeAt(i);
       
   203             i--;
       
   204         }
       
   205     }
       
   206 }
       
   207 
       
   208 HbInputModeProperties HbInputModeCachePrivate::propertiesFromString(const QString &entry) const
       
   209 {
       
   210     HbInputModeProperties result;
       
   211 
       
   212     QStringList parts = entry.split(' ');
       
   213     if (parts.count() == 4) {
       
   214         // See HbInputModeProperties::toString() for details,
       
   215         QString languageStr = parts[0] + QString(" ") + parts[1];
       
   216         HbInputLanguage language;
       
   217         language.fromString(languageStr);
       
   218         result.setLanguage(language);
       
   219         result.setInputMode((HbInputModeType)parts[2].toLong());
       
   220         result.setKeyboard((HbKeyboardType)parts[3].toLong());
       
   221     }
       
   222 
       
   223     return result;
       
   224 }
       
   225 
       
   226 HbInputModeProperties HbInputModeCachePrivate::propertiesFromState(const HbInputState &state) const
       
   227 {
       
   228     HbInputModeProperties result;
       
   229 
       
   230     result.setLanguage(state.language());
       
   231     result.setKeyboard(state.keyboard());
       
   232     result.setInputMode(state.inputMode());
       
   233 
       
   234     return HbInputModeProperties(result);
       
   235 }
   290 }
   236 
   291 
   237 HbInputMethod *HbInputModeCachePrivate::cachedMethod(HbInputMethodListItem &item)
   292 HbInputMethod *HbInputModeCachePrivate::cachedMethod(HbInputMethodListItem &item)
   238 {
   293 {
   239     if (!item.cached) {
   294     if (!item.cached) {
   241     }
   296     }
   242 
   297 
   243     return item.cached;
   298     return item.cached;
   244 }
   299 }
   245 
   300 
   246 void HbInputModeCachePrivate::updateMonitoredPaths()
       
   247 {
       
   248     QStringList watchedDirs = mWatcher->directories();
       
   249     if (!watchedDirs.isEmpty()) {
       
   250         mWatcher->removePaths(watchedDirs);
       
   251     }
       
   252 
       
   253     QStringList paths = HbInputSettingProxy::instance()->inputMethodPluginPaths();
       
   254     foreach(const QString &path, paths) {
       
   255         QDir dir(path);
       
   256         if (!dir.exists() && path.left(1) == "f") {
       
   257             mWatcher->addPath(QString("f:") + QDir::separator());
       
   258         } else {
       
   259             mWatcher->addPath(path);
       
   260         }
       
   261     }
       
   262 }
       
   263 
       
   264 bool HbInputModeCachePrivate::isMappedLanguage(const HbInputLanguage &language) const
   301 bool HbInputModeCachePrivate::isMappedLanguage(const HbInputLanguage &language) const
   265 {
   302 {
   266     if (language.defined()) {
   303     return (HbKeymapFactory::instance()->keymap(language) != 0);
   267         QList<HbInputLanguage> languages = HbKeymapFactory::instance()->availableLanguages();
       
   268         foreach(const HbInputLanguage &mappedLanguage, languages) {
       
   269             if (mappedLanguage == language) {
       
   270                 return true;
       
   271             }
       
   272         }
       
   273     }
       
   274 
       
   275     return false;
       
   276 }
   304 }
   277 
   305 
   278 /// @endcond
   306 /// @endcond
   279 
   307 
   280 /*!
   308 /*!
   293 */
   321 */
   294 HbInputModeCache::HbInputModeCache() : d_ptr(new HbInputModeCachePrivate())
   322 HbInputModeCache::HbInputModeCache() : d_ptr(new HbInputModeCachePrivate())
   295 {
   323 {
   296     Q_D(HbInputModeCache);
   324     Q_D(HbInputModeCache);
   297 
   325 
   298     // Start to monitor file system for changes.
       
   299     d->updateMonitoredPaths();
       
   300     connect(d->mWatcher, SIGNAL(directoryChanged(const QString &)), this, SLOT(directoryChanged(const QString &)));
       
   301 
       
   302     d->refresh();
   326     d->refresh();
   303 }
   327 }
   304 
   328 
   305 /*!
   329 /*!
   306 \internal
   330 \internal
   307 Destruct the object.
   331 Destruct the object.
   308 */
   332 */
   309 HbInputModeCache::~HbInputModeCache()
   333 HbInputModeCache::~HbInputModeCache()
   310 {
   334 {
   311     delete d_ptr;
   335     delete d_ptr;
   312 }
       
   313 
       
   314 /*!
       
   315 \internal
       
   316 This slot is called whenever a change in input method plugin file system is detected and
       
   317 the list needs to be refreshed.
       
   318 */
       
   319 void HbInputModeCache::directoryChanged(const QString &directory)
       
   320 {
       
   321     Q_D(HbInputModeCache);
       
   322 
       
   323     d->updateMonitoredPaths();
       
   324 
       
   325     if (!d->mShuttingDown) {
       
   326         d->refresh(directory);
       
   327     }
       
   328 }
   336 }
   329 
   337 
   330 /*!
   338 /*!
   331 \internal
   339 \internal
   332 Shuts down the object safely. This is needed mainly for singleton object. There has been a lot
   340 Shuts down the object safely. This is needed mainly for singleton object. There has been a lot
   342     foreach(HbInputMethodListItem method, d->mMethods) {
   350     foreach(HbInputMethodListItem method, d->mMethods) {
   343         delete method.cached;
   351         delete method.cached;
   344         method.cached = 0;
   352         method.cached = 0;
   345     }
   353     }
   346     d->mMethods.clear();
   354     d->mMethods.clear();
   347     delete d->mWatcher;
       
   348     d->mWatcher = 0;
       
   349 }
   355 }
   350 
   356 
   351 /*!
   357 /*!
   352 \internal
   358 \internal
   353 Loads given input method and caches it.
   359 Loads given input method and caches it.
   354 */
   360 */
   355 HbInputMethod *HbInputModeCache::loadInputMethod(const HbInputMethodDescriptor &inputMethod)
   361 HbInputMethod *HbInputModeCache::loadInputMethod(const HbInputMethodDescriptor &inputMethod)
   356 {
   362 {
   357     Q_D(HbInputModeCache);
   363     Q_D(HbInputModeCache);
       
   364     d->refresh();
   358 
   365 
   359     for (int i = 0; i < d->mMethods.count(); i++) {
   366     for (int i = 0; i < d->mMethods.count(); i++) {
   360         if (d->mMethods[i].descriptor.pluginNameAndPath() == inputMethod.pluginNameAndPath() &&
   367         if (d->mMethods.at(i).descriptor.pluginNameAndPath() == inputMethod.pluginNameAndPath() &&
   361             d->mMethods[i].descriptor.key() == inputMethod.key()) {
   368             d->mMethods.at(i).descriptor.key() == inputMethod.key()) {
   362             if (!d->mMethods[i].cached) {
   369             if (!d->mMethods.at(i).cached) {
   363                 d->mMethods[i].cached = d->methodInstance(inputMethod.pluginNameAndPath(), inputMethod.key());
   370                 d->mMethods[i].cached = d->methodInstance(inputMethod.pluginNameAndPath(), inputMethod.key());
   364             }
   371             }
   365 
   372 
   366             return d->mMethods[i].cached;
   373             return d->mMethods[i].cached;
   367         }
   374         }
   375 Lists all custom input methods.
   382 Lists all custom input methods.
   376 */
   383 */
   377 QList<HbInputMethodDescriptor> HbInputModeCache::listCustomInputMethods()
   384 QList<HbInputMethodDescriptor> HbInputModeCache::listCustomInputMethods()
   378 {
   385 {
   379     Q_D(HbInputModeCache);
   386     Q_D(HbInputModeCache);
       
   387     d->refresh();
   380 
   388 
   381     QList<HbInputMethodDescriptor> result;
   389     QList<HbInputMethodDescriptor> result;
   382 
   390 
   383     foreach(const HbInputMethodListItem &item, d->mMethods) {
   391     foreach(const HbInputMethodListItem &item, d->mMethods) {
   384         foreach(const QString &language, item.languages) {
   392         foreach(const QString &language, item.languages) {
   385             HbInputModeProperties properties = d->propertiesFromString(language);
   393             HbInputModeProperties properties = HbInputModeProperties::fromString(language);
   386             if (properties.inputMode() == HbInputModeCustom) {
   394             if (properties.inputMode() == HbInputModeCustom) {
   387                 result.append(item.descriptor);
   395                 result.append(item.descriptor);
   388                 break;
   396                 break;
   389             }
   397             }
   390         }
   398         }
   398 Lists custom input methods for given parameters.
   406 Lists custom input methods for given parameters.
   399 */
   407 */
   400 QList<HbInputMethodDescriptor> HbInputModeCache::listCustomInputMethods(Qt::Orientation orientation, const HbInputLanguage &language)
   408 QList<HbInputMethodDescriptor> HbInputModeCache::listCustomInputMethods(Qt::Orientation orientation, const HbInputLanguage &language)
   401 {
   409 {
   402     Q_D(HbInputModeCache);
   410     Q_D(HbInputModeCache);
       
   411     d->refresh();
   403 
   412 
   404     QList<HbInputMethodDescriptor> result;
   413     QList<HbInputMethodDescriptor> result;
   405 
   414 
   406     foreach (const HbInputMethodListItem &item, d->mMethods) {
   415     for (int i = 0; i < d->mMethods.count(); i++) {
   407         foreach (const QString &lang, item.languages) {
   416         foreach (const QString &lang, d->mMethods.at(i).languages) {
   408             HbInputModeProperties properties = d->propertiesFromString(lang);
   417             HbInputModeProperties properties = HbInputModeProperties::fromString(lang);
   409             
   418             
   410             // Find custom methods that supports given language or any language and
   419             // Find custom methods that supports given language or any language and
   411             // supports given orientation
   420             // supports given orientation
   412             if (properties.inputMode() == HbInputModeCustom &&
   421             if (properties.inputMode() == HbInputModeCustom &&
   413                 (properties.language() == language || properties.language() == HbInputLanguage()) &&
   422                 (properties.language() == language || properties.language() == HbInputLanguage()) &&
   414                 ((orientation == Qt::Vertical && properties.keyboard() == HbKeyboardTouchPortrait) ||
   423                 ((orientation == Qt::Vertical && properties.keyboard() == HbKeyboardTouchPortrait) ||
   415                 (orientation == Qt::Horizontal && properties.keyboard() == HbKeyboardTouchLandscape))) {
   424                 (orientation == Qt::Horizontal && properties.keyboard() == HbKeyboardTouchLandscape))) {
   416                 result.append(item.descriptor);
   425 
       
   426                 result.append(d->mMethods[i].descriptor);
   417                 break;
   427                 break;
   418             }
   428             }
   419         }
   429         }
   420     }
   430     }
   421 
   431 
   427 Returns default input method for given orientation.
   437 Returns default input method for given orientation.
   428 */
   438 */
   429 HbInputMethodDescriptor HbInputModeCache::defaultInputMethod(Qt::Orientation orientation)
   439 HbInputMethodDescriptor HbInputModeCache::defaultInputMethod(Qt::Orientation orientation)
   430 {
   440 {
   431     Q_D(HbInputModeCache);
   441     Q_D(HbInputModeCache);
   432 
   442     d->refresh();
   433     HbInputMethodDescriptor result;
   443 
   434     foreach (const HbInputMethodListItem &item, d->mMethods) {
   444     HbInputLanguage currentLanguage = HbInputSettingProxy::instance()->globalInputLanguage();
   435         foreach (const QString &language, item.languages) {
   445     bool mapped = d->isMappedLanguage(currentLanguage);
   436             HbInputModeProperties properties = d->propertiesFromString(language);
   446 
       
   447     for (int i = 0; i < d->mMethods.count(); i++) {
       
   448         foreach (const QString &language, d->mMethods[i].languages) {
       
   449             HbInputModeProperties properties = HbInputModeProperties::fromString(language);
       
   450 
       
   451             if (properties.language().undefined()) {
       
   452                 // The input method reports language range but current language is not mapped
       
   453                 // language. Skip this one. 
       
   454                 if (!mapped) {
       
   455                     continue; 
       
   456                 }
       
   457             } else {
       
   458                 // The input method reports support for specific language but it is not an exact
       
   459                 // match to current language. Skip this one 
       
   460                 if (properties.language() != currentLanguage) {
       
   461                     // It is not direct match either.
       
   462                     continue;
       
   463                 }
       
   464             }
   437 
   465 
   438             // Find default method that supports given orientation
   466             // Find default method that supports given orientation
   439             if (properties.inputMode() == HbInputModeDefault &&
   467             if (properties.inputMode() == HbInputModeDefault &&
   440                 ((orientation == Qt::Vertical && properties.keyboard() == HbKeyboardTouchPortrait) ||
   468                 ((orientation == Qt::Vertical && properties.keyboard() == HbKeyboardTouchPortrait) ||
   441                 (orientation == Qt::Horizontal && properties.keyboard() == HbKeyboardTouchLandscape))) {
   469                 (orientation == Qt::Horizontal && properties.keyboard() == HbKeyboardTouchLandscape))) {
   442                 result = item.descriptor;
   470                 return d->mMethods[i].descriptor;
   443                 break;
   471             }
   444             }
   472         }
   445         }
   473     }
   446     }
   474 
   447 
   475     return HbInputMethodDescriptor();
   448     return result;
       
   449 }
   476 }
   450 
   477 
   451 /*!
   478 /*!
   452 \internal
   479 \internal
   453 Find correct handler for given input state.
   480 Find correct handler for given input state.
   454 */
   481 */
   455 HbInputMethod *HbInputModeCache::findStateHandler(const HbInputState &state)
   482 HbInputMethod *HbInputModeCache::findStateHandler(const HbInputState &state)
   456 {
   483 {
   457     Q_D(HbInputModeCache);
   484     Q_D(HbInputModeCache);
   458 
   485     d->refresh();
   459     HbInputModeProperties stateProperties = d->propertiesFromState(state);
   486 
       
   487     HbInputModeProperties stateProperties(state);
   460     int languageRangeIndex = -1;
   488     int languageRangeIndex = -1;
   461 
   489 
   462     // First check if there is a method that matches excatly (ie. also specifies
   490     // First check if there is a method that matches excatly (ie. also specifies
   463     // the language).
   491     // the language).
   464     for (int i = 0; i < d->mMethods.count(); i++) {
   492     for (int i = 0; i < d->mMethods.count(); i++) {
   465         foreach(const QString &language, d->mMethods[i].languages) {
   493         foreach(const QString &language, d->mMethods[i].languages) {
   466             HbInputModeProperties properties = d->propertiesFromString(language);
   494             HbInputModeProperties properties = HbInputModeProperties::fromString(language);
   467             if (properties.language().undefined() &&
   495             if (properties.language().undefined() &&
   468                 properties.keyboard() == stateProperties.keyboard() &&
   496                 properties.keyboard() == stateProperties.keyboard() &&
   469                 properties.inputMode() == stateProperties.inputMode()) {
   497                 properties.inputMode() == stateProperties.inputMode()) {
   470                 // Remember the index, we'll need this in the next phase if no exact
   498                 // Remember the index, we'll need this in the next phase if no exact
   471                 // match is found.
   499                 // match is found.
   505 \internal
   533 \internal
   506 Returns the active input method.
   534 Returns the active input method.
   507 
   535 
   508 \sa HbInputMethod
   536 \sa HbInputMethod
   509 */
   537 */
   510 HbInputMethod *HbInputModeCache::activeMethod() const
   538 HbInputMethod *HbInputModeCache::activeMethod()
   511 {
   539 {
   512     Q_D(const HbInputModeCache);
   540     Q_D(HbInputModeCache);
       
   541     d->refresh();
   513 
   542 
   514     foreach(const HbInputMethodListItem &item, d->mMethods) {
   543     foreach(const HbInputMethodListItem &item, d->mMethods) {
   515         if (item.cached && item.cached->isActiveMethod()) {
   544         if (item.cached && item.cached->isActiveMethod()) {
   516             return item.cached;
   545             return item.cached;
   517         }
   546         }
   522 
   551 
   523 /*!
   552 /*!
   524 \internal
   553 \internal
   525 Lists available input languages.
   554 Lists available input languages.
   526 */
   555 */
   527 QList<HbInputLanguage> HbInputModeCache::listInputLanguages() const
   556 QList<HbInputLanguage> HbInputModeCache::listInputLanguages()
   528 {
   557 {
   529     Q_D(const HbInputModeCache);
   558     Q_D(HbInputModeCache);
       
   559     d->refresh();
   530 
   560 
   531     QList<HbInputLanguage> result;
   561     QList<HbInputLanguage> result;
   532 
   562 
   533     foreach(const HbInputMethodListItem &item, d->mMethods) {
   563     foreach(const HbInputMethodListItem &item, d->mMethods) {
   534         foreach(const QString &language, item.languages) {
   564         foreach(const QString &language, item.languages) {
   535             HbInputModeProperties mode = d->propertiesFromString(language);
   565             HbInputModeProperties mode = HbInputModeProperties::fromString(language);
   536             if (mode.inputMode() != HbInputModeCustom) {
   566             if (mode.inputMode() != HbInputModeCustom) {
   537                 if (mode.language().undefined()) {
   567                 if (mode.language().undefined()) {
   538                     // This is language range. Let's add everything
   568                     // This is language range. Let's add everything
   539                     // we have key mappings for.
   569                     // we have key mappings for.
   540                     QList<HbInputLanguage> languages = HbKeymapFactory::instance()->availableLanguages();
   570                     QList<HbInputLanguage> languages = HbKeymapFactory::instance()->availableLanguages();
   557 
   587 
   558 /*!
   588 /*!
   559 \internal
   589 \internal
   560 Returns true if given input method is able to handle given input state.
   590 Returns true if given input method is able to handle given input state.
   561 */
   591 */
   562 bool HbInputModeCache::acceptsState(const HbInputMethod *inputMethod, const HbInputState &state) const
   592 bool HbInputModeCache::acceptsState(const HbInputMethod *inputMethod, const HbInputState &state)
   563 {
   593 {
   564     Q_D(const HbInputModeCache);
   594     Q_D(HbInputModeCache);
       
   595     d->refresh();
   565 
   596 
   566     foreach(const HbInputMethodListItem &item, d->mMethods) {
   597     foreach(const HbInputMethodListItem &item, d->mMethods) {
   567         if (item.cached == inputMethod) {
   598         if (item.cached == inputMethod) {
   568             foreach(const QString &language, item.languages) {
   599             foreach(const QString &language, item.languages) {
   569                 HbInputModeProperties mode = d->propertiesFromString(language);
   600                 HbInputModeProperties mode = HbInputModeProperties::fromString(language);
   570                 // Check if keyboard type matches.
   601                 // Check if keyboard type matches.
   571                 if (mode.keyboard() == state.keyboard()) {
   602                 if (mode.keyboard() == state.keyboard()) {
   572                     // Check if input mode matches or it is a custom input method but
   603                     // Check if input mode matches or it is a custom input method but
   573                     // state's mode is not numeric.
   604                     // state's mode is not numeric.
   574                     if (mode.inputMode() == state.inputMode() ||
   605                     if (mode.inputMode() == state.inputMode() ||
   592 /*!
   623 /*!
   593 \internal
   624 \internal
   594 Returns input method descriptor for given input method. Returns empty descriptor if the framework
   625 Returns input method descriptor for given input method. Returns empty descriptor if the framework
   595 doesn't recognize given input method.
   626 doesn't recognize given input method.
   596 */
   627 */
   597 HbInputMethodDescriptor HbInputModeCache::descriptor(const HbInputMethod *inputMethod) const
   628 HbInputMethodDescriptor HbInputModeCache::descriptor(const HbInputMethod *inputMethod)
   598 {
   629 {
   599     Q_D(const HbInputModeCache);
   630     Q_D(HbInputModeCache);
       
   631     d->refresh();
   600 
   632 
   601     foreach(const HbInputMethodListItem &item, d->mMethods) {
   633     foreach(const HbInputMethodListItem &item, d->mMethods) {
   602         if (item.cached == inputMethod) {
   634         if (item.cached == inputMethod) {
   603             return item.descriptor;
   635             return item.descriptor;
   604         }
   636         }