mirror of
https://github.com/doublecmd/doublecmd.git
synced 2026-06-28 10:02:14 +00:00
FIX: After closing preset sort window, have the focus still in the MultiRename window so we're ready to continue without having to click on window. FIX: One element was not autosized in select text range in MultiRename. FIX: Fix typo in "OK" button in sort dialog for the MultiRename preset. RMV: In the MultiRename dialog, since there is no 'Clear mask' added dynamically, remove the associated things that were forgotten to remove in code and language files. ADD: In MultiRename dialog window, the three buttons with no caption now have tooltip to indicate their function. ADD: Edit file list for MultiRename based on current displayed new name instead of taken always the original name like it was. Not only it allows to have placeholders to do their job and have the editor to do the finition for few exceptions left, but it also makes the function compatible with another known orthodox file manager. We kept the other "Edit Names" that was present simply for legacy users used to it, even if with the new, simply having a [N]/[E] placeholders and launch "Edit Current New Names" would do the same job.
212 lines
7.1 KiB
ObjectPascal
212 lines
7.1 KiB
ObjectPascal
{
|
|
Double Commander
|
|
-------------------------------------------------------------------------
|
|
Form allowing user to sort a list of element via drag and drop
|
|
|
|
Copyright (C) 2020 Alexander Koblov (alexx2000@mail.ru)
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
}
|
|
|
|
unit fSortAnything;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
//Lazarus, Free-Pascal, etc.
|
|
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls,
|
|
Buttons, ButtonPanel,
|
|
|
|
//DC
|
|
uOSForms, uClassesEx;
|
|
|
|
type
|
|
{ TfrmSortAnything }
|
|
TfrmSortAnything = class(TModalForm)
|
|
ButtonPanel: TButtonPanel;
|
|
btnSort: TBitBtn;
|
|
lblSortAnything: TLabel;
|
|
lbSortAnything: TListBox;
|
|
procedure FormCreate(Sender: TObject);
|
|
procedure btnSortClick(Sender: TObject);
|
|
procedure lbSortAnythingDragDrop(Sender, {%H-}Source: TObject; X, Y: integer);
|
|
procedure lbSortAnythingDragOver(Sender, {%H-}Source: TObject; {%H-}X, {%H-}Y: integer; {%H-}State: TDragState; var Accept: boolean);
|
|
private
|
|
IniPropStorage: TIniPropStorageEx;
|
|
end;
|
|
|
|
var
|
|
frmSortAnything: TfrmSortAnything;
|
|
|
|
function HaveUserSortThisList(TheOwner: TCustomForm; const ACaption: string; const slListToSort: TStringList): integer;
|
|
|
|
implementation
|
|
|
|
{$R *.lfm}
|
|
|
|
|
|
uses
|
|
//Lazarus, Free-Pascal, etc.
|
|
|
|
//DC
|
|
uGlobs;
|
|
|
|
{ TfrmSortAnything }
|
|
|
|
{ TfrmSortAnything.FormCreate }
|
|
procedure TfrmSortAnything.FormCreate(Sender: TObject);
|
|
begin
|
|
IniPropStorage := InitPropStorage(Self);
|
|
end;
|
|
|
|
{ TfrmSortAnything.btnSortClick }
|
|
// Simply "lbSortAnything.Sorted" was working fine in Windows.
|
|
// When tested under Ubuntu 64 with "LAZ 2.0.6/FPC 3.0.4 x86_64-linux-gtk2", it was not working correctly.
|
|
// For example, if our list was like "D,A,C,B", it was sorted correctly.
|
|
// But if list was like sorted in reverse, like "D,C,B,A", it did nothing.
|
|
// If we set "D,C,A,B", or "C,D,B,A" or "D,B,C,A", it was working.
|
|
// So it seems when it was pre-sorted reversed, it does not sort.
|
|
// For the moment let's use a TStringList on-the-side for the job.
|
|
procedure TfrmSortAnything.btnSortClick(Sender: TObject);
|
|
var
|
|
slJustForSort: TStringList;
|
|
iIndex: integer;
|
|
begin
|
|
slJustForSort := TStringList.Create;
|
|
try
|
|
slJustForSort.Sorted := True;
|
|
slJustForSort.Duplicates := dupAccept;
|
|
slJustForSort.CaseSensitive := False;
|
|
for iIndex := 0 to pred(lbSortAnything.items.Count) do slJustForSort.Add(lbSortAnything.Items.Strings[iIndex]);
|
|
lbSortAnything.Items.BeginUpdate;
|
|
try
|
|
lbSortAnything.Items.Clear;
|
|
for iIndex := 0 to pred(slJustForSort.Count) do lbSortAnything.Items.Add(slJustForSort.Strings[iIndex]);
|
|
lbSortAnything.ItemIndex := 0;
|
|
finally
|
|
lbSortAnything.Items.EndUpdate;
|
|
end;
|
|
finally
|
|
slJustForSort.Free;
|
|
end;
|
|
end;
|
|
{ TfrmSortAnything.lbSortAnythingDragOver }
|
|
procedure TfrmSortAnything.lbSortAnythingDragOver(Sender, Source: TObject; X, Y: integer; State: TDragState; var Accept: boolean);
|
|
begin
|
|
Accept := True;
|
|
end;
|
|
|
|
{ TfrmSortAnything.lbSortAnythingDragDrop }
|
|
// Key prodecure here that will let user do the drag and drop in the list to move item in the order he wants.
|
|
// Basically we first remove from the list the elements to be moved...
|
|
// ... and then we place them back to the correct destination.
|
|
// The key thing is to determine where will be this destination location based on current selection and target position.
|
|
procedure TfrmSortAnything.lbSortAnythingDragDrop(Sender, Source: TObject; X, Y: integer);
|
|
var
|
|
iFirstSelection, iBeforeTarget, iSeeker, iDestIndex: integer;
|
|
bMoveSelectionUp: boolean;
|
|
slBuffer: TStringList;
|
|
begin
|
|
iDestIndex := lbSortAnything.GetIndexAtXY(X, Y);
|
|
|
|
if (iDestIndex >= 0) and (iDestIndex < lbSortAnything.Items.Count) then //Don't laught, apparently it's possible to get a iDestIndex=-1 if we move totally on top.
|
|
begin
|
|
//1o) Let's determine in which direction the move is taken place with hint about down move.
|
|
iFirstSelection := -1;
|
|
iBeforeTarget := 0;
|
|
iSeeker := 0;
|
|
while (iSeeker < lbSortAnything.Count) do
|
|
begin
|
|
if lbSortAnything.Selected[iSeeker] then
|
|
begin
|
|
if iFirstSelection = -1 then
|
|
iFirstSelection := iSeeker;
|
|
|
|
if iSeeker < iDestIndex then
|
|
Inc(iBeforeTarget);
|
|
end;
|
|
|
|
Inc(iSeeker);
|
|
end;
|
|
bMoveSelectionUp := (iDestIndex <= iFirstSelection);
|
|
|
|
if (iFirstSelection >= 0) then
|
|
begin
|
|
lbSortAnything.Items.BeginUpdate;
|
|
try
|
|
slBuffer := TStringList.Create;
|
|
try
|
|
//2o) Let's remove from the list the element that will be relocated.
|
|
for iSeeker := pred(lbSortAnything.Items.Count) downto 0 do
|
|
begin
|
|
if lbSortAnything.Selected[iSeeker] then
|
|
begin
|
|
slBuffer.Insert(0, lbSortAnything.Items[iSeeker]);
|
|
lbSortAnything.Items.Delete(iSeeker);
|
|
end;
|
|
end;
|
|
|
|
//3o) If we're moving down, we need to readjust destination based on elements seen prior the destination.
|
|
if not bMoveSelectionUp then
|
|
iDestIndex := iDestIndex - pred(iBeforeTarget);
|
|
|
|
//4o) Putting back elements in the list after move. It could be "inserted" or "added at the end" based on the result of move.
|
|
if iDestIndex < lbSortAnything.Items.Count then
|
|
begin
|
|
for iSeeker := pred(slBuffer.Count) downto 0 do
|
|
begin
|
|
lbSortAnything.Items.Insert(iDestIndex, slBuffer.Strings[iSeeker]);
|
|
lbSortAnything.Selected[iDestIndex] := True;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
for iSeeker := 0 to pred(slBuffer.Count) do
|
|
begin
|
|
lbSortAnything.Items.Add(slBuffer.Strings[iSeeker]);
|
|
lbSortAnything.Selected[pred(lbSortAnything.Items.Count)] := True;
|
|
end;
|
|
end;
|
|
finally
|
|
lbSortAnything.Items.EndUpdate;
|
|
end;
|
|
finally
|
|
slBuffer.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{ HaveUserSortThisList }
|
|
function HaveUserSortThisList(TheOwner: TCustomForm; const ACaption: string; const slListToSort: TStringList): integer;
|
|
begin
|
|
Result := mrCancel;
|
|
with TfrmSortAnything.Create(TheOwner) do
|
|
begin
|
|
try
|
|
Caption := ACaption;
|
|
lbSortAnything.Items.Assign(slListToSort);
|
|
Result := ShowModal;
|
|
if Result = mrOk then
|
|
slListToSort.Assign(lbSortAnything.Items);
|
|
finally
|
|
Free;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
end.
|
|
|