tdf#161543 Enhance the searching functionality in FD & FW
Change-Id: I1a21595228f886c942ae46d90e41705443d31550 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/170073 Reviewed-by: Heiko Tietze <heiko.tietze@documentfoundation.org> Reviewed-by: Andreas Heinisch <andreas.heinisch@yahoo.de> Tested-by: Jenkins
This commit is contained in:
parent
5b0256f30e
commit
d05e0be5f4
8 changed files with 276 additions and 46 deletions
|
@ -25,6 +25,7 @@
|
|||
#include "funcpage.hxx"
|
||||
#include <unotools/syslocale.hxx>
|
||||
#include <unotools/charclass.hxx>
|
||||
#include <unotools/textsearch.hxx>
|
||||
|
||||
namespace formula
|
||||
{
|
||||
|
@ -48,10 +49,10 @@ FuncPage::FuncPage(weld::Container* pParent, const IFunctionManager* _pFunctionM
|
|||
, m_xLbFunction(m_xBuilder->weld_tree_view(u"function"_ustr))
|
||||
, m_xScratchIter(m_xLbFunction->make_iterator())
|
||||
, m_xLbFunctionSearchString(m_xBuilder->weld_entry(u"search"_ustr))
|
||||
, m_xSimilaritySearch(m_xBuilder->weld_check_button(u"similaritysearch"_ustr))
|
||||
, m_xHelpButton(m_xBuilder->weld_button(u"help"_ustr))
|
||||
, m_pFunctionManager(_pFunctionManager)
|
||||
{
|
||||
m_xLbFunction->make_sorted();
|
||||
m_aHelpId = m_xLbFunction->get_help_id();
|
||||
|
||||
m_pFunctionManager->fillLastRecentlyUsedFunctions(aLRUList);
|
||||
|
@ -76,6 +77,7 @@ FuncPage::FuncPage(weld::Container* pParent, const IFunctionManager* _pFunctionM
|
|||
m_xLbFunction->connect_row_activated(LINK(this, FuncPage, DblClkHdl));
|
||||
m_xLbFunction->connect_key_press(LINK(this, FuncPage, KeyInputHdl));
|
||||
m_xLbFunctionSearchString->connect_changed(LINK(this, FuncPage, ModifyHdl));
|
||||
m_xSimilaritySearch->connect_toggled(LINK(this, FuncPage, SimilarityToggleHdl));
|
||||
m_xHelpButton->connect_clicked(LINK(this, FuncPage, SelHelpClickHdl));
|
||||
|
||||
m_xHelpButton->set_sensitive(false);
|
||||
|
@ -117,12 +119,26 @@ void FuncPage::impl_addFunctions(const IFunctionCategory* _pCategory, bool bFill
|
|||
}
|
||||
}
|
||||
|
||||
void FuncPage::SearchFunction(const OUString& rFuncName, const OUString& rSearchString,
|
||||
TFunctionDesc pDesc, const bool bSimilaritySearch)
|
||||
{
|
||||
std::pair<sal_Int32, sal_Int32> score = std::make_pair(0, 0);
|
||||
if (bSimilaritySearch && !utl::TextSearch::SimilaritySearch(rFuncName, rSearchString, score))
|
||||
return;
|
||||
if (!bSimilaritySearch && rFuncName.indexOf(rSearchString) < 0
|
||||
&& rSearchString.indexOf(rFuncName) < 0)
|
||||
return;
|
||||
|
||||
sFuncScores.insert(std::make_pair(score, std::make_pair(rFuncName, pDesc)));
|
||||
}
|
||||
|
||||
//aStr is non-empty when user types in the search box to search some function
|
||||
void FuncPage::UpdateFunctionList(const OUString& aStr)
|
||||
{
|
||||
m_xLbFunction->clear();
|
||||
m_xLbFunction->freeze();
|
||||
mCategories.clear();
|
||||
sFuncScores.clear();
|
||||
|
||||
const sal_Int32 nSelPos = m_xLbCategory->get_active();
|
||||
bool bCollapse = nSelPos == 1;
|
||||
|
@ -195,21 +211,23 @@ void FuncPage::UpdateFunctionList(const OUString& aStr)
|
|||
for (sal_uInt32 j = 0; j < nFunctionCount; ++j)
|
||||
{
|
||||
TFunctionDesc pDesc(pCategory->getFunction(j));
|
||||
// tdf#146781 - search for the desired function also in the description
|
||||
if (rCharClass.uppercase(pDesc->getFunctionName()).indexOf(aSearchStr) >= 0
|
||||
|| rCharClass.uppercase(pDesc->getDescription()).indexOf(aSearchStr) >= 0)
|
||||
{
|
||||
if (!pDesc->isHidden())
|
||||
{
|
||||
OUString aFunction(pDesc->getFunctionName());
|
||||
OUString sId(weld::toId(pDesc));
|
||||
const OUString aFunction(rCharClass.uppercase(pDesc->getFunctionName()));
|
||||
SearchFunction(aFunction, aSearchStr, pDesc, m_xSimilaritySearch->get_active());
|
||||
}
|
||||
}
|
||||
|
||||
weld::TreeIter* pCategoryIter
|
||||
= FillCategoriesMap(pCategory->getName(), bCollapse);
|
||||
m_xLbFunction->insert(pCategoryIter, -1, &aFunction, &sId, nullptr, nullptr,
|
||||
false, m_xScratchIter.get());
|
||||
}
|
||||
}
|
||||
for (const auto& func : sFuncScores)
|
||||
{
|
||||
TFunctionDesc pDesc(func.second.second);
|
||||
if (!pDesc->isHidden())
|
||||
{
|
||||
const OUString aCategory(pDesc->getCategory()->getName());
|
||||
const OUString aFunction(func.second.first);
|
||||
const OUString aFuncDescId(weld::toId(pDesc));
|
||||
weld::TreeIter* pCategory = FillCategoriesMap(aCategory, bCollapse);
|
||||
|
||||
m_xLbFunction->insert(pCategory, -1, &aFunction, &aFuncDescId, nullptr, nullptr,
|
||||
false, m_xScratchIter.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -231,11 +249,12 @@ void FuncPage::UpdateFunctionList(const OUString& aStr)
|
|||
|
||||
IMPL_LINK_NOARG(FuncPage, SelComboBoxHdl, weld::ComboBox&, void)
|
||||
{
|
||||
m_xLbFunctionSearchString->set_sensitive(m_xLbCategory->get_active() > 0);
|
||||
if (m_xLbCategory->get_active() == 0)
|
||||
m_xLbFunctionSearchString->set_text(u""_ustr);
|
||||
m_xHelpButton->set_sensitive(false);
|
||||
OUString searchStr = m_xLbFunctionSearchString->get_text();
|
||||
m_xLbFunction->set_help_id(m_aHelpId);
|
||||
UpdateFunctionList(searchStr);
|
||||
m_xHelpButton->set_sensitive(false);
|
||||
}
|
||||
|
||||
IMPL_LINK_NOARG(FuncPage, SelTreeViewHdl, weld::TreeView&, void)
|
||||
|
@ -270,6 +289,17 @@ IMPL_LINK_NOARG(FuncPage, DblClkHdl, weld::TreeView&, bool)
|
|||
}
|
||||
|
||||
IMPL_LINK_NOARG(FuncPage, ModifyHdl, weld::Entry&, void)
|
||||
{
|
||||
if (m_xLbCategory->get_active() == 0)
|
||||
{
|
||||
m_xLbCategory->set_active(1);
|
||||
m_xHelpButton->set_sensitive(false);
|
||||
}
|
||||
OUString searchStr = m_xLbFunctionSearchString->get_text();
|
||||
UpdateFunctionList(searchStr);
|
||||
}
|
||||
|
||||
IMPL_LINK_NOARG(FuncPage, SimilarityToggleHdl, weld::Toggleable&, void)
|
||||
{
|
||||
OUString searchStr = m_xLbFunctionSearchString->get_text();
|
||||
UpdateFunctionList(searchStr);
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include <vcl/weld.hxx>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace formula
|
||||
|
@ -42,6 +43,7 @@ private:
|
|||
std::unique_ptr<weld::TreeView> m_xLbFunction;
|
||||
std::unique_ptr<weld::TreeIter> m_xScratchIter;
|
||||
std::unique_ptr<weld::Entry> m_xLbFunctionSearchString;
|
||||
std::unique_ptr<weld::CheckButton> m_xSimilaritySearch;
|
||||
std::unique_ptr<weld::Button> m_xHelpButton;
|
||||
|
||||
Link<FuncPage&,void> aDoubleClickLink;
|
||||
|
@ -50,6 +52,8 @@ private:
|
|||
|
||||
::std::vector< TFunctionDesc > aLRUList;
|
||||
::std::unordered_map<OUString, std::unique_ptr<weld::TreeIter>> mCategories;
|
||||
::std::set<std::pair<std::pair<sal_Int32, sal_Int32>, std::pair<OUString, TFunctionDesc>>>
|
||||
sFuncScores;
|
||||
OUString m_aHelpId;
|
||||
|
||||
// tdf#104487 - remember last used function category
|
||||
|
@ -64,6 +68,7 @@ private:
|
|||
DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
|
||||
DECL_LINK(ModifyHdl, weld::Entry&, void);
|
||||
DECL_LINK(SelHelpClickHdl, weld::Button&, void);
|
||||
DECL_LINK(SimilarityToggleHdl, weld::Toggleable&, void);
|
||||
|
||||
void UpdateFunctionList(const OUString&);
|
||||
|
||||
|
@ -92,6 +97,8 @@ public:
|
|||
void SetSelectHdl( const Link<FuncPage&,void>& rLink ) { aSelectionLink = rLink; }
|
||||
|
||||
bool IsVisible() const { return m_xContainer->get_visible(); }
|
||||
|
||||
void SearchFunction(const OUString&, const OUString&, TFunctionDesc, const bool);
|
||||
};
|
||||
|
||||
} // formula
|
||||
|
|
|
@ -52,6 +52,26 @@
|
|||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="similaritysearch">
|
||||
<property name="label" translatable="yes" context="functionpage|similaritysearch">Similar</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">False</property>
|
||||
<property name="use-underline">True</property>
|
||||
<property name="draw-indicator">True</property>
|
||||
<child internal-child="accessible">
|
||||
<object class="AtkObject" id="similaritysearch-atkobject">
|
||||
<property name="AtkObject::accessible-description" translatable="yes" context="functionpage|extended_tip|similaritysearch">Search and Sort functions by similarity</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label1">
|
||||
<property name="visible">True</property>
|
||||
|
@ -64,7 +84,7 @@
|
|||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
|
@ -84,7 +104,7 @@
|
|||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">3</property>
|
||||
<property name="position">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
|
@ -99,7 +119,7 @@
|
|||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">4</property>
|
||||
<property name="position">5</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
|
@ -147,7 +167,7 @@
|
|||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">5</property>
|
||||
<property name="position">6</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
|
@ -163,7 +183,7 @@
|
|||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">6</property>
|
||||
<property name="position">7</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child internal-child="accessible">
|
||||
|
|
|
@ -27,6 +27,9 @@
|
|||
|
||||
#include <ostream>
|
||||
|
||||
#define WLD_THRESHOLD 3
|
||||
#define SMALL_STRING_THRESHOLD 4
|
||||
|
||||
class CharClass;
|
||||
|
||||
namespace com::sun::star::lang { struct Locale; }
|
||||
|
@ -209,6 +212,30 @@ public:
|
|||
|
||||
/* replace back references in the replace string by the sub expressions from the search result */
|
||||
static void ReplaceBackReferences( OUString& rReplaceStr, std::u16string_view rStr, const css::util::SearchResult& rResult );
|
||||
|
||||
/**
|
||||
* @brief Search for a string in a another one based on similarity
|
||||
* @param rString The string we compare with
|
||||
* @param rSearchString The search term
|
||||
* @param rSimilarityScore The similarity score (sent by reference to be filled)
|
||||
* @return True if the search term is found, false otherwise
|
||||
*/
|
||||
static bool SimilaritySearch(const OUString& rString, const OUString& rSearchString,
|
||||
::std::pair<sal_Int32, sal_Int32>& rSimilarityScore);
|
||||
/**
|
||||
* @brief Get similarity score between two strings
|
||||
* according to the length of the common substring and its position
|
||||
* @param rString The string we compare with
|
||||
* @param rSearchString The search term
|
||||
* @param nInitialScore The initial score
|
||||
* @param bFromStart True if the search is from the start
|
||||
* @return Score if the search term is found in the text, -1 otherwise
|
||||
*/
|
||||
static sal_Int32 GetSubstringSimilarity(std::u16string_view rString,
|
||||
std::u16string_view rSearchString,
|
||||
sal_Int32& nInitialScore, const bool bFromStart);
|
||||
static sal_Int32 GetWeightedLevenshteinDistance(const OUString& rString,
|
||||
const OUString& rSearchString);
|
||||
};
|
||||
|
||||
} // namespace utl
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <sfx2/viewsh.hxx>
|
||||
#include <formula/funcvarargs.h>
|
||||
#include <unotools/charclass.hxx>
|
||||
#include <unotools/textsearch.hxx>
|
||||
#include <vcl/svapp.hxx>
|
||||
#include <vcl/help.hxx>
|
||||
|
||||
|
@ -55,6 +56,7 @@ ScFunctionWin::ScFunctionWin(weld::Widget* pParent)
|
|||
, xScratchIter(xFuncList->make_iterator())
|
||||
, xInsertButton(m_xBuilder->weld_button(u"insert"_ustr))
|
||||
, xHelpButton(m_xBuilder->weld_button(u"help"_ustr))
|
||||
, xSimilaritySearch(m_xBuilder->weld_check_button(u"similaritysearch"_ustr))
|
||||
, xFiFuncDesc(m_xBuilder->weld_text_view(u"funcdesc"_ustr))
|
||||
, m_xSearchString(m_xBuilder->weld_entry(u"search"_ustr))
|
||||
, xConfigListener(new comphelper::ConfigurationListener(u"/org.openoffice.Office.Calc/Formula/Syntax"_ustr))
|
||||
|
@ -79,6 +81,7 @@ ScFunctionWin::ScFunctionWin(weld::Widget* pParent)
|
|||
xFuncList->connect_row_activated(LINK( this, ScFunctionWin, SetRowActivatedHdl));
|
||||
xInsertButton->connect_clicked(LINK( this, ScFunctionWin, SetSelectionClickHdl));
|
||||
xHelpButton->connect_clicked(LINK( this, ScFunctionWin, SetHelpClickHdl));
|
||||
xSimilaritySearch->connect_toggled(LINK(this, ScFunctionWin, SetSimilarityToggleHdl));
|
||||
|
||||
xCatBox->set_active(0);
|
||||
|
||||
|
@ -109,6 +112,7 @@ ScFunctionWin::~ScFunctionWin()
|
|||
xFuncList.reset();
|
||||
xInsertButton.reset();
|
||||
xHelpButton.reset();
|
||||
xSimilaritySearch.reset();
|
||||
xFiFuncDesc.reset();
|
||||
}
|
||||
|
||||
|
@ -189,6 +193,19 @@ void ScFunctionWin::UpdateLRUList()
|
|||
}
|
||||
}
|
||||
|
||||
void ScFunctionWin::SearchFunction(const OUString& rFuncName, const OUString& rSearchString,
|
||||
const ScFuncDesc* pDesc, const bool bSimilaritySearch)
|
||||
{
|
||||
std::pair<sal_Int32, sal_Int32> score = std::make_pair(0, 0);
|
||||
if (bSimilaritySearch && !utl::TextSearch::SimilaritySearch(rFuncName, rSearchString, score))
|
||||
return;
|
||||
if (!bSimilaritySearch && rFuncName.indexOf(rSearchString) < 0
|
||||
&& rSearchString.indexOf(rFuncName) < 0)
|
||||
return;
|
||||
|
||||
sFuncScores.insert(std::make_pair(score, std::make_pair(rFuncName, pDesc)));
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
#* Member: SetDescription
|
||||
#*------------------------------------------------------------------------
|
||||
|
@ -252,6 +269,7 @@ void ScFunctionWin::UpdateFunctionList(const OUString& rSearchString)
|
|||
xFuncList->clear();
|
||||
xFuncList->freeze();
|
||||
mCategories.clear();
|
||||
sFuncScores.clear();
|
||||
|
||||
bool bCollapse = nCategory == 0;
|
||||
bool bFilter = !rSearchString.isEmpty();
|
||||
|
@ -270,38 +288,31 @@ void ScFunctionWin::UpdateFunctionList(const OUString& rSearchString)
|
|||
const ScFuncDesc* pDesc = pFuncMgr->First(nCategory);
|
||||
while (pDesc)
|
||||
{
|
||||
OUString aCategory = pDesc->getCategory()->getName();
|
||||
OUString aFunction = pDesc->getFunctionName();
|
||||
OUString aFuncDescId = weld::toId(pDesc);
|
||||
const OUString aCategory(pDesc->getCategory()->getName());
|
||||
const OUString aFunction(pCharClass->uppercase(pDesc->getFunctionName()));
|
||||
const OUString aFuncDescId(weld::toId(pDesc));
|
||||
|
||||
if (!bFilter || (pCharClass->uppercase(aFunction).startsWith(aSearchStr)))
|
||||
if (bFilter)
|
||||
SearchFunction(aFunction, aSearchStr, pDesc, xSimilaritySearch->get_active());
|
||||
else
|
||||
{
|
||||
weld::TreeIter* pCategory = FillCategoriesMap(aCategory, bCollapse);
|
||||
xFuncList->insert(pCategory, -1, &aFunction, &aFuncDescId, nullptr, nullptr,
|
||||
false, xScratchIter.get());
|
||||
false, xScratchIter.get());
|
||||
}
|
||||
pDesc = pFuncMgr->Next();
|
||||
}
|
||||
|
||||
// Now add the functions that have the search string in the middle of the function name
|
||||
// Note that this will only be necessary if the search string is not empty
|
||||
if (bFilter)
|
||||
for (const auto& func : sFuncScores)
|
||||
{
|
||||
pDesc = pFuncMgr->First( nCategory );
|
||||
while ( pDesc )
|
||||
{
|
||||
OUString aCategory = pDesc->getCategory()->getName();
|
||||
OUString aFunction = pDesc->getFunctionName();
|
||||
OUString aFuncDescId = weld::toId(pDesc);
|
||||
pDesc = func.second.second;
|
||||
const OUString aCategory(pDesc->getCategory()->getName());
|
||||
const OUString aFunction(func.second.first);
|
||||
const OUString aFuncDescId(weld::toId(pDesc));
|
||||
weld::TreeIter* pCategory = FillCategoriesMap(aCategory, bCollapse);
|
||||
|
||||
if (pCharClass->uppercase(aFunction).indexOf(aSearchStr) > 0)
|
||||
{
|
||||
weld::TreeIter* pCategory = FillCategoriesMap(aCategory, bCollapse);
|
||||
xFuncList->insert(pCategory, -1, &aFunction, &aFuncDescId, nullptr, nullptr,
|
||||
false, xScratchIter.get());
|
||||
}
|
||||
pDesc = pFuncMgr->Next();
|
||||
}
|
||||
xFuncList->insert(pCategory, -1, &aFunction, &aFuncDescId, nullptr, nullptr, false,
|
||||
xScratchIter.get());
|
||||
}
|
||||
}
|
||||
else // LRU list
|
||||
|
@ -477,6 +488,11 @@ void ScFunctionWin::DoEnter(bool bDoubleOrEnter)
|
|||
|
||||
IMPL_LINK_NOARG(ScFunctionWin, ModifyHdl, weld::Entry&, void)
|
||||
{
|
||||
if (xCatBox->get_active() == 0)
|
||||
{
|
||||
xCatBox->set_active(1);
|
||||
xHelpButton->set_sensitive(false);
|
||||
}
|
||||
OUString searchStr = m_xSearchString->get_text();
|
||||
UpdateFunctionList(searchStr);
|
||||
SetDescription();
|
||||
|
@ -576,8 +592,9 @@ IMPL_LINK(ScFunctionWin, KeyInputHdl, const KeyEvent&, rEvent, bool)
|
|||
|
||||
IMPL_LINK_NOARG(ScFunctionWin, SelComboHdl, weld::ComboBox&, void)
|
||||
{
|
||||
if (xCatBox->get_active() == 0)
|
||||
m_xSearchString->set_text(u""_ustr);
|
||||
xHelpButton->set_sensitive(xCatBox->get_active() != 1);
|
||||
m_xSearchString->set_sensitive(xCatBox->get_active() > 0);
|
||||
OUString searchStr = m_xSearchString->get_text();
|
||||
UpdateFunctionList(searchStr);
|
||||
SetDescription();
|
||||
|
@ -638,6 +655,13 @@ IMPL_LINK_NOARG( ScFunctionWin, SetHelpClickHdl, weld::Button&, void )
|
|||
}
|
||||
}
|
||||
|
||||
IMPL_LINK_NOARG(ScFunctionWin, SetSimilarityToggleHdl, weld::Toggleable&, void)
|
||||
{
|
||||
OUString searchStr = m_xSearchString->get_text();
|
||||
UpdateFunctionList(searchStr);
|
||||
SetDescription();
|
||||
}
|
||||
|
||||
IMPL_LINK_NOARG( ScFunctionWin, SetRowActivatedHdl, weld::TreeView&, bool )
|
||||
{
|
||||
DoEnter(true); // saves the input
|
||||
|
|
|
@ -49,6 +49,7 @@ private:
|
|||
std::unique_ptr<weld::TreeIter> xScratchIter;
|
||||
std::unique_ptr<weld::Button> xInsertButton;
|
||||
std::unique_ptr<weld::Button> xHelpButton;
|
||||
std::unique_ptr<weld::CheckButton> xSimilaritySearch;
|
||||
std::unique_ptr<weld::TextView> xFiFuncDesc;
|
||||
std::unique_ptr<weld::Entry> m_xSearchString;
|
||||
|
||||
|
@ -59,6 +60,8 @@ private:
|
|||
OUString m_aListHelpId;
|
||||
OUString m_aSearchHelpId;
|
||||
|
||||
::std::set<std::pair<std::pair<sal_Int32, sal_Int32>, std::pair<OUString, const ScFuncDesc*>>>
|
||||
sFuncScores;
|
||||
::std::vector< const formula::IFunctionDescription*> aLRUList;
|
||||
::std::unordered_map<OUString, std::unique_ptr<weld::TreeIter>> mCategories;
|
||||
|
||||
|
@ -70,6 +73,7 @@ private:
|
|||
DECL_LINK( SetRowActivatedHdl, weld::TreeView&, bool );
|
||||
DECL_LINK( SetSelectionClickHdl, weld::Button&, void );
|
||||
DECL_LINK( SetHelpClickHdl, weld::Button&, void );
|
||||
DECL_LINK( SetSimilarityToggleHdl, weld::Toggleable&, void );
|
||||
DECL_LINK( SelComboHdl, weld::ComboBox&, void );
|
||||
DECL_LINK( SelTreeHdl, weld::TreeView&, void );
|
||||
DECL_LINK( ModifyHdl, weld::Entry&, void );
|
||||
|
@ -82,6 +86,7 @@ public:
|
|||
|
||||
void InitLRUList();
|
||||
void UpdateFunctionList(const OUString&);
|
||||
void SearchFunction(const OUString&, const OUString&, const ScFuncDesc*, const bool);
|
||||
};
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
||||
|
|
|
@ -145,7 +145,7 @@
|
|||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="orientation">horizontal</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkEntry" id="search">
|
||||
|
@ -166,6 +166,26 @@
|
|||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="similaritysearch">
|
||||
<property name="label" translatable="yes" context="functionpanel|similaritysearch">Similar</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">False</property>
|
||||
<property name="use-underline">True</property>
|
||||
<property name="draw-indicator">True</property>
|
||||
<child internal-child="accessible">
|
||||
<object class="AtkObject" id="similaritysearch-atkobject">
|
||||
<property name="AtkObject::accessible-description" translatable="yes" context="functionpanel|extended_tip|similaritysearch">Search and Sort functions by similarity</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
|
|
|
@ -353,6 +353,103 @@ void TextSearch::ReplaceBackReferences( OUString& rReplaceStr, std::u16string_vi
|
|||
rReplaceStr = sBuff.makeStringAndClear();
|
||||
}
|
||||
|
||||
bool TextSearch::SimilaritySearch(const OUString& rString, const OUString& rSearchString,
|
||||
::std::pair<sal_Int32, sal_Int32>& rSimilarityScore)
|
||||
{
|
||||
sal_Int32 nScore = 0;
|
||||
sal_Int32 nFirstScore = GetSubstringSimilarity(rString, rSearchString, nScore, true);
|
||||
if (nFirstScore == -1)
|
||||
nFirstScore = GetSubstringSimilarity(rString, rSearchString, nScore, false);
|
||||
if (nFirstScore == -1)
|
||||
{
|
||||
if (rSearchString.getLength() == 1)
|
||||
{
|
||||
if (rString.startsWith(rSearchString))
|
||||
nFirstScore = nScore;
|
||||
else if (rString.endsWith(rSearchString))
|
||||
nFirstScore = nScore + 1;
|
||||
nScore += 2;
|
||||
}
|
||||
else if (rString.getLength() == 1 && rSearchString.getLength() < SMALL_STRING_THRESHOLD)
|
||||
{
|
||||
if (rSearchString.startsWith(rString))
|
||||
nFirstScore = nScore;
|
||||
else if (rSearchString.endsWith(rString))
|
||||
nFirstScore = nScore + 1;
|
||||
nScore += 2;
|
||||
}
|
||||
}
|
||||
sal_Int32 nSecondScore = GetWeightedLevenshteinDistance(rString, rSearchString);
|
||||
|
||||
if (nFirstScore == -1 && nSecondScore >= WLD_THRESHOLD)
|
||||
return false;
|
||||
|
||||
rSimilarityScore.first = (nFirstScore == -1) ? nScore : nFirstScore;
|
||||
rSimilarityScore.second = nSecondScore;
|
||||
return true;
|
||||
}
|
||||
|
||||
sal_Int32 TextSearch::GetSubstringSimilarity(std::u16string_view rString,
|
||||
std::u16string_view rSearchString,
|
||||
sal_Int32& nInitialScore, const bool bFromStart)
|
||||
{
|
||||
sal_Int32 nScore = -1;
|
||||
for (sal_Int32 length = rSearchString.length(); length > 1; length--)
|
||||
{
|
||||
sal_Int32 nStartPos = bFromStart ? 0 : rSearchString.length() - length;
|
||||
std::u16string_view rSearchSubString = rSearchString.substr(nStartPos, length);
|
||||
if (rString.starts_with(rSearchSubString))
|
||||
{
|
||||
nScore = nInitialScore;
|
||||
break;
|
||||
}
|
||||
else if (rString.ends_with(rSearchSubString))
|
||||
{
|
||||
nScore = nInitialScore + 1;
|
||||
break;
|
||||
}
|
||||
else if (rString.find(rSearchSubString) != std::u16string_view::npos)
|
||||
{
|
||||
nScore = nInitialScore + 2;
|
||||
break;
|
||||
}
|
||||
nInitialScore += 3;
|
||||
}
|
||||
return nScore;
|
||||
}
|
||||
|
||||
sal_Int32 TextSearch::GetWeightedLevenshteinDistance(const OUString& rString,
|
||||
const OUString& rSearchString)
|
||||
{
|
||||
sal_Int32 n = rString.getLength();
|
||||
sal_Int32 m = rSearchString.getLength();
|
||||
std::vector<std::vector<sal_Int32>> ScoreDP(n + 1, std::vector<sal_Int32>(m + 1));
|
||||
|
||||
for (sal_Int32 i = 0; i <= n; i++)
|
||||
{
|
||||
ScoreDP[i][0] = i;
|
||||
}
|
||||
for (sal_Int32 j = 0; j <= m; j++)
|
||||
{
|
||||
ScoreDP[0][j] = j;
|
||||
}
|
||||
|
||||
for (sal_Int32 i = 1; i <= n; i++)
|
||||
{
|
||||
for (sal_Int32 j = 1; j <= m; j++)
|
||||
{
|
||||
sal_Int32& minE = ScoreDP[i][j];
|
||||
minE = ScoreDP[i - 1][j] + 1;
|
||||
minE = std::min(minE, ScoreDP[i][j - 1] + 1);
|
||||
if (rString[i - 1] != rSearchString[j - 1])
|
||||
minE = std::min(minE, ScoreDP[i - 1][j - 1] + 2);
|
||||
else
|
||||
minE = std::min(minE, ScoreDP[i - 1][j - 1]);
|
||||
}
|
||||
}
|
||||
return ScoreDP[n][m];
|
||||
}
|
||||
|
||||
} // namespace utl
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
||||
|
|
Loading…
Reference in a new issue