fluxbox/src/FbTk/MenuSearch.cc
Mathias Gumz 169d640610 Simplify code
* assume 'pattern' to always be lowercase
* rename some variables
2015-05-02 15:45:16 +02:00

220 lines
4.8 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "MenuSearch.hh"
#include "MenuItem.hh"
#include "StringUtil.hh"
#include "Resource.hh"
namespace {
size_t search_str_nowhere(const std::string& text, const std::string& pattern) {
return std::string::npos;
}
// finds 'pattern' at beginning of 'text'
size_t search_str_textstart(const std::string& text, const std::string& pattern) {
size_t l = std::min(text.size(), pattern.size());
if (l == 0) {
return std::string::npos;
}
size_t i;
for (i = l; i > 0; i--) {
if (std::tolower(text[i-1]) != pattern[i-1]) {
return std::string::npos;
}
}
return i;
}
// finds 'pattern' in 'text', case insensitive.
// returns position or std::string::npos if not found.
//
// implements BoyerMooreHorspool
size_t search_str_bmh(const std::string& text, const std::string& pattern) {
if (pattern.empty()) {
return 0;
}
if (text.empty() || pattern.size() > text.size()) {
return std::string::npos;
}
const size_t tlen = text.size();
const size_t plen = pattern.size();
size_t t; // index in text
// simple case, no need to be too clever
if (plen == 1) {
int b = pattern[0];
for (t = 0; t < tlen; t++) {
if (b == std::tolower(text[t])) {
return t;
}
}
return std::string::npos;
}
// prepare skip-table
//
size_t skip[256];
const size_t pe = plen - 1; // end index in pattern
size_t p; // index in pattern
for (p = 0; p < sizeof(skip)/sizeof(skip[0]); p++) {
skip[p] = plen;
}
for (p = 0; p < pe; p++) {
skip[pattern[p]] = pe - p;
}
// match
//
for (t = 0; (t+pe) < tlen; ) {
for (p = pe; std::tolower(text[t+p]) == pattern[p]; p--) {
if (p == 0) {
return t;
}
}
t += skip[std::tolower(text[t+pe])];
}
return std::string::npos;
}
// actually search function, depends on Mode
size_t (*search_str)(const std::string&, const std::string&) = search_str_textstart;
} // anonymous
namespace FbTk {
void MenuSearch::setMode(MenuSearch::Mode m) {
if (m == NOWHERE) {
search_str = search_str_nowhere;
} else if (m == SOMEWHERE) {
search_str = search_str_bmh;
} else {
search_str = search_str_textstart;
}
}
MenuSearch::MenuSearch(const std::vector<FbTk::MenuItem*>& items) :
m_items(items) {
}
size_t MenuSearch::size() const {
return pattern.size();
}
void MenuSearch::clear() {
pattern.clear();
}
void MenuSearch::add(char c) {
pattern.push_back(std::tolower(c));
}
void MenuSearch::backspace() {
size_t s = pattern.size();
if (s > 0) {
pattern.erase(s - 1, 1);
}
}
// is 'pattern' matching something?
bool MenuSearch::has_match() {
size_t l = m_items.size();
size_t i;
for (i = 0; i < l; i++) {
if (!m_items[i]->isEnabled())
continue;
if (search_str(m_items[i]->iTypeString(), pattern) != std::string::npos) {
return true;
}
}
return false;
}
// would 'the_pattern' match something?
bool MenuSearch::would_match(const std::string& the_pattern) {
size_t l = m_items.size();
size_t i;
for (i = 0; i < l; i++) {
if (!m_items[i]->isEnabled())
continue;
if (search_str(m_items[i]->iTypeString(), the_pattern) != std::string::npos) {
return true;
}
}
return false;
}
size_t MenuSearch::num_matches() {
size_t l = m_items.size();
size_t i, n;
for (i = 0, n = 0; i < l; i++) {
if (!m_items[i]->isEnabled())
continue;
if (search_str(m_items[i]->iTypeString(), pattern) != std::string::npos) {
n++;
}
}
return n;
}
// returns true if m_text matches against m_items[i] and stores
// the position where it matches in the string. an empty
// 'pattern' always matches
bool MenuSearch::get_match(size_t i, size_t& idx) {
if (i > m_items.size()) {
return false;
}
if (pattern.empty())
return true;
idx = search_str(m_items[i]->iTypeString(), pattern);
return idx != std::string::npos;
}
//
// resource-implementation related
template<>
std::string FbTk::Resource<FbTk::MenuSearch::Mode>::getString() const {
switch (m_value) {
case FbTk::MenuSearch::NOWHERE:
return "nowhere";
case FbTk::MenuSearch::SOMEWHERE:
return "somewhere";
default:
return "itemstart";
};
}
template<>
void FbTk::Resource<FbTk::MenuSearch::Mode>::setFromString(const char *strval) {
std::string val = FbTk::StringUtil::toLower(strval);
if (val == "nowhere") {
m_value = FbTk::MenuSearch::NOWHERE;
} else if (val == "somewhere") {
m_value = FbTk::MenuSearch::SOMEWHERE;
} else {
setDefaultValue();
}
}
}