From 54c8fd7ac8028a4ffb194a7cfc03a99915b4a0b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20J=C3=B6nsson?= Date: Mon, 1 Jun 2015 18:10:43 +0200 Subject: [PATCH 1/5] Make case of "all" consistent. --- PowerEditor/src/ScitillaComponent/FindReplaceDlg.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/PowerEditor/src/ScitillaComponent/FindReplaceDlg.cpp b/PowerEditor/src/ScitillaComponent/FindReplaceDlg.cpp index 39ba9980..289624bf 100644 --- a/PowerEditor/src/ScitillaComponent/FindReplaceDlg.cpp +++ b/PowerEditor/src/ScitillaComponent/FindReplaceDlg.cpp @@ -2658,10 +2658,10 @@ BOOL CALLBACK Finder::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam) tmp.push_back(MenuItemUnit(NPPM_INTERNAL_SCINTILLAFINFERUNCOLLAPSE, TEXT("Uncollapse all"))); tmp.push_back(MenuItemUnit(0, TEXT("Separator"))); tmp.push_back(MenuItemUnit(NPPM_INTERNAL_SCINTILLAFINFERCOPY, TEXT("Copy"))); - tmp.push_back(MenuItemUnit(NPPM_INTERNAL_SCINTILLAFINFERSELECTALL, TEXT("Select All"))); - tmp.push_back(MenuItemUnit(NPPM_INTERNAL_SCINTILLAFINFERCLEARALL, TEXT("Clear All"))); + tmp.push_back(MenuItemUnit(NPPM_INTERNAL_SCINTILLAFINFERSELECTALL, TEXT("Select all"))); + tmp.push_back(MenuItemUnit(NPPM_INTERNAL_SCINTILLAFINFERCLEARALL, TEXT("Clear all"))); tmp.push_back(MenuItemUnit(0, TEXT("Separator"))); - tmp.push_back(MenuItemUnit(NPPM_INTERNAL_SCINTILLAFINFEROPENALL, TEXT("Open All"))); + tmp.push_back(MenuItemUnit(NPPM_INTERNAL_SCINTILLAFINFEROPENALL, TEXT("Open all"))); scintillaContextmenu.create(_hSelf, tmp); From d6081a5f3785fe0565900fc4c7f6ce1a78e5c6ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20J=C3=B6nsson?= Date: Mon, 1 Jun 2015 18:39:22 +0200 Subject: [PATCH 2/5] Improve copy functionality in find results window Just copy the actual results, without the additional formatting with line and file name. It respects the hierarchy in the results, i.e. you can copy all results from a search operation, or from a specific file, or just the lines you selected. --- PowerEditor/src/MISC/Common/Common.cpp | 33 +++++++++ PowerEditor/src/MISC/Common/Common.h | 2 + PowerEditor/src/Notepad_plus.cpp | 30 +------- .../src/ScitillaComponent/FindReplaceDlg.cpp | 71 ++++++++++++++++++- .../src/ScitillaComponent/FindReplaceDlg.h | 4 ++ .../ScitillaComponent/ScintillaEditView.cpp | 10 +++ .../src/ScitillaComponent/ScintillaEditView.h | 1 + 7 files changed, 121 insertions(+), 30 deletions(-) diff --git a/PowerEditor/src/MISC/Common/Common.cpp b/PowerEditor/src/MISC/Common/Common.cpp index e5236475..eb6e8ece 100644 --- a/PowerEditor/src/MISC/Common/Common.cpp +++ b/PowerEditor/src/MISC/Common/Common.cpp @@ -777,4 +777,37 @@ double stodLocale(const generic_string& str, _locale_t loc, size_t* idx) if (idx != NULL) *idx = (size_t)(eptr - ptr); return ans; +} + +bool str2Clipboard(const TCHAR *str2cpy, HWND hwnd) +{ + if (!str2cpy) + return false; + + int len2Allocate = lstrlen(str2cpy) + 1; + len2Allocate *= sizeof(TCHAR); + unsigned int cilpboardFormat = CF_TEXT; + + cilpboardFormat = CF_UNICODETEXT; + + HGLOBAL hglbCopy = ::GlobalAlloc(GMEM_MOVEABLE, len2Allocate); + if (hglbCopy == NULL) + { + return false; + } + + if (!::OpenClipboard(hwnd)) //_pPublicInterface->getHSelf())) + return false; + + ::EmptyClipboard(); + + // Lock the handle and copy the text to the buffer. + TCHAR *pStr = (TCHAR *)::GlobalLock(hglbCopy); + lstrcpy(pStr, str2cpy); + ::GlobalUnlock(hglbCopy); + + // Place the handle on the clipboard. + ::SetClipboardData(cilpboardFormat, hglbCopy); + ::CloseClipboard(); + return true; } \ No newline at end of file diff --git a/PowerEditor/src/MISC/Common/Common.h b/PowerEditor/src/MISC/Common/Common.h index 519de712..22572d9c 100644 --- a/PowerEditor/src/MISC/Common/Common.h +++ b/PowerEditor/src/MISC/Common/Common.h @@ -198,4 +198,6 @@ generic_string stringJoin(const std::vector& strings, const gene generic_string stringTakeWhileAdmissable(const generic_string& input, const generic_string& admissable); double stodLocale(const generic_string& str, _locale_t loc, size_t* idx = NULL); +bool str2Clipboard(const TCHAR *str2cpy, HWND hwnd); + #endif //M30_IDE_COMMUN_H diff --git a/PowerEditor/src/Notepad_plus.cpp b/PowerEditor/src/Notepad_plus.cpp index 1d455312..7b63f764 100644 --- a/PowerEditor/src/Notepad_plus.cpp +++ b/PowerEditor/src/Notepad_plus.cpp @@ -4557,35 +4557,7 @@ void Notepad_plus::getCurrentOpenedFiles(Session & session, bool includUntitledD bool Notepad_plus::str2Cliboard(const TCHAR *str2cpy) { - if (!str2cpy) - return false; - - int len2Allocate = lstrlen(str2cpy) + 1; - len2Allocate *= sizeof(TCHAR); - unsigned int cilpboardFormat = CF_TEXT; - - cilpboardFormat = CF_UNICODETEXT; - - HGLOBAL hglbCopy = ::GlobalAlloc(GMEM_MOVEABLE, len2Allocate); - if (hglbCopy == NULL) - { - return false; - } - - if (!::OpenClipboard(_pPublicInterface->getHSelf())) - return false; - - ::EmptyClipboard(); - - // Lock the handle and copy the text to the buffer. - TCHAR *pStr = (TCHAR *)::GlobalLock(hglbCopy); - lstrcpy(pStr, str2cpy); - ::GlobalUnlock(hglbCopy); - - // Place the handle on the clipboard. - ::SetClipboardData(cilpboardFormat, hglbCopy); - ::CloseClipboard(); - return true; + return str2Clipboard(str2cpy, _pPublicInterface->getHSelf()); } //ONLY CALL IN CASE OF EMERGENCY: EXCEPTION diff --git a/PowerEditor/src/ScitillaComponent/FindReplaceDlg.cpp b/PowerEditor/src/ScitillaComponent/FindReplaceDlg.cpp index 289624bf..1279b3fa 100644 --- a/PowerEditor/src/ScitillaComponent/FindReplaceDlg.cpp +++ b/PowerEditor/src/ScitillaComponent/FindReplaceDlg.cpp @@ -2505,6 +2505,75 @@ void Finder::openAll() } } +bool Finder::isLineActualSearchResult(int line) +{ + const int foldLevel = _scintView.execute(SCI_GETFOLDLEVEL, line) & SC_FOLDLEVELNUMBERMASK; + return foldLevel == SC_FOLDLEVELBASE + 3; +} + +generic_string Finder::prepareStringForClipboard(generic_string s) +{ + // Input: a string like "\tLine 3: search result". + // Output: "search result" + s = stringReplace(s, TEXT("\r"), TEXT("")); + s = stringReplace(s, TEXT("\n"), TEXT("")); + const unsigned int firstColon = s.find(TEXT(':')); + if (firstColon == std::string::npos) + { + // Should never happen. + assert(false); + return s; + } + else + { + // Plus 2 in order to deal with ": ". + return s.substr(2 + firstColon); + } +} + +void Finder::copy() +{ + size_t fromLine, toLine; + { + const int selStart = _scintView.execute(SCI_GETSELECTIONSTART); + const int selEnd = _scintView.execute(SCI_GETSELECTIONEND); + const bool hasSelection = selStart != selEnd; + const pair lineRange = _scintView.getSelectionLinesRange(); + if (hasSelection && lineRange.first != lineRange.second) + { + fromLine = lineRange.first; + toLine = lineRange.second; + } + else + { + // Abuse fold levels to find out which lines to copy to clipboard. + // We get the current line and then the next line which has a smaller fold level (SCI_GETLASTCHILD). + // Then we loop all lines between them and determine which actually contain search results. + fromLine = _scintView.getCurrentLineNumber(); + const int selectedLineFoldLevel = _scintView.execute(SCI_GETFOLDLEVEL, fromLine) & SC_FOLDLEVELNUMBERMASK; + toLine = _scintView.execute(SCI_GETLASTCHILD, fromLine, selectedLineFoldLevel); + } + } + + std::vector lines; + for (size_t line = fromLine; line <= toLine; ++line) + { + if (isLineActualSearchResult(line)) + { + lines.push_back(prepareStringForClipboard(_scintView.getLine(line))); + } + } + const generic_string toClipboard = stringJoin(lines, TEXT("\r\n")); + if (!toClipboard.empty()) + { + if (!str2Clipboard(toClipboard.c_str(), _hSelf)) + { + assert(false); + ::MessageBox(NULL, TEXT("Error placing text in clipboard."), TEXT("Notepad++"), MB_ICONINFORMATION); + } + } +} + void Finder::beginNewFilesSearch() { //_scintView.execute(SCI_SETLEXER, SCLEX_NULL); @@ -2617,7 +2686,7 @@ BOOL CALLBACK Finder::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam) case NPPM_INTERNAL_SCINTILLAFINFERCOPY : { - _scintView.execute(SCI_COPY); + copy(); return TRUE; } diff --git a/PowerEditor/src/ScitillaComponent/FindReplaceDlg.h b/PowerEditor/src/ScitillaComponent/FindReplaceDlg.h index 3d21ee18..280afc29 100644 --- a/PowerEditor/src/ScitillaComponent/FindReplaceDlg.h +++ b/PowerEditor/src/ScitillaComponent/FindReplaceDlg.h @@ -144,6 +144,7 @@ public: void setFinderStyle(); void removeAll(); void openAll(); + void copy(); void beginNewFilesSearch(); void finishFilesSearch(int count); void gotoNextFoundResult(int direction); @@ -177,6 +178,9 @@ private: _scintView.execute(SCI_SETREADONLY, isReadOnly); }; + bool isLineActualSearchResult(int line); + generic_string prepareStringForClipboard(generic_string s); + static FoundInfo EmptyFoundInfo; static SearchResultMarking EmptySearchResultMarking; }; diff --git a/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp b/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp index 97922c18..1e206a9b 100644 --- a/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp +++ b/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp @@ -31,6 +31,7 @@ #include "Parameters.h" #include "Sorters.h" #include "TCHAR.h" +#include using namespace std; @@ -1913,6 +1914,15 @@ void ScintillaEditView::showCallTip(int startPos, const TCHAR * def) execute(SCI_CALLTIPSHOW, startPos, LPARAM(defA)); } +generic_string ScintillaEditView::getLine(int lineNumber) +{ + int lineLen = execute(SCI_LINELENGTH, lineNumber); + const int bufSize = lineLen; + std::unique_ptr buf = std::make_unique(bufSize); + getLine(lineNumber, buf.get(), bufSize); + return buf.get(); +} + void ScintillaEditView::getLine(int lineNumber, TCHAR * line, int lineBufferLen) { WcharMbcsConvertor *wmc = WcharMbcsConvertor::getInstance(); diff --git a/PowerEditor/src/ScitillaComponent/ScintillaEditView.h b/PowerEditor/src/ScitillaComponent/ScintillaEditView.h index eb2f34c1..f218b83e 100644 --- a/PowerEditor/src/ScitillaComponent/ScintillaEditView.h +++ b/PowerEditor/src/ScitillaComponent/ScintillaEditView.h @@ -272,6 +272,7 @@ public: int replaceTargetRegExMode(const TCHAR * re, int fromTargetPos = -1, int toTargetPos = -1) const; void showAutoComletion(int lenEntered, const TCHAR * list); void showCallTip(int startPos, const TCHAR * def); + generic_string getLine(int lineNumber); void getLine(int lineNumber, TCHAR * line, int lineBufferLen); void addText(int length, const char *buf); From 933aae4fc25f007ce4ca5375be2ddf2b2bd0a191 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20J=C3=B6nsson?= Date: Mon, 1 Jun 2015 18:47:24 +0200 Subject: [PATCH 3/5] Improve str2Clipboard. Make it take generic_string instead of TCHAR*, since at most callsites we already have a generic_string. Improve error handling. Depending on where we are in the function when we get an error, we need to free the memory, unlock the memory, or close the clipboard. Note that if SetClipboardData succeeds then we should not do anything more to the memory. --- PowerEditor/src/MISC/Common/Common.cpp | 52 ++++++++++++++++---------- PowerEditor/src/MISC/Common/Common.h | 2 +- PowerEditor/src/Notepad_plus.cpp | 6 +-- PowerEditor/src/Notepad_plus.h | 2 +- PowerEditor/src/NppCommands.cpp | 2 +- 5 files changed, 39 insertions(+), 25 deletions(-) diff --git a/PowerEditor/src/MISC/Common/Common.cpp b/PowerEditor/src/MISC/Common/Common.cpp index eb6e8ece..3b97a041 100644 --- a/PowerEditor/src/MISC/Common/Common.cpp +++ b/PowerEditor/src/MISC/Common/Common.cpp @@ -779,35 +779,49 @@ double stodLocale(const generic_string& str, _locale_t loc, size_t* idx) return ans; } -bool str2Clipboard(const TCHAR *str2cpy, HWND hwnd) +bool str2Clipboard(const generic_string &str2cpy, HWND hwnd) { - if (!str2cpy) - return false; - - int len2Allocate = lstrlen(str2cpy) + 1; - len2Allocate *= sizeof(TCHAR); - unsigned int cilpboardFormat = CF_TEXT; - - cilpboardFormat = CF_UNICODETEXT; - + int len2Allocate = (str2cpy.size() + 1) * sizeof(TCHAR); HGLOBAL hglbCopy = ::GlobalAlloc(GMEM_MOVEABLE, len2Allocate); if (hglbCopy == NULL) { return false; } - - if (!::OpenClipboard(hwnd)) //_pPublicInterface->getHSelf())) + if (!::OpenClipboard(hwnd)) + { + ::GlobalFree(hglbCopy); + ::CloseClipboard(); return false; - - ::EmptyClipboard(); - + } + if (!::EmptyClipboard()) + { + ::GlobalFree(hglbCopy); + ::CloseClipboard(); + return false; + } // Lock the handle and copy the text to the buffer. TCHAR *pStr = (TCHAR *)::GlobalLock(hglbCopy); - lstrcpy(pStr, str2cpy); + if (pStr == NULL) + { + ::GlobalUnlock(hglbCopy); + ::GlobalFree(hglbCopy); + ::CloseClipboard(); + return false; + } + _tcscpy_s(pStr, len2Allocate / sizeof(TCHAR), str2cpy.c_str()); ::GlobalUnlock(hglbCopy); - // Place the handle on the clipboard. - ::SetClipboardData(cilpboardFormat, hglbCopy); - ::CloseClipboard(); + unsigned int clipBoardFormat = CF_UNICODETEXT; + if (::SetClipboardData(clipBoardFormat, hglbCopy) == NULL) + { + ::GlobalUnlock(hglbCopy); + ::GlobalFree(hglbCopy); + ::CloseClipboard(); + return false; + } + if (!::CloseClipboard()) + { + return false; + } return true; } \ No newline at end of file diff --git a/PowerEditor/src/MISC/Common/Common.h b/PowerEditor/src/MISC/Common/Common.h index 22572d9c..80171755 100644 --- a/PowerEditor/src/MISC/Common/Common.h +++ b/PowerEditor/src/MISC/Common/Common.h @@ -198,6 +198,6 @@ generic_string stringJoin(const std::vector& strings, const gene generic_string stringTakeWhileAdmissable(const generic_string& input, const generic_string& admissable); double stodLocale(const generic_string& str, _locale_t loc, size_t* idx = NULL); -bool str2Clipboard(const TCHAR *str2cpy, HWND hwnd); +bool str2Clipboard(const generic_string &str2cpy, HWND hwnd); #endif //M30_IDE_COMMUN_H diff --git a/PowerEditor/src/Notepad_plus.cpp b/PowerEditor/src/Notepad_plus.cpp index 7b63f764..c81d48a5 100644 --- a/PowerEditor/src/Notepad_plus.cpp +++ b/PowerEditor/src/Notepad_plus.cpp @@ -1933,7 +1933,7 @@ void Notepad_plus::copyMarkedLines() globalStr = currentStr; } } - str2Cliboard(globalStr.c_str()); + str2Cliboard(globalStr); } void Notepad_plus::cutMarkedLines() @@ -1953,7 +1953,7 @@ void Notepad_plus::cutMarkedLines() } } _pEditView->execute(SCI_ENDUNDOACTION); - str2Cliboard(globalStr.c_str()); + str2Cliboard(globalStr); } void Notepad_plus::deleteMarkedLines(bool isMarked) @@ -4555,7 +4555,7 @@ void Notepad_plus::getCurrentOpenedFiles(Session & session, bool includUntitledD _invisibleEditView.execute(SCI_SETDOCPOINTER, 0, oldDoc); } -bool Notepad_plus::str2Cliboard(const TCHAR *str2cpy) +bool Notepad_plus::str2Cliboard(const generic_string & str2cpy) { return str2Clipboard(str2cpy, _pPublicInterface->getHSelf()); } diff --git a/PowerEditor/src/Notepad_plus.h b/PowerEditor/src/Notepad_plus.h index f0d4d607..d209080f 100644 --- a/PowerEditor/src/Notepad_plus.h +++ b/PowerEditor/src/Notepad_plus.h @@ -599,7 +599,7 @@ private: void doSynScorll(HWND hW); void setWorkingDir(const TCHAR *dir); - bool str2Cliboard(const TCHAR *str2cpy); + bool str2Cliboard(const generic_string & str2cpy); bool bin2Cliboard(const UCHAR *uchar2cpy, size_t length); bool getIntegralDockingData(tTbData & dockData, int & iCont, bool & isVisible); diff --git a/PowerEditor/src/NppCommands.cpp b/PowerEditor/src/NppCommands.cpp index a75a8186..2df44ee7 100644 --- a/PowerEditor/src/NppCommands.cpp +++ b/PowerEditor/src/NppCommands.cpp @@ -676,7 +676,7 @@ void Notepad_plus::command(int id) { generic_string dir(buf->getFullPathName()); PathRemoveFileSpec(dir); - str2Cliboard(dir.c_str()); + str2Cliboard(dir); } else if (id == IDM_EDIT_FILENAMETOCLIP) { From 23ac5e3da840d82b1e8561aa7f5fa70c2f6655d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20J=C3=B6nsson?= Date: Mon, 1 Jun 2015 18:48:49 +0200 Subject: [PATCH 4/5] Mark some methods as const. --- PowerEditor/src/ScitillaComponent/FindReplaceDlg.cpp | 4 ++-- PowerEditor/src/ScitillaComponent/FindReplaceDlg.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/PowerEditor/src/ScitillaComponent/FindReplaceDlg.cpp b/PowerEditor/src/ScitillaComponent/FindReplaceDlg.cpp index 1279b3fa..cf9fdb4b 100644 --- a/PowerEditor/src/ScitillaComponent/FindReplaceDlg.cpp +++ b/PowerEditor/src/ScitillaComponent/FindReplaceDlg.cpp @@ -2505,13 +2505,13 @@ void Finder::openAll() } } -bool Finder::isLineActualSearchResult(int line) +bool Finder::isLineActualSearchResult(int line) const { const int foldLevel = _scintView.execute(SCI_GETFOLDLEVEL, line) & SC_FOLDLEVELNUMBERMASK; return foldLevel == SC_FOLDLEVELBASE + 3; } -generic_string Finder::prepareStringForClipboard(generic_string s) +generic_string Finder::prepareStringForClipboard(generic_string s) const { // Input: a string like "\tLine 3: search result". // Output: "search result" diff --git a/PowerEditor/src/ScitillaComponent/FindReplaceDlg.h b/PowerEditor/src/ScitillaComponent/FindReplaceDlg.h index 280afc29..52a436c0 100644 --- a/PowerEditor/src/ScitillaComponent/FindReplaceDlg.h +++ b/PowerEditor/src/ScitillaComponent/FindReplaceDlg.h @@ -178,8 +178,8 @@ private: _scintView.execute(SCI_SETREADONLY, isReadOnly); }; - bool isLineActualSearchResult(int line); - generic_string prepareStringForClipboard(generic_string s); + bool isLineActualSearchResult(int line) const; + generic_string prepareStringForClipboard(generic_string s) const; static FoundInfo EmptyFoundInfo; static SearchResultMarking EmptySearchResultMarking; From f3934fadb726ae4471e1a8008da066bf3ebcfa1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20J=C3=B6nsson?= Date: Mon, 1 Jun 2015 18:55:25 +0200 Subject: [PATCH 5/5] Fix array termination error. --- PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp b/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp index 1e206a9b..c21646fc 100644 --- a/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp +++ b/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp @@ -1917,7 +1917,7 @@ void ScintillaEditView::showCallTip(int startPos, const TCHAR * def) generic_string ScintillaEditView::getLine(int lineNumber) { int lineLen = execute(SCI_LINELENGTH, lineNumber); - const int bufSize = lineLen; + const int bufSize = lineLen + 1; std::unique_ptr buf = std::make_unique(bufSize); getLine(lineNumber, buf.get(), bufSize); return buf.get(); @@ -1928,6 +1928,8 @@ void ScintillaEditView::getLine(int lineNumber, TCHAR * line, int lineBufferLen) WcharMbcsConvertor *wmc = WcharMbcsConvertor::getInstance(); unsigned int cp = execute(SCI_GETCODEPAGE); char *lineA = new char[lineBufferLen]; + // From Scintilla documentation for SCI_GETLINE: "The buffer is not terminated by a 0 character." + memset(lineA, '\0', sizeof(char) * lineBufferLen); execute(SCI_GETLINE, lineNumber, (LPARAM)lineA); const TCHAR *lineW = wmc->char2wchar(lineA, cp); lstrcpyn(line, lineW, lineBufferLen);