m_pFilterList = list;
}
+void DiffUtils::SetIgnoredSubstitutionsList(FilterList* list0, FilterList* list1)
+{
+ m_pIgnoredSubstitutionsList0 = list0;
+ m_pIgnoredSubstitutionsList1 = list1;
+}
+
/**
* @brief Set filedata.
* @param [in] items Count of filedata items to set.
~DiffUtils();
void SetCompareOptions(const CompareOptions & options);
void SetFilterList(FilterList * list);
+ void SetIgnoredSubstitutionsList(FilterList* list0, FilterList* list1);
void ClearFilterList();
void SetFileData(int items, file_data *data);
int diffutils_compare_files();
private:
std::unique_ptr<DiffutilsOptions> m_pOptions; /**< Compare options for diffutils. */
FilterList * m_pFilterList; /**< Filter list for line filters. */
+ FilterList* m_pIgnoredSubstitutionsList0;
+ FilterList* m_pIgnoredSubstitutionsList1;
file_data * m_inf; /**< Compared files data (for diffutils). */
int m_ndiffs; /**< Real diffs found. */
int m_ntrivialdiffs; /**< Ignored diffs found. */
, m_piAbortable(nullptr)
, m_bStopAfterFirstDiff(false)
, m_pFilterList(nullptr)
+, m_pTokenListsForIs{ nullptr, nullptr }
, m_pContentCompareOptions(nullptr)
, m_pQuickCompareOptions(nullptr)
, m_pOptions(nullptr)
bool m_bRecursive; /**< Do we include subfolders to compare? */
bool m_bPluginsEnabled; /**< Are plugins enabled? */
std::unique_ptr<FilterList> m_pFilterList; /**< Filter list for line filters */
+ std::unique_ptr<FilterList> m_pTokenListsForIs[2]; /// Two lists for Ignored Substitutions
private:
/**
#include "parsers/crystallineparser.h"
#include "SyntaxColors.h"
#include "MergeApp.h"
+#include "OptionsMgr.h"
+#include "OptionsDef.h"
+#include "TokenPairList.h"
+#include "stringdiffs.h"
+using namespace strdiff;
+
using Poco::Debugger;
using Poco::format;
, m_pDiffList(nullptr)
, m_bPathsAreTemp(false)
, m_pFilterList(nullptr)
+, m_pIgnoredSubstitutionsList{nullptr}
, m_bPluginsEnabled(false)
, m_status()
{
return linesMatch;
}
+bool MatchDiffVsIngoredSubstitutions
+(
+ const std::string &fullLine0,
+ const std::string &fullLine1,
+ const strdiff::wdiff &diff,
+ const IgnoredSubstitutionsFilterList &ignoredSubstitutionsList,
+ const bool optUseRegexpsForIgnoredSubstitutions,
+ const bool optMatchBothWays
+)
+{
+ int changeStartPos[2] = { diff.begin[0], diff.begin[1] };
+ int changeEndPos[2] = { diff.end[0], diff.end[1] };
+ int changeLen0 = changeEndPos[0] - changeStartPos[0] + 1;
+ int changeLen1 = changeEndPos[1] - changeStartPos[1] + 1;
+ std::string change0 = std::string(fullLine0.c_str() + changeStartPos[0], changeLen0);
+ std::string change1 = std::string(fullLine1.c_str() + changeStartPos[1], changeLen1);
+
+ size_t numIgnoredSubstitutions = ignoredSubstitutionsList.GetCount();
+
+ for (int f = 0; f < numIgnoredSubstitutions; f++)
+ {
+ const IgnoredSusbstitutionItem& filter = ignoredSubstitutionsList[f];
+ // Check if the common prefix and suffix fit into the line around the change
+ if
+ (
+ changeStartPos[0] < filter.CommonPrefixLength
+ || changeStartPos[1] < filter.CommonPrefixLength
+ || changeEndPos[0] >= fullLine0.length() - filter.CommonSuffixLength
+ || changeEndPos[1] >= fullLine1.length() - filter.CommonSuffixLength
+ )
+ continue; /// This filter does not fit into the line with its suffix and prefix
+
+ // Check if the common prefix and suffix match
+ bool continueWithNextFilter = false;
+ for (int p = 1; p <= filter.CommonPrefixLength; p++)
+ {
+ char char0 = fullLine0[changeStartPos[0] - p];
+ char char1 = fullLine1[changeStartPos[1] - p];
+ if (char0 != char1)
+ {
+ continueWithNextFilter = true;
+ break;
+ }
+ }
+
+ for (int s = 1; s <= filter.CommonSuffixLength; s++)
+ {
+ char char0 = fullLine0[changeEndPos[0] + s];
+ char char1 = fullLine1[changeEndPos[1] + s];
+ if (char0 != char1)
+ {
+ continueWithNextFilter = true;
+ break;
+ }
+ }
+
+ if (continueWithNextFilter)
+ continue;
+
+ if(optUseRegexpsForIgnoredSubstitutions)
+ {
+
+ if
+ (
+ ignoredSubstitutionsList.MatchBoth(f, change0, change1)
+ ||
+ optMatchBothWays
+ && ignoredSubstitutionsList.MatchBoth(f, change1, change0)
+ )
+ {
+ return true; /// a match found
+ }
+ }
+ else
+ {
+ if
+ (
+ filter.ChangedPart[0].compare(change0) == 0
+ && filter.ChangedPart[1].compare(change1) == 0
+ ||
+ optMatchBothWays
+ && filter.ChangedPart[0].compare(change1) == 0
+ && filter.ChangedPart[1].compare(change0) == 0
+ )
+ {
+ return true; /// a match found
+ }
+ }
+ }
+
+ return false; /// n0 match found
+}
+
/**
* @brief Walk the diff utils change script, building the WinMerge list of diff blocks
*/
struct change *next = script;
+ const bool optCompletelyBlankOutIgnoredSubstitutions = GetOptionsMgr()->GetBool(OPT_COMPLETELY_BLANK_OUT_IGNORED_SUBSTITUTIONS);
+ const bool optMatchBothWays = GetOptionsMgr()->GetBool(OPT_IGNORED_SUBSTITUTIONS_WORK_BOTH_WAYS);
+ const bool optUseRegexpsForIgnoredSubstitutions = GetOptionsMgr()->GetBool(OPT_USE_REGEXPS_FOR_IGNORED_SUBSTITUTIONS);
+
while (next != nullptr)
{
/* Find a set of changes that belong together. */
op = OP_TRIVIAL;
}
+ /// Handling Ignored Substitutions
+ if
+ (
+ op == OP_DIFF
+ //&& next != nullptr
+ && QtyLinesLeft > 0
+ && QtyLinesRight > 0
+ && m_files.GetSize() == 2
+ && m_pIgnoredSubstitutionsList
+ && m_pIgnoredSubstitutionsList->GetCount()
+ )
+ {
+ size_t len = file_data_ary[0].linbuf[thisob->line0 + 1] - file_data_ary[0].linbuf[thisob->line0];
+ const char* string = file_data_ary[0].linbuf[thisob->line0];
+ size_t stringlen = linelen(string, len);
+ std::string fullLine0 = std::string(string, stringlen);
+
+ len = file_data_ary[1].linbuf[thisob->line1 + 1] - file_data_ary[1].linbuf[thisob->line1];
+ string = file_data_ary[1].linbuf[thisob->line1];
+ stringlen = linelen(string, len);
+ std::string fullLine1 = std::string(string, stringlen);
+
+ bool case_sensitive = false;
+ bool eol_sensitive = false;
+ int whitespace = WHITESPACE_IGNORE_CHANGE;
+ int breakType = 1;// breakType==1 means break also on punctuation
+ bool byte_level = true;
+ std::vector<wdiff> worddiffs = ComputeWordDiffs(
+ ucr::toTString(fullLine0.c_str()), ucr::toTString(fullLine1.c_str()),
+ case_sensitive, eol_sensitive, whitespace, breakType, byte_level
+ );
+
+ if (!worddiffs.empty())
+ {
+ bool lineShouldBeIgnored = true; /// If all changes are ignored the line is ignored
+ for (std::vector<strdiff::wdiff>::const_iterator diffIt = worddiffs.begin(); diffIt != worddiffs.end(); ++diffIt)
+ {
+ if(!MatchDiffVsIngoredSubstitutions
+ (
+ fullLine0, fullLine1,
+ *diffIt,
+ *m_pIgnoredSubstitutionsList, optUseRegexpsForIgnoredSubstitutions,
+ optMatchBothWays
+ ))
+ {
+ lineShouldBeIgnored = false;
+ }
+ }
+
+ if (lineShouldBeIgnored)
+ {
+ if(optCompletelyBlankOutIgnoredSubstitutions)
+ op = OP_NONE;
+ else
+ op = OP_TRIVIAL;
+ }
+ }
+ }
+
AddDiffRange(m_pDiffList, trans_a0-1, trans_b0-1, trans_a1-1, trans_b1-1, op);
}
}
}
}
+IgnoredSubstitutionsFilterList* CDiffWrapper::GetIgnoredSubstitutionsList()
+{
+ return m_pIgnoredSubstitutionsList.get();
+}
+
+void CDiffWrapper::SetIgnoredSubstitutionsList(const FilterList* pIgnoredSubstitutionsList0, const FilterList* pIgnoredSubstitutionsList1)
+{
+ m_pIgnoredSubstitutionsList.reset(new IgnoredSubstitutionsFilterList());
+
+ if (!pIgnoredSubstitutionsList0 || pIgnoredSubstitutionsList0->GetCount() == 0)
+ {
+ m_pIgnoredSubstitutionsList.reset();
+ return;
+ }
+
+ const bool optUseRegexpsForIgnoredSubstitutions = GetOptionsMgr()->GetBool(OPT_USE_REGEXPS_FOR_IGNORED_SUBSTITUTIONS);
+
+ for (int f = 0; f < pIgnoredSubstitutionsList0->GetCount(); f++)
+ {
+ std::string s0 = (*pIgnoredSubstitutionsList0)[f].filterAsString;
+ std::string s1 = (*pIgnoredSubstitutionsList1)[f].filterAsString;
+ m_pIgnoredSubstitutionsList->Add(s0, s1, !optUseRegexpsForIgnoredSubstitutions);
+ }
+}
+
+void CDiffWrapper::SetIgnoredSubstitutionsList(const TokenPairList *ignoredSubstitutionsList)
+{
+ m_pIgnoredSubstitutionsList.reset(new IgnoredSubstitutionsFilterList());
+
+ // Remove filterlist if new filter is empty
+ if (!ignoredSubstitutionsList || ignoredSubstitutionsList->GetCount() == 0)
+ {
+ m_pIgnoredSubstitutionsList.reset();
+ return;
+ }
+
+ const bool optUseRegexpsForIgnoredSubstitutions = GetOptionsMgr()->GetBool(OPT_USE_REGEXPS_FOR_IGNORED_SUBSTITUTIONS);
+
+ for (int f = 0; f < ignoredSubstitutionsList->GetCount(); f++)
+ {
+ std::string s0 = ucr::toUTF8(ignoredSubstitutionsList->GetAt(f).filterStr0.c_str());
+ std::string s1 = ucr::toUTF8(ignoredSubstitutionsList->GetAt(f).filterStr1.c_str());
+ if(s0 != s1)
+ m_pIgnoredSubstitutionsList->Add(s0, s1, !optUseRegexpsForIgnoredSubstitutions);
+ }
+}
+
void CDiffWrapper::SetFilterCommentsSourceDef(const String& ext)
{
m_pFilterCommentsDef = CrystalLineParser::GetTextType(ext.c_str());
struct file_data;
class MovedLines;
class FilterList;
+class IgnoredSubstitutionsFilterList;
namespace CrystalLineParser { struct TextDefinition; };
/** @enum COMPARE_TYPE
void WritePatchFileTerminator(enum output_style output_style);
void SetFilterList(const String& filterStr);
void SetFilterList(const FilterList *pFilterList);
+ IgnoredSubstitutionsFilterList *GetIgnoredSubstitutionsList();
+ void SetIgnoredSubstitutionsList(const FilterList* pIgnoredSubstitutionsList0, const FilterList* pIgnoredSubstitutionsList1);
+ void SetIgnoredSubstitutionsList(const class TokenPairList *ignoredSubstitutionsList);
void SetFilterCommentsSourceDef(CrystalLineParser::TextDefinition *def) { m_pFilterCommentsDef = def; };
void SetFilterCommentsSourceDef(const String& ext);
void EnablePlugins(bool enable);
static void FreeDiffUtilsScript(struct change * & script);
bool RegExpFilter(int StartPos, int EndPos, const file_data * pinf) const;
+ IgnoredSubstitutionsFilterList *GetIgnoredSubstitutionsList(int index) const
+ {
+ return m_pIgnoredSubstitutionsList.get();
+ }
+
private:
DiffutilsOptions m_options;
DIFFSTATUS m_status; /**< Status of last compare */
std::unique_ptr<FilterList> m_pFilterList; /**< List of linefilters. */
+ std::unique_ptr<IgnoredSubstitutionsFilterList> m_pIgnoredSubstitutionsList;
+
PathContext m_files; /**< Full path to diff'ed file. */
PathContext m_alternativePaths; /**< file's alternative path (may be relative). */
PathContext m_originalFile; /**< file's original (NON-TEMP) path. */
#include "OptionsMgr.h"
#include "OptionsDiffOptions.h"
#include "LineFiltersList.h"
+#include "TokenPairList.h"
#include "FileFilterHelper.h"
#include "unicoder.h"
#include "DirActions.h"
pCtxt->m_pFilterList->AddRegExp(*it);
}
+void CDirDoc::LoadTokensForIgnoredSubstitutions(CDiffContext* pCtxt)
+{
+ ASSERT(pCtxt != nullptr);
+
+ bool ignoredSubstitutionsAreEnabled = GetOptionsMgr()->GetBool(OPT_IGNORED_SUBSTITUTIONS_ARE_ENABLED);
+ if (!ignoredSubstitutionsAreEnabled || theApp.m_pTokensForIs->GetCount() == 0)
+ {
+ pCtxt->m_pTokenListsForIs[0].reset();
+ pCtxt->m_pTokenListsForIs[1].reset();
+ return;
+ }
+
+ if (pCtxt->m_pTokenListsForIs[0])
+ pCtxt->m_pTokenListsForIs[0]->RemoveAllFilters();
+ else
+ pCtxt->m_pTokenListsForIs[0].reset(new FilterList());
+
+ if (pCtxt->m_pTokenListsForIs[1])
+ pCtxt->m_pTokenListsForIs[1]->RemoveAllFilters();
+ else
+ pCtxt->m_pTokenListsForIs[1].reset(new FilterList());
+
+ for (int f = 0; f < theApp.m_pTokensForIs->GetCount(); f++)
+ {
+ const TokenPair &tokenPair = theApp.m_pTokensForIs->GetAt(f);
+ pCtxt->m_pTokenListsForIs[0]->AddRegExp(ucr::toUTF8(tokenPair.filterStr0));
+ pCtxt->m_pTokenListsForIs[1]->AddRegExp(ucr::toUTF8(tokenPair.filterStr1));
+ }
+}
+
void CDirDoc::DiffThreadCallback(int& state)
{
PostMessage(m_pDirView->GetSafeHwnd(), MSG_UI_UPDATE, state, false);
void CDirDoc::InitDiffContext(CDiffContext *pCtxt)
{
LoadLineFilterList(pCtxt);
+ LoadTokensForIgnoredSubstitutions(pCtxt);
DIFFOPTIONS options = {0};
Options::DiffOptions::Load(GetOptionsMgr(), options);
protected:
void InitDiffContext(CDiffContext *pCtxt);
void LoadLineFilterList(CDiffContext *pCtxt);
+ void LoadTokensForIgnoredSubstitutions(CDiffContext* pCtxt);
// Generated message map functions
//{{AFX_MSG(CDirDoc)
return retval;
}
+static std::string ExtractCommonPrefix(const std::string& str0, const std::string& str1)
+{
+ size_t strlen0 = str0.length();
+ size_t strlen1 = str1.length();
+ size_t minStrlen = strlen0 < strlen1 ? strlen0 : strlen1;
+ for (size_t c = 0; c < minStrlen; c++)
+ {
+ if (str0[c] != str1[c])
+ return str0.substr(0, c);
+ }
+ return strlen0 < strlen1 ? str0 : str1;
+}
+
+static std::string ExtractCommonSuffix(const std::string& str0, const std::string& str1)
+{
+ size_t strlen0 = str0.length();
+ size_t strlen1 = str1.length();
+ size_t minStrlen = strlen0 < strlen1 ? strlen0 : strlen1;
+ for (size_t c = 0; c < minStrlen; c++)
+ {
+ if (str0[strlen0 - 1 - c] != str1[strlen1 - 1 - c])
+ return str0.substr(strlen0 - c, c);
+ }
+ return strlen0 < strlen1 ? str0 : str1;
+}
+
+template<int index>
+static std::string ExtractMiddleChangedPart(const std::string& str0, const std::string& str1)
+{
+ size_t strlen[2]{ str0.length(), str1.length() };
+ size_t minStrlen = strlen[0] < strlen[1] ? strlen[0] : strlen[1];
+ size_t diffStart = 0;
+ while (diffStart < minStrlen && str0[diffStart] == str1[diffStart])
+ diffStart++;
+ size_t diffEnd = minStrlen - 1;
+ while (diffEnd < minStrlen && str0[strlen[0] - 1 - diffEnd] == str1[strlen[1] - 1 - diffEnd])
+ diffEnd++;
+
+ const std::string* strs[2]{ &str0, &str1 };
+ return strs[index]->substr(diffStart, strlen[index] - diffEnd - 1);
+}
+
+IgnoredSusbstitutionItem::IgnoredSusbstitutionItem
+(
+ const std::string& filter0, const std::string& filter1,
+ int regexpCompileOptions, bool extractCommonSufixAndPrefix
+)
+ : CommonPrefix(extractCommonSufixAndPrefix ? ExtractCommonPrefix(filter0, filter1) : "")
+ , CommonPrefixLength(CommonPrefix.length())
+ , ChangedPart
+ {
+ extractCommonSufixAndPrefix ? ExtractMiddleChangedPart<0>(filter0, filter1) : filter0,
+ extractCommonSufixAndPrefix ? ExtractMiddleChangedPart<1>(filter0, filter1) : filter1
+ }
+ , CommonSuffix(extractCommonSufixAndPrefix ? ExtractCommonSuffix(filter0, filter1) : "")
+ , CommonSuffixLength(CommonSuffix.length())
+ , ChangedPartRegexp
+ {
+ Poco::RegularExpression(ChangedPart[0], regexpCompileOptions),
+ Poco::RegularExpression(ChangedPart[1], regexpCompileOptions)
+ }
+{
+}
+
+IgnoredSubstitutionsFilterList::IgnoredSubstitutionsFilterList()
+{
+}
+
+IgnoredSubstitutionsFilterList::~IgnoredSubstitutionsFilterList()
+{
+ RemoveAllFilters();
+}
+
+void IgnoredSubstitutionsFilterList::Add(const std::string& change0, const std::string& change1, bool extractCommonSufixAndPrefix)
+{
+ try
+ {
+ m_list.push_back
+ (
+ std::shared_ptr<IgnoredSusbstitutionItem>(
+ new IgnoredSusbstitutionItem(change0, change1, RegularExpression::RE_UTF8, extractCommonSufixAndPrefix)
+ ));
+ }
+ catch (...)
+ {
+ // TODO:
+ }
+}
+
+bool IgnoredSubstitutionsFilterList::MatchBoth
+(
+ size_t filterIndex,
+ const std::string& string0,
+ const std::string& string1,
+ int codepage/*=CP_UTF8*/
+) const
+{
+ bool retval = false;
+ const size_t count = m_list.size();
+
+ if (filterIndex >= count)
+ return false;
+
+ // convert string into UTF-8
+ ucr::buffer buf0(string0.length() * 2);
+ ucr::buffer buf1(string1.length() * 2);
+
+ if (codepage != ucr::CP_UTF_8)
+ {
+ ucr::convert(ucr::NONE, codepage, reinterpret_cast<const unsigned char*>(string0.c_str()),
+ string0.length(), ucr::UTF8, ucr::CP_UTF_8, &buf0);
+ ucr::convert(ucr::NONE, codepage, reinterpret_cast<const unsigned char*>(string1.c_str()),
+ string1.length(), ucr::UTF8, ucr::CP_UTF_8, &buf1);
+ }
+
+ const IgnoredSusbstitutionItem &item = *m_list[filterIndex];
+ int result = 0;
+ RegularExpression::Match match;
+ try
+ {
+ if (buf0.size > 0 && buf1.size > 0)
+ {
+ result =
+ item.ChangedPartRegexp[0].match(std::string(reinterpret_cast<const char*>(buf0.ptr), buf0.size), 0, match)
+ && item.ChangedPartRegexp[1].match(std::string(reinterpret_cast<const char*>(buf1.ptr), buf1.size), 0, match);
+ }
+ else
+ {
+ result =
+ item.ChangedPartRegexp[0].match(string0, 0, match)
+ && item.ChangedPartRegexp[1].match(string1, 0, match);
+ }
+ }
+ catch (...)
+ {
+ // TODO:
+ }
+ if (result > 0)
+ {
+ retval = true;
+ }
+
+ return retval;
+}
+
+void IgnoredSubstitutionsFilterList::RemoveAllFilters()
+{
+ m_list.clear();
+}
+
+bool IgnoredSubstitutionsFilterList::HasRegExps() const
+{
+ return !m_list.empty();
+}
+
+const IgnoredSusbstitutionItem &IgnoredSubstitutionsFilterList::operator[](int index) const
+{
+ return *m_list[index];
+}
+
+
void AddRegExp(const std::string& regularExpression);
void RemoveAllFilters();
bool HasRegExps() const;
+ size_t GetCount() const { return m_list.size(); }
bool Match(const std::string& string, int codepage = ucr::CP_UTF_8);
const char * GetLastMatchExpression() const;
+ const filter_item& operator[](int index) const;
private:
std::vector <filter_item_ptr> m_list;
};
+struct IgnoredSusbstitutionItem
+{
+ std::string CommonPrefix;
+ size_t CommonPrefixLength;
+ std::string ChangedPart[2];
+ std::string CommonSuffix;
+ size_t CommonSuffixLength;
+ Poco::RegularExpression ChangedPartRegexp[2]; /**< Compiled regular expression */
+
+ IgnoredSusbstitutionItem
+ (
+ const std::string& filter0, const std::string& filter1,
+ int regexpCompileOptions, bool extractCommonSufixAndPrefix
+ );
+};
+
+class IgnoredSubstitutionsFilterList
+{
+public:
+ IgnoredSubstitutionsFilterList();
+ ~IgnoredSubstitutionsFilterList();
+
+ void Add(const std::string& change0, const std::string& change1, bool extractCommonSufixAndPrefix);
+ void RemoveAllFilters();
+ bool HasRegExps() const;
+ size_t GetCount() const { return m_list.size(); }
+ bool MatchBoth
+ (
+ size_t filterIndex,
+ const std::string& string0,
+ const std::string& string1,
+ int codepage = CP_UTF8
+ ) const;
+ const IgnoredSusbstitutionItem &operator[](int index) const;
+
+private:
+ std::vector<std::shared_ptr<IgnoredSusbstitutionItem>> m_list;
+};
+
/**
* @brief Removes all expressions from the list.
*/
{
return m_lastMatchExpression->c_str();
}
+
+inline const filter_item& FilterList::operator[](int index) const
+{
+ const filter_item_ptr &item = m_list[index];
+ return *item;
+}
+
dw.SetCompareFiles(tFiles);
dw.SetOptions(m_pCtxt->GetOptions());
dw.SetFilterList(m_pCtxt->m_pFilterList.get());
+ dw.SetIgnoredSubstitutionsList(m_pCtxt->m_pTokenListsForIs[0].get(), m_pCtxt->m_pTokenListsForIs[1].get());
dw.SetFilterCommentsSourceDef(Ext);
dw.SetCreateDiffList(&diffList);
dw.LoadWinMergeDiffsFromDiffUtilsScript3(
--- /dev/null
+/**
+ * @file IgnoredSubstitutionsFiltersDlg.cpp
+ *
+ * @brief Implementation of Line Filter dialog
+ */
+
+#include "stdafx.h"
+#include "TokenPairList.h"
+#include "Merge.h"
+#include "IgnoredSubstitutionsDlg.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#endif
+
+/** @brief Location for file compare specific help to open. */
+static TCHAR FilterHelpLocation[] = _T("::/htmlhelp/Filters.html");
+
+/////////////////////////////////////////////////////////////////////////////
+// CPropLineFilter property page
+
+IMPLEMENT_DYNAMIC(IgnoredSubstitutionsDlg, CTrPropertyPage)
+
+/**
+ * @brief Constructor.
+ */
+IgnoredSubstitutionsDlg::IgnoredSubstitutionsDlg()
+ : CTrPropertyPage(IgnoredSubstitutionsDlg::IDD)
+ , m_pExternalRenameList(nullptr)
+ , InPlaceEdit(nullptr)
+{
+ //{{AFX_DATA_INIT(IgnoredSubstitutionsFiltersDlg)
+ m_IgnoredSubstitutionsAreEnabled = false;
+ m_IgnoredSubstitutionsWorkBothWays = false;
+ m_CompletelyBlankOutIgnoredSubstitutions = false;
+ m_UseRegexpsForIgnoredSubstitutions = false;
+ //}}AFX_DATA_INIT
+ m_strCaption = theApp.LoadDialogCaption(m_lpszTemplateName).c_str();
+ m_psp.pszTitle = m_strCaption;
+ m_psp.dwFlags |= PSP_USETITLE;
+ m_psp.hIcon = AfxGetApp()->LoadIcon(IDI_LINEFILTER);
+ m_psp.dwFlags |= PSP_USEHICON;
+}
+
+void IgnoredSubstitutionsDlg::DoDataExchange(CDataExchange* pDX)
+{
+ CPropertyPage::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(IgnoredSubstitutionsFiltersDlg)
+ DDX_Check(pDX, IDC_IGNORED_SUSBSTITUTIONS_ARE_ENABLED, m_IgnoredSubstitutionsAreEnabled);
+ DDX_Check(pDX, IDC_IGNORED_SUSBSTITUTIONS_WORK_BOTH_WAYS, m_IgnoredSubstitutionsWorkBothWays);
+ DDX_Check(pDX, IDC_COMPLETELY_BLANK_OUT_IGNORED_SUBSTITUTIONS, m_CompletelyBlankOutIgnoredSubstitutions);
+ DDX_Check(pDX, IDC_USE_REGEXPS_FOR_IGNORED_SUBSTITUTIONS, m_UseRegexpsForIgnoredSubstitutions);
+ //}}AFX_DATA_MAP
+ DDX_Control(pDX, IDC_IGNORED_SUBSTITUTIONS_FILTER, m_VisibleFiltersList);
+}
+
+BEGIN_MESSAGE_MAP(IgnoredSubstitutionsDlg, CTrPropertyPage)
+ //{{AFX_MSG_MAP(IgnoredSubstitutionsFiltersDlg)
+ ON_COMMAND(ID_HELP, OnHelp)
+ //}}AFX_MSG_MAP
+ ON_BN_CLICKED(IDC_LFILTER_ADDBTN, OnBnClickedAddBtn)
+ ON_BN_CLICKED(IDC_LFILTER_CLEARBTN, OnBnClickedClearBtn)
+ ON_BN_CLICKED(IDC_LFILTER_REMOVEBTN, OnBnClickedRemovebtn)
+ ON_NOTIFY(LVN_ENDLABELEDIT, IDC_IGNORED_SUBSTITUTIONS_FILTER, OnEndLabelEdit)
+END_MESSAGE_MAP()
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CPropLineFilter message handlers
+
+/**
+ * @brief Initialize the dialog.
+ */
+BOOL IgnoredSubstitutionsDlg::OnInitDialog()
+{
+ CTrPropertyPage::OnInitDialog();
+
+ InitList();
+
+ return TRUE; // return TRUE unless you set the focus to a control
+ // EXCEPTION: OCX Property Pages should return FALSE
+}
+
+
+void IgnoredSubstitutionsDlg::InitList()
+{
+ m_VisibleFiltersList.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP);
+ //m_VisibleFiltersList.SetExtendedStyle(LVS_EX_INFOTIP | LVS_EX_GRIDLINES);
+
+ const int lpx = CClientDC(this).GetDeviceCaps(LOGPIXELSX);
+ auto pointToPixel = [lpx](int point) { return MulDiv(point, lpx, 72); };
+
+ m_VisibleFiltersList.InsertColumn(0, _("On one panel").c_str(), LVCFMT_LEFT, pointToPixel(112));
+ m_VisibleFiltersList.InsertColumn(1, _("On the other panel").c_str(), LVCFMT_LEFT, pointToPixel(262));
+
+ if (m_pExternalRenameList)
+ {
+ for (int i = 0; i < (int)m_pExternalRenameList->GetCount(); i++)
+ {
+ const TokenPair& item = m_pExternalRenameList->GetAt(i);
+ m_VisibleFiltersList.InsertItem(i, item.filterStr0.c_str());
+ m_VisibleFiltersList.SetItemText(i, 1, item.filterStr1.c_str());
+ }
+ }
+}
+
+/**
+ * @brief Open help from mainframe when user presses F1.
+ */
+void IgnoredSubstitutionsDlg::OnHelp()
+{
+ theApp.ShowHelp(FilterHelpLocation);
+}
+
+/**
+ * @brief Called when Add-button is clicked.
+ */
+void IgnoredSubstitutionsDlg::OnBnClickedAddBtn()
+{
+ int num = m_VisibleFiltersList.GetItemCount();
+ int ind = m_VisibleFiltersList.InsertItem(num, _("<Edit here>").c_str());
+ m_VisibleFiltersList.SetItemText(num, 1, _("<Edit here>").c_str());
+
+ if (ind >= -1)
+ {
+ m_VisibleFiltersList.SetItemState(ind, LVIS_SELECTED, LVIS_SELECTED);
+ m_VisibleFiltersList.EnsureVisible(ind, FALSE);
+ //EditSelectedFilter();
+ }
+}
+
+/**
+ * @brief Called when Clear-button is clicked.
+ */
+void IgnoredSubstitutionsDlg::OnBnClickedClearBtn()
+{
+ m_VisibleFiltersList.DeleteAllItems();
+}
+
+/**
+ * @brief Save filters to list when exiting the dialog.
+ */
+void IgnoredSubstitutionsDlg::OnOK()
+{
+ m_pExternalRenameList->Empty();
+
+ for (int i = 0; i < m_VisibleFiltersList.GetItemCount(); i++)
+ {
+ String symbolBeforeRename = m_VisibleFiltersList.GetItemText(i, 0);
+ String symbolAfterRename = m_VisibleFiltersList.GetItemText(i, 1);
+ if(symbolBeforeRename != _("<Edit here>") && symbolAfterRename != _("<Edit here>"))
+ m_pExternalRenameList->AddFilter(symbolBeforeRename, symbolAfterRename);
+ }
+
+ CPropertyPage::OnClose();
+ //CDialog::OnOK(); //?
+}
+
+/**
+ * @brief Sets external filter list.
+ * @param [in] list External filter list.
+ */
+void IgnoredSubstitutionsDlg::SetList(TokenPairList *list)
+{
+ m_pExternalRenameList = list;
+}
+
+/**
+ * @brief Called when Remove button is clicked.
+ */
+void IgnoredSubstitutionsDlg::OnBnClickedRemovebtn()
+{
+ int sel = m_VisibleFiltersList.GetNextItem(-1, LVNI_SELECTED);
+ if (sel != -1)
+ {
+ m_VisibleFiltersList.DeleteItem(sel);
+ }
+
+ int newSel = min(m_VisibleFiltersList.GetItemCount() - 1, sel);
+ if (newSel >= -1)
+ {
+ m_VisibleFiltersList.SetItemState(newSel, LVIS_SELECTED, LVIS_SELECTED);
+ bool bPartialOk = false;
+ m_VisibleFiltersList.EnsureVisible(newSel, bPartialOk);
+ }
+}
+
+/**
+ * @brief Called when the user activates an item.
+ */
+// void IgnoredSubstitutionsFiltersDlg::OnLvnItemActivate(NMHDR *pNMHDR, LRESULT *pResult)
+// {
+// EditSelectedFilter();
+// *pResult = 0;
+// }
+
+/**
+ * @brief Called when in-place editing has finished.
+ */
+void IgnoredSubstitutionsDlg::OnEndLabelEdit(NMHDR *pNMHDR, LRESULT *pResult)
+{
+ m_VisibleFiltersList.OnEndLabelEdit(pNMHDR, pResult);
+}
--- /dev/null
+/**
+ * @file IgnoredSubstitutionsDlg.h
+ *
+ * @brief Declaration file for Line Filter dialog
+ *
+ */
+#pragma once
+
+#include "TrDialogs.h"
+#include "SubeditList.h"
+
+class IgnoredSubstitutionFiltersList;
+
+class IgnoredSubstitutionsDlg : public CTrPropertyPage
+{
+ DECLARE_DYNAMIC(IgnoredSubstitutionsDlg)
+
+// Construction
+public:
+ IgnoredSubstitutionsDlg();
+
+ void SetList(TokenPairList *list);
+
+// Dialog Data
+ //{{AFX_DATA(IgnoredSubstitutionsDlg)
+ enum { IDD = IDD_IGNORED_SUSBSTITUTIONS_DLG };
+ bool m_IgnoredSubstitutionsAreEnabled;
+ bool m_IgnoredSubstitutionsWorkBothWays;
+ bool m_CompletelyBlankOutIgnoredSubstitutions;
+ bool m_UseRegexpsForIgnoredSubstitutions;
+ //}}AFX_DATA
+
+// Overrides
+ // ClassWizard generate virtual function overrides
+ //{{AFX_VIRTUAL(IgnoredSubstitutionsDlg)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+
+ // Generated message map functions
+ //{{AFX_MSG(IgnoredSubstitutionsDlg)
+ virtual BOOL OnInitDialog() override;
+ afx_msg void OnHelp();
+ virtual void OnOK() override;
+ afx_msg void OnMouseMove(UINT nFlags, CPoint point);
+ afx_msg void OnBnClickedAddBtn();
+ afx_msg void OnBnClickedClearBtn();
+ afx_msg void OnBnClickedEditbtn();
+ afx_msg void OnBnClickedRemovebtn();
+ afx_msg void OnLvnItemActivate(NMHDR *pNMHDR, LRESULT *pResult);
+ afx_msg void OnLvnKeyDown(NMHDR *pNMHDR, LRESULT *pResult);
+ afx_msg void OnEndLabelEdit(NMHDR* pNMHDR, LRESULT* pResult);
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+ void InitList();
+
+private:
+ std::unique_ptr<CInPlaceEdit> InPlaceEdit;
+
+ CSubeditList m_VisibleFiltersList; /**< List control having filter strings */
+
+ TokenPairList *m_pExternalRenameList;
+};
using std::vector;
/** @brief Registry key for saving linefilters. */
-static const TCHAR FiltersRegPath[] =_T("LineFilters");
+static const TCHAR LineFiltersRegPath[] = _T("LineFilters");
/**
* @brief Default constructor.
void LineFiltersList::Initialize(COptionsMgr *pOptionsMgr)
{
assert(pOptionsMgr != nullptr);
- String valuename(FiltersRegPath);
+ String valuename(LineFiltersRegPath);
m_pOptionsMgr = pOptionsMgr;
for (unsigned i = 0; i < count; i++)
{
- String name = strutils::format(_T("%s/Filter%02u"), FiltersRegPath, i);
+ String name = strutils::format(_T("%s/Filter%02u"), LineFiltersRegPath, i);
m_pOptionsMgr->InitOption(name, _T(""));
String filter = m_pOptionsMgr->GetString(name);
- name = strutils::format(_T("%s/Enabled%02u"), FiltersRegPath, i);
+ name = strutils::format(_T("%s/Enabled%02u"), LineFiltersRegPath, i);
m_pOptionsMgr->InitOption(name, (int)true);
int enabled = m_pOptionsMgr->GetInt(name);
bool bEnabled = enabled ? true : false;
void LineFiltersList::SaveFilters()
{
assert(m_pOptionsMgr != nullptr);
- String valuename(FiltersRegPath);
+ String valuename(LineFiltersRegPath);
size_t count = m_items.size();
valuename += _T("/Values");
{
const LineFilterItemPtr& item = m_items[i];
- String name = strutils::format(_T("%s/Filter%02u"), FiltersRegPath, i);
+ String name = strutils::format(_T("%s/Filter%02u"), LineFiltersRegPath, i);
m_pOptionsMgr->InitOption(name, _T(""));
m_pOptionsMgr->SaveOption(name, item->filterStr);
- name = strutils::format(_T("%s/Enabled%02u"), FiltersRegPath, i);
+ name = strutils::format(_T("%s/Enabled%02u"), LineFiltersRegPath, i);
m_pOptionsMgr->InitOption(name, 0);
m_pOptionsMgr->SaveOption(name, (int)item->enabled);
}
// Remove options we don't need anymore
// We could have earlier 10 pcs but now we only need 5
- String filter = strutils::format(_T("%s/Filter%02u"), FiltersRegPath, count);
+ String filter = strutils::format(_T("%s/Filter%02u"), LineFiltersRegPath, count);
int retval1 = m_pOptionsMgr->RemoveOption(filter);
- filter = strutils::format(_T("%s/Enabled%02u"), FiltersRegPath, count);
+ filter = strutils::format(_T("%s/Enabled%02u"), LineFiltersRegPath, count);
int retval2 = m_pOptionsMgr->RemoveOption(filter);
while (retval1 == COption::OPT_OK || retval2 == COption::OPT_OK)
{
++count;
- filter = strutils::format(_T("%s/Filter%02u"), FiltersRegPath, count);
+ filter = strutils::format(_T("%s/Filter%02u"), LineFiltersRegPath, count);
retval1 = m_pOptionsMgr->RemoveOption(filter);
- filter = strutils::format(_T("%s/Enabled%02u"), FiltersRegPath, count);
+ filter = strutils::format(_T("%s/Enabled%02u"), LineFiltersRegPath, count);
retval2 = m_pOptionsMgr->RemoveOption(filter);
}
}
#include "HexMergeView.h"
#include "ImgMergeFrm.h"
#include "LineFiltersList.h"
+#include "TokenPairList.h"
#include "ConflictFileParser.h"
#include "LineFiltersDlg.h"
+#include "IgnoredSubstitutionsDlg.h"
#include "paths.h"
#include "Environment.h"
#include "PatchTool.h"
String title = _("Filters");
CPropertySheet sht(title.c_str());
LineFiltersDlg lineFiltersDlg;
+ IgnoredSubstitutionsDlg ignoredSubstitutionsFiltersDlg;
FileFiltersDlg fileFiltersDlg;
std::unique_ptr<LineFiltersList> lineFilters(new LineFiltersList());
+ std::unique_ptr<TokenPairList> ignoredSubstitutionsFilters(new TokenPairList());
String selectedFilter;
const String origFilter = theApp.m_pGlobalFileFilter->GetFilterNameOrMask();
sht.AddPage(&fileFiltersDlg);
sht.AddPage(&lineFiltersDlg);
+ sht.AddPage(&ignoredSubstitutionsFiltersDlg);
sht.m_psh.dwFlags |= PSH_NOAPPLYNOW; // Hide 'Apply' button since we don't need it
// Make sure all filters are up-to-date
lineFilters->CloneFrom(theApp.m_pLineFilters.get());
lineFiltersDlg.SetList(lineFilters.get());
+ const bool ignoredSubstitutionsAreEnabledOrig = GetOptionsMgr()->GetBool(OPT_IGNORED_SUBSTITUTIONS_ARE_ENABLED);
+ const bool ignoredSubstitutionsWorkBothWaysOrig = GetOptionsMgr()->GetBool(OPT_IGNORED_SUBSTITUTIONS_WORK_BOTH_WAYS);
+ const bool completelyBlankOutIgnoredSubstitutionsOrig = GetOptionsMgr()->GetBool(OPT_COMPLETELY_BLANK_OUT_IGNORED_SUBSTITUTIONS);
+ const bool optUseRegexpsForSubstitutionsOrig = GetOptionsMgr()->GetBool(OPT_USE_REGEXPS_FOR_IGNORED_SUBSTITUTIONS);
+
+ ignoredSubstitutionsFiltersDlg.m_IgnoredSubstitutionsAreEnabled = ignoredSubstitutionsAreEnabledOrig;
+ ignoredSubstitutionsFiltersDlg.m_IgnoredSubstitutionsWorkBothWays = ignoredSubstitutionsWorkBothWaysOrig;
+ ignoredSubstitutionsFiltersDlg.m_CompletelyBlankOutIgnoredSubstitutions = completelyBlankOutIgnoredSubstitutionsOrig;
+ ignoredSubstitutionsFiltersDlg.m_UseRegexpsForIgnoredSubstitutions = optUseRegexpsForSubstitutionsOrig;
+
+ ignoredSubstitutionsFilters->CloneFrom(theApp.m_pTokensForIs.get());
+ ignoredSubstitutionsFiltersDlg.SetList(ignoredSubstitutionsFilters.get());
+
if (sht.DoModal() == IDOK)
{
String strNone = _("<None>");
bool linefiltersEnabled = lineFiltersDlg.m_bIgnoreRegExp;
GetOptionsMgr()->SaveOption(OPT_LINEFILTER_ENABLED, linefiltersEnabled);
+ bool ignoredSubstitutionsAreEnabled = ignoredSubstitutionsFiltersDlg.m_IgnoredSubstitutionsAreEnabled;
+ GetOptionsMgr()->SaveOption(OPT_IGNORED_SUBSTITUTIONS_ARE_ENABLED, ignoredSubstitutionsAreEnabled);
+
+ bool ignoredSubstitutionsWorkBothWays = ignoredSubstitutionsFiltersDlg.m_IgnoredSubstitutionsWorkBothWays;
+ GetOptionsMgr()->SaveOption(OPT_IGNORED_SUBSTITUTIONS_WORK_BOTH_WAYS, ignoredSubstitutionsWorkBothWays);
+
+ bool completelyBlankOutIgnoredSubstitutions = ignoredSubstitutionsFiltersDlg.m_CompletelyBlankOutIgnoredSubstitutions;
+ GetOptionsMgr()->SaveOption(OPT_COMPLETELY_BLANK_OUT_IGNORED_SUBSTITUTIONS, completelyBlankOutIgnoredSubstitutions);
+
+ bool optUseRegexpsForSubstitutions = GetOptionsMgr()->GetBool(OPT_USE_REGEXPS_FOR_IGNORED_SUBSTITUTIONS);
+ GetOptionsMgr()->SaveOption(OPT_USE_REGEXPS_FOR_IGNORED_SUBSTITUTIONS, optUseRegexpsForSubstitutions);
+
+
// Check if compare documents need rescanning
bool bFileCompareRescan = false;
bool bFolderCompareRescan = false;
FRAMETYPE frame = GetFrameType(pFrame);
if (frame == FRAME_FILE)
{
- if (lineFiltersEnabledOrig != linefiltersEnabled ||
- !theApp.m_pLineFilters->Compare(lineFilters.get()))
+ if
+ (
+ linefiltersEnabled != lineFiltersEnabledOrig
+ || ignoredSubstitutionsAreEnabled != ignoredSubstitutionsAreEnabledOrig
+ || ignoredSubstitutionsWorkBothWays != ignoredSubstitutionsWorkBothWaysOrig
+ || completelyBlankOutIgnoredSubstitutions != completelyBlankOutIgnoredSubstitutionsOrig
+ || optUseRegexpsForSubstitutions != optUseRegexpsForSubstitutionsOrig
+ || !lineFilters->Compare(theApp.m_pLineFilters.get())
+ || !ignoredSubstitutionsFilters->Compare(theApp.m_pTokensForIs.get())
+ )
{
bFileCompareRescan = true;
}
theApp.m_pLineFilters->CloneFrom(lineFilters.get());
theApp.m_pLineFilters->SaveFilters();
+ theApp.m_pTokensForIs->CloneFrom(ignoredSubstitutionsFilters.get());
+ theApp.m_pTokensForIs->SaveFilters();
+
+
if (bFileCompareRescan)
{
for (auto pMergeDoc : GetAllMergeDocs())
#include "paths.h"
#include "FileFilterHelper.h"
#include "LineFiltersList.h"
+#include "TokenPairList.h"
#include "SyntaxColors.h"
#include "CCrystalTextMarkers.h"
#include "OptionsSyntaxColors.h"
, m_bEscShutdown(false)
, m_bExitIfNoDiff(MergeCmdLineInfo::Disabled)
, m_pLineFilters(new LineFiltersList())
+, m_pTokensForIs(new TokenPairList())
, m_pSyntaxColors(new SyntaxColors())
, m_pMarkers(new CCrystalTextMarkers())
, m_bMergingMode(false)
m_pLineFilters->Import(oldFilter);
}
+ if (m_pTokensForIs != nullptr)
+ m_pTokensForIs->Initialize(GetOptionsMgr());
+
// Check if filter folder is set, and create it if not
String pathMyFolders = GetOptionsMgr()->GetString(OPT_FILTER_USERPATH);
if (pathMyFolders.empty())
class ProjectFile;
class COptionsMgr;
class LineFiltersList;
+class TokenPairList;
class SyntaxColors;
class CCrystalTextMarkers;
CCrystalTextMarkers * GetMainMarkers() const { return m_pMarkers.get(); }
MergeCmdLineInfo::ExitNoDiff m_bExitIfNoDiff; /**< Exit if files are identical? */
std::unique_ptr<LineFiltersList> m_pLineFilters; /**< List of linefilters */
+ std::unique_ptr<TokenPairList> m_pTokensForIs;
WORD GetLangId() const;
void SetIndicators(CStatusBar &, const UINT *, int) const;
MENUITEM "Copy fro&m Right", ID_COPY_FROM_RIGHT\r
MENUITEM SEPARATOR\r
MENUITEM "&Select Line Difference\tF4", ID_SELECTLINEDIFF\r
+ MENUITEM "Add this change to &Ignored Substitutions", ID_ADD_TO_IGNORED_SUBSTITUTIONS\r
MENUITEM SEPARATOR\r
MENUITEM "&Undo", ID_EDIT_UNDO\r
MENUITEM "&Redo", ID_EDIT_REDO\r
\r
IDD_PROPPAGE_FILTER DIALOGEX 0, 0, 535, 188\r
STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION\r
-CAPTION "Linefilters"\r
+CAPTION "Line Filters"\r
FONT 8, "MS Shell Dlg", 0, 0, 0x1\r
BEGIN\r
CONTROL "Enable Line Filters",IDC_IGNOREREGEXP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,351,15\r
PUSHBUTTON "Remove",IDC_LFILTER_REMOVEBTN,116,167,50,14\r
END\r
\r
+IDD_IGNORED_SUSBSTITUTIONS_DLG DIALOGEX 0, 0, 365, 281\r
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION\r
+CAPTION "Ignored Substitutions"\r
+FONT 8, "MS Shell Dlg", 0, 0, 0x1\r
+BEGIN\r
+ CONTROL "Enable",IDC_IGNORED_SUSBSTITUTIONS_ARE_ENABLED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,28,351,9\r
+ CONTROL "",IDC_IGNORED_SUBSTITUTIONS_FILTER,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_EDITLABELS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,8,87,350,166\r
+ PUSHBUTTON "Add",IDC_LFILTER_ADDBTN,7,260,50,14\r
+ PUSHBUTTON "Remove",IDC_LFILTER_REMOVEBTN,63,260,50,14\r
+ LTEXT "The changes that appear on the panels as the listed pairs below will be ignored or marked as insignificant. Patches are unaffected.",IDC_STATIC,8,6,346,19\r
+ CONTROL "Ignore changes in both directions",IDC_IGNORED_SUSBSTITUTIONS_WORK_BOTH_WAYS,\r
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,57,351,10\r
+ CONTROL "Completely unhighlight the ignored changes",IDC_COMPLETELY_BLANK_OUT_IGNORED_SUBSTITUTIONS,\r
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,43,341,10\r
+ CONTROL "Use regular expressions",IDC_USE_REGEXPS_FOR_IGNORED_SUBSTITUTIONS,\r
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,72,350,10\r
+ PUSHBUTTON "Clear",IDC_LFILTER_CLEARBTN,307,261,50,14\r
+END\r
+\r
IDD_PROPPAGE_COLOR_SCHEMES DIALOGEX 0, 0, 255, 242\r
STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION\r
CAPTION "Colors"\r
\r
IDD_FILEFILTERS DIALOGEX 0, 0, 537, 188\r
STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION\r
-CAPTION "Filefilters"\r
+CAPTION "File Filters"\r
FONT 8, "MS Shell Dlg", 0, 0, 0x1\r
BEGIN\r
CONTROL "",IDC_FILTERFILE_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,10,7,517,153\r
BEGIN\r
END\r
\r
+ IDD_IGNORED_SUSBSTITUTIONS_DLG, DIALOG\r
+ BEGIN\r
+ BOTTOMMARGIN, 196\r
+ END\r
+\r
IDD_PROPPAGE_COLOR_SCHEMES, DIALOG\r
BEGIN\r
END\r
<ClCompile Include="LineFiltersDlg.cpp">\r
<Filter>MFCGui\Dialogs\Source Files</Filter>\r
</ClCompile>\r
+ <ClCompile Include="SubeditList.cpp">\r
+ <Filter>MFCGui\Dialogs\Source Files</Filter>\r
+ </ClCompile>\r
<ClCompile Include="LoadSaveCodepageDlg.cpp">\r
<Filter>MFCGui\Dialogs\Source Files</Filter>\r
</ClCompile>\r
<ClCompile Include="..\Externals\crystaledit\editlib\utils\hqbitmap.cpp">\r
<Filter>EditLib\Utils</Filter>\r
</ClCompile>\r
+ <ClCompile Include="IgnoredSubstitutionsDlg.cpp">\r
+ <Filter>MFCGui\Dialogs\Source Files</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="TokenPairList.cpp">\r
+ <Filter>Source Files</Filter>\r
+ </ClCompile>\r
<ClCompile Include="..\Externals\crystaledit\editlib\parsers\javascript.cpp">\r
<Filter>EditLib\Parsers\Source Files</Filter>\r
</ClCompile>\r
<ClInclude Include="IntToIntMap.h">\r
<Filter>Header Files</Filter>\r
</ClInclude>\r
- <ClInclude Include="LineFiltersList.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
<ClInclude Include="locality.h">\r
<Filter>Header Files</Filter>\r
</ClInclude>\r
<ClInclude Include="..\Externals\crystaledit\editlib\utils\hqbitmap.h">\r
<Filter>EditLib\Utils</Filter>\r
</ClInclude>\r
+ <ClInclude Include="LineFiltersList.h">\r
+ <Filter>Header Files</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="IgnoredSubstitutionsDlg.h">\r
+ <Filter>MFCGui\Dialogs\Header Files</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="TokenPairList.h">\r
+ <Filter>Header Files</Filter>\r
+ </ClInclude>\r
</ItemGroup>\r
<ItemGroup>\r
<None Include="res\binarydiff.ico">\r
<PrecompiledHeaderOutputFile>$(IntDir)$(TargetName)2.pch</PrecompiledHeaderOutputFile>\r
</ClCompile>\r
<ClCompile Include="LineFiltersDlg.cpp" />\r
+ <ClCompile Include="IgnoredSubstitutionsDlg.cpp" />\r
+ <ClCompile Include="SubeditList.cpp" />\r
<ClCompile Include="LineFiltersList.cpp">\r
<PrecompiledHeader>Use</PrecompiledHeader>\r
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderOutputFile>$(IntDir)$(TargetName)2.pch</PrecompiledHeaderOutputFile>\r
</ClCompile>\r
+ <ClCompile Include="TokenPairList.cpp">\r
+ <PrecompiledHeader>Use</PrecompiledHeader>\r
+ <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\r
+ <PrecompiledHeaderOutputFile>$(IntDir)$(TargetName)2.pch</PrecompiledHeaderOutputFile>\r
+ </ClCompile>\r
<ClCompile Include="LoadSaveCodepageDlg.cpp" />\r
<ClCompile Include="locality.cpp">\r
<PrecompiledHeader>Use</PrecompiledHeader>\r
<ClInclude Include="Common\LanguageSelect.h" />\r
<ClInclude Include="JumpList.h" />\r
<ClInclude Include="LineFiltersDlg.h" />\r
+ <ClInclude Include="IgnoredSubstitutionsDlg.h" />\r
<ClInclude Include="LineFiltersList.h" />\r
+ <ClInclude Include="TokenPairList.h" />\r
<ClInclude Include="LoadSaveCodepageDlg.h" />\r
<ClInclude Include="locality.h" />\r
<ClInclude Include="LocationBar.h" />\r
<ClCompile Include="LineFiltersDlg.cpp">\r
<Filter>MFCGui\Dialogs\Source Files</Filter>\r
</ClCompile>\r
+ <ClCompile Include="SubeditList.cpp">\r
+ <Filter>MFCGui\Dialogs\Source Files</Filter>\r
+ </ClCompile>\r
<ClCompile Include="LoadSaveCodepageDlg.cpp">\r
<Filter>MFCGui\Dialogs\Source Files</Filter>\r
</ClCompile>\r
<ClCompile Include="..\Externals\crystaledit\editlib\utils\hqbitmap.cpp">\r
<Filter>EditLib\Utils</Filter>\r
</ClCompile>\r
+ <ClCompile Include="IgnoredSubstitutionsDlg.cpp">\r
+ <Filter>MFCGui\Dialogs\Source Files</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="TokenPairList.cpp">\r
+ <Filter>Source Files</Filter>\r
+ </ClCompile>\r
<ClCompile Include="..\Externals\crystaledit\editlib\parsers\javascript.cpp">\r
<Filter>EditLib\Parsers\Source Files</Filter>\r
</ClCompile>\r
<ClInclude Include="IntToIntMap.h">\r
<Filter>Header Files</Filter>\r
</ClInclude>\r
- <ClInclude Include="LineFiltersList.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
<ClInclude Include="locality.h">\r
<Filter>Header Files</Filter>\r
</ClInclude>\r
<ClInclude Include="..\Externals\crystaledit\editlib\utils\hqbitmap.h">\r
<Filter>EditLib\Utils</Filter>\r
</ClInclude>\r
+ <ClInclude Include="LineFiltersList.h">\r
+ <Filter>Header Files</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="IgnoredSubstitutionsDlg.h">\r
+ <Filter>MFCGui\Dialogs\Header Files</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="TokenPairList.h">\r
+ <Filter>Header Files</Filter>\r
+ </ClInclude>\r
</ItemGroup>\r
<ItemGroup>\r
<None Include="res\binarydiff.ico">\r
#include "MergeLineFlags.h"
#include "FileOrFolderSelect.h"
#include "LineFiltersList.h"
+#include "TokenPairList.h"
#include "TempFile.h"
#include "codepage_detect.h"
#include "SelectUnpackerDlg.h"
{
m_diffWrapper.SetFilterList(_T(""));
}
+
+ if (GetOptionsMgr()->GetBool(OPT_IGNORED_SUBSTITUTIONS_ARE_ENABLED) && theApp.m_pTokensForIs)
+ {
+ m_diffWrapper.SetIgnoredSubstitutionsList(theApp.m_pTokensForIs.get());
+ }
+ else
+ {
+ m_diffWrapper.SetIgnoredSubstitutionsList(nullptr);
+ }
+
if (GetView(0, 0)->m_CurSourceDef->type != 0)
m_diffWrapper.SetFilterCommentsSourceDef(GetView(0, 0)->m_CurSourceDef);
else
public:
typedef enum { BYTEDIFF, WORDDIFF } DIFFLEVEL;
void Showlinediff(CMergeEditView *pView, bool bReversed = false);
+ void AddToIgnoredSubstitutions(CMergeEditView* pView, bool bReversed = false);
std::vector<WordDiff> GetWordDiffArrayInDiffBlock(int nDiff);
std::vector<WordDiff> GetWordDiffArray(int nLineIndex);
void ClearWordDiffCache(int nDiff = -1);
#include "DiffTextBuffer.h"
#include "stringdiffs.h"
#include "UnicodeString.h"
+#include "TokenPairList.h"
+#include "OptionsMgr.h"
+#include "OptionsDef.h"
+#include "Merge.h"
#ifdef _DEBUG
#define new DEBUG_NEW
void CMergeDoc::Showlinediff(CMergeEditView *pView, bool bReversed)
{
CRect rc[3];
- int nBuffer;
Computelinediff(pView, rc, bReversed);
if (std::all_of(rc, rc + m_nBuffers, [](auto& rc) { return rc.top == -1; }))
{
String caption = _("Line difference");
- String msg = _("No difference");
+ String msg = _("No differences to select found");
MessageBox(pView->GetSafeHwnd(), msg.c_str(), caption.c_str(), MB_OK);
return;
}
// Actually display selection areas on screen in both edit panels
- for (int nGroup = 0; nGroup < m_nGroups; nGroup++)
- for (nBuffer = 0; nBuffer < m_nBuffers; nBuffer++)
- HighlightDiffRect(m_pView[nGroup][nBuffer], rc[nBuffer]);
+ for (int nBuffer = 0; nBuffer < m_nBuffers; nBuffer++)
+ HighlightDiffRect(m_pView[pView->m_nThisGroup][nBuffer], rc[nBuffer]);
+}
+
+void CMergeDoc::AddToIgnoredSubstitutions(CMergeEditView* pView, bool bReversed)
+{
+ if (m_nBuffers != 2)
+ return; /// Not clear what to do for a 3-way merge
+
+ CRect rc[3];
+
+ Computelinediff(pView, rc, bReversed);
+
+ bool optIgnoredSubstitutionsWorkBothWays = GetOptionsMgr()->GetBool(OPT_IGNORED_SUBSTITUTIONS_WORK_BOTH_WAYS);
+
+ if (std::all_of(rc, rc + m_nBuffers, [](auto& rc) { return rc.top == -1; }))
+ {
+ String caption = _("Line difference");
+ String msg = _("No differences found to add as ignored substitution");
+ MessageBox(pView->GetSafeHwnd(), msg.c_str(), caption.c_str(), MB_OK);
+ return;
+ }
+
+ // Actually display selection areas on screen in both edit panels
+ String selectedText[3];
+ for (int nBuffer = 0; nBuffer < m_nBuffers; nBuffer++)
+ {
+ HighlightDiffRect(m_pView[pView->m_nThisGroup][nBuffer], rc[nBuffer]);
+ selectedText[nBuffer] = String(m_pView[pView->m_nThisGroup][nBuffer]->GetSelectedText());
+ }
+
+ if (selectedText[0].empty() && selectedText[1].empty())
+ {
+ return;
+ }
+
+
+ /// Check whether the pair is already registered with Ignored Substitutions
+ TokenPairList &ignoredSubstitutionsList = *theApp.m_pTokensForIs.get();
+ for (int f = 0; f < ignoredSubstitutionsList.GetCount(); f++)
+ {
+ String str0 = ignoredSubstitutionsList.GetAt(f).filterStr0;
+ String str1 = ignoredSubstitutionsList.GetAt(f).filterStr1;
+ if
+ (
+ str0 == selectedText[0]
+ && str1 == selectedText[1]
+ ||
+ optIgnoredSubstitutionsWorkBothWays
+ && str1 == selectedText[0]
+ && str0 == selectedText[1]
+ )
+ {
+ String caption = _("The pair is already present in the list of Ignored Substiturions");
+ String msg = strutils::format(_T("\"%s\" <-> \"%s\""), selectedText[0], selectedText[1]);
+ MessageBox(pView->GetSafeHwnd(), msg.c_str(), caption.c_str(), MB_OK);
+ return; /// The substitution pair is already registered
+ }
+ }
+
+ String caption = _("Add this change to Ignored Substitutions?");
+ String msg = strutils::format(_T("\"%s\" <-> \"%s\""), selectedText[0], selectedText[1]);
+ if (MessageBox(pView->GetSafeHwnd(), msg.c_str(), caption.c_str(), MB_YESNO) == IDYES)
+ {
+ ignoredSubstitutionsList.AddFilter(selectedText[0], selectedText[1]);
+ FlushAndRescan(true);
+ //Rescan();
+ }
+ return;
}
static inline bool IsDiffPerLine(bool bTableEditing, const DIFFRANGE& cd)
ON_UPDATE_COMMAND_UI(ID_SELECTLINEDIFF, OnUpdateSelectLineDiff)
ON_COMMAND(ID_SELECTPREVLINEDIFF, OnSelectLineDiff<true>)
ON_UPDATE_COMMAND_UI(ID_SELECTPREVLINEDIFF, OnUpdateSelectLineDiff)
+ ON_COMMAND(ID_ADD_TO_IGNORED_SUBSTITUTIONS, OnAddToIgnoredSubstitutions<false>)
+ ON_UPDATE_COMMAND_UI(ID_ADD_TO_IGNORED_SUBSTITUTIONS, OnUpdateAddToIgnoredSubstitutions)
ON_WM_CONTEXTMENU()
ON_UPDATE_COMMAND_UI(ID_EDIT_REPLACE, OnUpdateEditReplace)
ON_COMMAND(ID_FILE_LEFT_READONLY, OnLeftReadOnly)
pCmdUI->Enable(!GetDocument()->IsEditedAfterRescan());
}
+template<bool reversed>
+void CMergeEditView::OnAddToIgnoredSubstitutions()
+{
+ // Pass this to the document, to compare this file to other
+ GetDocument()->AddToIgnoredSubstitutions(this, reversed);
+}
+
+void CMergeEditView::OnUpdateAddToIgnoredSubstitutions(CCmdUI* pCmdUI)
+{
+ pCmdUI->Enable(GetDocument()->m_nBuffers == 2 && !GetDocument()->IsEditedAfterRescan());
+}
+
+
/**
* @brief Enable/disable Replace-menuitem
*/
template<bool reversed>
afx_msg void OnSelectLineDiff();
afx_msg void OnUpdateSelectLineDiff(CCmdUI* pCmdUI);
+ template<bool reversed>
+ afx_msg void OnAddToIgnoredSubstitutions();
+ afx_msg void OnUpdateAddToIgnoredSubstitutions(CCmdUI* pCmdUI);
afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
afx_msg void OnUpdateEditReplace(CCmdUI* pCmdUI);
afx_msg void OnLeftReadOnly();
extern const String OPT_FILTER_USERPATH OP("Settings/UserFilterPath");
extern const String OPT_FILEFILTER_SHARED OP("Settings/Filters/Shared");
+/// Ignored Susbstitutions
+extern const String OPT_IGNORED_SUBSTITUTIONS_ARE_ENABLED OP("Settings/IgnoredSubstitutionsAreEnabled");
+extern const String OPT_IGNORED_SUBSTITUTIONS_WORK_BOTH_WAYS OP("Settings/IgnoredSubstitutionsWorkBothWays");
+extern const String OPT_COMPLETELY_BLANK_OUT_IGNORED_SUBSTITUTIONS OP("Settings/CompletelyBlankOutIgnoredSusbstitutions");
+extern const String OPT_USE_REGEXPS_FOR_IGNORED_SUBSTITUTIONS OP("Settings/UseRegexpsForIgnoredSubstitutions");
+
// Archive support
extern const String OPT_ARCHIVE_ENABLE OP("Merge7z/Enable");
extern const String OPT_ARCHIVE_PROBETYPE OP("Merge7z/ProbeSignature");
pOptions->InitOption(OPT_CUSTOM_TEMP_PATH, _T(""));
pOptions->InitOption(OPT_LINEFILTER_ENABLED, false);
+ pOptions->InitOption(OPT_IGNORED_SUBSTITUTIONS_ARE_ENABLED, false);
+ pOptions->InitOption(OPT_IGNORED_SUBSTITUTIONS_WORK_BOTH_WAYS, false);
+ pOptions->InitOption(OPT_COMPLETELY_BLANK_OUT_IGNORED_SUBSTITUTIONS, false);
+ pOptions->InitOption(OPT_USE_REGEXPS_FOR_IGNORED_SUBSTITUTIONS, false);
+
pOptions->InitOption(OPT_FILEFILTER_CURRENT, _T("*.*"));
// CMainFrame initializes this when it is empty.
pOptions->InitOption(OPT_FILTER_USERPATH, _T(""));
--- /dev/null
+// SubeditList.cpp : implementation file
+//
+
+#include "stdafx.h"
+#include "subedit.h"
+#include "SubeditList.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+#define IDC_IPEDIT 1000
+
+/// Some stuff is from https://www.codeguru.com/cpp/controls/listview/editingitemsandsubitem/article.php/c923/Editable-subitems.htm
+
+/////////////////////////////////////////////////////////////////////////////
+// CSubeditList
+
+CSubeditList::CSubeditList()
+{
+}
+
+CSubeditList::~CSubeditList()
+{
+}
+
+// HitTestEx - Determine the row index and column index for a point
+// Returns - the row index or -1 if point is not over a row
+// point - point to be tested.
+// col - to hold the column index
+int CSubeditList::HitTestEx(CPoint &point, int *col) const
+{
+ int colnum = 0;
+ int row = HitTest( point, NULL );
+
+ if( col ) *col = 0;
+
+ // Make sure that the ListView is in LVS_REPORT
+ if( (GetWindowLong(m_hWnd, GWL_STYLE) & LVS_TYPEMASK) != LVS_REPORT )
+ return row;
+
+ // Get the top and bottom row visible
+ row = GetTopIndex();
+ int bottom = row + GetCountPerPage();
+ if( bottom > GetItemCount() )
+ bottom = GetItemCount();
+
+ // Get the number of columns
+ CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
+ int nColumnCount = pHeader->GetItemCount();
+
+ // Loop through the visible rows
+ for( ;row <=bottom;row++)
+ {
+ // Get bounding rect of item and check whether point falls in it.
+ CRect rect;
+ GetItemRect( row, &rect, LVIR_BOUNDS );
+ if( rect.PtInRect(point) )
+ {
+ // Now find the column
+ for( colnum = 0; colnum < nColumnCount; colnum++ )
+ {
+ int colwidth = GetColumnWidth(colnum);
+ if( point.x >= rect.left
+ && point.x <= (rect.left + colwidth ) )
+ {
+ if( col ) *col = colnum;
+ return row;
+ }
+ rect.left += colwidth;
+ }
+ }
+ }
+ return -1;
+}
+
+
+BEGIN_MESSAGE_MAP(CSubeditList, CListCtrl)
+ //{{AFX_MSG_MAP(CSubeditList)
+ // NOTE - the ClassWizard will add and remove mapping macros here.
+ ON_NOTIFY(LVN_ENDLABELEDIT, IDC_IGNORED_SUBSTITUTIONS_FILTER, OnEndLabelEdit)
+ ON_WM_LBUTTONDOWN()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CSubeditList message handlers
+
+
+// EditSubLabel - Start edit of a sub item label
+// Returns - Temporary pointer to the new edit control
+// nItem - The row index of the item to edit
+// nCol - The column of the sub item.
+//CEdit* CSubeditList::EditSubLabel(int nItem, int nCol)
+CInPlaceEdit* CSubeditList::EditSubLabel( int nItem, int nCol )
+{
+ // The returned pointer should not be saved
+
+ // Make sure that the item is visible
+ if( !EnsureVisible( nItem, TRUE ) ) return NULL;
+
+ // Make sure that nCol is valid
+ CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
+ int nColumnCount = pHeader->GetItemCount();
+ if( nCol >= nColumnCount || GetColumnWidth(nCol) < 5 )
+ return NULL;
+
+ // Get the column offset
+ int offset = 0;
+ for( int i = 0; i < nCol; i++ )
+ offset += GetColumnWidth( i );
+
+ CRect rect;
+ GetItemRect( nItem, &rect, LVIR_BOUNDS );
+
+ // Now scroll if we need to expose the column
+ CRect rcClient;
+ GetClientRect( &rcClient );
+ if( offset + rect.left < 0 || offset + rect.left > rcClient.right )
+ {
+ CSize size;
+ size.cx = offset + rect.left;
+ size.cy = 0;
+ Scroll( size );
+ rect.left -= size.cx;
+ }
+
+ // Get Column alignment
+ LV_COLUMN lvcol;
+ lvcol.mask = LVCF_FMT;
+ GetColumn( nCol, &lvcol );
+ DWORD dwStyle ;
+ if((lvcol.fmt&LVCFMT_JUSTIFYMASK) == LVCFMT_LEFT)
+ dwStyle = ES_LEFT;
+ else if((lvcol.fmt&LVCFMT_JUSTIFYMASK) == LVCFMT_RIGHT)
+ dwStyle = ES_RIGHT;
+ else dwStyle = ES_CENTER;
+
+ rect.left += offset+4;
+ rect.right = rect.left + GetColumnWidth( nCol ) - 3 ;
+ if( rect.right > rcClient.right) rect.right = rcClient.right;
+
+ dwStyle |= WS_BORDER|WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL;
+ CInPlaceEdit *pEdit = new CInPlaceEdit(nItem, nCol, GetItemText( nItem, nCol ));
+ pEdit->Create( dwStyle, rect, this, IDC_IPEDIT );
+
+ return pEdit;
+}
+
+void CSubeditList::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
+{
+ if( GetFocus() != this ) SetFocus();
+ CListCtrl::OnHScroll(nSBCode, nPos, pScrollBar);
+}
+
+void CSubeditList::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
+{
+ if( GetFocus() != this ) SetFocus();
+ CListCtrl::OnVScroll(nSBCode, nPos, pScrollBar);
+}
+
+void CSubeditList::OnEndLabelEdit(NMHDR* pNMHDR, LRESULT* pResult)
+{
+ LV_DISPINFO *plvDispInfo = (LV_DISPINFO *)pNMHDR;
+ LV_ITEM *plvItem = &plvDispInfo->item;
+
+ if (plvItem->pszText != NULL)
+ {
+ SetItemText(plvItem->iItem, plvItem->iSubItem, plvItem->pszText);
+ }
+ *pResult = FALSE;
+}
+
+void CSubeditList::OnBeginLabelEdit(NMHDR* pNMHDR, LRESULT* pResult)
+{
+ LV_DISPINFO* plvDispInfo = (LV_DISPINFO*)pNMHDR;
+ LV_ITEM* plvItem = &plvDispInfo->item;
+ plvItem->iSubItem = 1;
+
+// if (plvItem->pszText != NULL)
+// {
+// SetItemText(plvItem->iItem, plvItem->iSubItem, plvItem->pszText);
+// }
+ *pResult = FALSE;
+}
+
+void CSubeditList::OnLButtonDown(UINT nFlags, CPoint point)
+{
+ int index;
+ CListCtrl::OnLButtonDown(nFlags, point);
+
+ int colnum;
+ if( ( index = HitTestEx( point, &colnum )) != -1 )
+ {
+ UINT flag = LVIS_FOCUSED;
+ //if ((GetItemState(index, flag) & flag) == flag && colnum > 0)
+ if ((GetItemState(index, flag) & flag) == flag)
+ {
+ // Add check for LVS_EDITLABELS
+ if( GetWindowLong(m_hWnd, GWL_STYLE) & LVS_EDITLABELS )
+ EditSubLabel( index, colnum );
+ }
+ else
+ SetItemState( index, LVIS_SELECTED | LVIS_FOCUSED ,
+ LVIS_SELECTED | LVIS_FOCUSED);
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CInPlaceEdit
+
+CInPlaceEdit::CInPlaceEdit(int iItem, int iSubItem, CString sInitText)
+:m_sInitText( sInitText )
+{
+ m_iItem = iItem;
+ m_iSubItem = iSubItem;
+ m_bESC = FALSE;
+}
+
+CInPlaceEdit::~CInPlaceEdit()
+{
+}
+
+
+BEGIN_MESSAGE_MAP(CInPlaceEdit, CEdit)
+ //{{AFX_MSG_MAP(CInPlaceEdit)
+ ON_WM_KILLFOCUS()
+ ON_WM_NCDESTROY()
+ ON_WM_CHAR()
+ ON_WM_CREATE()
+ //}}AFX_MSG_MAP
+ ON_WM_LBUTTONDOWN()
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CInPlaceEdit message handlers
+
+BOOL CInPlaceEdit::PreTranslateMessage(MSG* pMsg)
+{
+ if( pMsg->message == WM_KEYDOWN )
+ {
+ if(pMsg->wParam == VK_RETURN
+ || pMsg->wParam == VK_DELETE
+ || pMsg->wParam == VK_ESCAPE
+ || GetKeyState( VK_CONTROL)
+ )
+ {
+ ::TranslateMessage(pMsg);
+ ::DispatchMessage(pMsg);
+ return TRUE; // DO NOT process further
+ }
+ }
+
+ return CEdit::PreTranslateMessage(pMsg);
+}
+
+
+void CInPlaceEdit::OnKillFocus(CWnd* pNewWnd)
+{
+ CEdit::OnKillFocus(pNewWnd);
+
+ CString str;
+ GetWindowText(str);
+
+ // Send Notification to parent of ListView ctrl
+ LV_DISPINFO dispinfo;
+ dispinfo.hdr.hwndFrom = GetParent()->m_hWnd;
+ dispinfo.hdr.idFrom = GetDlgCtrlID();
+ dispinfo.hdr.code = LVN_ENDLABELEDIT;
+
+ dispinfo.item.mask = LVIF_TEXT;
+ dispinfo.item.iItem = m_iItem;
+ dispinfo.item.iSubItem = m_iSubItem;
+ dispinfo.item.pszText = m_bESC ? NULL : LPTSTR((LPCTSTR)str);
+ dispinfo.item.cchTextMax = str.GetLength();
+
+ GetParent()->GetParent()->SendMessage( WM_NOTIFY, GetParent()->GetDlgCtrlID(),
+ (LPARAM)&dispinfo );
+
+ DestroyWindow();
+}
+
+void CInPlaceEdit::OnNcDestroy()
+{
+ CEdit::OnNcDestroy();
+
+ delete this;
+}
+
+
+void CInPlaceEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
+{
+ if( nChar == VK_ESCAPE || nChar == VK_RETURN)
+ {
+ if( nChar == VK_ESCAPE )
+ m_bESC = TRUE;
+ GetParent()->SetFocus();
+ return;
+ }
+
+
+ CEdit::OnChar(nChar, nRepCnt, nFlags);
+
+ // Resize edit control if needed
+
+ // Get text extent
+ CString str;
+
+ GetWindowText( str );
+ CWindowDC dc(this);
+ CFont *pFont = GetParent()->GetFont();
+ CFont *pFontDC = dc.SelectObject( pFont );
+ CSize size = dc.GetTextExtent( str );
+ dc.SelectObject( pFontDC );
+ size.cx += 5; // add some extra buffer
+
+ // Get client rect
+ CRect rect, parentrect;
+ GetClientRect( &rect );
+ GetParent()->GetClientRect( &parentrect );
+
+ // Transform rect to parent coordinates
+ ClientToScreen( &rect );
+ GetParent()->ScreenToClient( &rect );
+
+ // Check whether control needs to be resized
+ // and whether there is space to grow
+ if( size.cx > rect.Width() )
+ {
+ if( size.cx + rect.left < parentrect.right )
+ rect.right = rect.left + size.cx;
+ else
+ rect.right = parentrect.right;
+ MoveWindow( &rect );
+ }
+}
+
+int CInPlaceEdit::OnCreate(LPCREATESTRUCT lpCreateStruct)
+{
+ if (CEdit::OnCreate(lpCreateStruct) == -1)
+ return -1;
+
+ // Set the proper font
+ CFont* font = GetParent()->GetFont();
+ SetFont(font);
+
+ SetWindowText( m_sInitText );
+ SetFocus();
+ SetSel( 0, -1 );
+ return 0;
+}
--- /dev/null
+#if !defined(AFX_SUBEDITLIST_H__335134F3_37B4_4739_AC9B_4AFB32C37E60__INCLUDED_)
+#define AFX_SUBEDITLIST_H__335134F3_37B4_4739_AC9B_4AFB32C37E60__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+// SubeditList.h : header file
+//
+
+class CInPlaceEdit : public CEdit
+{
+// Construction
+public:
+ CInPlaceEdit(int iItem, int iSubItem, CString sInitText);
+
+// Attributes
+public:
+
+// Operations
+public:
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CInPlaceEdit)
+ public:
+ virtual BOOL PreTranslateMessage(MSG* pMsg);
+ //}}AFX_VIRTUAL
+
+// Implementation
+public:
+ virtual ~CInPlaceEdit();
+
+ // Generated message map functions
+protected:
+ //{{AFX_MSG(CInPlaceEdit)
+ afx_msg void OnKillFocus(CWnd* pNewWnd);
+ afx_msg void OnNcDestroy();
+ afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
+ afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
+ //}}AFX_MSG
+
+ DECLARE_MESSAGE_MAP()
+private:
+ int m_iItem;
+ int m_iSubItem;
+ CString m_sInitText;
+ BOOL m_bESC; // To indicate whether ESC key was pressed
+};
+
+class CSubeditList : public CListCtrl
+{
+// Construction
+public:
+ CSubeditList();
+
+// Attributes
+public:
+
+// Operations
+public:
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CSubeditList)
+ //}}AFX_VIRTUAL
+
+// Implementation
+public:
+ virtual ~CSubeditList();
+
+ CInPlaceEdit *EditSubLabel(int nItem, int nCol);
+ // Generated message map functions
+//protected:
+ //{{AFX_MSG(CSubeditList)
+ // NOTE - the ClassWizard will add and remove member functions here.
+ afx_msg int HitTestEx(CPoint& point, int* col) const;
+ afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
+ afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
+ afx_msg void OnEndLabelEdit(NMHDR* pNMHDR, LRESULT* pResult);
+ afx_msg void OnBeginLabelEdit(NMHDR* pNMHDR, LRESULT* pResult);
+ afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
+ //}}AFX_MSG
+
+ DECLARE_MESSAGE_MAP()
+};
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_SUBEDITLIST_H__335134F3_37B4_4739_AC9B_4AFB32C37E60__INCLUDED_)
--- /dev/null
+/**
+ * @file TokenPairList.cpp
+ *
+ * @brief Implementation for IgnoredSubstitutionsFiltersList class.
+ */
+
+#include "pch.h"
+#include "TokenPairList.h"
+#include <vector>
+#include <cassert>
+#include "OptionsMgr.h"
+#include "UnicodeString.h"
+
+using std::vector;
+
+/** @brief Registry key for saving Ignored Substitutions filters. */
+static const TCHAR IgnoredSubstitutionsRegPath[] = _T("IgnoredSubstitutions");
+
+/**
+ * @brief Default constructor.
+ */
+TokenPairList::TokenPairList()
+: m_pOptionsMgr(nullptr)
+{
+}
+
+/**
+ * @brief Destructor, empties the list.
+ */
+TokenPairList::~TokenPairList()
+{
+}
+
+/**
+ * @brief Add new filter to the list.
+ * @param [in] filter Filter string to add.
+ * @param [in] enabled Is filter enabled?
+ */
+void TokenPairList::AddFilter(const String& filter0, const String& filter1)
+{
+ std::shared_ptr<TokenPair> item(new TokenPair());
+ item->filterStr0 = filter0;
+ item->filterStr1 = filter1;
+ m_items.push_back(item);
+}
+
+/**
+ * @brief Return filter from given index.
+ * @param [in] ind Index of filter.
+ * @return Filter item from the index. If the index is beyond table limit,
+ * return the last item in the list.
+ */
+const TokenPair & TokenPairList::GetAt(size_t ind) const
+{
+ if (ind < m_items.size())
+ return *m_items[ind];
+ else
+ return *m_items.back();
+}
+
+/**
+ * @brief Clone filter list from another list.
+ * This function clones filter list from another list. Current items in the
+ * list are removed and new items added from the given list.
+ * @param [in] list List to clone.
+ */
+void TokenPairList::CloneFrom(const TokenPairList *list)
+{
+ Empty();
+ size_t count = list->GetCount();
+
+ for (size_t i = 0; i < count; i++)
+ {
+ const TokenPair &item = list->GetAt(i);
+ AddFilter(item.filterStr0, item.filterStr1);
+ }
+}
+
+/**
+ * @brief Compare filter lists.
+ * @param [in] list List to compare.
+ * @return true if lists are identical, false otherwise.
+ */
+bool TokenPairList::Compare(const TokenPairList *list) const
+{
+ if (list->GetCount() != GetCount())
+ return false;
+
+ for (size_t i = 0; i < GetCount(); i++)
+ {
+ const TokenPair &item1 = list->GetAt(i);
+ const TokenPair &item2 = GetAt(i);
+
+ if
+ (
+ item1.filterStr0 != item2.filterStr0
+ || item1.filterStr1 != item2.filterStr1
+ )
+ return false;
+ }
+ return true;
+}
+
+/**
+ * @brief Read filter list from the options system.
+ * @param [in] pOptionsMgr Pointer to options system.
+ */
+void TokenPairList::Initialize(COptionsMgr *pOptionsMgr)
+{
+ assert(pOptionsMgr != nullptr);
+ String valuename(IgnoredSubstitutionsRegPath);
+
+ m_pOptionsMgr = pOptionsMgr;
+
+ size_t count = m_items.size();
+ valuename += _T("/Values");
+ m_pOptionsMgr->InitOption(valuename, static_cast<int>(count));
+ count = m_pOptionsMgr->GetInt(valuename);
+
+ for (unsigned i = 0; i < count; i++)
+ {
+ String name0 = strutils::format(_T("%s/Filter%02u_0"), IgnoredSubstitutionsRegPath, i);
+ m_pOptionsMgr->InitOption(name0, _T(""));
+ String filterStr0 = m_pOptionsMgr->GetString(name0);
+
+ String name1 = strutils::format(_T("%s/Filter%02u_1"), IgnoredSubstitutionsRegPath, i);
+ m_pOptionsMgr->InitOption(name1, _T(""));
+ String filterStr1 = m_pOptionsMgr->GetString(name1);
+
+ AddFilter(filterStr0, filterStr1);
+ }
+}
+
+/**
+ * @brief Save Ignored Substitutions to options system.
+ */
+void TokenPairList::SaveFilters()
+{
+ assert(m_pOptionsMgr != nullptr);
+ String valuename(IgnoredSubstitutionsRegPath);
+
+ size_t count = m_items.size();
+ valuename += _T("/Values");
+ m_pOptionsMgr->SaveOption(valuename, static_cast<int>(count));
+
+ for (size_t i = 0; i < count; i++)
+ {
+ const std::shared_ptr<TokenPair> &item = m_items[i];
+
+ String name0 = strutils::format(_T("%s/Filter%02u_0"), IgnoredSubstitutionsRegPath, i);
+ m_pOptionsMgr->InitOption(name0, _T(""));
+ m_pOptionsMgr->SaveOption(name0, item->filterStr0);
+
+ String name1 = strutils::format(_T("%s/Filter%02u_1"), IgnoredSubstitutionsRegPath, i);
+ m_pOptionsMgr->InitOption(name1, _T(""));
+ m_pOptionsMgr->SaveOption(name1, item->filterStr1);
+ }
+
+ // Remove options we don't need anymore
+ // We could have earlier 10 pcs but now we only need 5
+ String filter = strutils::format(_T("%s/Enabled%02u"), IgnoredSubstitutionsRegPath, count);
+ int retval = m_pOptionsMgr->RemoveOption(filter);
+
+ String filter0 = strutils::format(_T("%s/Filter%02u_0"), IgnoredSubstitutionsRegPath, count);
+ int retval0 = m_pOptionsMgr->RemoveOption(filter0);
+
+ String filter1 = strutils::format(_T("%s/Filter%02u_1"), IgnoredSubstitutionsRegPath, count);
+ int retval1 = m_pOptionsMgr->RemoveOption(filter1);
+
+ while (retval == COption::OPT_OK || retval0 == COption::OPT_OK || retval1 == COption::OPT_OK)
+ {
+ ++count;
+ filter = strutils::format(_T("%s/Enabled%02u"), IgnoredSubstitutionsRegPath, count);
+ retval = m_pOptionsMgr->RemoveOption(filter);
+ filter0 = strutils::format(_T("%s/Filter%02u_0"), IgnoredSubstitutionsRegPath, count);
+ retval0 = m_pOptionsMgr->RemoveOption(filter);
+ filter1 = strutils::format(_T("%s/Filter%02u_1"), IgnoredSubstitutionsRegPath, count);
+ retval1 = m_pOptionsMgr->RemoveOption(filter);
+ }
+}
--- /dev/null
+/**
+ * @file IgnoredSubstitutionsFiltersList.h
+ *
+ * @brief Declaration file for IgnoredSubstitutionsFiltersList class
+ */
+#pragma once
+
+#include <vector>
+#include <memory>
+#include "UnicodeString.h"
+
+class COptionsMgr;
+
+/**
+ @brief Structure for filter.
+ */
+struct TokenPair
+{
+ String filterStr0;
+ String filterStr1;
+};
+
+/**
+ @brief List of raw Ignored Substitution pairs.
+ */
+class TokenPairList
+{
+public:
+ TokenPairList();
+ ~TokenPairList();
+
+ void AddFilter(const String& filter0, const String& filter1);
+ size_t GetCount() const;
+ void Empty();
+ const TokenPair &GetAt(size_t ind) const;
+ void CloneFrom(const TokenPairList *list);
+ bool Compare(const TokenPairList *list) const;
+
+ void Initialize(COptionsMgr *pOptionsMgr);
+ void SaveFilters();
+
+private:
+ std::vector<std::shared_ptr<TokenPair>> m_items; /**< List for linefilter items */
+ COptionsMgr * m_pOptionsMgr; /**< Options-manager for storage */
+};
+
+/**
+ * @brief Returns count of items in the list.
+ * @return Count of filters in the list.
+ */
+inline size_t TokenPairList::GetCount() const
+{
+ return m_items.size();
+}
+
+/**
+ * @brief Empties the list.
+ */
+inline void TokenPairList::Empty()
+{
+ m_items.clear();
+}
#define IDD_OPEN 202\r
#define IDD_PROPPAGE_GENERAL 205\r
#define IDD_PROPPAGE_FILTER 207\r
+#define IDD_IGNORED_SUSBSTITUTIONS_DLG 208\r
#define IDD_PROPPAGE_SYSTEM 209\r
#define IDD_EDITOR_HEADERBAR 210\r
#define IDD_GENERATE_PATCH 211\r
#define IDC_ALL_WHITE 1027\r
#define IDC_WHITE_CHANGE 1028\r
#define IDC_WHITESPACE 1029\r
+#define IDC_IGNORED_SUSBSTITUTIONS_ARE_ENABLED 1030\r
#define IDC_EOL_SENSITIVE 1032\r
#define IDC_CP_SENSITIVE 1033\r
#define IDC_DIFFERENCE_COLOR 1035\r
#define IDC_LFILTER_ADDBTN 1321\r
#define IDC_LFILTER_EDITBTN 1322\r
#define IDC_LFILTER_REMOVEBTN 1323\r
+#define IDC_IGNORED_SUBSTITUTIONS_FILTER 1324\r
#define IDC_ASK_MULTIWINDOW_CLOSE 1326\r
#define IDC_COLDLG_LIST 1327\r
#define IDC_PRESERVE_FILETIME 1328\r
#define IDC_INDENT_HEURISTIC 8829\r
#define IDC_LIST_FILE 8830\r
#define IDC_FLDCONFIRM_DONTASKAGAIN 8831\r
+#define IDC_IGNORED_SUSBSTITUTIONS_WORK_BOTH_WAYS 8832\r
+#define IDC_COMPLETELY_BLANK_OUT_IGNORED_SUBSTITUTIONS 8833\r
+#define IDC_USE_REGEXPS_FOR_IGNORED_SUBSTITUTIONS 8834\r
+#define IDC_LFILTER_CLEARBTN 8836\r
#define IDS_SPLASH_DEVELOPERS 8976\r
#define IDS_SPLASH_GPLTEXT 8977\r
#define IDS_MESSAGEBOX_OK 9001\r
#define ID_SWAPPANES_SWAP12 34170\r
#define ID_SWAPPANES_SWAP23 34171\r
#define ID_SWAPPANES_SWAP13 34172\r
+#define ID_ADD_TO_IGNORED_SUBSTITUTIONS 34173\r
\r
// Next default values for new objects\r
// \r
#ifndef APSTUDIO_READONLY_SYMBOLS\r
#define _APS_3D_CONTROLS 1\r
#define _APS_NEXT_RESOURCE_VALUE 253\r
-#define _APS_NEXT_COMMAND_VALUE 34173\r
+#define _APS_NEXT_COMMAND_VALUE 34174\r
#define _APS_NEXT_CONTROL_VALUE 8832\r
#define _APS_NEXT_SYMED_VALUE 117\r
#endif\r
--- /dev/null
+// subedit.h : main header file for the SUBEDIT application
+//
+
+#if !defined(AFX_SUBEDIT_H__071E4499_6320_49E5_B602_E6F7873ED145__INCLUDED_)
+#define AFX_SUBEDIT_H__071E4499_6320_49E5_B602_E6F7873ED145__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#ifndef __AFXWIN_H__
+ #error include 'stdafx.h' before including this file for PCH
+#endif
+
+#include "resource.h" // main symbols
+
+/////////////////////////////////////////////////////////////////////////////
+// CSubeditApp:
+// See subedit.cpp for the implementation of this class
+//
+
+class CSubeditApp : public CWinApp
+{
+public:
+ CSubeditApp();
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CSubeditApp)
+ public:
+ virtual BOOL InitInstance();
+ //}}AFX_VIRTUAL
+
+// Implementation
+ //{{AFX_MSG(CSubeditApp)
+ afx_msg void OnAppAbout();
+ // NOTE - the ClassWizard will add and remove member functions here.
+ // DO NOT EDIT what you see in these blocks of generated code !
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_SUBEDIT_H__071E4499_6320_49E5_B602_E6F7873ED145__INCLUDED_)