| 1 | /* | 
| 2 |  * Qt implementation of TCIME library | 
| 3 |  * This file is part of the Qt Virtual Keyboard module. | 
| 4 |  * Contact: http://www.qt.io/licensing/ | 
| 5 |  * | 
| 6 |  * Copyright (C) 2015  The Qt Company | 
| 7 |  * Copyright 2010 Google Inc. | 
| 8 |  * | 
| 9 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
| 10 |  * you may not use this file except in compliance with the License. | 
| 11 |  * You may obtain a copy of the License at | 
| 12 |  * | 
| 13 |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
| 14 |  * | 
| 15 |  * Unless required by applicable law or agreed to in writing, software | 
| 16 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
| 17 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
| 18 |  * See the License for the specific language governing permissions and | 
| 19 |  * limitations under the License. | 
| 20 |  */ | 
| 21 |  | 
| 22 | #include "cangjiedictionary.h" | 
| 23 | #include "cangjietable.h" | 
| 24 |  | 
| 25 | using namespace tcime; | 
| 26 |  | 
| 27 | bool CangjieDictionary::_simplified = false; | 
| 28 |  | 
| 29 | CangjieDictionary::CangjieDictionary() : | 
| 30 |     WordDictionary(), | 
| 31 |     _collator(QLocale(QLatin1String("zh_TW" ))) | 
| 32 | { | 
| 33 | } | 
| 34 |  | 
| 35 | bool CangjieDictionary::simplified() const | 
| 36 | { | 
| 37 |     return _simplified; | 
| 38 | } | 
| 39 |  | 
| 40 | void CangjieDictionary::setSimplified(bool simplified) | 
| 41 | { | 
| 42 |     _simplified = simplified; | 
| 43 | } | 
| 44 |  | 
| 45 | QStringList CangjieDictionary::getWords(const QString &input) const | 
| 46 | { | 
| 47 |     // Look up the index in the dictionary for the specified input. | 
| 48 |     int primaryIndex = CangjieTable::getPrimaryIndex(code: input); | 
| 49 |     if (primaryIndex < 0 || primaryIndex >= dictionary().size()) | 
| 50 |         return QStringList(); | 
| 51 |  | 
| 52 |     // [25 * 26] char[] array; each primary entry points to a char[] | 
| 53 |     // containing words with the same primary index; then words can be looked up | 
| 54 |     // by their secondary index stored at the beginning of each char[]. | 
| 55 |     const DictionaryEntry &data = dictionary()[primaryIndex]; | 
| 56 |     if (data.isEmpty()) | 
| 57 |         return QStringList(); | 
| 58 |  | 
| 59 |     if (_simplified) | 
| 60 |         // Sort words of this primary index for simplified-cangjie. | 
| 61 |         return sortWords(data); | 
| 62 |  | 
| 63 |     int secondaryIndex = CangjieTable::getSecondaryIndex(code: input); | 
| 64 |     if (secondaryIndex < 0) | 
| 65 |         return QStringList(); | 
| 66 |  | 
| 67 |     // Find words match this secondary index for cangjie. | 
| 68 |     return searchWords(secondaryIndex, data); | 
| 69 | } | 
| 70 |  | 
| 71 | class DictionaryComparator | 
| 72 | { | 
| 73 | public: | 
| 74 |     explicit DictionaryComparator(const std::vector<QCollatorSortKey> &sortKeys) : | 
| 75 |         sortKeys(sortKeys) | 
| 76 |     {} | 
| 77 |  | 
| 78 |     bool operator()(int a, int b) | 
| 79 |     { | 
| 80 |         return sortKeys[a] < sortKeys[b]; | 
| 81 |     } | 
| 82 |  | 
| 83 | private: | 
| 84 |     const std::vector<QCollatorSortKey> &sortKeys; | 
| 85 | }; | 
| 86 |  | 
| 87 | QStringList CangjieDictionary::sortWords(const DictionaryEntry &data) const | 
| 88 | { | 
| 89 |     int length = data.size() / 2; | 
| 90 |     std::vector<QCollatorSortKey> sortKeys; | 
| 91 |     QList<int> keys; | 
| 92 |     sortKeys.reserve(n: length); | 
| 93 |     keys.reserve(asize: length); | 
| 94 |     for (int i = 0; i < length; ++i) { | 
| 95 |         sortKeys.push_back(x: _collator.sortKey(string: data[length + i])); | 
| 96 |         keys.append(t: i); | 
| 97 |     } | 
| 98 |     DictionaryComparator dictionaryComparator(sortKeys); | 
| 99 |     std::sort(first: keys.begin(), last: keys.end(), comp: dictionaryComparator); | 
| 100 |  | 
| 101 |     QStringList words; | 
| 102 |     for (int i = 0; i < length; ++i) | 
| 103 |         words.append(t: data[length + keys[i]]); | 
| 104 |  | 
| 105 |     return words; | 
| 106 | } | 
| 107 |  | 
| 108 | QStringList CangjieDictionary::searchWords(int secondaryIndex, const DictionaryEntry &data) const | 
| 109 | { | 
| 110 |     int length = data.size() / 2; | 
| 111 |  | 
| 112 |     DictionaryEntry::ConstIterator start = data.constBegin(); | 
| 113 |     DictionaryEntry::ConstIterator end = start + length; | 
| 114 |     DictionaryEntry::ConstIterator rangeStart = std::lower_bound(first: start, last: end, val: (DictionaryWord)secondaryIndex); | 
| 115 |     if (rangeStart == end || *rangeStart != QChar(secondaryIndex)) | 
| 116 |         return QStringList(); | 
| 117 |  | 
| 118 |     // There may be more than one words with the same index; look up words with | 
| 119 |     // the same secondary index. | 
| 120 |     while (rangeStart != start) { | 
| 121 |         if (*(rangeStart - 1) != (DictionaryWord)secondaryIndex) | 
| 122 |             break; | 
| 123 |         rangeStart--; | 
| 124 |     } | 
| 125 |  | 
| 126 |     DictionaryEntry::ConstIterator rangeEnd = rangeStart + 1; | 
| 127 |     while (rangeEnd != end) { | 
| 128 |         if (*rangeEnd != (DictionaryWord)secondaryIndex) | 
| 129 |             break; | 
| 130 |         rangeEnd++; | 
| 131 |     } | 
| 132 |  | 
| 133 |     QStringList words; | 
| 134 |     words.reserve(asize: rangeEnd - rangeStart); | 
| 135 |     for (DictionaryEntry::ConstIterator rangeIndex = rangeStart; rangeIndex < rangeEnd; ++rangeIndex) { | 
| 136 |         DictionaryEntry::ConstIterator item(rangeIndex + length); | 
| 137 |         words.append(t: *item); | 
| 138 |     } | 
| 139 |  | 
| 140 |     return words; | 
| 141 | } | 
| 142 |  |