lazarus/ide/editorfilemanager.pas

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.