Skip to content

Commit

Permalink
Add "Open" context menu to open file, folder, link and email for sele…
Browse files Browse the repository at this point in the history
…cted text or text around caret.

Add "Open Containing Folder" menu to open containing folder for current file, selected text, or text around caret.
  • Loading branch information
zufuliu committed Oct 31, 2018
1 parent e87ff65 commit 3f0fd7c
Show file tree
Hide file tree
Showing 17 changed files with 332 additions and 90 deletions.
2 changes: 1 addition & 1 deletion metapath/src/Dialogs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1199,7 +1199,7 @@ INT_PTR CALLBACK GetFilterDlgProc(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lP
RECT rc;

GetWindowRect(GetDlgItem(hwnd, IDC_BROWSEFILTER), &rc);
//MapWindowPoints(hwnd,NULL,(POINT*)&rc,2);
//MapWindowPoints(hwnd, NULL, (POINT*)&rc, 2);
// Seems that TrackPopupMenuEx() works with client coords...?
const DWORD dwCmd = TrackPopupMenuEx(hMenu, TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, rc.left + 1, rc.bottom + 1, hwnd, NULL);

Expand Down
4 changes: 2 additions & 2 deletions metapath/src/Dlapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ BOOL DirList_TerminateIconThread(HWND hwnd) {
LPDLDATA lpdl = (LPVOID)GetProp(hwnd, pDirListProp);
SetEvent(lpdl->hExitThread);

//WaitForSingleObject(lpdl->hTerminatedThread,INFINITE);
//WaitForSingleObject(lpdl->hTerminatedThread, INFINITE);
while (WaitForSingleObject(lpdl->hTerminatedThread, 0) != WAIT_OBJECT_0) {
MSG msg;
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
Expand Down Expand Up @@ -1172,7 +1172,7 @@ BOOL IL_GetDisplayName(LPSHELLFOLDER lpsf, LPCITEMIDLIST pidl, DWORD dwFlags, LP
// break;
//
//case STRRET_CSTR:
// lstrcpyn(lpszDisplayName,str.cStr,nDisplayName);
// lstrcpyn(lpszDisplayName, str.cStr, nDisplayName);
// break;
//}
//return TRUE;
Expand Down
14 changes: 7 additions & 7 deletions metapath/src/Helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,7 @@ BOOL PathGetLnkPath(LPCWSTR pszLnkFile, LPWSTR pszResPath, int cchResPath) {
if (SUCCEEDED(psl->lpVtbl->QueryInterface(psl, &IID_IPersistFile, (void **)(&ppf)))) {
WCHAR wsz[MAX_PATH];

/*MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED, pszLnkFile, -1, wsz, MAX_PATH);*/
/*MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pszLnkFile, -1, wsz, MAX_PATH);*/
lstrcpy(wsz, pszLnkFile);

if (SUCCEEDED(ppf->lpVtbl->Load(ppf, wsz, STGM_READ))) {
Expand Down Expand Up @@ -777,7 +777,7 @@ BOOL PathCreateLnk(LPCWSTR pszLnkDir, LPCWSTR pszPath) {

if (SUCCEEDED(psl->lpVtbl->QueryInterface(psl, &IID_IPersistFile, (void **)(&ppf)))) {
WCHAR wsz[MAX_PATH];
/*MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED, tchLnkFileName,-1,wsz,MAX_PATH);*/
/*MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, tchLnkFileName, -1, wsz, MAX_PATH);*/
lstrcpy(wsz, tchLnkFileName);

if (NOERROR == psl->lpVtbl->SetPath(psl, pszPath) && SUCCEEDED(ppf->lpVtbl->Save(ppf, wsz, TRUE))) {
Expand Down Expand Up @@ -1035,7 +1035,7 @@ HDROP CreateDropHandle(LPCWSTR lpFileName) {
//
// ExecDDECommand()
//
// Execute a DDE command (Msg,App,Topic)
// Execute a DDE command (Msg, App, Topic)
//
//
HDDEDATA CALLBACK DdeCallback(UINT uType, UINT uFmt, HCONV hconv, HSZ hsz1, HSZ hsz2, HDDEDATA hdata, ULONG_PTR dwData1, ULONG_PTR dwData2) {
Expand Down Expand Up @@ -1374,9 +1374,9 @@ BOOL MRU_Save(LPMRULIST pmru) {
/*if (pmru->iFlags & MRU_UTF8) {
WCHAR tchItem[1024];
WCHAR wchItem[1024];
int cbw = MultiByteToWideChar(CP_UTF8,0,pmru->pszItems[i],-1,wchItem,COUNTOF(wchItem));
WideCharToMultiByte(CP_UTF7,0,wchItem,cbw,tchItem,COUNTOF(tchItem),NULL,NULL);
IniSectionSetString(pIniSection,tchName,tchItem);
int cbw = MultiByteToWideChar(CP_UTF8, 0, pmru->pszItems[i], -1, wchItem, COUNTOF(wchItem));
WideCharToMultiByte(CP_UTF7, 0, wchItem, cbw, tchItem, COUNTOF(tchItem), NULL, NULL);
IniSectionSetString(pIniSection, tchName, tchItem);
}
else*/
IniSectionSetString(pIniSection, tchName, pmru->pszItems[i]);
Expand Down Expand Up @@ -1435,7 +1435,7 @@ BOOL GetThemedDialogFont(LPWSTR lpFaceName, WORD *wSize) {
HTHEME hTheme = (HTHEME)(INT_PTR)(GetProcAddress(hModUxTheme, "OpenThemeData"))(NULL, L"WINDOWSTYLE;WINDOW");
if (hTheme) {
LOGFONT lf;
if (S_OK == (HRESULT)(GetProcAddress(hModUxTheme, "GetThemeSysFont"))(hTheme,/*TMT_MSGBOXFONT*/805, &lf)) {
if (S_OK == (HRESULT)(GetProcAddress(hModUxTheme, "GetThemeSysFont"))(hTheme, /*TMT_MSGBOXFONT*/805, &lf)) {
if (lf.lfHeight < 0) {
lf.lfHeight = -lf.lfHeight;
}
Expand Down
7 changes: 3 additions & 4 deletions metapath/src/metapath.c
Original file line number Diff line number Diff line change
Expand Up @@ -1195,7 +1195,7 @@ LRESULT MsgCommand(HWND hwnd, WPARAM wParam, LPARAM lParam) {
if (PathGetLnkPath(dli.szFileName, tch, COUNTOF(tch))) {
ExpandEnvironmentStringsEx(tch, COUNTOF(tch));
const DWORD dwAttr = GetFileAttributes(tch);
if ((dwAttr == (DWORD)(-1)) || (dwAttr & FILE_ATTRIBUTE_DIRECTORY)) {
if ((dwAttr == INVALID_FILE_ATTRIBUTES) || (dwAttr & FILE_ATTRIBUTE_DIRECTORY)) {
DisplayLnkFile(dli.szFileName);
} else {
// Made sure link points to a file
Expand Down Expand Up @@ -1230,7 +1230,7 @@ LRESULT MsgCommand(HWND hwnd, WPARAM wParam, LPARAM lParam) {
if (PathGetLnkPath(dli.szFileName, tch, COUNTOF(tch))) {
ExpandEnvironmentStringsEx(tch, COUNTOF(tch));
const DWORD dwAttr = GetFileAttributes(tch);
if ((dwAttr == (DWORD)(-1)) || (dwAttr & FILE_ATTRIBUTE_DIRECTORY)) {
if ((dwAttr == INVALID_FILE_ATTRIBUTES) || (dwAttr & FILE_ATTRIBUTE_DIRECTORY)) {
DisplayLnkFile(dli.szFileName);
} else {
// Made sure link points to a file
Expand Down Expand Up @@ -3040,7 +3040,7 @@ BOOL DisplayPath(LPCWSTR lpPath, UINT uIdError) {
ListView_EnsureVisible(hwndDirList, 0, FALSE);
return TRUE;
}
{ // !(dwAttr & FILE_ATTRIBUTE_DIRECTORY)
{
// szPath will be modified...
lstrcpy(szTmp, szPath);

Expand All @@ -3066,7 +3066,6 @@ BOOL DisplayPath(LPCWSTR lpPath, UINT uIdError) {
}
}

// dwAttr != (DWORD)(-1)
ErrorMessage(2, uIdError);
return FALSE;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Dlapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
typedef struct tagDLDATA { // dl
HWND hwnd; // HWND of ListView Control
UINT cbidl; // Size of pidl
LPITEMIDLIST pidl; // Directory Id
LPITEMIDLIST pidl; // Directory Id
LPSHELLFOLDER lpsf; // IShellFolder Interface to pidl
WCHAR szPath[MAX_PATH]; // Pathname to Directory Id
int iDefIconFolder; // Default Folder Icon
Expand Down
238 changes: 233 additions & 5 deletions src/Edit.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include <windows.h>
#include <shlwapi.h>
#include <shlobj.h>
#include <commctrl.h>
#include <commdlg.h>
#include <stdio.h>
Expand Down Expand Up @@ -2490,7 +2491,7 @@ void EditAlignText(HWND hwnd, int nMode) {
int iMinIndent = BUFSIZE_ALIGN;
int iMaxLength = 0;
for (int iLine = iLineStart; iLine <= iLineEnd; iLine++) {
int iLineEndPos = (int)SendMessage(hwnd, SCI_GETLINEENDPOSITION,iLine, 0);
int iLineEndPos = (int)SendMessage(hwnd, SCI_GETLINEENDPOSITION, iLine, 0);
const int iLineIndentPos = (int)SendMessage(hwnd, SCI_GETLINEINDENTPOSITION, iLine, 0);

if (iLineIndentPos != iLineEndPos) {
Expand Down Expand Up @@ -5940,10 +5941,8 @@ void EditSelectionAction(HWND hwnd, int action) {
return;
}

DWORD cchSelection = (int)SendMessage(hwnd, SCI_GETSELECTIONEND, 0, 0)
- (int)SendMessage(hwnd, SCI_GETSELECTIONSTART, 0, 0);

if (cchSelection > 0 && cchSelection < 512 && SendMessage(hwnd, SCI_GETSELTEXT, 0, 0) < 512) {
const int cchSelection = (int)SendMessage(hwnd, SCI_GETSELTEXT, 0, 0);
if (cchSelection > 0 && cchSelection < 512) {
char mszSelection[512] = {0};
SendMessage(hwnd, SCI_GETSELTEXT, 0, (LPARAM)mszSelection);
mszSelection[cchSelection] = 0; // zero terminate
Expand Down Expand Up @@ -5993,6 +5992,235 @@ void EditSelectionAction(HWND hwnd, int action) {
}
}

void OpenContainingFolder(HWND hwnd, LPCWSTR pszFile) {
LPITEMIDLIST pidlEntry = ILCreateFromPath(pszFile);
if (pidlEntry) {
WCHAR wchDirectory[MAX_PATH];
lstrcpyn(wchDirectory, pszFile, COUNTOF(wchDirectory));
PathRemoveFileSpec(wchDirectory);
LPITEMIDLIST pidl = ILCreateFromPath(wchDirectory);

BOOL succ = FALSE;
if (pidl) {
const HRESULT hr = SHOpenFolderAndSelectItems(pidl, 1, (LPCITEMIDLIST *)(&pidlEntry), 0);
ILFree(pidl);
succ = hr == S_OK;
}
ILFree(pidlEntry);
if (succ) {
return;
}
}

// open a new explorer window every time
LPWSTR szParameters = (LPWSTR)NP2HeapAlloc((lstrlen(pszFile) + 64) * sizeof(WCHAR));
lstrcpy(szParameters, L"/select,");
lstrcat(szParameters, L"\"");
lstrcat(szParameters, pszFile);
lstrcat(szParameters, L"\"");
ShellExecute(hwnd, L"open", L"explorer", szParameters, NULL, SW_SHOW);
NP2HeapFree(szParameters);
}

void TryBrowseFile(HWND hwnd, LPCWSTR pszFile, BOOL bWarn) {
WCHAR tchParam[MAX_PATH + 4] = L"";
WCHAR tchExeFile[MAX_PATH + 4];
WCHAR tchTemp[MAX_PATH + 4];

if (!IniGetString(INI_SECTION_NAME_FLAGS, L"filebrowser.exe", L"", tchTemp, COUNTOF(tchTemp))) {
if (!SearchPath(NULL, L"metapath.exe", NULL, COUNTOF(tchExeFile), tchExeFile, NULL)) {
GetModuleFileName(NULL, tchExeFile, COUNTOF(tchExeFile));
PathRemoveFileSpec(tchExeFile);
PathAppend(tchExeFile, L"metapath.exe");
}
} else {
ExtractFirstArgument(tchTemp, tchExeFile, tchParam);
if (PathIsRelative(tchExeFile)) {
if (!SearchPath(NULL, tchExeFile, NULL, COUNTOF(tchTemp), tchTemp, NULL)) {
GetModuleFileName(NULL, tchTemp, COUNTOF(tchTemp));
PathRemoveFileSpec(tchTemp);
PathAppend(tchTemp, tchExeFile);
lstrcpy(tchExeFile, tchTemp);
}
}
}

if (StrNotEmpty(tchParam) && StrNotEmpty(pszFile)) {
StrCatBuff(tchParam, L" ", COUNTOF(tchParam));
}

if (StrNotEmpty(pszFile)) {
lstrcpy(tchTemp, pszFile);
PathQuoteSpaces(tchTemp);
StrCatBuff(tchParam, tchTemp, COUNTOF(tchParam));
}

SHELLEXECUTEINFO sei;
ZeroMemory(&sei, sizeof(SHELLEXECUTEINFO));

sei.cbSize = sizeof(SHELLEXECUTEINFO);
sei.fMask = SEE_MASK_FLAG_NO_UI | /*SEE_MASK_NOZONECHECKS*/0x00800000;
sei.hwnd = hwnd;
sei.lpVerb = NULL;
sei.lpFile = tchExeFile;
sei.lpParameters = tchParam;
sei.lpDirectory = NULL;
sei.nShow = SW_SHOWNORMAL;

ShellExecuteEx(&sei);

if ((INT_PTR)sei.hInstApp < 32) {
if (bWarn) {
if (MsgBox(MBYESNOWARN, IDS_ERR_BROWSE) == IDYES) {
OpenHelpLink(hwnd, IDM_HELP_LATEST_RELEASE);
}
} else if (StrNotEmpty(pszFile)) {
OpenContainingFolder(hwnd, pszFile);
}
}
}

void EditOpenSelection(HWND hwnd, int type) {
int cchSelection = (int)SendMessage(hwnd, SCI_GETSELTEXT, 0, 0);
char *mszSelection = NULL;
if (cchSelection > 1) {
mszSelection = (char *)NP2HeapAlloc(cchSelection);
SendMessage(hwnd, SCI_GETSELTEXT, 0, (LPARAM)mszSelection);
char *lpsz = strpbrk(mszSelection, "\r\n\t");
if (lpsz) {
*lpsz = '\0';
}
} else {
// get string around caret
const int iCurrentPos = (int)SendMessage(hwnd, SCI_GETCURRENTPOS, 0, 0);
const int iLine = (int)SendMessage(hwnd, SCI_LINEFROMPOSITION, iCurrentPos, 0);
cchSelection = (int)SendMessage(hwnd, SCI_GETLINE, iLine, 0);
if (cchSelection == 0) {
return;
}

const int iLineStart = (int)SendMessage(hwnd, SCI_POSITIONFROMLINE, iLine, 0);
mszSelection = (char *)NP2HeapAlloc(cchSelection);
SendMessage(hwnd, SCI_GETLINE, iLine, (LPARAM)mszSelection);

const int iPos = iCurrentPos - iLineStart;
char *lpsz = strpbrk(mszSelection + iPos, " \r\n\t");
if (lpsz) {
*lpsz = '\0';
}
lpsz = mszSelection + iPos;
while (lpsz >= mszSelection) {
if (*lpsz == ' ' || *lpsz == '\t') {
*lpsz++ = '\0';
break;
} else {
--lpsz;
}
}

cchSelection = lstrlenA(lpsz);
if (cchSelection == 0) {
NP2HeapFree(mszSelection);
return;
}

if (lpsz > mszSelection) {
strcpy(mszSelection, lpsz);
}
}

/* remove quotes and spaces and some invalid filename characters (except '/', '\' and '?') */
StrTrimA(mszSelection, " \"<>|:*");
if (StrNotEmptyA(mszSelection)) {
LPWSTR wszSelection = (LPWSTR)NP2HeapAlloc((max_i(MAX_PATH, cchSelection) + 32) * sizeof(WCHAR));
LPWSTR link = wszSelection + 16;

const UINT cpEdit = (UINT)SendMessage(hwnd, SCI_GETCODEPAGE, 0, 0);
MultiByteToWideChar(cpEdit, 0, mszSelection, -1, link, cchSelection);

WCHAR wchDirectory[MAX_PATH] = L"";
DWORD dwAttributes = GetFileAttributes(link);
if (dwAttributes == INVALID_FILE_ATTRIBUTES) {
WCHAR path[MAX_PATH];
if (StrNotEmpty(szCurFile)) {
lstrcpy(wchDirectory, szCurFile);
PathRemoveFileSpec(wchDirectory);
PathCombine(path, wchDirectory, link);
dwAttributes = GetFileAttributes(path);
}
if (dwAttributes == INVALID_FILE_ATTRIBUTES && GetFullPathName(link, COUNTOF(path), path, NULL)) {
dwAttributes = GetFileAttributes(path);
}
if (dwAttributes != INVALID_FILE_ATTRIBUTES) {
lstrcpy(link, path);
}
}

if (type == 4) { // containing folder
if (dwAttributes == INVALID_FILE_ATTRIBUTES) {
type = 0;
}
} else if (dwAttributes != INVALID_FILE_ATTRIBUTES) {
if (dwAttributes & FILE_ATTRIBUTE_DIRECTORY) {
type = 3;
} else {
const BOOL can = Style_CanOpenFile(link);
// open supported file in a new window
type = can ? 2 : 1;
}
} else if (StrChr(link, L':')) { // link
// TODO: check scheme
type = 1;
} else if (StrChr(link, L'@')) { // email
lstrcpy(wszSelection, L"mailto:");
lstrcpy(wszSelection + CSTRLEN(L"mailto:"), link);
type = 1;
link = wszSelection;
}

switch (type) {
case 1:
ShellExecute(hwndMain, L"open", link, NULL, NULL, SW_SHOWNORMAL);
break;

case 2: {
WCHAR szModuleName[MAX_PATH];
GetModuleFileName(NULL, szModuleName, COUNTOF(szModuleName));

lstrcpyn(wchDirectory, link, COUNTOF(wchDirectory));
PathRemoveFileSpec(wchDirectory);
PathQuoteSpaces(link);

SHELLEXECUTEINFO sei;
ZeroMemory(&sei, sizeof(SHELLEXECUTEINFO));
sei.cbSize = sizeof(SHELLEXECUTEINFO);
sei.fMask = /*SEE_MASK_NOZONECHECKS*/0x00800000;
sei.hwnd = hwndMain;
sei.lpVerb = NULL;
sei.lpFile = szModuleName;
sei.lpParameters = link;
sei.lpDirectory = wchDirectory;
sei.nShow = SW_SHOWNORMAL;

ShellExecuteEx(&sei);
}
break;

case 3:
TryBrowseFile(hwndMain, link, FALSE);
break;

case 4:
OpenContainingFolder(hwndMain, link);
break;
}

NP2HeapFree(wszSelection);
}

NP2HeapFree(mszSelection);
}

//=============================================================================
//
// FileVars_Init()
Expand Down
3 changes: 3 additions & 0 deletions src/Edit.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ void EditShowUnicodeControlCharacter(HWND hwnd, BOOL bShow);
BOOL EditSortDlg(HWND hwnd, int *piSortFlags);
BOOL EditAlignDlg(HWND hwnd, int *piAlignMode);
void EditSelectionAction(HWND hwnd, int action);
void OpenContainingFolder(HWND hwnd, LPCWSTR pszFile);
void TryBrowseFile(HWND hwnd, LPCWSTR pszFile, BOOL bWarn);
void EditOpenSelection(HWND hwnd, int type);

// in Print.cpp
BOOL EditPrint(HWND hwnd, LPCWSTR pszDocTitle, LPCWSTR pszPageFormat);
Expand Down

0 comments on commit 3f0fd7c

Please sign in to comment.