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 SrcEditorByListItem(ListIndex: integer): 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 i: Integer; SrcEdit: TSourceEditor; begin for i:=CheckListBox1.Count-1 downto 0 do if CheckListBox1.Checked[i] then begin SrcEdit:=SrcEditorByListItem(i); 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 SrcEdit: TSourceEditor; i: Integer; begin i:=CheckListBox1.ItemIndex; if (i>-1) and (i 0) and (FilterEdit.Filter='') and not SortAlphabetically then begin SrcEdit:=SrcEditorByListItem(i); Assert(Assigned(SrcEdit), 'TEditorFileManagerForm.MoveUpBtnClick: SrcEdit is not assigned.'); if SrcEdit.PageIndex > 0 then begin // First move the source editor tab SrcEdit.SourceNotebook.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 i: Integer; SrcEdit: TSourceEditor; begin for i:=0 to CheckListBox1.Count-1 do if CheckListBox1.Selected[i] then begin // Find first selected. SrcEdit:=SrcEditorByListItem(CheckListBox1.ItemIndex); Assert(Assigned(SrcEdit), 'TEditorFileManagerForm.ActivateButtonClick: SrcEdit is not assigned.'); SrcEdit.Activate; Break; end; end; // Private methods procedure TEditorFileManagerForm.CloseListItem(ListIndex: integer); var SrcEdit: TSourceEditor; begin SrcEdit:=SrcEditorByListItem(ListIndex); 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 SrcEdit: TSourceEditor; i, j: Integer; sw: TSourceNotebook; Modi: String; begin FilterEdit.Items.Clear; with SourceEditorManager do for i:=0 to SourceWindowCount-1 do begin sw:=SourceWindows[i]; Assert(sw.PageCount=sw.EditorCount, 'sw.PageCount<>sw.EditorCount'); for j:=0 to sw.EditorCount-1 do begin SrcEdit:=sw.FindSourceEditorWithPageIndex(j); if SrcEdit.Modified then Modi:='* ' else Modi:=''; FilterEdit.Items.Add(Modi+SrcEdit.FileName); end; end; FilterEdit.InvalidateFilter; FileCountLabel.Caption:=Format(dlgFiles,[IntToStr(SourceEditorManager.SourceEditorCount)]); end; function TEditorFileManagerForm.SrcEditorByListItem(ListIndex: integer): TSourceEditor; var s: String; begin s:=CheckListBox1.Items[ListIndex]; if (s<>'') and (s[1]='*') then // Modified indicator delete(s, 1, 2); Result:=SourceEditorManager.SourceEditorIntfWithFilename(s); 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 SrcEdit: TSourceEditor; UpEnabled, DownEnabled: Boolean; begin UpEnabled:=False; DownEnabled:=False; if (ListIndex>-1) and (ListIndex0) 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.