From 494e094c7620dfb8e15a749d862f31442b524ca2 Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Thu, 2 Aug 2012 17:36:16 +0200 Subject: [PATCH] Fixed issue #1303: Past Recent Message command in commit dialog doesn't work Synced FindBugID-stuff with TortoiseSVN. Signed-off-by: Sven Strickroth --- src/Changelog.txt | 1 + src/TortoiseProc/CommitDlg.cpp | 89 +++++----- src/TortoiseProc/ProjectProperties.cpp | 289 ++++++++++++--------------------- src/TortoiseProc/ProjectProperties.h | 38 ++++- src/Utils/CommonAppUtils.cpp | 27 +++ src/Utils/CommonAppUtils.h | 10 ++ 6 files changed, 225 insertions(+), 229 deletions(-) diff --git a/src/Changelog.txt b/src/Changelog.txt index 6636fe92d..9d1642628 100644 --- a/src/Changelog.txt +++ b/src/Changelog.txt @@ -33,6 +33,7 @@ Released: unreleased * Fixed issue #1255: Adding non-versioned files from the commit dialog does not always work * Fixed issue #620: Unmodified files appear in the Modified File list while committing * Fixed issue #774: Revert does not work for submodules + * Fixed issue #1303: Past Recent Message command in commit dialog doesn't work = Release 1.7.11.3 = Released: 2012-07-07 diff --git a/src/TortoiseProc/CommitDlg.cpp b/src/TortoiseProc/CommitDlg.cpp index e3b037ac9..e166bd849 100644 --- a/src/TortoiseProc/CommitDlg.cpp +++ b/src/TortoiseProc/CommitDlg.cpp @@ -504,44 +504,6 @@ void CCommitDlg::OnOK() //std::set checkedLists; //std::set uncheckedLists; - // now let the bugtraq plugin check the commit message - CComPtr pProvider2 = NULL; - if (m_BugTraqProvider) - { - HRESULT hr = m_BugTraqProvider.QueryInterface(&pProvider2); - if (SUCCEEDED(hr)) - { - BSTR temp = NULL; - CString common = g_Git.m_CurrentDir; - BSTR repositoryRoot = common.AllocSysString(); - BSTR parameters = m_bugtraq_association.GetParameters().AllocSysString(); - BSTR commonRoot = SysAllocString(m_pathList.GetCommonRoot().GetDirectory().GetWinPath()); - BSTR commitMessage = m_sLogMessage.AllocSysString(); - SAFEARRAY *pathList = SafeArrayCreateVector(VT_BSTR, 0, m_selectedPathList.GetCount()); - - for (LONG index = 0; index < m_selectedPathList.GetCount(); ++index) - SafeArrayPutElement(pathList, &index, m_selectedPathList[index].GetGitPathString().AllocSysString()); - - if (FAILED(hr = pProvider2->CheckCommit(GetSafeHwnd(), parameters, repositoryRoot, commonRoot, pathList, commitMessage, &temp))) - { - COMError ce(hr); - CString sErr; - sErr.Format(IDS_ERR_FAILEDISSUETRACKERCOM, m_bugtraq_association.GetProviderName(), ce.GetMessageAndDescription().c_str()); - CMessageBox::Show(m_hWnd, sErr, _T("TortoiseGit"), MB_ICONERROR); - } - else - { - CString sError = temp; - if (!sError.IsEmpty()) - { - CMessageBox::Show(m_hWnd, sError, _T("TortoiseGit"), MB_ICONERROR); - return; - } - SysFreeString(temp); - } - } - } - //CString checkedfiles; //CString uncheckedfiles; @@ -728,7 +690,9 @@ void CCommitDlg::OnOK() //} m_sBugID.Trim(); - if (!m_sBugID.IsEmpty()) + CString sExistingBugID = m_ProjectProperties.FindBugID(m_sLogMessage); + sExistingBugID.Trim(); + if (!m_sBugID.IsEmpty() && m_sBugID.Compare(sExistingBugID)) { m_sBugID.Replace(_T(", "), _T(",")); m_sBugID.Replace(_T(" ,"), _T(",")); @@ -740,6 +704,44 @@ void CCommitDlg::OnOK() m_sLogMessage = sBugID + _T("\n") + m_sLogMessage; } + // now let the bugtraq plugin check the commit message + CComPtr pProvider2 = NULL; + if (m_BugTraqProvider) + { + HRESULT hr = m_BugTraqProvider.QueryInterface(&pProvider2); + if (SUCCEEDED(hr)) + { + BSTR temp = NULL; + CString common = g_Git.m_CurrentDir; + BSTR repositoryRoot = common.AllocSysString(); + BSTR parameters = m_bugtraq_association.GetParameters().AllocSysString(); + BSTR commonRoot = SysAllocString(m_pathList.GetCommonRoot().GetDirectory().GetWinPath()); + BSTR commitMessage = m_sLogMessage.AllocSysString(); + SAFEARRAY *pathList = SafeArrayCreateVector(VT_BSTR, 0, m_selectedPathList.GetCount()); + + for (LONG index = 0; index < m_selectedPathList.GetCount(); ++index) + SafeArrayPutElement(pathList, &index, m_selectedPathList[index].GetGitPathString().AllocSysString()); + + if (FAILED(hr = pProvider2->CheckCommit(GetSafeHwnd(), parameters, repositoryRoot, commonRoot, pathList, commitMessage, &temp))) + { + COMError ce(hr); + CString sErr; + sErr.Format(IDS_ERR_FAILEDISSUETRACKERCOM, m_bugtraq_association.GetProviderName(), ce.GetMessageAndDescription().c_str()); + CMessageBox::Show(m_hWnd, sErr, _T("TortoiseGit"), MB_ICONERROR); + } + else + { + CString sError = temp; + if (!sError.IsEmpty()) + { + CMessageBox::Show(m_hWnd, sError, _T("TortoiseGit"), MB_ICONERROR); + return; + } + SysFreeString(temp); + } + } + } + //if(checkedfiles.GetLength()>0) if (bAddSuccess && (nchecked || m_bCommitAmend || CTGitPath(g_Git.m_CurrentDir).IsMergeActive())) { @@ -1791,8 +1793,8 @@ void CCommitDlg::OnBnClickedHistory() CString sMsg = historyDlg.GetSelectedText(); if (sMsg != m_cLogMessage.GetText().Left(sMsg.GetLength())) { - CString sBugID = m_ProjectProperties.GetBugIDFromLog(sMsg); - if (!sBugID.IsEmpty()) + CString sBugID = m_ProjectProperties.FindBugID(sMsg); + if ((!sBugID.IsEmpty()) && ((GetDlgItem(IDC_BUGID)->IsWindowVisible()))) { SetDlgItemText(IDC_BUGID, sBugID); } @@ -1829,6 +1831,7 @@ void CCommitDlg::OnBnClickedBugtraqbutton() // first try the IBugTraqProvider2 interface CComPtr pProvider2 = NULL; HRESULT hr = m_BugTraqProvider.QueryInterface(&pProvider2); + bool bugIdOutSet = false; if (SUCCEEDED(hr)) { //CString common = m_ListCtrl.GetCommonURL(false).GetGitPathString(); @@ -1848,6 +1851,7 @@ void CCommitDlg::OnBnClickedBugtraqbutton() { if (bugIDOut) { + bugIdOutSet = true; m_sBugID = bugIDOut; SysFreeString(bugIDOut); SetDlgItemText(IDC_BUGID, m_sBugID); @@ -1907,7 +1911,7 @@ void CCommitDlg::OnBnClickedBugtraqbutton() if (!m_ProjectProperties.sMessage.IsEmpty()) { CString sBugID = m_ProjectProperties.FindBugID(m_sLogMessage); - if (!sBugID.IsEmpty()) + if (!sBugID.IsEmpty() && !bugIdOutSet) { SetDlgItemText(IDC_BUGID, sBugID); } @@ -1920,7 +1924,6 @@ void CCommitDlg::OnBnClickedBugtraqbutton() SafeArrayDestroy(pathList); SysFreeString(originalMessage); SysFreeString(temp); - } void CCommitDlg::FillPatchView() diff --git a/src/TortoiseProc/ProjectProperties.cpp b/src/TortoiseProc/ProjectProperties.cpp index e3cb165f7..20e6aa01b 100644 --- a/src/TortoiseProc/ProjectProperties.cpp +++ b/src/TortoiseProc/ProjectProperties.cpp @@ -20,15 +20,25 @@ #include "TortoiseProc.h" #include "UnicodeUtils.h" #include "ProjectProperties.h" +#include "AppUtils.h" //#include "GitProperties.h" #include "TGitPath.h" -#include #include "git.h" using namespace std; +struct num_compare +{ + bool operator() (const CString& lhs, const CString& rhs) const + { + return StrCmpLogicalW(lhs, rhs) < 0; + } +}; + ProjectProperties::ProjectProperties(void) + : regExNeedUpdate (true) + , nBugIdPos(-1) { bNumber = TRUE; bWarnIfNoIssue = FALSE; @@ -96,6 +106,7 @@ BOOL ProjectProperties::ReadProps(CTGitPath path) GetStringProps(this->sLabel,BUGTRAQPROPNAME_LABEL); GetStringProps(this->sMessage,BUGTRAQPROPNAME_MESSAGE); + nBugIdPos = sMessage.Find(L"%BUGID%"); GetStringProps(this->sUrl,BUGTRAQPROPNAME_URL); GetBOOLProps(this->bWarnIfNoIssue,BUGTRAQPROPNAME_WARNIFNOISSUE); @@ -335,10 +346,10 @@ CString ProjectProperties::GetBugIDFromLog(CString& msg) CString sFirstPart; CString sLastPart; BOOL bTop = FALSE; - if (sMessage.Find(_T("%BUGID%"))<0) + if (nBugIdPos < 0) return sBugID; - sFirstPart = sMessage.Left(sMessage.Find(_T("%BUGID%"))); - sLastPart = sMessage.Mid(sMessage.Find(_T("%BUGID%"))+7); + sFirstPart = sMessage.Left(nBugIdPos); + sLastPart = sMessage.Mid(nBugIdPos + 7); msg.TrimRight('\n'); if (msg.ReverseFind('\n')>=0) { @@ -370,6 +381,10 @@ CString ProjectProperties::GetBugIDFromLog(CString& msg) else sBugLine = msg; } + if (sBugLine.IsEmpty() && (msg.ReverseFind('\n') < 0)) + { + sBugLine = msg.Mid(msg.ReverseFind('\n')+1); + } if (sBugLine.Left(sFirstPart.GetLength()).Compare(sFirstPart)!=0) sBugLine.Empty(); if (sBugLine.Right(sLastPart.GetLength()).Compare(sLastPart)!=0) @@ -401,14 +416,28 @@ CString ProjectProperties::GetBugIDFromLog(CString& msg) return sBugID; } -BOOL ProjectProperties::FindBugID(const CString& msg, CWnd * pWnd) +void ProjectProperties::AutoUpdateRegex() +{ + if (regExNeedUpdate) + { + try + { + regCheck = tr1::wregex(sCheckRe); + regBugID = tr1::wregex(sBugIDRe); + } + catch (std::exception) + { + } + + regExNeedUpdate = false; + } +} + +std::vector ProjectProperties::FindBugIDPositions(const CString& msg) { size_t offset1 = 0; size_t offset2 = 0; - bool bFound = false; - - if (sUrl.IsEmpty()) - return FALSE; + std::vector result; // first use the checkre string to find bug ID's in the message if (!sCheckRe.IsEmpty()) @@ -419,8 +448,7 @@ BOOL ProjectProperties::FindBugID(const CString& msg, CWnd * pWnd) // match with two regex strings (without grouping!) try { - const tr1::wregex regCheck(sCheckRe); - const tr1::wregex regBugID(sBugIDRe); + AutoUpdateRegex(); const tr1::wsregex_iterator end; wstring s = msg; for (tr1::wsregex_iterator it(s.begin(), s.end(), regCheck); it != end; ++it) @@ -433,14 +461,7 @@ BOOL ProjectProperties::FindBugID(const CString& msg, CWnd * pWnd) ATLTRACE(_T("matched id : %s\n"), (*it2)[0].str().c_str()); ptrdiff_t matchposID = it2->position(0); CHARRANGE range = {(LONG)(matchpos+matchposID), (LONG)(matchpos+matchposID+(*it2)[0].str().size())}; - pWnd->SendMessage(EM_EXSETSEL, NULL, (LPARAM)&range); - CHARFORMAT2 format; - SecureZeroMemory(&format, sizeof(CHARFORMAT2)); - format.cbSize = sizeof(CHARFORMAT2); - format.dwMask = CFM_LINK; - format.dwEffects = CFE_LINK; - pWnd->SendMessage(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&format); - bFound = true; + result.push_back(range); } } } @@ -450,7 +471,7 @@ BOOL ProjectProperties::FindBugID(const CString& msg, CWnd * pWnd) { try { - const tr1::wregex regCheck(sCheckRe); + AutoUpdateRegex(); const tr1::wsregex_iterator end; wstring s = msg; for (tr1::wsregex_iterator it(s.begin(), s.end(), regCheck); it != end; ++it) @@ -462,30 +483,24 @@ BOOL ProjectProperties::FindBugID(const CString& msg, CWnd * pWnd) { ATLTRACE(_T("matched id : %s\n"), wstring(match[1]).c_str()); CHARRANGE range = {(LONG)(match[1].first-s.begin()), (LONG)(match[1].second-s.begin())}; - pWnd->SendMessage(EM_EXSETSEL, NULL, (LPARAM)&range); - CHARFORMAT2 format; - SecureZeroMemory(&format, sizeof(CHARFORMAT2)); - format.cbSize = sizeof(CHARFORMAT2); - format.dwMask = CFM_LINK; - format.dwEffects = CFE_LINK; - pWnd->SendMessage(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&format); - bFound = true; + result.push_back(range); } } } catch (exception) {} } } - else if ((!bFound)&&(!sMessage.IsEmpty())) + else if (result.empty() && (!sMessage.IsEmpty())) { CString sBugLine; CString sFirstPart; CString sLastPart; BOOL bTop = FALSE; - if (sMessage.Find(_T("%BUGID%"))<0) - return FALSE; - sFirstPart = sMessage.Left(sMessage.Find(_T("%BUGID%"))); - sLastPart = sMessage.Mid(sMessage.Find(_T("%BUGID%"))+7); + if (nBugIdPos < 0) + return result; + + sFirstPart = sMessage.Left(nBugIdPos); + sLastPart = sMessage.Mid(nBugIdPos + 7); CString sMsg = msg; sMsg.TrimRight('\n'); if (sMsg.ReverseFind('\n')>=0) @@ -515,10 +530,12 @@ BOOL ProjectProperties::FindBugID(const CString& msg, CWnd * pWnd) bTop = TRUE; } if (sBugLine.IsEmpty()) - return FALSE; + return result; + CString sBugIDPart = sBugLine.Mid(sFirstPart.GetLength(), sBugLine.GetLength() - sFirstPart.GetLength() - sLastPart.GetLength()); if (sBugIDPart.IsEmpty()) - return FALSE; + return result; + //the bug id part can contain several bug id's, separated by commas if (!bTop) offset1 = sMsg.GetLength() - sBugLine.GetLength() + sFirstPart.GetLength(); @@ -529,144 +546,34 @@ BOOL ProjectProperties::FindBugID(const CString& msg, CWnd * pWnd) { offset2 = offset1 + sBugIDPart.Find(','); CHARRANGE range = {(LONG)offset1, (LONG)offset2}; - pWnd->SendMessage(EM_EXSETSEL, NULL, (LPARAM)&range); - CHARFORMAT2 format; - SecureZeroMemory(&format, sizeof(CHARFORMAT2)); - format.cbSize = sizeof(CHARFORMAT2); - format.dwMask = CFM_LINK; - format.dwEffects = CFE_LINK; - pWnd->SendMessage(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&format); + result.push_back(range); sBugIDPart = sBugIDPart.Mid(sBugIDPart.Find(',')+1); offset1 = offset2 + 1; } offset2 = offset1 + sBugIDPart.GetLength(); CHARRANGE range = {(LONG)offset1, (LONG)offset2}; - pWnd->SendMessage(EM_EXSETSEL, NULL, (LPARAM)&range); - CHARFORMAT2 format; - SecureZeroMemory(&format, sizeof(CHARFORMAT2)); - format.cbSize = sizeof(CHARFORMAT2); - format.dwMask = CFM_LINK; - format.dwEffects = CFE_LINK; - pWnd->SendMessage(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&format); - return TRUE; + result.push_back(range); } - return FALSE; + + return result; } -std::set ProjectProperties::FindBugIDs(const CString& msg) +BOOL ProjectProperties::FindBugID(const CString& msg, CWnd * pWnd) { - size_t offset1 = 0; - size_t offset2 = 0; - bool bFound = false; + std::vector positions = FindBugIDPositions(msg); + CAppUtils::SetCharFormat(pWnd, CFM_LINK, CFE_LINK, positions); + + return positions.empty() ? FALSE : TRUE; +} + +std::set ProjectProperties::FindBugIDs (const CString& msg) +{ + std::vector positions = FindBugIDPositions(msg); std::set bugIDs; - // first use the checkre string to find bug ID's in the message - if (!sCheckRe.IsEmpty()) + for (std::vector::iterator iter = positions.begin(), end = positions.end(); iter != end; ++iter) { - if (!sBugIDRe.IsEmpty()) - { - // match with two regex strings (without grouping!) - try - { - const tr1::wregex regCheck(sCheckRe); - const tr1::wregex regBugID(sBugIDRe); - const tr1::wsregex_iterator end; - wstring s = msg; - for (tr1::wsregex_iterator it(s.begin(), s.end(), regCheck); it != end; ++it) - { - // (*it)[0] is the matched string - wstring matchedString = (*it)[0]; - for (tr1::wsregex_iterator it2(matchedString.begin(), matchedString.end(), regBugID); it2 != end; ++it2) - { - ATLTRACE(_T("matched id : %s\n"), (*it2)[0].str().c_str()); - bugIDs.insert(CString((*it2)[0].str().c_str())); - } - } - } - catch (exception) {} - } - else - { - try - { - const tr1::wregex regCheck(sCheckRe); - const tr1::wsregex_iterator end; - wstring s = msg; - for (tr1::wsregex_iterator it(s.begin(), s.end(), regCheck); it != end; ++it) - { - const tr1::wsmatch match = *it; - // we define group 1 as the whole issue text and - // group 2 as the bug ID - if (match.size() >= 2) - { - ATLTRACE(_T("matched id : %s\n"), wstring(match[1]).c_str()); - bugIDs.insert(CString(wstring(match[1]).c_str())); - } - } - } - catch (exception) {} - } - } - else if ((!bFound)&&(!sMessage.IsEmpty())) - { - CString sBugLine; - CString sFirstPart; - CString sLastPart; - BOOL bTop = FALSE; - if (sMessage.Find(_T("%BUGID%"))<0) - return bugIDs; - sFirstPart = sMessage.Left(sMessage.Find(_T("%BUGID%"))); - sLastPart = sMessage.Mid(sMessage.Find(_T("%BUGID%"))+7); - CString sMsg = msg; - sMsg.TrimRight('\n'); - if (sMsg.ReverseFind('\n')>=0) - { - if (bAppend) - sBugLine = sMsg.Mid(sMsg.ReverseFind('\n')+1); - else - { - sBugLine = sMsg.Left(sMsg.Find('\n')); - bTop = TRUE; - } - } - else - sBugLine = sMsg; - if (sBugLine.Left(sFirstPart.GetLength()).Compare(sFirstPart)!=0) - sBugLine.Empty(); - if (sBugLine.Right(sLastPart.GetLength()).Compare(sLastPart)!=0) - sBugLine.Empty(); - if (sBugLine.IsEmpty()) - { - if (sMsg.Find('\n')>=0) - sBugLine = sMsg.Left(sMsg.Find('\n')); - if (sBugLine.Left(sFirstPart.GetLength()).Compare(sFirstPart)!=0) - sBugLine.Empty(); - if (sBugLine.Right(sLastPart.GetLength()).Compare(sLastPart)!=0) - sBugLine.Empty(); - bTop = TRUE; - } - if (sBugLine.IsEmpty()) - return bugIDs; - CString sBugIDPart = sBugLine.Mid(sFirstPart.GetLength(), sBugLine.GetLength() - sFirstPart.GetLength() - sLastPart.GetLength()); - if (sBugIDPart.IsEmpty()) - return bugIDs; - //the bug id part can contain several bug id's, separated by commas - if (!bTop) - offset1 = sMsg.GetLength() - sBugLine.GetLength() + sFirstPart.GetLength(); - else - offset1 = sFirstPart.GetLength(); - sBugIDPart.Trim(_T(",")); - while (sBugIDPart.Find(',')>=0) - { - offset2 = offset1 + sBugIDPart.Find(','); - CHARRANGE range = {(LONG)offset1, (LONG)offset2}; - bugIDs.insert(msg.Mid(range.cpMin, range.cpMax-range.cpMin)); - sBugIDPart = sBugIDPart.Mid(sBugIDPart.Find(',')+1); - offset1 = offset2 + 1; - } - offset2 = offset1 + sBugIDPart.GetLength(); - CHARRANGE range = {(LONG)offset1, (LONG)offset2}; - bugIDs.insert(msg.Mid(range.cpMin, range.cpMax-range.cpMin)); + bugIDs.insert(msg.Mid(iter->cpMin, iter->cpMax - iter->cpMin)); } return bugIDs; @@ -675,18 +582,31 @@ std::set ProjectProperties::FindBugIDs(const CString& msg) CString ProjectProperties::FindBugID(const CString& msg) { CString sRet; - - std::set bugIDs = FindBugIDs(msg); - - for (std::set::iterator it = bugIDs.begin(); it != bugIDs.end(); ++it) + if (!sCheckRe.IsEmpty() || (nBugIdPos >= 0)) { - sRet += *it; - sRet += _T(" "); + std::vector positions = FindBugIDPositions(msg); + std::set bugIDs; + for (std::vector::iterator iter = positions.begin(), end = positions.end(); iter != end; ++iter) + { + bugIDs.insert(msg.Mid(iter->cpMin, iter->cpMax - iter->cpMin)); + } + + for (std::set::iterator it = bugIDs.begin(); it != bugIDs.end(); ++it) + { + sRet += *it; + sRet += _T(" "); + } + sRet.Trim(); } - sRet.Trim(); + return sRet; } +bool ProjectProperties::MightContainABugID() +{ + return !sCheckRe.IsEmpty() || (nBugIdPos >= 0); +} + CString ProjectProperties::GetBugIDUrl(const CString& sBugID) { CString ret; @@ -702,15 +622,6 @@ CString ProjectProperties::GetBugIDUrl(const CString& sBugID) BOOL ProjectProperties::CheckBugID(const CString& sID) { - if (!sCheckRe.IsEmpty()&&(!bNumber)&&!sID.IsEmpty()) - { - CString sBugID = sID; - sBugID.Replace(_T(", "), _T(",")); - sBugID.Replace(_T(" ,"), _T(",")); - CString sMsg = sMessage; - sMsg.Replace(_T("%BUGID%"), sBugID); - return HasBugID(sMsg); - } if (bNumber) { // check if the revision actually _is_ a number @@ -720,7 +631,7 @@ BOOL ProjectProperties::CheckBugID(const CString& sID) for (int i=0; i #include "TGitPath.h" using namespace std; +#include #define BUGTRAQPROPNAME_LABEL _T("bugtraq.label") #define BUGTRAQPROPNAME_MESSAGE _T("bugtraq.message") @@ -82,10 +83,21 @@ public: * \param msg the log message * \param pWnd Pointer to a rich edit control */ +#ifdef _RICHEDIT_ + std::vector FindBugIDPositions(const CString& msg); +#endif BOOL FindBugID(const CString& msg, CWnd * pWnd); CString FindBugID(const CString& msg); std::set FindBugIDs(const CString& msg); + + /** + * Check whether calling \ref FindBugID or \ref FindBugIDPositions + * is worthwhile. If the result is @a false, those functions would + * return empty strings or sets, respectively. + */ + bool MightContainABugID(); + /** * Searches for the BugID inside a log message. If one is found, * that BugID is returned. If none is found, an empty string is returned. @@ -140,6 +152,16 @@ public: * Returns the path from which the properties were read. */ CTGitPath GetPropsPath() {return propsPath;} + + /** replaces bNumer: a regular expression string to check the validity of + * the entered bug ID. */ + const CString& GetCheckRe() const {return sCheckRe;} + void SetCheckRe(const CString& s) {sCheckRe = s;regExNeedUpdate=true;AutoUpdateRegex();} + + /** used to extract the bug ID from the string matched by sCheckRe */ + const CString& GetBugIDRe() const {return sBugIDRe;} + void SetBugIDRe(const CString& s) {sBugIDRe = s;regExNeedUpdate=true;AutoUpdateRegex();} + public: /** The label to show in the commit dialog where the issue number/bug id * is entered. Example: "Bug-ID: " or "Issue-No.:". Default is "Bug-ID :" */ @@ -229,6 +251,20 @@ public: private: CString sAutoProps; CTGitPath propsPath; + + /** + * Constructing regex objects is expensive. Therefore, cache them here. + */ + void AutoUpdateRegex(); + + bool CheckStringProp(CString& s, const std::string& propname, const CString& propval, LPCSTR prop); + + bool regExNeedUpdate; + std::tr1::wregex regCheck; + std::tr1::wregex regBugID; + + int nBugIdPos; ///< result of sMessage.Find(L"%BUGID%"); + #ifdef DEBUG friend class PropTest; #endif diff --git a/src/Utils/CommonAppUtils.cpp b/src/Utils/CommonAppUtils.cpp index 6e7b77d20..a00bc5a1c 100644 --- a/src/Utils/CommonAppUtils.cpp +++ b/src/Utils/CommonAppUtils.cpp @@ -207,3 +207,30 @@ bool CCommonAppUtils::FileOpenSave(CString& path, int * filterindex, UINT title, delete [] pszFilters; return false; } + +void CCommonAppUtils::SetCharFormat(CWnd* window, DWORD mask , DWORD effects, const std::vector& positions) +{ + CHARFORMAT2 format; + SecureZeroMemory(&format, sizeof(CHARFORMAT2)); + format.cbSize = sizeof(CHARFORMAT2); + format.dwMask = mask; + format.dwEffects = effects; + format.crTextColor = effects; + + for (std::vector::const_iterator iter = positions.begin(), end = positions.end(); iter != end; ++iter) + { + CHARRANGE range = *iter; + window->SendMessage(EM_EXSETSEL, NULL, (LPARAM)&range); + window->SendMessage(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&format); + } +} + +void CCommonAppUtils::SetCharFormat(CWnd* window, DWORD mask, DWORD effects ) +{ + CHARFORMAT2 format; + SecureZeroMemory(&format, sizeof(CHARFORMAT2)); + format.cbSize = sizeof(CHARFORMAT2); + format.dwMask = mask; + format.dwEffects = effects; + window->SendMessage(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&format); +} diff --git a/src/Utils/CommonAppUtils.h b/src/Utils/CommonAppUtils.h index cbba3c199..5d1c1b734 100644 --- a/src/Utils/CommonAppUtils.h +++ b/src/Utils/CommonAppUtils.h @@ -38,6 +38,16 @@ public: static bool FileOpenSave(CString& path, int * filterindex, UINT title, UINT filter, bool bOpen, HWND hwndOwner = NULL); + /** + * Apply the @a effects or color (depending on @a mask) + * for all char ranges given in @a positions to the + * @a window text. + */ + static void SetCharFormat(CWnd* window, DWORD mask, DWORD effects, const std::vector& positions); + +private: + static void SetCharFormat(CWnd* window, DWORD mask, DWORD effects); + protected: CCommonAppUtils(void){}; ~CCommonAppUtils(void){}; -- 2.11.4.GIT