Adding HistoryService::getHistoryItemsByKeywordsString(). 40/49540/4
authorAdam Skobodzinski <a.skobodzins@partner.samsung.com>
Wed, 14 Oct 2015 08:55:08 +0000 (10:55 +0200)
committerAdam Skobodzinski <a.skobodzins@partner.samsung.com>
Fri, 16 Oct 2015 13:03:44 +0000 (06:03 -0700)
[Issue]    https://bugs.tizen.org/jira/browse/TT-161
[Problem]  "Url from history" needed new method in HistoryService getting urls basing on a keywords string.
[Solution] New method in HistoryService.

Signed-off-by: Adam Skobodzinski <a.skobodzins@partner.samsung.com>
Change-Id: I0d2ed414eb6af2b7cb61a14dfb9f7024e55a6729

services/HistoryService/CMakeLists.txt
services/HistoryService/HistoryMatchFinder/HistoryMatchFinder.cpp [new file with mode: 0644]
services/HistoryService/HistoryMatchFinder/HistoryMatchFinder.h [new file with mode: 0644]
services/HistoryService/HistoryService.cpp
services/HistoryService/HistoryService.h

index 0a5dcf72e71068f18114fb10ab04d00e493128ea..188f929c720b61c8e376f0cdae233c788ba2330e 100644 (file)
@@ -3,11 +3,13 @@ PROJECT(HistoryService)
 set(HistoryService_SOURCES
        HistoryService.cpp
        HistoryItem.cpp
+       HistoryMatchFinder/HistoryMatchFinder.cpp
 )
 
 set(HistoryService_HEADERS
        HistoryService.h
        HistoryItem.h
+       HistoryMatchFinder/HistoryMatchFinder.h
 )
 
 include(Coreheaders)
diff --git a/services/HistoryService/HistoryMatchFinder/HistoryMatchFinder.cpp b/services/HistoryService/HistoryMatchFinder/HistoryMatchFinder.cpp
new file mode 100644 (file)
index 0000000..67a2efc
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * 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 */
diff --git a/services/HistoryService/HistoryMatchFinder/HistoryMatchFinder.h b/services/HistoryService/HistoryMatchFinder/HistoryMatchFinder.h
new file mode 100644 (file)
index 0000000..78bfb38
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * 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_ */
index f641b857b302f88d30c567db4d7431b0f1bad538..a346c7142d828013e9e5c903c90a4f82a8e58e52 100644 (file)
@@ -25,6 +25,7 @@
 #include "HistoryService.h"
 #include "HistoryItem.h"
 #include "AbstractWebEngine.h"
+#include "HistoryMatchFinder/HistoryMatchFinder.h"
 #include "EflTools.h"
 #include "Tools/GeneralTools.h"
 
@@ -43,6 +44,7 @@ const int SEARCH_LIKE = 1;
 HistoryService::HistoryService() : m_testDbMod(false)
 {
     BROWSER_LOGD("HistoryService");
+    m_historyMatchFinder = std::make_shared<HistoryMatchFinder>();
 }
 
 HistoryService::~HistoryService()
@@ -261,9 +263,10 @@ void HistoryService::cleanMostVisitedHistoryItems()
     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;
@@ -475,5 +478,49 @@ std::shared_ptr<HistoryItemVector> HistoryService::getHistoryItems(bp_history_da
     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;
+}
+
 }
 }
index fc5b7eb988beddf2af4ff418d816054126181852..3eda79354e21dc2a7099d9a5a4faf5ce19c58253 100644 (file)
@@ -35,6 +35,9 @@ namespace tizen_browser
 namespace services
 {
 
+class HistoryMatchFinder;
+typedef std::shared_ptr<HistoryMatchFinder> HistoryMatchFinderPtr;
+
 class BROWSER_EXPORT HistoryService: public tizen_browser::core::AbstractService
 {
 public:
@@ -56,7 +59,23 @@ 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);
 
@@ -69,6 +88,7 @@ private:
     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