ADD: delete dialog - option to skip recycle bin; FIX: KDE trash widget refresh

This commit is contained in:
heredie 2026-05-22 11:39:52 -06:00
commit da603167b2
5 changed files with 91 additions and 15 deletions

View file

@ -34,6 +34,20 @@ inherited frmDeleteDlg: TfrmDeleteDlg
ShowAccelChar = False
WordWrap = True
end
object chkUseTrash: TCheckBox[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 = chkUseTrashChange
end
end
inherited pnlButtons: TPanel
AnchorSideLeft.Control = Owner

View file

@ -13,15 +13,19 @@ type
{ TfrmDeleteDlg }
TfrmDeleteDlg = class(TfrmButtonForm)
chkUseTrash: TCheckBox;
lblMessage: TLabel;
procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
procedure chkUseTrashChange(Sender: TObject);
private
{ private declarations }
FMsgTrash: String;
FMsgNoTrash: 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, NoTrashMessage: String; FileSource: IFileSource; out QueueId: TOperationsManagerQueueIdentifier; var UseTrash: Boolean): Boolean; overload;
implementation
@ -41,6 +45,28 @@ begin
end;
end;
function ShowDeleteDialog(TheOwner: TComponent; const TrashMessage, NoTrashMessage: String;
FileSource: IFileSource; out QueueId: TOperationsManagerQueueIdentifier;
var UseTrash: Boolean): Boolean;
begin
with TfrmDeleteDlg.Create(TheOwner, FileSource) do
begin
Caption:= Application.Title;
FMsgTrash:= TrashMessage;
FMsgNoTrash:= NoTrashMessage;
chkUseTrash.Visible:= True;
chkUseTrash.Checked:= UseTrash;
if UseTrash then
lblMessage.Caption:= TrashMessage
else
lblMessage.Caption:= NoTrashMessage;
Result:= ShowModal = mrOK;
if Result then UseTrash:= chkUseTrash.Checked;
QueueId:= QueueIdentifier;
Free;
end;
end;
{$R *.lfm}
{ TfrmDeleteDlg }
@ -55,5 +81,13 @@ begin
end;
end;
procedure TfrmDeleteDlg.chkUseTrashChange(Sender: TObject);
begin
if chkUseTrash.Checked then
lblMessage.Caption:= FMsgTrash
else
lblMessage.Caption:= FMsgNoTrash;
end;
end.

View file

@ -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;

View file

@ -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;

View file

@ -2592,11 +2592,13 @@ var
theFilesToDelete: TFiles;
// 12.05.2009 - if delete to trash, then show another messages
MsgDelSel, MsgDelFlDr : string;
MsgTrash, MsgNoTrash: String;
Operation: TFileSourceOperation;
bRecycle: Boolean;
bConfirmation, HasConfirmationParam: Boolean;
Param, ParamTrashCan: String;
BoolValue: Boolean;
TrashAvailable: Boolean;
QueueId: TOperationsManagerQueueIdentifier = FreeOperationsQueueId;
begin
with frmMain.ActiveFrame do
@ -2637,11 +2639,12 @@ begin
end;
// Save parameter for later use
TrashAvailable := FileSource.IsClass(TFileSystemFileSource) and
mbCheckTrash(CurrentPath);
BoolValue := bRecycle;
if bRecycle then
bRecycle := FileSource.IsClass(TFileSystemFileSource) and
mbCheckTrash(CurrentPath);
bRecycle := TrashAvailable;
if not HasConfirmationParam then
begin
@ -2675,16 +2678,24 @@ 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]);
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;
Message := Format(MsgDelFlDr, [theFilesToDelete.Count]) + Message;
end;
if (bConfirmation = False) or (ShowDeleteDialog(frmMain, Message, FileSource, QueueId)) then
if (bConfirmation = False) or
(TrashAvailable and ShowDeleteDialog(frmMain, MsgTrash, MsgNoTrash, FileSource, QueueId, bRecycle)) or
((not TrashAvailable) and ShowDeleteDialog(frmMain, Message, FileSource, QueueId)) then
begin
// Restore focus to main window after confirmation dialog closes
if bConfirmation and frmMain.ActiveFrame.CanSetFocus then