mirror of
https://github.com/doublecmd/doublecmd.git
synced 2026-06-21 09:58:13 +00:00
UPD: Show error message when cannot display context menu (Windows).
This commit is contained in:
parent
4c1a356f3c
commit
e2bd37a131
3 changed files with 205 additions and 181 deletions
|
|
@ -43,6 +43,9 @@ const
|
|||
sCmdVerbCopy = 'copy';
|
||||
sCmdVerbPaste = 'paste';
|
||||
|
||||
type
|
||||
EContextMenuException = class(Exception);
|
||||
|
||||
{$IFDEF UNIX}
|
||||
type
|
||||
TContextMenu = class(TPopupMenu)
|
||||
|
|
@ -91,7 +94,7 @@ implementation
|
|||
uses
|
||||
fMain, uOSUtils, uGlobs, uLng, uDCUtils, uShellExecute
|
||||
{$IF DEFINED(MSWINDOWS)}
|
||||
, Dialogs, Graphics, uFileSystemFile, uTotalCommander
|
||||
, Dialogs, Graphics, comobj, uFileSystemFile, uTotalCommander
|
||||
{$ENDIF}
|
||||
{$IF DEFINED(LINUX)}
|
||||
, uFileSystemWatcher, inotify, uMimeActions
|
||||
|
|
@ -249,7 +252,7 @@ var
|
|||
begin
|
||||
Result := nil;
|
||||
|
||||
OleCheck(SHGetDesktopFolder(DeskTopFolder));
|
||||
OleCheckUTF8(SHGetDesktopFolder(DeskTopFolder));
|
||||
try
|
||||
List := CoTaskMemAlloc(SizeOf(PItemIDList)*Files.Count);
|
||||
ZeroMemory(List, SizeOf(PItemIDList)*Files.Count);
|
||||
|
|
@ -258,15 +261,15 @@ begin
|
|||
begin
|
||||
S := UTF8Decode(Files[I].Path);
|
||||
|
||||
OleCheck(DeskTopFolder.ParseDisplayName(Handle, nil, PWideChar(S), pchEaten, PathPIDL, dwAttributes));
|
||||
OleCheckUTF8(DeskTopFolder.ParseDisplayName(Handle, nil, PWideChar(S), pchEaten, PathPIDL, dwAttributes));
|
||||
try
|
||||
OleCheck(DeskTopFolder.BindToObject(PathPIDL, nil, IID_IShellFolder, Folder));
|
||||
OleCheckUTF8(DeskTopFolder.BindToObject(PathPIDL, nil, IID_IShellFolder, Folder));
|
||||
finally
|
||||
CoTaskMemFree(PathPIDL);
|
||||
end;
|
||||
|
||||
S := UTF8Decode(Files[I].Name);
|
||||
OleCheck(Folder.ParseDisplayName(Handle, nil, PWideChar(S), pchEaten, tmpPIDL, dwAttributes));
|
||||
OleCheckUTF8(Folder.ParseDisplayName(Handle, nil, PWideChar(S), pchEaten, tmpPIDL, dwAttributes));
|
||||
(List + i)^ := tmpPIDL;
|
||||
end;
|
||||
|
||||
|
|
@ -305,174 +308,180 @@ var
|
|||
begin
|
||||
|
||||
try
|
||||
if Files.Count = 0 then Exit;
|
||||
|
||||
contMenu := GetIContextMenu(Owner.Handle, Files);
|
||||
if Assigned(contMenu) then
|
||||
try
|
||||
menu := CreatePopupMenu;
|
||||
OleCheck(contMenu.QueryContextMenu(menu, 0, 1, $7FFF, CMF_EXPLORE or CMF_CANRENAME));
|
||||
contMenu.QueryInterface(IID_IContextMenu2, ICM2); // to handle submenus.
|
||||
//------------------------------------------------------------------------------
|
||||
{ Actions submenu }
|
||||
aFile := Files[0];
|
||||
if (Files.Count = 1) then
|
||||
if Files.Count = 0 then Exit;
|
||||
|
||||
contMenu := GetIContextMenu(Owner.Handle, Files);
|
||||
if Assigned(contMenu) then
|
||||
try
|
||||
menu := CreatePopupMenu;
|
||||
OleCheckUTF8(contMenu.QueryContextMenu(menu, 0, 1, $7FFF, CMF_EXPLORE or CMF_CANRENAME));
|
||||
contMenu.QueryInterface(IID_IContextMenu2, ICM2); // to handle submenus.
|
||||
//------------------------------------------------------------------------------
|
||||
{ Actions submenu }
|
||||
aFile := Files[0];
|
||||
if (Files.Count = 1) then
|
||||
begin
|
||||
hActionsSubMenu := CreatePopupMenu;
|
||||
|
||||
// Read actions from doublecmd.ext
|
||||
sl:=TStringList.Create;
|
||||
|
||||
if gExts.GetExtActions(aFile, sl) then
|
||||
begin
|
||||
//founded any commands
|
||||
InsertMenuItemEx(menu, hActionsSubMenu, PWChar(UTF8Decode(rsMnuActions)), 0, 333, MFT_STRING);
|
||||
for i:=0 to sl.Count-1 do
|
||||
begin
|
||||
sCmd:=sl.Strings[i];
|
||||
if pos('VIEW=',sCmd)>0 then Continue; // view command is only for viewer
|
||||
ReplaceExtCommand(sCmd, aFile, aFile.Path);
|
||||
|
||||
sCmd:= RemoveQuotation(sCmd);
|
||||
InsertMenuItemEx(hActionsSubMenu,0, PWChar(UTF8Decode(sCmd)), 0, I + $1000, MFT_STRING);
|
||||
end;
|
||||
end;
|
||||
|
||||
if not (aFile.IsDirectory or aFile.IsLinkToDirectory) then
|
||||
begin
|
||||
if sl.Count = 0 then
|
||||
InsertMenuItemEx(menu, hActionsSubMenu, PWChar(UTF8Decode(rsMnuActions)), 0, 333, MFT_STRING)
|
||||
else
|
||||
// now add delimiter
|
||||
InsertMenuItemEx(hActionsSubMenu,0, nil, 0, 0, MFT_SEPARATOR);
|
||||
|
||||
// now add VIEW item
|
||||
sCmd:= '{!VIEWER}' + aFile.Path + aFile.Name;
|
||||
I := sl.Add(sCmd);
|
||||
InsertMenuItemEx(hActionsSubMenu,0, PWChar(UTF8Decode(sCmd)), 1, I + $1000, MFT_STRING);
|
||||
|
||||
// now add EDITconfigure item
|
||||
sCmd:= '{!EDITOR}' + aFile.Path + aFile.Name;
|
||||
I := sl.Add(sCmd);
|
||||
InsertMenuItemEx(hActionsSubMenu,0, PWChar(UTF8Decode(sCmd)), 1, I + $1000, MFT_STRING);
|
||||
end;
|
||||
end;
|
||||
{ /Actions submenu }
|
||||
//------------------------------------------------------------------------------
|
||||
cmd := UINT(TrackPopupMenu(menu, TPM_LEFTALIGN or TPM_LEFTBUTTON or TPM_RIGHTBUTTON or TPM_RETURNCMD, X, Y, 0, Owner.Handle, nil));
|
||||
finally
|
||||
if hActionsSubMenu <> 0 then
|
||||
DestroyMenu(hActionsSubMenu);
|
||||
if menu <> 0 then
|
||||
DestroyMenu(menu);
|
||||
ICM2 := nil;
|
||||
end;
|
||||
|
||||
if (cmd > 0) and (cmd < $1000) then
|
||||
begin
|
||||
hActionsSubMenu := CreatePopupMenu;
|
||||
iCmd := LongInt(Cmd) - 1;
|
||||
OleCheckUTF8(contMenu.GetCommandString(iCmd, GCS_VERBA, nil, ZVerb, SizeOf(ZVerb)));
|
||||
sVerb := StrPas(ZVerb);
|
||||
|
||||
// Read actions from doublecmd.ext
|
||||
sl:=TStringList.Create;
|
||||
|
||||
if gExts.GetExtActions(aFile, sl) then
|
||||
if SameText(sVerb, sCmdVerbDelete) then
|
||||
begin
|
||||
//founded any commands
|
||||
InsertMenuItemEx(menu, hActionsSubMenu, PWChar(UTF8Decode(rsMnuActions)), 0, 333, MFT_STRING);
|
||||
for i:=0 to sl.Count-1 do
|
||||
begin
|
||||
sCmd:=sl.Strings[i];
|
||||
if pos('VIEW=',sCmd)>0 then Continue; // view command is only for viewer
|
||||
ReplaceExtCommand(sCmd, aFile, aFile.Path);
|
||||
|
||||
sCmd:= RemoveQuotation(sCmd);
|
||||
InsertMenuItemEx(hActionsSubMenu,0, PWChar(UTF8Decode(sCmd)), 0, I + $1000, MFT_STRING);
|
||||
end;
|
||||
end;
|
||||
|
||||
if not (aFile.IsDirectory or aFile.IsLinkToDirectory) then
|
||||
begin
|
||||
if sl.Count = 0 then
|
||||
InsertMenuItemEx(menu, hActionsSubMenu, PWChar(UTF8Decode(rsMnuActions)), 0, 333, MFT_STRING)
|
||||
if ssShift in GetKeyShiftState then
|
||||
Actions.cm_Delete('recyclesettingrev')
|
||||
else
|
||||
// now add delimiter
|
||||
InsertMenuItemEx(hActionsSubMenu,0, nil, 0, 0, MFT_SEPARATOR);
|
||||
|
||||
// now add VIEW item
|
||||
sCmd:= '{!VIEWER}' + aFile.Path + aFile.Name;
|
||||
I := sl.Add(sCmd);
|
||||
InsertMenuItemEx(hActionsSubMenu,0, PWChar(UTF8Decode(sCmd)), 1, I + $1000, MFT_STRING);
|
||||
|
||||
// now add EDITconfigure item
|
||||
sCmd:= '{!EDITOR}' + aFile.Path + aFile.Name;
|
||||
I := sl.Add(sCmd);
|
||||
InsertMenuItemEx(hActionsSubMenu,0, PWChar(UTF8Decode(sCmd)), 1, I + $1000, MFT_STRING);
|
||||
Actions.cm_Delete('recyclesetting');
|
||||
bHandled := True;
|
||||
end
|
||||
else if SameText(sVerb, sCmdVerbRename) then
|
||||
begin
|
||||
if Files.Count = 1 then
|
||||
with Files[0] do
|
||||
begin
|
||||
if Name <> (ExtractFileDrive(Name)+PathDelim) then
|
||||
frmMain.actRenameOnly.Execute
|
||||
else // change drive label
|
||||
begin
|
||||
sCmd:= mbGetVolumeLabel(Name, True);
|
||||
if InputQuery(rsMsgSetVolumeLabel, rsMsgVolumeLabel, sCmd) then
|
||||
mbSetVolumeLabel(Name, sCmd);
|
||||
end;
|
||||
end
|
||||
else
|
||||
frmMain.actRename.Execute;
|
||||
bHandled := True;
|
||||
end
|
||||
else if SameText(sVerb, sCmdVerbOpen) then
|
||||
begin
|
||||
if Files.Count = 1 then
|
||||
with Files[0] do
|
||||
begin
|
||||
if IsDirectory or IsLinkToDirectory then
|
||||
begin
|
||||
if Name = '..' then
|
||||
frmMain.ActiveFrame.ChangePathToParent(True)
|
||||
else
|
||||
frmMain.ActiveFrame.ChangePathToChild(Files[0]);
|
||||
bHandled := True;
|
||||
end; // is dir
|
||||
end; // with
|
||||
end
|
||||
else if SameText(sVerb, sCmdVerbCut) then
|
||||
begin
|
||||
frmMain.actCutToClipboard.Execute;
|
||||
bHandled := True;
|
||||
end
|
||||
else if SameText(sVerb, sCmdVerbCopy) then
|
||||
begin
|
||||
frmMain.actCopyToClipboard.Execute;
|
||||
bHandled := True;
|
||||
end
|
||||
else if SameText(sVerb, sCmdVerbPaste) then
|
||||
begin
|
||||
frmMain.actPasteFromClipboard.Execute;
|
||||
bHandled := True;
|
||||
end;
|
||||
|
||||
if not bHandled then
|
||||
begin
|
||||
FillChar(cmici, SizeOf(cmici), #0);
|
||||
with cmici do
|
||||
begin
|
||||
cbSize := sizeof(cmici);
|
||||
hwnd := Owner.Handle;
|
||||
lpVerb := PChar(cmd - 1);
|
||||
nShow := SW_NORMAL;
|
||||
end;
|
||||
OleCheckUTF8(contMenu.InvokeCommand(cmici));
|
||||
end;
|
||||
|
||||
end // if cmd > 0
|
||||
else if (cmd >= $1000) then // actions sub menu
|
||||
begin
|
||||
sCmd:= sl.Strings[cmd - $1000];
|
||||
ReplaceExtCommand(sCmd, aFile, aFile.Path);
|
||||
sCmd:= Copy(sCmd, pos('=',sCmd)+1, length(sCmd));
|
||||
try
|
||||
with frmMain.ActiveFrame do
|
||||
begin
|
||||
(*
|
||||
VFS via another file source
|
||||
|
||||
if (Pos('{!VFS}',sCmd)>0) and pnlFile.VFS.FindModule(CurrentPath + fri.sName) then
|
||||
begin
|
||||
pnlFile.LoadPanelVFS(@fri);
|
||||
Exit;
|
||||
end;
|
||||
*)
|
||||
if not ProcessExtCommand(sCmd, CurrentPath) then
|
||||
frmMain.ExecCmd(sCmd);
|
||||
end;
|
||||
finally
|
||||
bHandled:= True;
|
||||
end;
|
||||
end;
|
||||
{ /Actions submenu }
|
||||
//------------------------------------------------------------------------------
|
||||
cmd := UINT(TrackPopupMenu(menu, TPM_LEFTALIGN or TPM_LEFTBUTTON or TPM_RIGHTBUTTON or TPM_RETURNCMD, X, Y, 0, Owner.Handle, nil));
|
||||
finally
|
||||
if hActionsSubMenu <> 0 then
|
||||
DestroyMenu(hActionsSubMenu);
|
||||
if menu <> 0 then
|
||||
DestroyMenu(menu);
|
||||
ICM2 := nil;
|
||||
FreeAndNil(Files);
|
||||
if Assigned(sl) then
|
||||
FreeAndNil(sl);
|
||||
end;
|
||||
|
||||
if (cmd > 0) and (cmd < $1000) then
|
||||
begin
|
||||
iCmd := LongInt(Cmd) - 1;
|
||||
OleCheck(contMenu.GetCommandString(iCmd, GCS_VERBA, nil, ZVerb, SizeOf(ZVerb)));
|
||||
sVerb := StrPas(ZVerb);
|
||||
|
||||
if SameText(sVerb, sCmdVerbDelete) then
|
||||
begin
|
||||
if ssShift in GetKeyShiftState then
|
||||
Actions.cm_Delete('recyclesettingrev')
|
||||
else
|
||||
Actions.cm_Delete('recyclesetting');
|
||||
bHandled := True;
|
||||
end
|
||||
else if SameText(sVerb, sCmdVerbRename) then
|
||||
begin
|
||||
if Files.Count = 1 then
|
||||
with Files[0] do
|
||||
begin
|
||||
if Name <> (ExtractFileDrive(Name)+PathDelim) then
|
||||
frmMain.actRenameOnly.Execute
|
||||
else // change drive label
|
||||
begin
|
||||
sCmd:= mbGetVolumeLabel(Name, True);
|
||||
if InputQuery(rsMsgSetVolumeLabel, rsMsgVolumeLabel, sCmd) then
|
||||
mbSetVolumeLabel(Name, sCmd);
|
||||
end;
|
||||
end
|
||||
else
|
||||
frmMain.actRename.Execute;
|
||||
bHandled := True;
|
||||
end
|
||||
else if SameText(sVerb, sCmdVerbOpen) then
|
||||
begin
|
||||
if Files.Count = 1 then
|
||||
with Files[0] do
|
||||
begin
|
||||
if IsDirectory or IsLinkToDirectory then
|
||||
begin
|
||||
if Name = '..' then
|
||||
frmMain.ActiveFrame.ChangePathToParent(True)
|
||||
else
|
||||
frmMain.ActiveFrame.ChangePathToChild(Files[0]);
|
||||
bHandled := True;
|
||||
end; // is dir
|
||||
end; // with
|
||||
end
|
||||
else if SameText(sVerb, sCmdVerbCut) then
|
||||
begin
|
||||
frmMain.actCutToClipboard.Execute;
|
||||
bHandled := True;
|
||||
end
|
||||
else if SameText(sVerb, sCmdVerbCopy) then
|
||||
begin
|
||||
frmMain.actCopyToClipboard.Execute;
|
||||
bHandled := True;
|
||||
end
|
||||
else if SameText(sVerb, sCmdVerbPaste) then
|
||||
begin
|
||||
frmMain.actPasteFromClipboard.Execute;
|
||||
bHandled := True;
|
||||
end;
|
||||
|
||||
if not bHandled then
|
||||
begin
|
||||
FillChar(cmici, SizeOf(cmici), #0);
|
||||
with cmici do
|
||||
begin
|
||||
cbSize := sizeof(cmici);
|
||||
hwnd := Owner.Handle;
|
||||
lpVerb := PChar(cmd - 1);
|
||||
nShow := SW_NORMAL;
|
||||
end;
|
||||
OleCheck(contMenu.InvokeCommand(cmici));
|
||||
end;
|
||||
|
||||
end // if cmd > 0
|
||||
else if (cmd >= $1000) then // actions sub menu
|
||||
begin
|
||||
sCmd:= sl.Strings[cmd - $1000];
|
||||
ReplaceExtCommand(sCmd, aFile, aFile.Path);
|
||||
sCmd:= Copy(sCmd, pos('=',sCmd)+1, length(sCmd));
|
||||
try
|
||||
with frmMain.ActiveFrame do
|
||||
begin
|
||||
(*
|
||||
VFS via another file source
|
||||
|
||||
if (Pos('{!VFS}',sCmd)>0) and pnlFile.VFS.FindModule(CurrentPath + fri.sName) then
|
||||
begin
|
||||
pnlFile.LoadPanelVFS(@fri);
|
||||
Exit;
|
||||
end;
|
||||
*)
|
||||
if not ProcessExtCommand(sCmd, CurrentPath) then
|
||||
frmMain.ExecCmd(sCmd);
|
||||
end;
|
||||
finally
|
||||
bHandled:= True;
|
||||
end;
|
||||
end;
|
||||
finally
|
||||
FreeAndNil(Files);
|
||||
if Assigned(sl) then
|
||||
FreeAndNil(sl);
|
||||
except
|
||||
on e: EOleError do
|
||||
raise EContextMenuException.Create(e.Message);
|
||||
end;
|
||||
end;
|
||||
{$ELSE}
|
||||
|
|
@ -735,19 +744,25 @@ var
|
|||
begin
|
||||
if Files.Count = 0 then Exit;
|
||||
|
||||
contMenu := GetIContextMenu(frmMain.Handle, Files);
|
||||
if Assigned(contMenu) then
|
||||
begin
|
||||
FillChar(cmici, sizeof(cmici), #0);
|
||||
with cmici do
|
||||
begin
|
||||
cbSize := sizeof(cmici);
|
||||
hwnd := frmMain.Handle;
|
||||
lpVerb := 'properties';
|
||||
nShow := SW_SHOWNORMAL;
|
||||
end;
|
||||
try
|
||||
contMenu := GetIContextMenu(frmMain.Handle, Files);
|
||||
if Assigned(contMenu) then
|
||||
begin
|
||||
FillChar(cmici, sizeof(cmici), #0);
|
||||
with cmici do
|
||||
begin
|
||||
cbSize := sizeof(cmici);
|
||||
hwnd := frmMain.Handle;
|
||||
lpVerb := 'properties';
|
||||
nShow := SW_SHOWNORMAL;
|
||||
end;
|
||||
|
||||
OleCheck(contMenu.InvokeCommand(cmici));
|
||||
OleCheckUTF8(contMenu.InvokeCommand(cmici));
|
||||
end;
|
||||
|
||||
except
|
||||
on e: EOleError do
|
||||
raise EContextMenuException.Create(e.Message);
|
||||
end;
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
|
|
|||
|
|
@ -1792,8 +1792,8 @@ function SHGetDesktopFolder(var ppshf: IShellFolder): HResult; stdcall;
|
|||
function SHChangeIconDialog(hOwner: THandle; var FileName: UTF8String; var IconIndex: Integer): Boolean;
|
||||
function SHGetOverlayIconIndex(const sFilePath, sFileName: UTF8String): Integer;
|
||||
|
||||
procedure OleError(ErrorCode: HResult);
|
||||
procedure OleCheck(Result: HResult);
|
||||
procedure OleErrorUTF8(ErrorCode: HResult);
|
||||
procedure OleCheckUTF8(Result: HResult);
|
||||
|
||||
implementation
|
||||
uses
|
||||
|
|
@ -1935,14 +1935,14 @@ begin
|
|||
end; // SHGetDesktopFolder
|
||||
end;
|
||||
|
||||
procedure OleError(ErrorCode: HResult);
|
||||
procedure OleErrorUTF8(ErrorCode: HResult);
|
||||
begin
|
||||
raise EOleError.Create(UTF8Encode(SysErrorMessage(ErrorCode)));
|
||||
end;
|
||||
|
||||
procedure OleCheck(Result: HResult);
|
||||
procedure OleCheckUTF8(Result: HResult);
|
||||
begin
|
||||
if not Succeeded(Result) then OleError(Result);
|
||||
if not Succeeded(Result) then OleErrorUTF8(Result);
|
||||
end;
|
||||
|
||||
end. { ShlObjAdditional }
|
||||
|
|
|
|||
|
|
@ -55,6 +55,8 @@ const cf_Null=0;
|
|||
procedure EnableAction(ActionState: PActionState; Enabled: Boolean);
|
||||
class function Methods(AClass:TClass) : TStringList;
|
||||
|
||||
procedure ShowException(e: Exception);
|
||||
|
||||
procedure OnCalcStatisticsStateChanged(Operation: TFileSourceOperation;
|
||||
Event: TFileSourceOperationEvent);
|
||||
procedure OnCalcChecksumStateChanged(Operation: TFileSourceOperation;
|
||||
|
|
@ -348,8 +350,8 @@ begin
|
|||
if Assigned(t.code) then
|
||||
begin
|
||||
Result:=cf_Null;
|
||||
TCommandFunc(t)(param);
|
||||
end;
|
||||
TCommandFunc(t)(param);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
|
|
@ -535,6 +537,11 @@ begin
|
|||
EnableAction(PActionState(FActionsState.List[i]^.Data), Enable);
|
||||
end;
|
||||
|
||||
procedure TActs.ShowException(e: Exception);
|
||||
begin
|
||||
MessageDlg(Application.Title, rsMsgLogError + LineEnding + e.Message, mtError, [mbOK], 0);
|
||||
end;
|
||||
|
||||
//------------------------------------------------------
|
||||
|
||||
procedure TActs.OnCalcStatisticsStateChanged(Operation: TFileSourceOperation;
|
||||
|
|
@ -675,9 +682,11 @@ begin
|
|||
SelectedFiles := Panel.SelectedFiles;
|
||||
try
|
||||
if SelectedFiles.Count > 0 then
|
||||
begin
|
||||
try
|
||||
ShowContextMenu(Panel, SelectedFiles, X, Y);
|
||||
SelectedFiles := nil; // freed by ShowContextMenu
|
||||
except
|
||||
on e: EContextMenuException do
|
||||
ShowException(e);
|
||||
end;
|
||||
|
||||
finally
|
||||
|
|
@ -712,9 +721,9 @@ begin
|
|||
begin
|
||||
// Change file source, if the file under cursor can be opened as another file source.
|
||||
try
|
||||
ChooseFileSource(TargetPage.FileView, aFile);
|
||||
except
|
||||
on e: EFileSourceException do
|
||||
ChooseFileSource(TargetPage.FileView, aFile);
|
||||
except
|
||||
on e: EFileSourceException do
|
||||
MessageDlg('Error', e.Message, mtError, [mbOK], 0);
|
||||
end;
|
||||
end;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue