mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-05 23:17:57 +02:00
466 lines
15 KiB
ObjectPascal
466 lines
15 KiB
ObjectPascal
unit EditorFileManager;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, sysutils,
|
|
Forms, Controls, CheckLst, ButtonPanel, StdCtrls, Buttons, ExtCtrls, Menus, LCLType,
|
|
LazLoggerBase,
|
|
ListFilterEdit,
|
|
IDEImagesIntf, LazIDEIntf, IDEHelpIntf, SrcEditorIntf, IDEWindowIntf,
|
|
IDEOptionDefs,
|
|
SourceEditor, LazarusIDEStrConsts;
|
|
|
|
type
|
|
|
|
{ TEditorFileManagerForm }
|
|
|
|
TEditorFileManagerForm = class(TForm)
|
|
ActivateMenuItem: TMenuItem;
|
|
FileCountLabel: TLabel;
|
|
MoveDownBtn: TSpeedButton;
|
|
MoveUpBtn: TSpeedButton;
|
|
FilterPanel: TPanel;
|
|
OpenButton: TSpeedButton;
|
|
SaveCheckedButton: TBitBtn;
|
|
ButtonPanel1: TButtonPanel;
|
|
CloseCheckedButton: TBitBtn;
|
|
CloseMenuItem: TMenuItem;
|
|
Panel1: TPanel;
|
|
PopupMenu1: TPopupMenu;
|
|
CheckAllCheckBox: TCheckBox;
|
|
CheckListBox1: TCheckListBox;
|
|
FilterEdit: TListFilterEdit;
|
|
SortAlphabeticallyButton: TSpeedButton;
|
|
procedure ActivateMenuItemClick(Sender: TObject);
|
|
procedure CheckListBox1DblClick(Sender: TObject);
|
|
procedure CheckListBox1KeyDown(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
procedure CheckListBox1KeyPress(Sender: TObject; var Key: char);
|
|
procedure CloseButtonClick(Sender: TObject);
|
|
procedure DoEditorsChanged(Sender: TObject);
|
|
procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
|
|
procedure HelpButtonClick(Sender: TObject);
|
|
procedure MoveDownBtnClick(Sender: TObject);
|
|
procedure MoveUpBtnClick(Sender: TObject);
|
|
procedure CheckListBox1Click(Sender: TObject);
|
|
procedure CheckListBox1ItemClick(Sender: TObject; Index: integer);
|
|
procedure CloseCheckedButtonClick(Sender: TObject);
|
|
procedure PopupMenu1Popup(Sender: TObject);
|
|
procedure SaveCheckedButtonClick(Sender: TObject);
|
|
procedure CloseMenuItemClick(Sender: TObject);
|
|
procedure FormCreate(Sender: TObject);
|
|
procedure ActivateButtonClick(Sender: TObject);
|
|
procedure CheckAllCheckBoxClick(Sender: TObject);
|
|
procedure SortAlphabeticallyButtonClick(Sender: TObject);
|
|
private
|
|
FSortAlphabetically: boolean;
|
|
procedure CloseListItem(ListIndex: integer);
|
|
procedure PopulateList;
|
|
function SrcWinAndEditorByListItem(ListIndex: integer;
|
|
out SourceWindow: TSourceNotebook): TSourceEditor;
|
|
procedure SetSortAlphabetically(AValue: boolean);
|
|
procedure UpdateCheckAllCaption;
|
|
procedure UpdateButtons;
|
|
procedure UpdateMoveButtons(ListIndex: integer);
|
|
public
|
|
destructor Destroy; override;
|
|
property SortAlphabetically: boolean read FSortAlphabetically write SetSortAlphabetically;
|
|
end;
|
|
|
|
var
|
|
EditorFileManagerForm: TEditorFileManagerForm;
|
|
|
|
procedure ShowEditorFileManagerForm(State: TIWGetFormState = iwgfShowOnTop);
|
|
|
|
implementation
|
|
|
|
{$R *.lfm}
|
|
|
|
procedure ShowEditorFileManagerForm(State: TIWGetFormState);
|
|
begin
|
|
if EditorFileManagerForm = Nil then
|
|
IDEWindowCreators.CreateForm(EditorFileManagerForm,TEditorFileManagerForm,
|
|
State=iwgfDisabled,LazarusIDE.OwningComponent)
|
|
else if State=iwgfDisabled then
|
|
EditorFileManagerForm.DisableAlign;
|
|
if State>=iwgfShow then
|
|
IDEWindowCreators.ShowForm(EditorFileManagerForm,State=iwgfShowOnTop);
|
|
end;
|
|
|
|
{ TEditorFileManagerForm }
|
|
|
|
procedure TEditorFileManagerForm.FormCreate(Sender: TObject);
|
|
begin
|
|
Name := NonModalIDEWindowNames[nmiwEditorFileManager];
|
|
|
|
SourceEditorManager.RegisterChangeEvent(semEditorCreate, @DoEditorsChanged);
|
|
SourceEditorManager.RegisterChangeEvent(semEditorDestroy, @DoEditorsChanged);
|
|
|
|
PopulateList; // Populate the list with all open editor file names
|
|
// Captions
|
|
Caption:=lisSourceEditorWindowManager;
|
|
ActivateMenuItem.Caption:=lisActivate;
|
|
CloseMenuItem.Caption:=lisClose;
|
|
CheckAllCheckBox.Caption:=lisCheckAll;
|
|
SaveCheckedButton.Caption:=lisSaveAllChecked;
|
|
CloseCheckedButton.Caption:=lisCloseAllChecked;
|
|
MoveUpBtn.Hint:=lisMoveSelectedUp;
|
|
MoveDownBtn.Hint:=lisMoveSelectedDown;
|
|
// Icons
|
|
PopupMenu1.Images:=IDEImages.Images_16;
|
|
ActivateMenuItem.ImageIndex:=IDEImages.LoadImage('laz_open');
|
|
CloseMenuItem.ImageIndex:=IDEImages.LoadImage('menu_close');
|
|
IDEImages.AssignImage(CloseCheckedButton, 'menu_close_all');
|
|
IDEImages.AssignImage(SaveCheckedButton, 'menu_save_all');
|
|
IDEImages.AssignImage(MoveUpBtn, 'arrow_up');
|
|
IDEImages.AssignImage(MoveDownBtn, 'arrow_down');
|
|
// Buttons on FilterPanel
|
|
IDEImages.AssignImage(OpenButton, 'laz_open');
|
|
OpenButton.Hint:=lisActivateSelected;
|
|
SortAlphabeticallyButton.Hint:=lisPESortFilesAlphabetically;
|
|
IDEImages.AssignImage(SortAlphabeticallyButton, 'pkg_sortalphabetically');
|
|
end;
|
|
|
|
procedure TEditorFileManagerForm.CheckListBox1Click(Sender: TObject);
|
|
var
|
|
clb: TCheckListBox;
|
|
begin
|
|
clb:=Sender as TCheckListBox;
|
|
// Enable Activate when there is a selected item.
|
|
OpenButton.Enabled:=clb.SelCount>0;
|
|
UpdateMoveButtons(clb.ItemIndex);
|
|
end;
|
|
|
|
procedure TEditorFileManagerForm.CheckListBox1ItemClick(Sender: TObject; Index: integer);
|
|
var
|
|
clb: TCheckListBox;
|
|
i: Integer;
|
|
HasChecked: Boolean;
|
|
begin
|
|
clb:=Sender as TCheckListBox;
|
|
// Notify the filter edit that item's checked state has changed.
|
|
if Index>-1 then
|
|
FilterEdit.ItemWasClicked(clb.Items[Index], clb.Checked[Index]);
|
|
// Enable save and close buttons when there are checked items.
|
|
HasChecked:=False;
|
|
for i:=clb.Count-1 downto 0 do
|
|
if clb.Checked[i] then begin
|
|
HasChecked:=True;
|
|
Break;
|
|
end;
|
|
SaveCheckedButton.Enabled:=HasChecked;
|
|
CloseCheckedButton.Enabled:=HasChecked;
|
|
CloseMenuItem.Enabled:=HasChecked;
|
|
CheckAllCheckBox.Enabled:=clb.Count>0;
|
|
// If all items were unchecked, change CheckAllCheckBox state.
|
|
if CheckAllCheckBox.Checked and not HasChecked then begin
|
|
CheckAllCheckBox.Checked:=HasChecked;
|
|
UpdateCheckAllCaption;
|
|
end;
|
|
CheckListBox1Click(CheckListBox1); // Call also OnClick handler for other controls.
|
|
end;
|
|
|
|
procedure TEditorFileManagerForm.CheckAllCheckBoxClick(Sender: TObject);
|
|
var
|
|
cb: TCheckBox;
|
|
i: Integer;
|
|
begin
|
|
cb:=Sender as TCheckBox;
|
|
UpdateCheckAllCaption;
|
|
// Set / reset all CheckListBox1 items.
|
|
for i:=0 to CheckListBox1.Count-1 do begin
|
|
if CheckListBox1.Checked[i]<>cb.Checked then begin
|
|
CheckListBox1.Checked[i]:=cb.Checked;
|
|
FilterEdit.ItemWasClicked(CheckListBox1.Items[i], cb.Checked); // Notify the filter
|
|
end;
|
|
end;
|
|
CheckListBox1ItemClick(CheckListBox1, CheckListBox1.Count-1);
|
|
end;
|
|
|
|
procedure TEditorFileManagerForm.SortAlphabeticallyButtonClick(Sender: TObject);
|
|
begin
|
|
SortAlphabetically:=SortAlphabeticallyButton.Down;
|
|
end;
|
|
|
|
procedure TEditorFileManagerForm.SaveCheckedButtonClick(Sender: TObject);
|
|
var
|
|
SrcWindow: TSourceNotebook;
|
|
SrcEdit: TSourceEditor;
|
|
i: Integer;
|
|
begin
|
|
for i:=CheckListBox1.Count-1 downto 0 do
|
|
if CheckListBox1.Checked[i] then begin
|
|
SrcEdit:=SrcWinAndEditorByListItem(i, SrcWindow);
|
|
Assert(Assigned(SrcEdit), 'TEditorFileManagerForm.SaveCheckedButtonClick: SrcEdit is not assigned.');
|
|
if (not SrcEdit.CodeBuffer.IsVirtual) and (LazarusIDE.DoSaveEditorFile(SrcEdit, []) <> mrOk) then
|
|
DebugLn(['TSourceNotebook.EncodingClicked LazarusIDE.DoSaveEditorFile failed']);
|
|
end;
|
|
end;
|
|
|
|
procedure TEditorFileManagerForm.CloseCheckedButtonClick(Sender: TObject);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i:=CheckListBox1.Count-1 downto 0 do
|
|
if CheckListBox1.Checked[i] then
|
|
CloseListItem(i);
|
|
PopulateList;
|
|
UpdateButtons;
|
|
end;
|
|
|
|
procedure TEditorFileManagerForm.PopupMenu1Popup(Sender: TObject);
|
|
var
|
|
HasSelected: Boolean;
|
|
begin
|
|
HasSelected:=CheckListBox1.SelCount>0;
|
|
ActivateMenuItem.Enabled:=HasSelected;
|
|
CloseMenuItem.Enabled:=HasSelected;
|
|
end;
|
|
|
|
procedure TEditorFileManagerForm.CloseMenuItemClick(Sender: TObject);
|
|
begin
|
|
CloseListItem(CheckListBox1.ItemIndex);
|
|
PopulateList;
|
|
UpdateButtons;
|
|
end;
|
|
|
|
procedure TEditorFileManagerForm.ActivateMenuItemClick(Sender: TObject);
|
|
begin
|
|
ActivateButtonClick(nil);
|
|
end;
|
|
|
|
procedure TEditorFileManagerForm.CheckListBox1DblClick(Sender: TObject);
|
|
begin
|
|
ActivateButtonClick(nil);
|
|
end;
|
|
|
|
procedure TEditorFileManagerForm.CheckListBox1KeyDown(Sender: TObject;
|
|
var Key: Word; Shift: TShiftState);
|
|
begin
|
|
if (ssCtrl in Shift ) and ((Key = VK_UP) or (Key = VK_DOWN)) then begin
|
|
if Key = VK_UP then
|
|
MoveUpBtnClick(nil)
|
|
else
|
|
MoveDownBtnClick(nil);
|
|
Key:=VK_UNKNOWN;
|
|
end;
|
|
end;
|
|
|
|
procedure TEditorFileManagerForm.CheckListBox1KeyPress(Sender: TObject; var Key: char);
|
|
begin
|
|
if Key = char(VK_RETURN) then
|
|
ActivateButtonClick(nil);
|
|
end;
|
|
|
|
procedure TEditorFileManagerForm.CloseButtonClick(Sender: TObject);
|
|
begin
|
|
Close;
|
|
end;
|
|
|
|
procedure TEditorFileManagerForm.DoEditorsChanged(Sender: TObject);
|
|
begin
|
|
PopulateList;
|
|
end;
|
|
|
|
procedure TEditorFileManagerForm.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
|
|
begin
|
|
if (Key = VK_ESCAPE) and (Shift = []) then
|
|
Close;
|
|
end;
|
|
|
|
procedure TEditorFileManagerForm.HelpButtonClick(Sender: TObject);
|
|
begin
|
|
LazarusHelp.ShowHelpForIDEControl(Self);
|
|
end;
|
|
|
|
procedure TEditorFileManagerForm.MoveDownBtnClick(Sender: TObject);
|
|
var
|
|
SrcWindow: TSourceNotebook;
|
|
SrcEdit: TSourceEditor;
|
|
i: Integer;
|
|
begin
|
|
i:=CheckListBox1.ItemIndex;
|
|
if (i>-1) and (i<CheckListBox1.Items.Count-1)
|
|
and (FilterEdit.Filter='') and not SortAlphabetically then begin
|
|
SrcEdit:=SrcWinAndEditorByListItem(i, SrcWindow);
|
|
Assert(Assigned(SrcEdit), 'TEditorFileManagerForm.MoveDownBtnClick: SrcEdit is not assigned.');
|
|
if SrcEdit.PageIndex < SrcWindow.PageCount-1 then begin
|
|
// First move the source editor tab
|
|
SrcWindow.MoveEditor(SrcEdit.PageIndex, SrcEdit.PageIndex+1);
|
|
// Then switch the list items
|
|
FilterEdit.Items.Exchange(i, i+1);
|
|
FilterEdit.InvalidateFilter;
|
|
UpdateMoveButtons(i+1);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TEditorFileManagerForm.MoveUpBtnClick(Sender: TObject);
|
|
var
|
|
SrcWindow: TSourceNotebook;
|
|
SrcEdit: TSourceEditor;
|
|
i: Integer;
|
|
begin
|
|
i := CheckListBox1.ItemIndex;
|
|
if (i > 0) and (FilterEdit.Filter='') and not SortAlphabetically then begin
|
|
SrcEdit:=SrcWinAndEditorByListItem(i, SrcWindow);
|
|
Assert(Assigned(SrcEdit), 'TEditorFileManagerForm.MoveUpBtnClick: SrcEdit is not assigned.');
|
|
if SrcEdit.PageIndex > 0 then begin
|
|
// First move the source editor tab
|
|
SrcWindow.MoveEditor(SrcEdit.PageIndex, SrcEdit.PageIndex-1);
|
|
// Then switch the list items
|
|
FilterEdit.Items.Exchange(i, i-1);
|
|
FilterEdit.InvalidateFilter;
|
|
UpdateMoveButtons(i-1);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TEditorFileManagerForm.ActivateButtonClick(Sender: TObject);
|
|
var
|
|
SrcWindow: TSourceNotebook;
|
|
SrcEdit: TSourceEditor;
|
|
i: Integer;
|
|
begin
|
|
for i:=0 to CheckListBox1.Count-1 do
|
|
if CheckListBox1.Selected[i] then begin // Find first selected.
|
|
SrcEdit:=SrcWinAndEditorByListItem(CheckListBox1.ItemIndex, SrcWindow);
|
|
Assert(Assigned(SrcEdit), 'TEditorFileManagerForm.ActivateButtonClick: SrcEdit is not assigned.');
|
|
SrcEdit.Activate;
|
|
SrcWindow.FocusEditor;
|
|
Break;
|
|
end;
|
|
end;
|
|
|
|
// Private methods
|
|
|
|
procedure TEditorFileManagerForm.CloseListItem(ListIndex: integer);
|
|
var
|
|
SrcWindow: TSourceNotebook;
|
|
SrcEdit: TSourceEditor;
|
|
begin
|
|
SrcEdit:=SrcWinAndEditorByListItem(ListIndex, SrcWindow);
|
|
Assert(Assigned(SrcEdit), 'TEditorFileManagerForm.CloseListItem: SrcEdit is not assigned.');
|
|
LazarusIDE.DoCloseEditorFile(SrcEdit, [cfSaveFirst]);
|
|
end;
|
|
|
|
procedure TEditorFileManagerForm.PopulateList;
|
|
// Populate the list with all open editor file names
|
|
var
|
|
SrcWindow: TSourceNotebook;
|
|
SrcEdit: TSourceEditor;
|
|
Modi, Suffix: String;
|
|
i, j: Integer;
|
|
begin
|
|
FilterEdit.Items.Clear;
|
|
with SourceEditorManager do
|
|
for i:=0 to SourceWindowCount-1 do begin
|
|
SrcWindow:=SourceWindows[i];
|
|
Assert(SrcWindow.PageCount=SrcWindow.EditorCount, 'sw.PageCount<>sw.EditorCount');
|
|
if SourceWindowCount>1 then
|
|
Suffix:=Format(' [%d]', [i+1])
|
|
else
|
|
Suffix:='';
|
|
for j:=0 to SrcWindow.EditorCount-1 do begin
|
|
SrcEdit:=SrcWindow.FindSourceEditorWithPageIndex(j);
|
|
if SrcEdit.Modified then
|
|
Modi:='* '
|
|
else
|
|
Modi:='';
|
|
FilterEdit.Items.Add(Modi+SrcEdit.FileName+Suffix);
|
|
end;
|
|
end;
|
|
FilterEdit.InvalidateFilter;
|
|
FileCountLabel.Caption:=Format(dlgFiles,[IntToStr(SourceEditorManager.SourceEditorCount)]);
|
|
end;
|
|
|
|
function TEditorFileManagerForm.SrcWinAndEditorByListItem(ListIndex: integer;
|
|
out SourceWindow: TSourceNotebook): TSourceEditor;
|
|
var
|
|
s, WinS: String;
|
|
i, WinNro: Integer;
|
|
begin
|
|
SourceWindow:=Nil;
|
|
s:=CheckListBox1.Items[ListIndex];
|
|
if s='' then Exit(Nil);
|
|
if s[1]='*' then // Modified indicator
|
|
delete(s, 1, 2);
|
|
WinS:='';
|
|
WinNro:=0;
|
|
i:=Length(s);
|
|
if s[i]=']' then begin // Editor window number at the end
|
|
repeat
|
|
Dec(i);
|
|
if (i<=0) or (s[i]='[') then break;
|
|
Insert(s[i],WinS,1);
|
|
until false;
|
|
if i<=0 then Exit(Nil); // Something went wrong
|
|
Dec(i,2); // Skip a space and '['
|
|
SetLength(s,i);
|
|
WinNro:=StrToInt(WinS)-1;
|
|
end;
|
|
SourceWindow:=SourceEditorManager.SourceWindows[WinNro];
|
|
Result:=SourceWindow.SourceEditorIntfWithFilename(s) as TSourceEditor;
|
|
end;
|
|
|
|
procedure TEditorFileManagerForm.SetSortAlphabetically(AValue: boolean);
|
|
begin
|
|
if FSortAlphabetically=AValue then exit;
|
|
FSortAlphabetically:=AValue;
|
|
SortAlphabeticallyButton.Down:=FSortAlphabetically;
|
|
FilterEdit.SortData:=FSortAlphabetically;
|
|
end;
|
|
|
|
procedure TEditorFileManagerForm.UpdateCheckAllCaption;
|
|
// Caption text: check all / uncheck all
|
|
begin
|
|
if CheckAllCheckBox.Checked then
|
|
CheckAllCheckBox.Caption:=lisUncheckAll
|
|
else
|
|
CheckAllCheckBox.Caption:=lisCheckAll;
|
|
end;
|
|
|
|
procedure TEditorFileManagerForm.UpdateButtons;
|
|
// Update the filter and buttons. Reuse event handlers for it.
|
|
begin
|
|
FilterEdit.InvalidateFilter;
|
|
CheckListBox1ItemClick(CheckListBox1, CheckListBox1.Count-1);
|
|
end;
|
|
|
|
procedure TEditorFileManagerForm.UpdateMoveButtons(ListIndex: integer);
|
|
var
|
|
SrcWindow: TSourceNotebook;
|
|
SrcEdit: TSourceEditor;
|
|
UpEnabled, DownEnabled: Boolean;
|
|
begin
|
|
UpEnabled:=False;
|
|
DownEnabled:=False;
|
|
if (ListIndex>-1) and (ListIndex<CheckListBox1.Items.Count)
|
|
and (FilterEdit.Filter='') and not SortAlphabetically then begin
|
|
//DebugLn(['TEditorFileManagerForm.UpdateMoveButtons: Filename', CheckListBox1.Items[ListIndex], ', ListIndex:', ListIndex]);
|
|
SrcEdit:=SrcWinAndEditorByListItem(ListIndex, SrcWindow);
|
|
if Assigned(SrcEdit) then begin
|
|
DownEnabled:=(ListIndex<CheckListBox1.Items.Count-1)
|
|
and (SrcEdit.PageIndex<SrcWindow.PageCount-1);
|
|
UpEnabled:=(ListIndex>0) and (SrcEdit.PageIndex>0);
|
|
end;
|
|
end;
|
|
MoveUpBtn.Enabled:=UpEnabled;
|
|
MoveDownBtn.Enabled:=DownEnabled;
|
|
end;
|
|
|
|
destructor TEditorFileManagerForm.Destroy;
|
|
begin
|
|
if SourceEditorManager <> nil then begin
|
|
SourceEditorManager.UnRegisterChangeEvent(semEditorCreate, @DoEditorsChanged);
|
|
SourceEditorManager.UnRegisterChangeEvent(semEditorDestroy, @DoEditorsChanged);
|
|
end;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
end.
|
|
|