2 * @file SubstitutionFiltersList.cpp
4 * @brief Implementation for SubstitutionFiltersList class.
8 #include "SubstitutionFiltersList.h"
9 #include "SubstitutionList.h"
12 #include <Poco/Exception.h>
13 #include "OptionsMgr.h"
14 #include "OptionsDef.h"
15 #include "UnicodeString.h"
17 /** @brief Registry key for saving Substitution filters. */
18 static const TCHAR SubstitutionFiltersRegPath[] = _T("SubstitutionFilters");
21 * @brief Default constructor.
23 SubstitutionFiltersList::SubstitutionFiltersList()
24 : m_pOptionsMgr(nullptr)
29 * @brief Destructor, empties the list.
31 SubstitutionFiltersList::~SubstitutionFiltersList() = default;
34 * @brief Add new filter to the list.
35 * @param [in] filter Filter string to add.
36 * @param [in] enabled Is filter enabled?
38 void SubstitutionFiltersList::Add(const String& filter0, const String& filter1,
39 bool useRegExp, bool caseSensitive, bool matchWholeWordOnly, bool enabled)
41 SubstitutionFilter item;
42 item.useRegExp = useRegExp;
43 item.caseSensitive = caseSensitive;
44 item.matchWholeWordOnly = matchWholeWordOnly;
45 item.pattern = filter0;
46 item.replacement = filter1;
47 item.enabled = enabled;
48 m_items.emplace_back(item);
52 * @brief Return filter from given index.
53 * @param [in] ind Index of filter.
54 * @return Filter item from the index. If the index is beyond table limit,
55 * return the last item in the list.
57 const SubstitutionFilter& SubstitutionFiltersList::GetAt(size_t ind) const
59 if (ind < m_items.size())
62 return m_items.back();
66 * @brief Clone filter list from another list.
67 * This function clones filter list from another list. Current items in the
68 * list are removed and new items added from the given list.
69 * @param [in] list List to clone.
71 void SubstitutionFiltersList::CloneFrom(const SubstitutionFiltersList *list)
74 size_t count = list->GetCount();
75 m_enabled = list->m_enabled;
76 for (size_t i = 0; i < count; i++)
78 const SubstitutionFilter &item = list->GetAt(i);
79 Add(item.pattern, item.replacement, item.useRegExp,
80 item.caseSensitive, item.matchWholeWordOnly, item.enabled);
85 * @brief Compare filter lists.
86 * @param [in] list List to compare.
87 * @return true if lists are identical, false otherwise.
89 bool SubstitutionFiltersList::Compare(const SubstitutionFiltersList *list) const
91 if (list->GetCount() != GetCount())
93 if (list->GetEnabled() != GetEnabled())
96 for (size_t i = 0; i < GetCount(); i++)
98 const SubstitutionFilter &item1 = list->GetAt(i);
99 const SubstitutionFilter &item2 = GetAt(i);
103 item1.enabled != item2.enabled
104 || item1.useRegExp != item2.useRegExp
105 || item1.caseSensitive != item2.caseSensitive
106 || item1.matchWholeWordOnly != item2.matchWholeWordOnly
107 || item1.pattern != item2.pattern
108 || item1.replacement != item2.replacement
116 * @brief Read filter list from the options system.
117 * @param [in] pOptionsMgr Pointer to options system.
119 void SubstitutionFiltersList::Initialize(COptionsMgr *pOptionsMgr)
121 assert(pOptionsMgr != nullptr);
122 String valuename(SubstitutionFiltersRegPath);
124 m_pOptionsMgr = pOptionsMgr;
126 m_enabled = m_pOptionsMgr->GetBool(OPT_SUBSTITUTION_FILTERS_ENABLED);
128 size_t count = m_items.size();
129 valuename += _T("/Values");
130 m_pOptionsMgr->InitOption(valuename, static_cast<int>(count));
131 count = m_pOptionsMgr->GetInt(valuename);
133 for (unsigned i = 0; i < count; i++)
135 String nameEnabled = strutils::format(_T("%s/Enabled%02u"), SubstitutionFiltersRegPath, i);
136 m_pOptionsMgr->InitOption(nameEnabled, true);
137 bool enabled = m_pOptionsMgr->GetBool(nameEnabled);
139 String nameUseRegExp = strutils::format(_T("%s/UseRegExp%02u"), SubstitutionFiltersRegPath, i);
140 m_pOptionsMgr->InitOption(nameUseRegExp, false);
141 bool useRegExp = m_pOptionsMgr->GetBool(nameUseRegExp);
143 String nameCaseSensitive = strutils::format(_T("%s/CaseSensitive%02u"), SubstitutionFiltersRegPath, i);
144 m_pOptionsMgr->InitOption(nameCaseSensitive, false);
145 bool caseSensitive = m_pOptionsMgr->GetBool(nameCaseSensitive);
147 String nameMatchWholeWordOnly = strutils::format(_T("%s/MatchWholeWordOnly%02u"), SubstitutionFiltersRegPath, i);
148 m_pOptionsMgr->InitOption(nameMatchWholeWordOnly, false);
149 bool matchWholeWordOnly = m_pOptionsMgr->GetBool(nameMatchWholeWordOnly);
151 String name0 = strutils::format(_T("%s/Pattern%02u"), SubstitutionFiltersRegPath, i);
152 m_pOptionsMgr->InitOption(name0, _T(""));
153 String pattern = m_pOptionsMgr->GetString(name0);
155 String name1 = strutils::format(_T("%s/Replacement%02u"), SubstitutionFiltersRegPath, i);
156 m_pOptionsMgr->InitOption(name1, _T(""));
157 String replacement = m_pOptionsMgr->GetString(name1);
159 Add(pattern, replacement, useRegExp, caseSensitive, matchWholeWordOnly, enabled);
164 * @brief Save Substitution Filters to options system.
166 void SubstitutionFiltersList::SaveFilters()
168 assert(m_pOptionsMgr != nullptr);
169 String valuename(SubstitutionFiltersRegPath);
171 m_pOptionsMgr->SaveOption(OPT_SUBSTITUTION_FILTERS_ENABLED, m_enabled);
173 size_t count = m_items.size();
174 valuename += _T("/Values");
175 m_pOptionsMgr->SaveOption(valuename, static_cast<int>(count));
177 for (size_t i = 0; i < count; i++)
179 const SubstitutionFilter& item = m_items[i];
181 String nameEnabled = strutils::format(_T("%s/Enabled%02u"), SubstitutionFiltersRegPath, i);
182 m_pOptionsMgr->InitOption(nameEnabled, true);
183 m_pOptionsMgr->SaveOption(nameEnabled, item.enabled);
185 String nameUseRegExp = strutils::format(_T("%s/UseRegExp%02u"), SubstitutionFiltersRegPath, i);
186 m_pOptionsMgr->InitOption(nameUseRegExp, false);
187 m_pOptionsMgr->SaveOption(nameUseRegExp, item.useRegExp);
189 String nameCaseSensitive = strutils::format(_T("%s/CaseSensitive%02u"), SubstitutionFiltersRegPath, i);
190 m_pOptionsMgr->InitOption(nameCaseSensitive, false);
191 m_pOptionsMgr->SaveOption(nameCaseSensitive, item.caseSensitive);
193 String nameMatchWholeWordOnly = strutils::format(_T("%s/MatchWholeWordOnly%02u"), SubstitutionFiltersRegPath, i);
194 m_pOptionsMgr->InitOption(nameMatchWholeWordOnly, false);
195 m_pOptionsMgr->SaveOption(nameMatchWholeWordOnly, item.matchWholeWordOnly);
197 String name0 = strutils::format(_T("%s/Pattern%02u"), SubstitutionFiltersRegPath, i);
198 m_pOptionsMgr->InitOption(name0, _T(""));
199 m_pOptionsMgr->SaveOption(name0, item.pattern);
201 String name1 = strutils::format(_T("%s/Replacement%02u"), SubstitutionFiltersRegPath, i);
202 m_pOptionsMgr->InitOption(name1, _T(""));
203 m_pOptionsMgr->SaveOption(name1, item.replacement);
206 // Remove options we don't need anymore
207 // We could have earlier 10 pcs but now we only need 5
208 String filterEnabled = strutils::format(_T("%s/Enabled%02u"), SubstitutionFiltersRegPath, count);
209 int retvalEnabled = m_pOptionsMgr->RemoveOption(filterEnabled);
211 String filterUseRegExp = strutils::format(_T("%s/UseRegExp%02u"), SubstitutionFiltersRegPath, count);
212 int retvalUseRegExp = m_pOptionsMgr->RemoveOption(filterUseRegExp);
214 String filterCaseSensitive = strutils::format(_T("%s/CaseSensitive%02u"), SubstitutionFiltersRegPath, count);
215 int retvalCaseSensitive = m_pOptionsMgr->RemoveOption(filterCaseSensitive);
217 String filterMatchWholeWordOnly = strutils::format(_T("%s/MatchWholeWordOnly%02u"), SubstitutionFiltersRegPath, count);
218 int retvalMatchWholeWordOnly = m_pOptionsMgr->RemoveOption(filterMatchWholeWordOnly);
220 String filter0 = strutils::format(_T("%s/Pattern%02u"), SubstitutionFiltersRegPath, count);
221 int retval0 = m_pOptionsMgr->RemoveOption(filter0);
223 String filter1 = strutils::format(_T("%s/Replacement%02u"), SubstitutionFiltersRegPath, count);
224 int retval1 = m_pOptionsMgr->RemoveOption(filter1);
226 while (retvalEnabled == COption::OPT_OK || retvalUseRegExp == COption::OPT_OK ||
227 retvalCaseSensitive == COption::OPT_OK || retvalMatchWholeWordOnly == COption::OPT_OK ||
228 retval0 == COption::OPT_OK || retval1 == COption::OPT_OK)
231 filterEnabled = strutils::format(_T("%s/Enabled%02u"), SubstitutionFiltersRegPath, count);
232 retvalEnabled = m_pOptionsMgr->RemoveOption(filterEnabled);
233 filterUseRegExp = strutils::format(_T("%s/UseRegExp%02u"), SubstitutionFiltersRegPath, count);
234 retvalUseRegExp = m_pOptionsMgr->RemoveOption(filterUseRegExp);
235 filterCaseSensitive = strutils::format(_T("%s/CaseSensitive%02u"), SubstitutionFiltersRegPath, count);
236 retvalCaseSensitive = m_pOptionsMgr->RemoveOption(filterCaseSensitive);
237 filterMatchWholeWordOnly = strutils::format(_T("%s/MatchWholeWordOnly%02u"), SubstitutionFiltersRegPath, count);
238 retvalMatchWholeWordOnly = m_pOptionsMgr->RemoveOption(filterMatchWholeWordOnly);
239 filter0 = strutils::format(_T("%s/Pattern%02u"), SubstitutionFiltersRegPath, count);
240 retval0 = m_pOptionsMgr->RemoveOption(filter0);
241 filter1 = strutils::format(_T("%s/Replacement%02u"), SubstitutionFiltersRegPath, count);
242 retval1 = m_pOptionsMgr->RemoveOption(filter1);
246 std::shared_ptr<SubstitutionList> SubstitutionFiltersList::MakeSubstitutionList(bool throwIfInvalid)
249 std::shared_ptr<SubstitutionList> plist(new SubstitutionList);
250 for (auto& item : m_items)
252 if (item.enabled && !item.pattern.empty())
259 ucr::toUTF8(item.pattern),
260 ucr::toUTF8(item.replacement),
261 (item.caseSensitive ? 0 : Poco::RegularExpression::RE_CASELESS) |
262 Poco::RegularExpression::RE_MULTILINE);
267 ucr::toUTF8(item.pattern),
268 ucr::toUTF8(item.replacement),
269 item.caseSensitive, item.matchWholeWordOnly);
272 catch (const Poco::RegularExpressionException& e)
278 _snprintf_s(msg, _TRUNCATE, "#%d: %s", i + 1, e.message().c_str());
279 throw Poco::RegularExpressionException(msg, e.code());