mirror of
https://github.com/doublecmd/doublecmd.git
synced 2026-06-21 09:58:13 +00:00
Merge ec5f26ec51 into 54d6654ad1
This commit is contained in:
commit
2e6653b4a7
6 changed files with 205 additions and 35 deletions
|
|
@ -12,7 +12,7 @@ inherited frmDeleteDlg: TfrmDeleteDlg
|
|||
Constraints.MinWidth = 400
|
||||
KeyPreview = True
|
||||
OnKeyDown = FormKeyDown
|
||||
Position = poScreenCenter
|
||||
Position = poOwnerFormCenter
|
||||
inherited pnlContent: TPanel
|
||||
Height = 1
|
||||
Width = 399
|
||||
|
|
@ -34,6 +34,48 @@ inherited frmDeleteDlg: TfrmDeleteDlg
|
|||
ShowAccelChar = False
|
||||
WordWrap = True
|
||||
end
|
||||
object rbTrash: TRadioButton[1]
|
||||
AnchorSideLeft.Control = pnlContent
|
||||
AnchorSideTop.Control = lblMessage
|
||||
AnchorSideTop.Side = asrBottom
|
||||
Left = 0
|
||||
Height = 23
|
||||
Top = 1
|
||||
Width = 399
|
||||
Anchors = [akTop, akLeft]
|
||||
Caption = 'Move to &Recycle Bin'
|
||||
TabOrder = 1
|
||||
Visible = False
|
||||
OnChange = rbModeChange
|
||||
end
|
||||
object rbDelete: TRadioButton[2]
|
||||
AnchorSideLeft.Control = pnlContent
|
||||
AnchorSideTop.Control = rbTrash
|
||||
AnchorSideTop.Side = asrBottom
|
||||
Left = 0
|
||||
Height = 23
|
||||
Top = 24
|
||||
Width = 399
|
||||
Anchors = [akTop, akLeft]
|
||||
Caption = 'Delete &permanently'
|
||||
TabOrder = 2
|
||||
Visible = False
|
||||
OnChange = rbModeChange
|
||||
end
|
||||
object rbWipe: TRadioButton[3]
|
||||
AnchorSideLeft.Control = pnlContent
|
||||
AnchorSideTop.Control = rbDelete
|
||||
AnchorSideTop.Side = asrBottom
|
||||
Left = 0
|
||||
Height = 23
|
||||
Top = 47
|
||||
Width = 399
|
||||
Anchors = [akTop, akLeft]
|
||||
Caption = '&Wipe (secure erase)'
|
||||
TabOrder = 3
|
||||
Visible = False
|
||||
OnChange = rbModeChange
|
||||
end
|
||||
end
|
||||
inherited pnlButtons: TPanel
|
||||
AnchorSideLeft.Control = Owner
|
||||
|
|
|
|||
|
|
@ -9,19 +9,27 @@ uses
|
|||
Buttons, Menus, StdCtrls, fButtonForm, uOperationsManager, uFileSource;
|
||||
|
||||
type
|
||||
TDeleteMode = (dmTrash, dmDelete, dmWipe);
|
||||
|
||||
{ TfrmDeleteDlg }
|
||||
|
||||
TfrmDeleteDlg = class(TfrmButtonForm)
|
||||
rbTrash: TRadioButton;
|
||||
rbDelete: TRadioButton;
|
||||
rbWipe: TRadioButton;
|
||||
lblMessage: TLabel;
|
||||
procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
|
||||
procedure rbModeChange(Sender: TObject);
|
||||
private
|
||||
{ private declarations }
|
||||
FMessages: array[TDeleteMode] of String;
|
||||
public
|
||||
{ public declarations }
|
||||
end;
|
||||
|
||||
function ShowDeleteDialog(TheOwner: TComponent; const Message: String; FileSource: IFileSource; out QueueId: TOperationsManagerQueueIdentifier): Boolean;
|
||||
function ShowDeleteDialog(TheOwner: TComponent; const Message: String; FileSource: IFileSource; out QueueId: TOperationsManagerQueueIdentifier): Boolean; overload;
|
||||
function ShowDeleteDialog(TheOwner: TComponent; const TrashMessage, DeleteMessage, WipeMessage: String;
|
||||
FileSource: IFileSource; out QueueId: TOperationsManagerQueueIdentifier;
|
||||
ShowTrash, ShowWipe: Boolean; var DeleteMode: TDeleteMode): Boolean; overload;
|
||||
|
||||
implementation
|
||||
|
||||
|
|
@ -30,14 +38,52 @@ uses
|
|||
|
||||
function ShowDeleteDialog(TheOwner: TComponent; const Message: String; FileSource: IFileSource;
|
||||
out QueueId: TOperationsManagerQueueIdentifier): Boolean;
|
||||
var
|
||||
Dlg: TfrmDeleteDlg;
|
||||
begin
|
||||
with TfrmDeleteDlg.Create(TheOwner, FileSource) do
|
||||
begin
|
||||
Caption:= Application.Title;
|
||||
lblMessage.Caption:= Message;
|
||||
Result:= ShowModal = mrOK;
|
||||
QueueId:= QueueIdentifier;
|
||||
Free;
|
||||
Dlg := TfrmDeleteDlg.Create(TheOwner, FileSource);
|
||||
try
|
||||
Dlg.Caption := Application.Title;
|
||||
Dlg.lblMessage.Caption := Message;
|
||||
Result := Dlg.ShowModal = mrOK;
|
||||
QueueId := Dlg.QueueIdentifier;
|
||||
finally
|
||||
Dlg.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
function ShowDeleteDialog(TheOwner: TComponent; const TrashMessage, DeleteMessage, WipeMessage: String;
|
||||
FileSource: IFileSource; out QueueId: TOperationsManagerQueueIdentifier;
|
||||
ShowTrash, ShowWipe: Boolean; var DeleteMode: TDeleteMode): Boolean;
|
||||
var
|
||||
Dlg: TfrmDeleteDlg;
|
||||
begin
|
||||
Dlg := TfrmDeleteDlg.Create(TheOwner, FileSource);
|
||||
try
|
||||
Dlg.Caption := Application.Title;
|
||||
Dlg.FMessages[dmTrash] := TrashMessage;
|
||||
Dlg.FMessages[dmDelete] := DeleteMessage;
|
||||
Dlg.FMessages[dmWipe] := WipeMessage;
|
||||
Dlg.rbTrash.Visible := ShowTrash;
|
||||
Dlg.rbDelete.Visible := True;
|
||||
Dlg.rbWipe.Visible := ShowWipe;
|
||||
// Set initial selection; fall back to dmDelete if the preferred mode is unavailable
|
||||
case DeleteMode of
|
||||
dmTrash: if ShowTrash then Dlg.rbTrash.Checked := True else Dlg.rbDelete.Checked := True;
|
||||
dmWipe: if ShowWipe then Dlg.rbWipe.Checked := True else Dlg.rbDelete.Checked := True;
|
||||
else Dlg.rbDelete.Checked := True;
|
||||
end;
|
||||
Dlg.lblMessage.Caption := Dlg.FMessages[DeleteMode];
|
||||
Result := Dlg.ShowModal = mrOK;
|
||||
if Result then
|
||||
begin
|
||||
if Dlg.rbTrash.Checked then DeleteMode := dmTrash
|
||||
else if Dlg.rbWipe.Checked then DeleteMode := dmWipe
|
||||
else DeleteMode := dmDelete;
|
||||
end;
|
||||
QueueId := Dlg.QueueIdentifier;
|
||||
finally
|
||||
Dlg.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
|
@ -47,13 +93,48 @@ end;
|
|||
|
||||
procedure TfrmDeleteDlg.FormKeyDown(Sender: TObject; var Key: Word;
|
||||
Shift: TShiftState);
|
||||
var
|
||||
Modes: array[0..2] of TRadioButton;
|
||||
Count, Cur, I: Integer;
|
||||
begin
|
||||
if (Key = VK_RETURN) and (ssShift in Shift) then
|
||||
begin
|
||||
btnOK.Click;
|
||||
Key:= 0;
|
||||
case Key of
|
||||
VK_RETURN:
|
||||
begin
|
||||
btnOK.Click;
|
||||
Key := 0;
|
||||
end;
|
||||
VK_UP, VK_DOWN:
|
||||
begin
|
||||
{ Build ordered list of visible radio buttons. }
|
||||
Count := 0;
|
||||
Cur := -1;
|
||||
for I := 0 to 2 do
|
||||
Modes[I] := nil;
|
||||
if rbTrash.Visible then begin Modes[Count] := rbTrash; if rbTrash.Checked then Cur := Count; Inc(Count); end;
|
||||
if rbDelete.Visible then begin Modes[Count] := rbDelete; if rbDelete.Checked then Cur := Count; Inc(Count); end;
|
||||
if rbWipe.Visible then begin Modes[Count] := rbWipe; if rbWipe.Checked then Cur := Count; Inc(Count); end;
|
||||
if Count > 1 then
|
||||
begin
|
||||
if Key = VK_DOWN then
|
||||
Cur := (Cur + 1) mod Count
|
||||
else
|
||||
Cur := (Cur + Count - 1) mod Count;
|
||||
Modes[Cur].Checked := True;
|
||||
end;
|
||||
Key := 0;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TfrmDeleteDlg.rbModeChange(Sender: TObject);
|
||||
var
|
||||
Mode: TDeleteMode;
|
||||
begin
|
||||
if rbTrash.Checked then Mode := dmTrash
|
||||
else if rbWipe.Checked then Mode := dmWipe
|
||||
else Mode := dmDelete;
|
||||
lblMessage.Caption := FMessages[Mode];
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@ uses
|
|||
uFileSourceOperationOptions,
|
||||
uFileSourceOperationUI,
|
||||
uFile,
|
||||
uDescr, uGlobs, uLog;
|
||||
uDescr, uGlobs, uLog
|
||||
{$IF DEFINED(UNIX)}, uKde{$ENDIF};
|
||||
|
||||
type
|
||||
|
||||
|
|
@ -125,6 +126,13 @@ end;
|
|||
procedure TFileSystemDeleteOperation.MainExecute;
|
||||
begin
|
||||
ProcessList(FFullFilesTreeToDelete);
|
||||
{$IF DEFINED(UNIX)}
|
||||
// Notify KDE trash widget to refresh after a recycle operation.
|
||||
// kioclient5 move /dev/null trash:/ fails intentionally but triggers the
|
||||
// KDE widget to pick up external changes to the trash directory.
|
||||
// See: https://github.com/doublecmd/doublecmd/issues/2688
|
||||
if FRecycle then RefreshKdeTrashWidget;
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
procedure TFileSystemDeleteOperation.Finalize;
|
||||
|
|
|
|||
|
|
@ -2970,6 +2970,9 @@ object frmMain: TfrmMain
|
|||
object mnuContextRenameOnly: TMenuItem
|
||||
Action = actRenameOnly
|
||||
end
|
||||
object mnuContextWipe: TMenuItem
|
||||
Action = actWipe
|
||||
end
|
||||
object mnuContextDelete: TMenuItem
|
||||
Action = actDelete
|
||||
end
|
||||
|
|
|
|||
|
|
@ -29,9 +29,11 @@ uses
|
|||
Classes, SysUtils, uMyUnix;
|
||||
|
||||
function KioOpen(const URL: String): Boolean;
|
||||
procedure RefreshKdeTrashWidget;
|
||||
|
||||
var
|
||||
HasKdeOpen: Boolean = False;
|
||||
KdeOpen: String = 'kioclient';
|
||||
|
||||
implementation
|
||||
|
||||
|
|
@ -40,7 +42,6 @@ uses
|
|||
|
||||
var
|
||||
KdeVersion: String;
|
||||
KdeOpen: String = 'kioclient';
|
||||
|
||||
function KioOpen(const URL: String): Boolean;
|
||||
begin
|
||||
|
|
@ -60,6 +61,14 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
procedure RefreshKdeTrashWidget;
|
||||
begin
|
||||
// This intentionally-failing move triggers KDE to refresh its trash widget.
|
||||
// See: https://github.com/doublecmd/doublecmd/issues/2688
|
||||
if HasKdeOpen then
|
||||
ExecuteProcess(KdeOpen, ['--noninteractive', 'move', '/dev/null', 'trash:/']);
|
||||
end;
|
||||
|
||||
procedure Initialize;
|
||||
begin
|
||||
if (DesktopEnv = DE_KDE) then
|
||||
|
|
@ -67,7 +76,7 @@ begin
|
|||
KdeVersion:= GetEnvironmentVariable('KDE_SESSION_VERSION');
|
||||
if KdeVersion = '5' then KdeOpen:= 'kioclient5';
|
||||
HasKdeOpen:= FindExecutableInSystemPath(KdeOpen);
|
||||
// if HasKdeOpen then FileTrashUtf8:= @FileTrash;
|
||||
if HasKdeOpen then FileTrashUtf8:= @FileTrash;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
|
|
|||
|
|
@ -2630,11 +2630,15 @@ var
|
|||
theFilesToDelete: TFiles;
|
||||
// 12.05.2009 - if delete to trash, then show another messages
|
||||
MsgDelSel, MsgDelFlDr : string;
|
||||
MsgTrash, MsgNoTrash, MsgWipe: String;
|
||||
Operation: TFileSourceOperation;
|
||||
bRecycle: Boolean;
|
||||
bConfirmation, HasConfirmationParam: Boolean;
|
||||
Confirmed: Boolean;
|
||||
Param, ParamTrashCan: String;
|
||||
BoolValue: Boolean;
|
||||
TrashAvailable, WipeAvailable: Boolean;
|
||||
DeleteMode: TDeleteMode;
|
||||
QueueId: TOperationsManagerQueueIdentifier = FreeOperationsQueueId;
|
||||
begin
|
||||
with frmMain.ActiveFrame do
|
||||
|
|
@ -2675,11 +2679,13 @@ begin
|
|||
end;
|
||||
|
||||
// Save parameter for later use
|
||||
TrashAvailable := FileSource.IsClass(TFileSystemFileSource) and
|
||||
mbCheckTrash(CurrentPath);
|
||||
WipeAvailable := fsoWipe in FileSource.GetOperationsTypes;
|
||||
BoolValue := bRecycle;
|
||||
|
||||
if bRecycle then
|
||||
bRecycle := FileSource.IsClass(TFileSystemFileSource) and
|
||||
mbCheckTrash(CurrentPath);
|
||||
bRecycle := TrashAvailable;
|
||||
|
||||
if not HasConfirmationParam then
|
||||
begin
|
||||
|
|
@ -2713,16 +2719,35 @@ begin
|
|||
try
|
||||
if (theFilesToDelete.Count = 0) then Exit;
|
||||
if (theFilesToDelete.Count = 1) then
|
||||
Message:= Format(MsgDelSel, [theFilesToDelete[0].Name])
|
||||
begin
|
||||
MsgTrash := Format(rsMsgDelSelT, [theFilesToDelete[0].Name]);
|
||||
MsgNoTrash := Format(rsMsgDelSel, [theFilesToDelete[0].Name]);
|
||||
MsgWipe := Format(rsMsgWipeSel, [theFilesToDelete[0].Name]);
|
||||
Message := Format(MsgDelSel, [theFilesToDelete[0].Name]);
|
||||
end
|
||||
else begin
|
||||
Message:= Format(MsgDelFlDr, [theFilesToDelete.Count]) + LineEnding;
|
||||
for I:= 0 to Min(4, theFilesToDelete.Count - 1) do
|
||||
begin
|
||||
Message+= LineEnding + theFilesToDelete[I].Name;
|
||||
end;
|
||||
if theFilesToDelete.Count > 5 then Message+= LineEnding + '...';
|
||||
// Build the file list suffix once and share it across all message variants
|
||||
Message := LineEnding;
|
||||
for I:= 0 to Min(4, theFilesToDelete.Count - 1) do
|
||||
Message += LineEnding + theFilesToDelete[I].Name;
|
||||
if theFilesToDelete.Count > 5 then Message += LineEnding + '...';
|
||||
MsgTrash := Format(rsMsgDelFlDrT, [theFilesToDelete.Count]) + Message;
|
||||
MsgNoTrash := Format(rsMsgDelFlDr, [theFilesToDelete.Count]) + Message;
|
||||
MsgWipe := Format(rsMsgWipeFlDr, [theFilesToDelete.Count]) + Message;
|
||||
Message := Format(MsgDelFlDr, [theFilesToDelete.Count]) + Message;
|
||||
end;
|
||||
if (bConfirmation = False) or (ShowDeleteDialog(frmMain, Message, FileSource, QueueId)) then
|
||||
// Default delete mode based on current recycle setting
|
||||
if bRecycle then DeleteMode := dmTrash else DeleteMode := dmDelete;
|
||||
// Show confirmation dialog; choose extended or simple variant based on available modes
|
||||
if not bConfirmation then
|
||||
Confirmed := True
|
||||
else if TrashAvailable or WipeAvailable then
|
||||
Confirmed := ShowDeleteDialog(frmMain, MsgTrash, MsgNoTrash, MsgWipe,
|
||||
FileSource, QueueId,
|
||||
TrashAvailable, WipeAvailable, DeleteMode)
|
||||
else
|
||||
Confirmed := ShowDeleteDialog(frmMain, Message, FileSource, QueueId);
|
||||
if Confirmed then
|
||||
begin
|
||||
// Restore focus to main window after confirmation dialog closes
|
||||
if bConfirmation and frmMain.ActiveFrame.CanSetFocus then
|
||||
|
|
@ -2757,25 +2782,27 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
Operation := FileSource.CreateDeleteOperation(theFilesToDelete);
|
||||
|
||||
if Assigned(Operation) then
|
||||
// Dispatch to wipe or delete based on dialog choice
|
||||
if DeleteMode = dmWipe then
|
||||
Operation := FileSource.CreateWipeOperation(theFilesToDelete)
|
||||
else
|
||||
begin
|
||||
bRecycle := (DeleteMode = dmTrash);
|
||||
Operation := FileSource.CreateDeleteOperation(theFilesToDelete);
|
||||
// Special case for filesystem - 'recycle' parameter.
|
||||
if Operation is TFileSystemDeleteOperation then
|
||||
if Assigned(Operation) and (Operation is TFileSystemDeleteOperation) then
|
||||
with Operation as TFileSystemDeleteOperation do
|
||||
begin
|
||||
// 30.04.2009 - передаем параметр корзины в поток.
|
||||
Recycle := bRecycle;
|
||||
end;
|
||||
|
||||
// Start operation.
|
||||
OperationsManager.AddOperation(Operation, QueueId, False);
|
||||
end
|
||||
else
|
||||
begin
|
||||
msgWarning(rsMsgNotImplemented);
|
||||
end;
|
||||
|
||||
if Assigned(Operation) then
|
||||
// Start operation.
|
||||
OperationsManager.AddOperation(Operation, QueueId, False)
|
||||
else
|
||||
msgWarning(rsMsgNotImplemented);
|
||||
end;
|
||||
|
||||
finally
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue