diff --git a/PowerEditor/installer/nativeLang/english.xml b/PowerEditor/installer/nativeLang/english.xml index a564878ea..f5b748e57 100644 --- a/PowerEditor/installer/nativeLang/english.xml +++ b/PowerEditor/installer/nativeLang/english.xml @@ -91,7 +91,7 @@ - + @@ -334,6 +334,7 @@ + diff --git a/PowerEditor/installer/nativeLang/french.xml b/PowerEditor/installer/nativeLang/french.xml index dad4ba028..4dc021cbc 100644 --- a/PowerEditor/installer/nativeLang/french.xml +++ b/PowerEditor/installer/nativeLang/french.xml @@ -95,6 +95,7 @@ + @@ -331,6 +332,7 @@ + diff --git a/PowerEditor/src/MISC/Common/Common.cpp b/PowerEditor/src/MISC/Common/Common.cpp index f50552538..eaacb312c 100644 --- a/PowerEditor/src/MISC/Common/Common.cpp +++ b/PowerEditor/src/MISC/Common/Common.cpp @@ -1101,3 +1101,28 @@ bool isCertificateValidated(const generic_string & fullFilePath, const generic_s return isOK; } + +bool isAssoCommandExisting(LPCTSTR FullPathName) +{ + bool isAssoCommandExisting = false; + + bool isFileExisting = PathFileExists(FullPathName) != FALSE; + + if (isFileExisting) + { + PTSTR ext = PathFindExtension(FullPathName); + + HRESULT hres; + wchar_t buffer[MAX_PATH] = TEXT(""); + DWORD bufferLen = MAX_PATH; + + // check if association exist + hres = AssocQueryString(ASSOCF_VERIFY|ASSOCF_INIT_IGNOREUNKNOWN, ASSOCSTR_COMMAND, ext, NULL, buffer, &bufferLen); + + isAssoCommandExisting = (hres == S_OK) // check if association exist and no error + && (buffer != NULL) // check if buffer is not NULL + && (wcsstr(buffer, TEXT("notepad++.exe")) == NULL); // check association with notepad++ + + } + return isAssoCommandExisting; +} \ No newline at end of file diff --git a/PowerEditor/src/MISC/Common/Common.h b/PowerEditor/src/MISC/Common/Common.h index 75f61e260..b4886cb05 100644 --- a/PowerEditor/src/MISC/Common/Common.h +++ b/PowerEditor/src/MISC/Common/Common.h @@ -187,3 +187,4 @@ generic_string uintToString(unsigned int val); HWND CreateToolTip(int toolID, HWND hDlg, HINSTANCE hInst, const PTSTR pszText); bool isCertificateValidated(const generic_string & fullFilePath, const generic_string & subjectName2check); +bool isAssoCommandExisting(LPCTSTR FullPathName); diff --git a/PowerEditor/src/Notepad_plus.cpp b/PowerEditor/src/Notepad_plus.cpp index bc6eac5d9..6d9767562 100644 --- a/PowerEditor/src/Notepad_plus.cpp +++ b/PowerEditor/src/Notepad_plus.cpp @@ -49,6 +49,7 @@ #include "functionListPanel.h" #include "fileBrowser.h" #include "LongRunningOperation.h" +#include "Common.h" using namespace std; @@ -1943,6 +1944,8 @@ void Notepad_plus::checkDocState() enableCommand(IDM_FILE_OPEN_FOLDER, isFileExisting, MENU); enableCommand(IDM_FILE_RELOAD, isFileExisting, MENU); + enableCommand(IDM_FILE_OPEN_DEFAULT_VIEWER, isAssoCommandExisting(curBuf->getFullPathName()), MENU); + enableConvertMenuItems(curBuf->getEolFormat()); checkUnicodeMenuItems(); checkLangsMenu(-1); diff --git a/PowerEditor/src/Notepad_plus.rc b/PowerEditor/src/Notepad_plus.rc index 4ff3089e6..a6a81f04c 100644 --- a/PowerEditor/src/Notepad_plus.rc +++ b/PowerEditor/src/Notepad_plus.rc @@ -222,6 +222,7 @@ BEGIN MENUITEM "Explorer", IDM_FILE_OPEN_FOLDER MENUITEM "cmd", IDM_FILE_OPEN_CMD END + MENUITEM "Open in Default Viewer" IDM_FILE_OPEN_DEFAULT_VIEWER MENUITEM "Open Folder as Workspace...", IDM_FILE_OPENFOLDERASWORSPACE MENUITEM "Re&load from Disk", IDM_FILE_RELOAD MENUITEM "&Save", IDM_FILE_SAVE diff --git a/PowerEditor/src/NppCommands.cpp b/PowerEditor/src/NppCommands.cpp index e2d3f912b..3af525985 100644 --- a/PowerEditor/src/NppCommands.cpp +++ b/PowerEditor/src/NppCommands.cpp @@ -105,6 +105,34 @@ void Notepad_plus::command(int id) } break; + case IDM_FILE_OPEN_DEFAULT_VIEWER: + { + // Opens file in its default viewer. + // Has the same effect as double–clicking this file in Windows Explorer. + BufferID buf = _pEditView->getCurrentBufferID(); + HINSTANCE res = ::ShellExecute(NULL, TEXT("open"), buf->getFullPathName(), NULL, NULL, SW_SHOW); + + // As per MSDN (https://msdn.microsoft.com/en-us/library/windows/desktop/bb762153(v=vs.85).aspx) + // If the function succeeds, it returns a value greater than 32. + // If the function fails, it returns an error value that indicates the cause of the failure. + int retResult = reinterpret_cast(res); + if (retResult <= 32) + { + generic_string errorMsg; + errorMsg += GetLastErrorAsString(retResult); + errorMsg += TEXT("An attempt was made to execute the below command."); + errorMsg += TEXT("\n----------------------------------------------------------"); + errorMsg += TEXT("\nCommand: "); + errorMsg += buf->getFullPathName(); + errorMsg += TEXT("\nError Code: "); + errorMsg += intToString(retResult); + errorMsg += TEXT("\n----------------------------------------------------------"); + + ::MessageBox(_pPublicInterface->getHSelf(), errorMsg.c_str(), TEXT("ShellExecute - ERROR"), MB_ICONINFORMATION | MB_APPLMODAL); + } + } + break; + case IDM_FILE_OPENFOLDERASWORSPACE: { generic_string folderPath = folderBrowser(_pPublicInterface->getHSelf(), TEXT("Select a folder to add in Folder as Workspace panel")); diff --git a/PowerEditor/src/NppNotification.cpp b/PowerEditor/src/NppNotification.cpp index 9318e1daf..632db9058 100644 --- a/PowerEditor/src/NppNotification.cpp +++ b/PowerEditor/src/NppNotification.cpp @@ -32,6 +32,7 @@ #include "VerticalFileSwitcher.h" #include "ProjectPanel.h" #include "documentMap.h" +#include "Common.h" #include using namespace std; @@ -514,7 +515,8 @@ BOOL Notepad_plus::notify(SCNotification *notification) if (!_tabPopupMenu.isCreated()) { - std::vector itemUnitArray; + // IMPORTANT: If list below is modified, you have to change the value of tabContextMenuItemPos[] in localization.cpp file + std::vector itemUnitArray; itemUnitArray.push_back(MenuItemUnit(IDM_FILE_CLOSE, TEXT("Close"))); itemUnitArray.push_back(MenuItemUnit(IDM_FILE_CLOSEALL_BUT_CURRENT, TEXT("Close All BUT This"))); itemUnitArray.push_back(MenuItemUnit(IDM_FILE_CLOSEALL_TOLEFT, TEXT("Close All to the Left"))); @@ -529,6 +531,8 @@ BOOL Notepad_plus::notify(SCNotification *notification) itemUnitArray.push_back(MenuItemUnit(IDM_FILE_OPEN_FOLDER, TEXT("Open Containing Folder in Explorer"))); itemUnitArray.push_back(MenuItemUnit(IDM_FILE_OPEN_CMD, TEXT("Open Containing Folder in cmd"))); itemUnitArray.push_back(MenuItemUnit(0, NULL)); + itemUnitArray.push_back(MenuItemUnit(IDM_FILE_OPEN_DEFAULT_VIEWER, TEXT("Open in Default Viewer"))); + itemUnitArray.push_back(MenuItemUnit(0, NULL)); itemUnitArray.push_back(MenuItemUnit(IDM_EDIT_SETREADONLY, TEXT("Read-Only"))); itemUnitArray.push_back(MenuItemUnit(IDM_EDIT_CLEARREADONLY, TEXT("Clear Read-Only Flag"))); itemUnitArray.push_back(MenuItemUnit(0, NULL)); @@ -540,6 +544,7 @@ BOOL Notepad_plus::notify(SCNotification *notification) itemUnitArray.push_back(MenuItemUnit(IDM_VIEW_CLONE_TO_ANOTHER_VIEW, TEXT("Clone to Other View"))); itemUnitArray.push_back(MenuItemUnit(IDM_VIEW_GOTO_NEW_INSTANCE, TEXT("Move to New Instance"))); itemUnitArray.push_back(MenuItemUnit(IDM_VIEW_LOAD_IN_NEW_INSTANCE, TEXT("Open in New Instance"))); + // IMPORTANT: If list above is modified, you have to change the value of tabContextMenuItemPos[] in localization.cpp file _tabPopupMenu.create(_pPublicInterface->getHSelf(), itemUnitArray); _nativeLangSpeaker.changeLangTabContextMenu(_tabPopupMenu.getMenuHandle()); @@ -560,6 +565,8 @@ BOOL Notepad_plus::notify(SCNotification *notification) _tabPopupMenu.enableItem(IDM_FILE_DELETE, isFileExisting); _tabPopupMenu.enableItem(IDM_FILE_RENAME, isFileExisting); + _tabPopupMenu.enableItem(IDM_FILE_OPEN_DEFAULT_VIEWER, isAssoCommandExisting(buf->getFullPathName())); + bool isDirty = buf->isDirty(); bool isUntitled = buf->isUntitled(); _tabPopupMenu.enableItem(IDM_VIEW_GOTO_NEW_INSTANCE, !(isDirty||isUntitled)); diff --git a/PowerEditor/src/Parameters.cpp b/PowerEditor/src/Parameters.cpp index 9ba6ca9b1..a9df4e53c 100644 --- a/PowerEditor/src/Parameters.cpp +++ b/PowerEditor/src/Parameters.cpp @@ -81,6 +81,7 @@ static const WinMenuKeyDefinition winKeyDefs[] = { VK_O, IDM_FILE_OPEN, true, false, false, nullptr }, { VK_NULL, IDM_FILE_OPEN_FOLDER, false, false, false, nullptr }, { VK_NULL, IDM_FILE_OPEN_CMD, false, false, false, nullptr }, + { VK_NULL, IDM_FILE_OPEN_DEFAULT_VIEWER, false, false, false, nullptr }, { VK_NULL, IDM_FILE_OPENFOLDERASWORSPACE, false, false, false, nullptr }, { VK_NULL, IDM_FILE_RELOAD, false, false, false, nullptr }, { VK_S, IDM_FILE_SAVE, true, false, false, nullptr }, diff --git a/PowerEditor/src/localization.cpp b/PowerEditor/src/localization.cpp index d78421679..268c5e802 100644 --- a/PowerEditor/src/localization.cpp +++ b/PowerEditor/src/localization.cpp @@ -364,27 +364,32 @@ void NativeLangSpeaker::changeMenuLang(HMENU menuHandle, generic_string & plugin static const int tabContextMenuItemPos[] = { +// +-------------- The order in tab menu (NppNotification.cpp : if (!_tabPopupMenu.isCreated()) +// | +// | +------ Number in english.xml (.xml) : +// | | 0, // 0 : Close 1, // 1 : Close ALL BUT This 4, // 2 : Save 5, // 3 : Save As 9, // 4 : Print - 21, // 5 : Move to Other View - 22, // 6 : Clone to Other View - 17, // 7 : Full File Path to Clipboard - 18, // 8 : Filename to Clipboard - 19, // 9 : Current Dir. Path to Clipboard + 23, // 5 : Move to Other View + 24, // 6 : Clone to Other View + 19, // 7 : Full File Path to Clipboard + 20, // 8 : Filename to Clipboard + 21, // 9 : Current Dir. Path to Clipboard 6, // 10: Rename 7, // 11: Move to Recycle Bin - 14, // 12: Read-Only - 15, // 13: Clear Read-Only Flag - 23, // 14: Move to New Instance - 24, // 15: Open to New Instance + 16, // 12: Read-Only + 17, // 13: Clear Read-Only Flag + 25, // 14: Move to New Instance + 26, // 15: Open to New Instance 8, // 16: Reload 2, // 17: Close ALL to the Left 3, // 18: Close ALL to the Right 11, // 19: Open Containing Folder in Explorer 12, // 20: Open Containing Folder in cmd + 14, // 21: Open in Default Viewer -1 //-------End }; diff --git a/PowerEditor/src/menuCmdID.h b/PowerEditor/src/menuCmdID.h index f24430093..8018faa02 100644 --- a/PowerEditor/src/menuCmdID.h +++ b/PowerEditor/src/menuCmdID.h @@ -56,10 +56,11 @@ #define IDM_FILE_OPEN_CMD (IDM_FILE + 20) #define IDM_FILE_RESTORELASTCLOSEDFILE (IDM_FILE + 21) #define IDM_FILE_OPENFOLDERASWORSPACE (IDM_FILE + 22) + #define IDM_FILE_OPEN_DEFAULT_VIEWER (IDM_FILE + 23) // IMPORTANT: If list above is modified, you have to change the following values: // To be updated if new menu item(s) is (are) added in menu "File" - #define IDM_FILEMENU_LASTONE IDM_FILE_OPENFOLDERASWORSPACE + #define IDM_FILEMENU_LASTONE IDM_FILE_OPEN_DEFAULT_VIEWER // 0 based position of command "Exit" including the bars in the file menu // and without counting "Recent files history" items @@ -68,25 +69,26 @@ // 1 Open... // 2 Open Containing Folder // 3 Open Folder as Workspace -// 4 Reload from Disk -// 5 Save -// 6 Save As... -// 7 Save a Copy As... -// 8 Save All -// 9 Rename... -//10 Close -//11 Close All -//12 Close More -//13 Move to Recycle Bin -//14 -------- -//15 Load Session... -//16 Save Session... -//17 -------- -//18 Print... -//19 Print Now -//20 -------- -//21 Exit - #define IDM_FILEMENU_EXISTCMDPOSITION 21 +// 4 Open in Default Viewer +// 5 Reload from Disk +// 6 Save +// 7 Save As... +// 8 Save a Copy As... +// 9 Save All +//10 Rename... +//11 Close +//12 Close All +//13 Close More +//14 Move to Recycle Bin +//15 -------- +//16 Load Session... +//17 Save Session... +//18 -------- +//19 Print... +//20 Print Now +//21 -------- +//22 Exit + #define IDM_FILEMENU_EXISTCMDPOSITION 22 #define IDM_EDIT (IDM + 2000)