diff options
Diffstat (limited to 'src/FbTk/MenuSearch.cc')
-rw-r--r-- | src/FbTk/MenuSearch.cc | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/src/FbTk/MenuSearch.cc b/src/FbTk/MenuSearch.cc new file mode 100644 index 0000000..da903f4 --- /dev/null +++ b/src/FbTk/MenuSearch.cc | |||
@@ -0,0 +1,221 @@ | |||
1 | #include "MenuSearch.hh" | ||
2 | #include "MenuItem.hh" | ||
3 | #include "StringUtil.hh" | ||
4 | #include "Resource.hh" | ||
5 | |||
6 | namespace { | ||
7 | |||
8 | size_t search_str_nowhere(const std::string& text, const std::string& pattern) { | ||
9 | return std::string::npos; | ||
10 | } | ||
11 | |||
12 | // finds 'pattern' at beginning of 'text' | ||
13 | size_t search_str_textstart(const std::string& text, const std::string& pattern) { | ||
14 | |||
15 | size_t l = std::min(text.size(), pattern.size()); | ||
16 | if (l == 0) { | ||
17 | return std::string::npos; | ||
18 | } | ||
19 | |||
20 | size_t i; | ||
21 | for (i = l; i > 0; i--) { | ||
22 | if (std::tolower(text[i-1]) != std::tolower(pattern[i-1])) { | ||
23 | return std::string::npos; | ||
24 | } | ||
25 | } | ||
26 | |||
27 | return i; | ||
28 | } | ||
29 | |||
30 | // finds 'pattern' in 'text', case insensitive. | ||
31 | // returns position or std::string::npos if not found. | ||
32 | // | ||
33 | // implements Boyer–Moore–Horspool | ||
34 | size_t search_str_bmh(const std::string& text, const std::string& pattern) { | ||
35 | |||
36 | if (pattern.empty()) { | ||
37 | return 0; | ||
38 | } | ||
39 | if (text.empty() || pattern.size() > text.size()) { | ||
40 | return std::string::npos; | ||
41 | } | ||
42 | |||
43 | size_t t; | ||
44 | size_t tlen = text.size(); | ||
45 | |||
46 | // simple case, no need to be too clever | ||
47 | if (pattern.size() == 1) { | ||
48 | int b = std::tolower(pattern[0]); | ||
49 | for (t = 0; t < tlen; t++) { | ||
50 | if (b == std::tolower(text[t])) { | ||
51 | return t; | ||
52 | } | ||
53 | } | ||
54 | return std::string::npos; | ||
55 | } | ||
56 | |||
57 | |||
58 | size_t plast = pattern.size() - 1; | ||
59 | size_t p; | ||
60 | |||
61 | // prepare skip-table | ||
62 | // | ||
63 | size_t skip[256]; | ||
64 | for (p = 0; p < sizeof(skip)/sizeof(skip[0]); p++) { | ||
65 | skip[p] = plast + 1; | ||
66 | } | ||
67 | for (p = 0; p < plast; p++) { | ||
68 | skip[std::tolower(pattern[p])] = plast - p; | ||
69 | } | ||
70 | |||
71 | // match | ||
72 | for (t = 0; t + plast < tlen; ) { | ||
73 | for (p = plast; std::tolower(text[t+p]) == std::tolower(pattern[p]); p--) { | ||
74 | if (p == 0) { | ||
75 | return t+p; | ||
76 | } | ||
77 | } | ||
78 | t += skip[std::tolower(text[t+p])]; | ||
79 | } | ||
80 | |||
81 | return std::string::npos; | ||
82 | } | ||
83 | |||
84 | |||
85 | // actually search function, depends on Mode | ||
86 | size_t (*search_str)(const std::string&, const std::string&) = search_str_textstart; | ||
87 | |||
88 | } // anonymous | ||
89 | |||
90 | |||
91 | |||
92 | namespace FbTk { | ||
93 | |||
94 | |||
95 | void MenuSearch::setMode(MenuSearch::Mode m) { | ||
96 | if (m == NOWHERE) { | ||
97 | search_str = search_str_nowhere; | ||
98 | } else if (m == SOMEWHERE) { | ||
99 | search_str = search_str_bmh; | ||
100 | } else { | ||
101 | search_str = search_str_textstart; | ||
102 | } | ||
103 | } | ||
104 | |||
105 | |||
106 | |||
107 | MenuSearch::MenuSearch(const std::vector<FbTk::MenuItem*>& items) : | ||
108 | m_items(items) { | ||
109 | } | ||
110 | |||
111 | size_t MenuSearch::size() const { | ||
112 | return pattern.size(); | ||
113 | } | ||
114 | |||
115 | void MenuSearch::clear() { | ||
116 | pattern.clear(); | ||
117 | } | ||
118 | |||
119 | void MenuSearch::add(char c) { | ||
120 | pattern.push_back(c); | ||
121 | } | ||
122 | |||
123 | void MenuSearch::backspace() { | ||
124 | size_t s = pattern.size(); | ||
125 | if (s > 0) { | ||
126 | pattern.erase(s - 1, 1); | ||
127 | } | ||
128 | } | ||
129 | |||
130 | // is 'pattern' matching something? | ||
131 | bool MenuSearch::has_match() { | ||
132 | size_t l = m_items.size(); | ||
133 | size_t i; | ||
134 | for (i = 0; i < l; i++) { | ||
135 | if (!m_items[i]->isEnabled()) | ||
136 | continue; | ||
137 | if (search_str(m_items[i]->iTypeString(), pattern) != std::string::npos) { | ||
138 | return true; | ||
139 | } | ||
140 | } | ||
141 | return false; | ||
142 | } | ||
143 | |||
144 | // would 'the_pattern' match something? | ||
145 | bool MenuSearch::would_match(const std::string& the_pattern) { | ||
146 | size_t l = m_items.size(); | ||
147 | size_t i; | ||
148 | for (i = 0; i < l; i++) { | ||
149 | if (!m_items[i]->isEnabled()) | ||
150 | continue; | ||
151 | if (search_str(m_items[i]->iTypeString(), the_pattern) != std::string::npos) { | ||
152 | return true; | ||
153 | } | ||
154 | } | ||
155 | return false; | ||
156 | } | ||
157 | |||
158 | size_t MenuSearch::num_matches() { | ||
159 | size_t l = m_items.size(); | ||
160 | size_t i, n; | ||
161 | for (i = 0, n = 0; i < l; i++) { | ||
162 | if (!m_items[i]->isEnabled()) | ||
163 | continue; | ||
164 | if (search_str(m_items[i]->iTypeString(), pattern) != std::string::npos) { | ||
165 | n++; | ||
166 | } | ||
167 | } | ||
168 | return n; | ||
169 | } | ||
170 | |||
171 | |||
172 | // returns true if m_text matches against m_items[i] and stores | ||
173 | // the position where it matches in the string. an empty | ||
174 | // 'pattern' always matches | ||
175 | bool MenuSearch::get_match(size_t i, size_t& idx) { | ||
176 | if (i > m_items.size()) { | ||
177 | return false; | ||
178 | } | ||
179 | |||
180 | if (pattern.empty()) | ||
181 | return true; | ||
182 | |||
183 | idx = search_str(m_items[i]->iTypeString(), pattern); | ||
184 | return idx != std::string::npos; | ||
185 | } | ||
186 | |||
187 | |||
188 | |||
189 | |||
190 | // | ||
191 | // resource-implementation related | ||
192 | |||
193 | template<> | ||
194 | std::string FbTk::Resource<FbTk::MenuSearch::Mode>::getString() const { | ||
195 | |||
196 | switch (m_value) { | ||
197 | case FbTk::MenuSearch::NOWHERE: | ||
198 | return "nowhere"; | ||
199 | case FbTk::MenuSearch::SOMEWHERE: | ||
200 | return "somewhere"; | ||
201 | default: | ||
202 | return "itemstart"; | ||
203 | }; | ||
204 | } | ||
205 | |||
206 | template<> | ||
207 | void FbTk::Resource<FbTk::MenuSearch::Mode>::setFromString(const char *strval) { | ||
208 | |||
209 | std::string val = FbTk::StringUtil::toLower(strval); | ||
210 | if (val == "nowhere") { | ||
211 | m_value = FbTk::MenuSearch::NOWHERE; | ||
212 | } else if (val == "somewhere") { | ||
213 | m_value = FbTk::MenuSearch::SOMEWHERE; | ||
214 | } else { | ||
215 | setDefaultValue(); | ||
216 | } | ||
217 | |||
218 | std::cerr << "** " << val << " " << m_value << "\n"; | ||
219 | } | ||
220 | |||
221 | } | ||