20 ** |
20 ** |
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" |
|
26 |
25 #include <QInputContextPlugin> |
27 #include <QInputContextPlugin> |
26 #include <QLocale> |
28 #include <QLocale> |
27 #include <QFileSystemWatcher> |
29 #include <QFileSystemWatcher> |
28 #include <QLibrary> |
30 #include <QLibrary> |
29 #include <QPluginLoader> |
31 #include <QPluginLoader> |
30 #include <QDir> |
32 #include <QDir> |
31 |
33 |
32 #include "hbinputmodecache_p.h" |
|
33 #include "hbinpututils.h" |
34 #include "hbinpututils.h" |
34 #include "hbinputmethod.h" |
35 #include "hbinputmethod.h" |
35 #include "hbinputsettingproxy.h" |
36 #include "hbinputsettingproxy.h" |
36 #include "hbinputmodeproperties.h" |
37 #include "hbinputmodeproperties.h" |
37 #include "hbinputkeymapfactory.h" |
38 #include "hbinputkeymapfactory.h" |
67 { |
68 { |
68 public: |
69 public: |
69 HbInputModeCachePrivate() : mWatcher(new QFileSystemWatcher()), mShuttingDown(false) {} |
70 HbInputModeCachePrivate() : mWatcher(new QFileSystemWatcher()), mShuttingDown(false) {} |
70 ~HbInputModeCachePrivate() {} |
71 ~HbInputModeCachePrivate() {} |
71 void refresh(const QString &directory = QString()); |
72 void refresh(const QString &directory = QString()); |
72 QInputContextPlugin *pluginInstance(const QString& pluginFileName) const; |
73 QInputContextPlugin *pluginInstance(const QString &pluginFileName) const; |
73 HbInputMethod *methodInstance(const QString &pluginFileName, const QString &key) const; |
74 HbInputMethod *methodInstance(const QString &pluginFileName, const QString &key) const; |
74 HbInputModeProperties propertiesFromString(const QString &entry) const; |
75 HbInputModeProperties propertiesFromString(const QString &entry) const; |
75 HbInputModeProperties propertiesFromState(const HbInputState &state) const; |
76 HbInputModeProperties propertiesFromState(const HbInputState &state) const; |
76 HbInputMethod *cachedMethod(HbInputMethodListItem &item); |
77 HbInputMethod *cachedMethod(HbInputMethodListItem &item); |
77 void updateMonitoredPaths(); |
78 void updateMonitoredPaths(); |
81 QFileSystemWatcher *mWatcher; |
82 QFileSystemWatcher *mWatcher; |
82 QList<HbInputMethodListItem> mMethods; |
83 QList<HbInputMethodListItem> mMethods; |
83 bool mShuttingDown; |
84 bool mShuttingDown; |
84 }; |
85 }; |
85 |
86 |
86 QInputContextPlugin* HbInputModeCachePrivate::pluginInstance(const QString& pluginFileName) const |
87 QInputContextPlugin *HbInputModeCachePrivate::pluginInstance(const QString &pluginFileName) const |
87 { |
88 { |
88 if (QLibrary::isLibrary(pluginFileName)) { |
89 if (QLibrary::isLibrary(pluginFileName)) { |
89 QPluginLoader loader(pluginFileName); |
90 QPluginLoader loader(pluginFileName); |
90 QObject* plugin = loader.instance(); |
91 QObject *plugin = loader.instance(); |
91 if (plugin) { |
92 if (plugin) { |
92 return qobject_cast<QInputContextPlugin*>(plugin); |
93 return qobject_cast<QInputContextPlugin *>(plugin); |
93 } |
94 } |
94 } |
95 } |
95 |
96 |
96 return 0; |
97 return 0; |
97 } |
98 } |
99 HbInputMethod *HbInputModeCachePrivate::methodInstance(const QString &pluginFileName, const QString &key) const |
100 HbInputMethod *HbInputModeCachePrivate::methodInstance(const QString &pluginFileName, const QString &key) const |
100 { |
101 { |
101 QInputContextPlugin *plugin = pluginInstance(pluginFileName); |
102 QInputContextPlugin *plugin = pluginInstance(pluginFileName); |
102 if (plugin) { |
103 if (plugin) { |
103 QInputContext *instance = plugin->create(key); |
104 QInputContext *instance = plugin->create(key); |
104 HbInputMethod *result = qobject_cast<HbInputMethod*>(instance); |
105 HbInputMethod *result = qobject_cast<HbInputMethod *>(instance); |
105 if (result) { |
106 if (result) { |
106 QStringList languages = plugin->languages(key); |
107 QStringList languages = plugin->languages(key); |
107 QList<HbInputModeProperties> modeList; |
108 QList<HbInputModeProperties> modeList; |
108 foreach (QString language, languages) { |
109 foreach(const QString &language, languages) { |
109 modeList.append(propertiesFromString(language)); |
110 modeList.append(propertiesFromString(language)); |
110 } |
111 } |
111 result->d_ptr->mInputModes = modeList; |
112 result->d_ptr->mInputModes = modeList; |
112 } |
113 } |
113 return result; |
114 return result; |
114 } |
115 } |
128 mMethods[k].toBeRemoved = true; |
129 mMethods[k].toBeRemoved = true; |
129 } |
130 } |
130 |
131 |
131 // Query plugin paths and scan the folders. |
132 // Query plugin paths and scan the folders. |
132 QStringList folders = HbInputSettingProxy::instance()->inputMethodPluginPaths(); |
133 QStringList folders = HbInputSettingProxy::instance()->inputMethodPluginPaths(); |
133 foreach (QString folder, folders) { |
134 foreach(const QString &folder, folders) { |
134 QDir dir(folder); |
135 QDir dir(folder); |
135 for (unsigned int i = 0; i < dir.count(); i++) { |
136 for (unsigned int i = 0; i < dir.count(); i++) { |
136 QString path = QString(dir.absolutePath()); |
137 QString path = QString(dir.absolutePath()); |
137 if (path.right(1) != "\\" && path.right(1) != "/") { |
138 if (path.right(1) != "\\" && path.right(1) != "/") { |
138 path += QDir::separator(); |
139 path += QDir::separator(); |
139 } |
140 } |
140 path += dir[i]; |
141 path += dir[i]; |
141 QInputContextPlugin* inputContextPlugin = pluginInstance(path); |
142 QInputContextPlugin *inputContextPlugin = pluginInstance(path); |
142 if (inputContextPlugin) { |
143 if (inputContextPlugin) { |
143 HbInputMethodListItem listItem; |
144 HbInputMethodListItem listItem; |
144 listItem.descriptor.setPluginNameAndPath(dir.absolutePath() + QDir::separator() + dir[i]); |
145 listItem.descriptor.setPluginNameAndPath(dir.absolutePath() + QDir::separator() + dir[i]); |
145 |
146 |
146 // For each found plugin, check if there is already a list item for it. |
147 // For each found plugin, check if there is already a list item for it. |
147 // If not, then add one. |
148 // If not, then add one. |
148 QStringList contextKeys = inputContextPlugin->keys(); |
149 QStringList contextKeys = inputContextPlugin->keys(); |
149 foreach (QString key, contextKeys) { |
150 foreach(const QString &key, contextKeys) { |
150 listItem.descriptor.setKey(key); |
151 listItem.descriptor.setKey(key); |
151 listItem.descriptor.setDisplayName(inputContextPlugin->displayName(key)); |
152 listItem.descriptor.setDisplayName(inputContextPlugin->displayName(key)); |
152 |
153 |
153 int index = mMethods.indexOf(listItem); |
154 int index = mMethods.indexOf(listItem); |
154 if (index >= 0) { |
155 if (index >= 0) { |
182 } |
183 } |
183 |
184 |
184 // Replace it with null input context. |
185 // Replace it with null input context. |
185 HbInputMethod *master = HbInputMethodNull::Instance(); |
186 HbInputMethod *master = HbInputMethodNull::Instance(); |
186 master->d_ptr->mIsActive = true; |
187 master->d_ptr->mIsActive = true; |
187 QInputContext* proxy = master->d_ptr->proxy(); |
188 QInputContext *proxy = master->d_ptr->proxy(); |
188 if (proxy != qApp->inputContext()) |
189 if (proxy != qApp->inputContext()) { |
189 qApp->setInputContext(proxy); |
190 qApp->setInputContext(proxy); |
|
191 } |
190 } |
192 } |
191 delete mMethods[i].cached; |
193 delete mMethods[i].cached; |
192 mMethods.removeAt(i); |
194 mMethods.removeAt(i); |
193 i--; |
195 i--; |
194 } |
196 } |
197 |
199 |
198 HbInputModeProperties HbInputModeCachePrivate::propertiesFromString(const QString &entry) const |
200 HbInputModeProperties HbInputModeCachePrivate::propertiesFromString(const QString &entry) const |
199 { |
201 { |
200 HbInputModeProperties result; |
202 HbInputModeProperties result; |
201 |
203 |
202 QStringList parts = entry.split(" "); |
204 QStringList parts = entry.split(' '); |
203 if (parts.count() == 4) { |
205 if (parts.count() == 4) { |
204 // See HbInputModeProperties::toString() for details, |
206 // See HbInputModeProperties::toString() for details, |
205 QString languageStr = parts[0] + QString(" ") + parts[1]; |
207 QString languageStr = parts[0] + QString(" ") + parts[1]; |
206 HbInputLanguage language; |
208 HbInputLanguage language; |
207 language.fromString(languageStr); |
209 language.fromString(languageStr); |
239 if (!watchedDirs.isEmpty()) { |
241 if (!watchedDirs.isEmpty()) { |
240 mWatcher->removePaths(watchedDirs); |
242 mWatcher->removePaths(watchedDirs); |
241 } |
243 } |
242 |
244 |
243 QStringList paths = HbInputSettingProxy::instance()->inputMethodPluginPaths(); |
245 QStringList paths = HbInputSettingProxy::instance()->inputMethodPluginPaths(); |
244 foreach (QString path, paths) { |
246 foreach(const QString &path, paths) { |
245 QDir dir(path); |
247 QDir dir(path); |
246 if (!dir.exists() && path.left(1) == "f") { |
248 if (!dir.exists() && path.left(1) == "f") { |
247 mWatcher->addPath(QString("f:") + QDir::separator()); |
249 mWatcher->addPath(QString("f:") + QDir::separator()); |
248 } else { |
250 } else { |
249 mWatcher->addPath(path); |
251 mWatcher->addPath(path); |
253 |
255 |
254 bool HbInputModeCachePrivate::isMappedLanguage(const HbInputLanguage &language) const |
256 bool HbInputModeCachePrivate::isMappedLanguage(const HbInputLanguage &language) const |
255 { |
257 { |
256 if (language.defined()) { |
258 if (language.defined()) { |
257 QList<HbInputLanguage> languages = HbKeymapFactory::instance()->availableLanguages(); |
259 QList<HbInputLanguage> languages = HbKeymapFactory::instance()->availableLanguages(); |
258 foreach (const HbInputLanguage mappedLanguage, languages) { |
260 foreach(const HbInputLanguage &mappedLanguage, languages) { |
259 if (mappedLanguage == language) { |
261 if (mappedLanguage == language) { |
260 return true; |
262 return true; |
261 } |
263 } |
262 } |
264 } |
263 } |
265 } |
327 void HbInputModeCache::shutdown() |
329 void HbInputModeCache::shutdown() |
328 { |
330 { |
329 Q_D(HbInputModeCache); |
331 Q_D(HbInputModeCache); |
330 d->mShuttingDown = true; |
332 d->mShuttingDown = true; |
331 |
333 |
332 foreach (HbInputMethodListItem method, d->mMethods) { |
334 foreach(HbInputMethodListItem method, d->mMethods) { |
333 delete method.cached; |
335 delete method.cached; |
334 method.cached = 0; |
336 method.cached = 0; |
335 } |
337 } |
336 d->mMethods.clear(); |
338 d->mMethods.clear(); |
337 delete d->mWatcher; |
339 delete d->mWatcher; |
340 |
342 |
341 /*! |
343 /*! |
342 \internal |
344 \internal |
343 Loads given input method and caches it. |
345 Loads given input method and caches it. |
344 */ |
346 */ |
345 HbInputMethod* HbInputModeCache::loadInputMethod(const HbInputMethodDescriptor &inputMethod) |
347 HbInputMethod *HbInputModeCache::loadInputMethod(const HbInputMethodDescriptor &inputMethod) |
346 { |
348 { |
347 Q_D(HbInputModeCache); |
349 Q_D(HbInputModeCache); |
348 |
350 |
349 for (int i = 0; i < d->mMethods.count(); i++) { |
351 for (int i = 0; i < d->mMethods.count(); i++) { |
350 if (d->mMethods[i].descriptor.pluginNameAndPath() == inputMethod.pluginNameAndPath() && |
352 if (d->mMethods[i].descriptor.pluginNameAndPath() == inputMethod.pluginNameAndPath() && |
368 { |
370 { |
369 Q_D(HbInputModeCache); |
371 Q_D(HbInputModeCache); |
370 |
372 |
371 QList<HbInputMethodDescriptor> result; |
373 QList<HbInputMethodDescriptor> result; |
372 |
374 |
373 foreach (HbInputMethodListItem item, d->mMethods) { |
375 foreach(const HbInputMethodListItem &item, d->mMethods) { |
374 foreach (QString language, item.languages) { |
376 foreach(const QString &language, item.languages) { |
375 HbInputModeProperties properties = d->propertiesFromString(language); |
377 HbInputModeProperties properties = d->propertiesFromString(language); |
376 if (properties.inputMode() == HbInputModeCustom) { |
378 if (properties.inputMode() == HbInputModeCustom) { |
377 result.append(item.descriptor); |
379 result.append(item.descriptor); |
378 break; |
380 break; |
379 } |
381 } |
385 |
387 |
386 /*! |
388 /*! |
387 \internal |
389 \internal |
388 Find correct handler for given input state. |
390 Find correct handler for given input state. |
389 */ |
391 */ |
390 HbInputMethod* HbInputModeCache::findStateHandler(const HbInputState& state) |
392 HbInputMethod *HbInputModeCache::findStateHandler(const HbInputState &state) |
391 { |
393 { |
392 Q_D(HbInputModeCache); |
394 Q_D(HbInputModeCache); |
393 |
395 |
394 HbInputModeProperties stateProperties = d->propertiesFromState(state); |
396 HbInputModeProperties stateProperties = d->propertiesFromState(state); |
395 int languageRangeIndex = -1; |
397 int languageRangeIndex = -1; |
396 |
398 |
397 // First check if there is a method that matches excatly (ie. also specifies |
399 // First check if there is a method that matches excatly (ie. also specifies |
398 // the language). |
400 // the language). |
399 for (int i = 0; i < d->mMethods.count(); i++) { |
401 for (int i = 0; i < d->mMethods.count(); i++) { |
400 foreach (QString language, d->mMethods[i].languages) { |
402 foreach(const QString &language, d->mMethods[i].languages) { |
401 HbInputModeProperties properties = d->propertiesFromString(language); |
403 HbInputModeProperties properties = d->propertiesFromString(language); |
402 if (properties.language().undefined() && |
404 if (properties.language().undefined() && |
403 properties.keyboard() == stateProperties.keyboard() && |
405 properties.keyboard() == stateProperties.keyboard() && |
404 properties.inputMode() == stateProperties.inputMode()) { |
406 properties.inputMode() == stateProperties.inputMode()) { |
405 // Remember the index, we'll need this in the next phase if no exact |
407 // Remember the index, we'll need this in the next phase if no exact |
419 // range, meaning that the language is left unspecified in which case we'll |
421 // range, meaning that the language is left unspecified in which case we'll |
420 // use key mapping factory for matching. |
422 // use key mapping factory for matching. |
421 if (languageRangeIndex >= 0) { |
423 if (languageRangeIndex >= 0) { |
422 QList<HbInputLanguage> languages = HbKeymapFactory::instance()->availableLanguages(); |
424 QList<HbInputLanguage> languages = HbKeymapFactory::instance()->availableLanguages(); |
423 |
425 |
424 foreach(HbInputLanguage language, languages) { |
426 foreach(const HbInputLanguage &language, languages) { |
425 // exact match is returned If the country variant is specified in state language, |
427 // exact match is returned If the country variant is specified in state language, |
426 // otherwise a method that matches to only language range is returned. |
428 // otherwise a method that matches to only language range is returned. |
427 bool exactMatchFound = (stateProperties.language().variant() != QLocale::AnyCountry) ? |
429 bool exactMatchFound = (stateProperties.language().variant() != QLocale::AnyCountry) ? |
428 (language == stateProperties.language()) : |
430 (language == stateProperties.language()) : |
429 (language.language() == stateProperties.language().language()); |
431 (language.language() == stateProperties.language().language()); |
430 if (exactMatchFound) { |
432 if (exactMatchFound) { |
431 return d->cachedMethod(d->mMethods[languageRangeIndex]); |
433 return d->cachedMethod(d->mMethods[languageRangeIndex]); |
432 } |
434 } |
433 } |
435 } |
434 } |
436 } |
440 \internal |
442 \internal |
441 Returns the active input method. |
443 Returns the active input method. |
442 |
444 |
443 \sa HbInputMethod |
445 \sa HbInputMethod |
444 */ |
446 */ |
445 HbInputMethod* HbInputModeCache::activeMethod() const |
447 HbInputMethod *HbInputModeCache::activeMethod() const |
446 { |
448 { |
447 Q_D(const HbInputModeCache); |
449 Q_D(const HbInputModeCache); |
448 |
450 |
449 foreach (HbInputMethodListItem item, d->mMethods) { |
451 foreach(const HbInputMethodListItem &item, d->mMethods) { |
450 if (item.cached && item.cached->isActiveMethod()) { |
452 if (item.cached && item.cached->isActiveMethod()) { |
451 return item.cached; |
453 return item.cached; |
452 } |
454 } |
453 } |
455 } |
454 |
456 |
463 { |
465 { |
464 Q_D(const HbInputModeCache); |
466 Q_D(const HbInputModeCache); |
465 |
467 |
466 QList<HbInputLanguage> result; |
468 QList<HbInputLanguage> result; |
467 |
469 |
468 foreach (HbInputMethodListItem item, d->mMethods) { |
470 foreach(const HbInputMethodListItem &item, d->mMethods) { |
469 foreach (QString language, item.languages) { |
471 foreach(const QString &language, item.languages) { |
470 HbInputModeProperties mode = d->propertiesFromString(language); |
472 HbInputModeProperties mode = d->propertiesFromString(language); |
471 if (mode.inputMode() != HbInputModeCustom) { |
473 if (mode.inputMode() != HbInputModeCustom) { |
472 if (mode.language().undefined()) { |
474 if (mode.language().undefined()) { |
473 // This is language range. Let's add everything |
475 // This is language range. Let's add everything |
474 // we have key mappings for. |
476 // we have key mappings for. |
475 QList<HbInputLanguage> languages = HbKeymapFactory::instance()->availableLanguages(); |
477 QList<HbInputLanguage> languages = HbKeymapFactory::instance()->availableLanguages(); |
476 foreach (HbInputLanguage mappedLanguage, languages) { |
478 foreach(const HbInputLanguage &mappedLanguage, languages) { |
477 if (!result.contains(mappedLanguage)) { |
479 if (!result.contains(mappedLanguage)) { |
478 result.append(mappedLanguage); |
480 result.append(mappedLanguage); |
479 } |
481 } |
480 } |
482 } |
481 } else { |
483 } else { |
496 */ |
498 */ |
497 bool HbInputModeCache::acceptsState(const HbInputMethod *inputMethod, const HbInputState &state) const |
499 bool HbInputModeCache::acceptsState(const HbInputMethod *inputMethod, const HbInputState &state) const |
498 { |
500 { |
499 Q_D(const HbInputModeCache); |
501 Q_D(const HbInputModeCache); |
500 |
502 |
501 foreach (const HbInputMethodListItem item, d->mMethods) { |
503 foreach(const HbInputMethodListItem &item, d->mMethods) { |
502 if (item.cached == inputMethod) { |
504 if (item.cached == inputMethod) { |
503 foreach (const QString language, item.languages) { |
505 foreach(const QString &language, item.languages) { |
504 HbInputModeProperties mode = d->propertiesFromString(language); |
506 HbInputModeProperties mode = d->propertiesFromString(language); |
505 // Check if keyboard type matches. |
507 // Check if keyboard type matches. |
506 if (mode.keyboard() == state.keyboard()) { |
508 if (mode.keyboard() == state.keyboard()) { |
507 // Check if input mode matches or it is a custom input method but |
509 // Check if input mode matches or it is a custom input method but |
508 // state's mode is not numeric. |
510 // state's mode is not numeric. |
531 */ |
533 */ |
532 HbInputMethodDescriptor HbInputModeCache::descriptor(const HbInputMethod *inputMethod) const |
534 HbInputMethodDescriptor HbInputModeCache::descriptor(const HbInputMethod *inputMethod) const |
533 { |
535 { |
534 Q_D(const HbInputModeCache); |
536 Q_D(const HbInputModeCache); |
535 |
537 |
536 foreach (HbInputMethodListItem item, d->mMethods) { |
538 foreach(const HbInputMethodListItem &item, d->mMethods) { |
537 if (item.cached == inputMethod) { |
539 if (item.cached == inputMethod) { |
538 return item.descriptor; |
540 return item.descriptor; |
539 } |
541 } |
540 } |
542 } |
541 |
543 |