set(HistoryService_SOURCES
HistoryService.cpp
HistoryItem.cpp
+ HistoryMatchFinder/HistoryMatchFinder.cpp
)
set(HistoryService_HEADERS
HistoryService.h
HistoryItem.h
+ HistoryMatchFinder/HistoryMatchFinder.h
)
include(Coreheaders)
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <boost/algorithm/string.hpp>
+#include <services/HistoryService/HistoryMatchFinder/HistoryMatchFinder.h>
+#include <core/BrowserLogger.h>
+
+namespace tizen_browser {
+namespace services {
+
+void HistoryMatchFinder::removeMismatches(
+ const shared_ptr<HistoryItemVector>& historyItems,
+ const vector<string>& keywords) const
+{
+ for (auto itItem = historyItems->begin(); itItem != historyItems->end();) {
+ if (!stringMatchesKeywords((*itItem)->getUrl(), keywords.begin(),
+ keywords.end())) {
+ // remove url not matching all keywords
+ itItem = historyItems->erase(itItem);
+ } else {
+ ++itItem;
+ }
+ }
+}
+
+bool HistoryMatchFinder::stringMatchesKeywords(const string& url,
+ const vector<string>::const_iterator itKeywordsBegin,
+ const vector<string>::const_iterator itKeywordsEnd) const
+{
+ for (auto it = itKeywordsBegin; it != itKeywordsEnd; ++it)
+ if (!simplePatternMatch(url, *it))
+ return false;
+ return true;
+}
+
+void HistoryMatchFinder::splitKeywordsString(const string& keywordsString,
+ vector<string>& resultKeywords) const
+{
+ boost::algorithm::split(resultKeywords, keywordsString,
+ boost::is_any_of("\t "), boost::token_compress_on);
+ // remove empty elements
+ for (auto it = resultKeywords.begin(); it != resultKeywords.end();) {
+ if (it->empty()) {
+ it = resultKeywords.erase(it);
+ } else {
+ ++it;
+ }
+ }
+}
+
+void HistoryMatchFinder::downcaseStrings(vector<string>& resultKeywords) const
+{
+ for (auto& str : resultKeywords) {
+ boost::algorithm::to_lower(str);
+ }
+}
+
+unsigned HistoryMatchFinder::getLongest(const vector<string>& strVec) const
+{
+ unsigned posLongest = 0;
+ for (auto it = strVec.begin() + 1; it != strVec.end(); ++it)
+ if (it->length() > strVec.at(posLongest).length())
+ posLongest = distance(strVec.begin(), it);
+ return posLongest;
+}
+
+bool HistoryMatchFinder::simplePatternMatch(const string &text,
+ const string &pattern) const
+{
+ if (pattern.empty() || text.empty()) {
+ return pattern.empty() && text.empty();
+ }
+ for (auto it = text.begin(); it != text.end(); ++it) {
+ const auto mismatches = mismatch(pattern.begin(), pattern.end(), it);
+ if (mismatches.first == pattern.end()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+} /* namespace services */
+} /* namespace tizen_browser */
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HISTORYMATCHFINDER_H_
+#define HISTORYMATCHFINDER_H_
+
+#include <string>
+#include <vector>
+
+#include "services/HistoryService/HistoryItem.h"
+
+using namespace std;
+
+namespace tizen_browser {
+namespace services {
+
+class HistoryMatchFinder
+{
+public:
+
+ /**
+ * @brief removes history items not matching given keywords
+ * @param historyItems vector from which mismatching items will be removed
+ * @param keywords keywords (history item is a match, when all keywords are
+ * matching)
+ */
+ void removeMismatches(
+ const std::shared_ptr<HistoryItemVector>& historyItems,
+ const vector<string>& keywords) const;
+
+ /**
+ * @brief splits given string by removing spaces
+ * @param keywordsString string to split
+ * @param resultKeywords vector to which result strings are stored
+ */
+ void splitKeywordsString(const string& keywordsString,
+ vector<string>& resultKeywords) const;
+
+ /**
+ * @brief convert all strings to downcase strings
+ * @param resultKeywords converted strings
+ */
+ void downcaseStrings(vector<string>& resultKeywords) const;
+
+ /**
+ * @brief searches for the longest string
+ * @param strings vector with strings
+ * @return position of the longest string in vector
+ */
+ unsigned getLongest(const vector<string>& strings) const;
+
+ /**
+ * @brief checks if given string contains all given keywords
+ * @param stringChecked checked string
+ * @param itKeywordsBegin keywords vector's begin iterator
+ * @param itKeywordsEnd keywords vector's end iterator
+ */
+ bool stringMatchesKeywords(const string& stringChecked,
+ const vector<string>::const_iterator itKeywordsBegin,
+ const vector<string>::const_iterator itKeywordsEnd) const;
+
+ /**
+ * @brief checks if string contains given pattern
+ * E.g. (abcd, bc) -> true, (abcd, ad) -> false
+ *
+ * @param text checked text
+ * @param pattern checked pattern
+ */
+ bool simplePatternMatch(const string &text, const string &pattern) const;
+
+};
+
+} /* namespace services */
+} /* namespace tizen_browser */
+
+#endif /* HISTORYMATCHFINDER_H_ */
#include "HistoryService.h"
#include "HistoryItem.h"
#include "AbstractWebEngine.h"
+#include "HistoryMatchFinder/HistoryMatchFinder.h"
#include "EflTools.h"
#include "Tools/GeneralTools.h"
HistoryService::HistoryService() : m_testDbMod(false)
{
BROWSER_LOGD("HistoryService");
+ m_historyMatchFinder = std::make_shared<HistoryMatchFinder>();
}
HistoryService::~HistoryService()
BROWSER_LOGD("Deleted Most Visited Sites!");
}
-std::shared_ptr<HistoryItemVector> HistoryService::getHistoryItemsByURL(const std::string& url, int maxItems)
+std::shared_ptr<HistoryItemVector> HistoryService::getHistoryItemsByKeyword(
+ const std::string & keyword, int maxItems)
{
- std::string search("%" + tools::extractDomain(url) + "%"); // add SQL 'any character' signs
+ std::string search("%" + keyword + "%"); // add SQL 'any character' signs
std::shared_ptr<HistoryItemVector> items(new HistoryItemVector);
int *ids=nullptr;
return ret_history_list;
}
+std::shared_ptr<HistoryItemVector> HistoryService::getHistoryItemsByURL(
+ const std::string& url, int maxItems)
+{
+ return getHistoryItemsByKeyword(tools::extractDomain(url), maxItems);
+}
+
+std::shared_ptr<HistoryItemVector> HistoryService::getHistoryItemsByKeywordsString(
+ const std::string& keywordsString, int maxItems)
+{
+ if (keywordsString.empty())
+ return std::make_shared<HistoryItemVector>();
+
+ std::vector<std::string> keywords;
+ m_historyMatchFinder->splitKeywordsString(keywordsString, keywords);
+
+ // the longer the keyword is, the faster search will be
+ const unsigned longestKeywordPos = m_historyMatchFinder->getLongest(
+ keywords);
+ std::string longestKeyword = keywords.at(longestKeywordPos);
+ boost::algorithm::to_lower(longestKeyword);
+
+ // assumption: search starts when longest keyword is at least 3 characters long
+ if (longestKeyword.length() < 3) {
+ return std::make_shared<HistoryItemVector>();
+ }
+
+ // get all results for the longest keyword
+ std::shared_ptr<HistoryItemVector> historyItems = getHistoryItemsByKeyword(
+ longestKeyword, -1);
+
+ if (keywords.size() > 1) {
+ // longestKeywordPos is already handled
+ keywords.erase(keywords.begin() + longestKeywordPos);
+ m_historyMatchFinder->downcaseStrings(keywords);
+ m_historyMatchFinder->removeMismatches(historyItems, keywords);
+ }
+
+ if (historyItems->size() > maxItems) {
+ historyItems->erase(historyItems->begin() + maxItems,
+ historyItems->end());
+ }
+ return historyItems;
+}
+
}
}
namespace services
{
+class HistoryMatchFinder;
+typedef std::shared_ptr<HistoryMatchFinder> HistoryMatchFinderPtr;
+
class BROWSER_EXPORT HistoryService: public tizen_browser::core::AbstractService
{
public:
std::shared_ptr<HistoryItem> getCurrentTab();
std::shared_ptr<HistoryItemVector> getMostVisitedHistoryItems();
void cleanMostVisitedHistoryItems();
+ std::shared_ptr<HistoryItemVector> getHistoryItemsByKeyword(const std::string & keyword, int maxItems);
std::shared_ptr<HistoryItemVector> getHistoryItemsByURL(const std::string & url, int maxItems);
+
+ /**
+ * @brief Searches for history items matching given pattern.
+ *
+ * Splits pattern into words by removing spaces. History item matches
+ * pattern, when its url contains all words (order not considered).
+ *
+ * @param keywords
+ * @param maxItems
+ * @return vector of shared pointers to history items matching given
+ * pattern
+ */
+ std::shared_ptr<HistoryItemVector> getHistoryItemsByKeywordsString(
+ const std::string& keywordsString, int maxItems);
+
int getHistoryItemsCount();
void setStorageServiceTestMode(bool testmode = true);
bool m_testDbMod;;
std::vector<std::shared_ptr<HistoryItem>> history_list;
std::shared_ptr<tizen_browser::services::StorageService> m_storageManager;
+ HistoryMatchFinderPtr m_historyMatchFinder;
/**
* @throws StorageExceptionInitialization on error