lazarus/ide/inputfiledialog.pas
mattias d9f87ef6eb updatepofiles is now case sensitive,
replaced many places, where Application was needlessly Owner
updated po files, started Configure IDE Install Package dialog,
implemented removing double file package links

git-svn-id: trunk@6388 -
2004-12-18 10:20:22 +00:00

625 lines
17 KiB
ObjectPascal

{ $Id$ }
{
/***************************************************************************
inputfiledialog.pas
-------------------
TInputFileDialog is a dialog to let the user set some filenames.
***************************************************************************/
Author: Mattias Gaertner
*****************************************************************************
* *
* See the file COPYING.modifiedLGPL, included in this distribution, *
* for details about the copyright. *
* *
* 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. *
* *
*****************************************************************************
}
unit InputFileDialog;
{$mode objfpc}{$H+}
interface
uses
// LCL
Classes, SysUtils, Math, Forms, Controls, Dialogs, Buttons, StdCtrls,
FileUtil, LResources,
// IDE
TransferMacros, InputHistory;
type
TInputFileFlag = (iftDirectory, iftFilename, iftCmdLine,
iftNotEmpty, iftMustExist);
TInputFileFlags = set of TInputFileFlag;
TInputFileDialog = class(TForm)
OkButton: TButton;
CancelButton: TButton;
OpenDialog: TOpenDialog;
procedure OkButtonClick(Sender: TObject);
procedure CancelButtonClick(Sender: TObject);
procedure FormResize(Sender: TObject);
procedure InputFileDlgButtonClick(Sender: TObject);
private
FFileCount: integer;
FFileTitles: TStringList;
FFileDescs: TStringList;
FFileNames: TStringList;
FFileFlags: ^TInputFileFlags;
FInputGroupboxes: TList; // list TGroupBox
FInputLabels: TList; // list of list of TLabel
FInputDescs: TStringList;
FInputEdits: TList; // list of TEdit
FInputFileDlgButtons: TList; // list of TButton
FTransferMacros: TTransferMacroList;
FUpdateCount: integer;
FForceUpdate: boolean;
function GetFileDescriptions(Index: integer): string;
function GetFileTitles(Index: integer): string;
function GetFileFlags(Index: integer): TInputFileFlags;
function GetFilenames(Index: integer): string;
procedure SetFileCount(const AValue: integer);
procedure SetFileDescriptions(Index: integer; const AValue: string);
procedure SetFileTitles(Index: integer; const AValue: string);
procedure SetFileFlags(Index: integer; const AValue: TInputFileFlags);
procedure SetFilenames(Index: integer; const AValue: string);
procedure SetTransferMacros(const AValue: TTransferMacroList);
function UpdateNeeded: boolean;
function GetInputEdit(Index: integer): TEdit;
function GetInputFileDlgButton(Index: integer): TButton;
function GetLabelList(Index: integer): TList;
function GetLabel(Index, Line: integer): TLabel;
function GetGroupBox(Index: integer): TGroupBox;
function LabelListCount(Index: integer): integer;
function FileIndexOfFileDlgBtn(Button: TButton): integer;
procedure CreateInputComponents;
procedure CreateMissingGroupBoxes;
procedure CreateEditComponents;
procedure CreateFileDlgButtonComponents;
procedure CreateLabelComponents;
procedure DeleteUnusedGroupBoxes;
procedure DeleteLabelList(Index: integer);
procedure DeleteAllLabels;
procedure ResizeComponents;
public
constructor Create(TheOwner: TComponent); override;
destructor Destroy; override;
procedure BeginUpdate;
procedure EndUpdate;
procedure UpdateDlg;
function FilenameIsValidForFileIndex(Filename: string;
Index: integer): boolean;
public
property FileCount: integer read FFileCount write SetFileCount;
property FileTitles[Index: integer]: string
read GetFileTitles write SetFileTitles;
property FileNames[Index: integer]: string
read GetFileNames write SetFileNames;
property FileDescs[Index: integer]: string
read GetFileDescriptions write SetFileDescriptions;
property FileFlags[Index: integer]: TInputFileFlags
read GetFileFlags write SetFileFlags;
property Macros: TTransferMacroList
read FTransferMacros write SetTransferMacros;
end;
function GetInputFileDialog: TInputFileDialog;
implementation
var InputFileDlg: TInputFileDialog;
function GetInputFileDialog: TInputFileDialog;
begin
if InputFileDlg=nil then
InputFileDlg:=TInputFileDialog.Create(nil);
Result:=InputFileDlg;
end;
{ TInputFileDialog }
procedure TInputFileDialog.OkButtonClick(Sender: TObject);
var i: integer;
CurEdit: TEdit;
begin
for i:=0 to FileCount-1 do begin
CurEdit:=GetInputEdit(i);
CurEdit.Text:=CurEdit.Text;
if not FilenameIsValidForFileIndex(CurEdit.Text,i) then begin
if MessageDlg('Invalid file',
'The file "'+CurEdit.Text+'"'#13
+'is invalid for the '+GetGroupBox(i).Caption,mtInformation,
[mbCancel,mbAbort],0)=mrAbort
then
ModalResult:=mrCancel
else
exit;
end;
FFileNames[i]:=CurEdit.Text;
end;
ModalResult:=mrOk
end;
procedure TInputFileDialog.CancelButtonClick(Sender: TObject);
begin
ModalResult:=mrCancel;
end;
procedure TInputFileDialog.FormResize(Sender: TObject);
begin
ResizeComponents;
end;
procedure TInputFileDialog.InputFileDlgButtonClick(Sender: TObject);
var
FileIndex: integer;
AFilename: string;
begin
FileIndex:=FileIndexOfFileDlgBtn(TButton(Sender));
if FileIndex<0 then exit;
if OpenDialog=nil then OpenDialog:=TOpenDialog.Create(Self);
with OpenDialog do begin
InputHistories.ApplyFileDialogSettings(OpenDialog);
Title:='Select '+GetGroupBox(FileIndex).Caption;
if (not Execute) then exit;
InputHistories.StoreFileDialogSettings(OpenDialog);
AFilename:=Filename;
if not FilenameIsValidForFileIndex(AFilename,FileIndex) then exit;
GetInputEdit(FileIndex).Text:=AFilename;
end;
end;
function TInputFileDialog.GetFileDescriptions(Index: integer): string;
begin
Result:=FFileDescs[Index];
end;
function TInputFileDialog.GetFileTitles(Index: integer): string;
begin
Result:=FFileTitles[Index];
end;
function TInputFileDialog.GetFileFlags(Index: integer): TInputFileFlags;
begin
Result:=FFileFlags[Index];
end;
function TInputFileDialog.GetFilenames(Index: integer): string;
begin
Result:=FFileNames[Index];
end;
procedure TInputFileDialog.SetFileCount(const AValue: integer);
procedure SetStringListCount(sl: TStringlist);
begin
while sl.Count>AValue do
sl.Delete(sl.Count-1);
while sl.Count<AValue do
sl.Add('');
end;
var i: integer;
begin
if FFileCount=AValue then exit;
BeginUpdate;
SetStringListCount(FFileNames);
SetStringListCount(FFileDescs);
SetStringListCount(FFileTitles);
if FFileFlags<>nil then begin
FreeMem(FFileFlags);
FFileFlags:=nil;
end;
if AValue>0 then begin
Getmem(FFileFlags,SizeOf(TInputFileFlags)*AValue);
for i:=0 to AValue-1 do FFileFlags[i]:=[iftDirectory,iftNotEmpty];
end;
FFileCount:=AValue;
EndUpdate;
end;
procedure TInputFileDialog.SetFileDescriptions(Index: integer;
const AValue: string);
begin
FFileDescs[Index]:=AValue;
UpdateDlg;
end;
procedure TInputFileDialog.SetFileTitles(Index: integer; const AValue: string);
begin
FFileTitles[Index]:=AValue;
UpdateDlg;
end;
procedure TInputFileDialog.SetFileFlags(Index: integer;
const AValue: TInputFileFlags);
begin
FFileFlags[Index]:=AValue;
UpdateDlg;
end;
procedure TInputFileDialog.SetFilenames(Index: integer; const AValue: string);
begin
FFileNames[Index]:=AValue;
UpdateDlg;
end;
procedure TInputFileDialog.SetTransferMacros(const AValue: TTransferMacroList);
begin
FTransferMacros:=AValue;
end;
procedure TInputFileDialog.UpdateDlg;
begin
if (FUpdateCount<>0) or (not UpdateNeeded) then exit;
CreateInputComponents;
FormResize(Self);
end;
function TInputFileDialog.FilenameIsValidForFileIndex(Filename: string;
Index: integer): boolean;
var CurFileFlags: TInputFileFlags;
begin
Result:=false;
CurFileFlags:=FileFlags[Index];
if (iftNotEmpty in CurFileFlags) and (Filename='') then exit;
if ([iftMustExist,iftCmdLine]*CurFileFlags=[iftMustExist])
and (Filename<>'') then begin
if FTransferMacros<>nil then
Macros.SubstituteStr(Filename);
Filename:=ExpandFileName(Filename);
if (not (iftDirectory in CurFileFlags)) and DirPathExists(Filename)
then
exit;
if (not (iftFilename in CurFileFlags)) and FileExists(Filename)
and (not DirPathExists(Filename))
then
exit;
end;
Result:=true;
end;
function TInputFileDialog.UpdateNeeded: boolean;
var i: integer;
begin
Result:=true;
if FForceUpdate then exit;
FForceUpdate:=true;
// check file count
if FileCount<>FInputEdits.Count then exit;
// check files
for i:=0 to FileCount-1 do begin
if FFileTitles[i]<>GetGroupBox(I).Caption then exit;
if FFileNames[i]<>GetInputEdit(I).Text then exit;
if FFileDescs[i]<>FInputDescs[i] then exit;
end;
FForceUpdate:=false;
Result:=false;
end;
function TInputFileDialog.GetInputEdit(Index: integer): TEdit;
begin
Result:=TEdit(FInputEdits[Index]);
end;
function TInputFileDialog.GetInputFileDlgButton(Index: integer): TButton;
begin
Result:=TButton(FInputFileDlgButtons[Index]);
end;
function TInputFileDialog.GetLabelList(Index: integer): TList;
begin
Result:=TList(FInputLabels[Index]);
end;
function TInputFileDialog.GetLabel(Index, Line: integer): TLabel;
begin
Result:=TLabel(GetLabelList(Index)[Line]);
end;
function TInputFileDialog.GetGroupBox(Index: integer): TGroupBox;
begin
Result:=TGroupBox(FInputGroupboxes[Index]);
end;
function TInputFileDialog.LabelListCount(Index: integer): integer;
begin
Result:=GetLabelList(Index).Count;
end;
function TInputFileDialog.FileIndexOfFileDlgBtn(Button: TButton): integer;
begin
for Result:=0 to FInputFileDlgButtons.Count-1 do
if GetInputFileDlgButton(Result)=Button then exit;
Result:=-1;
end;
procedure TInputFileDialog.CreateInputComponents;
begin
CreateMissingGroupBoxes;
CreateEditComponents;
CreateFileDlgButtonComponents;
CreateLabelComponents;
DeleteUnusedGroupBoxes;
end;
procedure TInputFileDialog.CreateMissingGroupBoxes;
var
NewGroupBox: TGroupBox;
begin
// add new TGroupBoxes
while FInputGroupboxes.Count<FFileCount do begin
NewGroupBox:=TGroupBox.Create(Self);
with NewGroupBox do begin
Name:='InputGroupBox'+IntToStr(FInputGroupboxes.Count);
Parent:=Self;
Visible:=true;
end;
FInputGroupboxes.Add(NewGroupBox);
end;
end;
procedure TInputFileDialog.CreateEditComponents;
var
NewEdit: TEdit;
i: integer;
begin
// add new TEdits
while FInputEdits.Count<FFileCount do begin
i:=FInputEdits.Count;
NewEdit:=TEdit.Create(Self);
with NewEdit do begin
Name:='InputEdit'+IntToStr(i);
Parent:=GetGroupBox(i);
Visible:=true;
end;
FInputEdits.Add(NewEdit);
end;
// remove old unused TEdits
while FInputEdits.Count>FFileCount do begin
GetInputEdit(FInputEdits.Count-1).Free;
FInputEdits.Delete(FInputEdits.Count-1);
end;
// upadte existing TEdits
for i:=0 to FInputEdits.Count-1 do
GetInputEdit(i).Text:=FFileNames[i];
end;
procedure TInputFileDialog.CreateFileDlgButtonComponents;
var NewButton: TButton;
i: integer;
begin
// add new TButtons
while FInputFileDlgButtons.Count<FFileCount do begin
i:=FInputFileDlgButtons.Count;
NewButton:=TButton.Create(Self);
with NewButton do begin
Name:='InputFileDlgButtin'+IntToStr(i);
Parent:=GetGroupBox(i);
Caption:='...';
OnClick:=@InputFileDlgButtonClick;
Visible:=true;
end;
FInputFileDlgButtons.Add(NewButton);
end;
// remove unused TButtons
while FInputFileDlgButtons.Count>FFileCount do begin
GetInputFileDlgButton(FInputFileDlgButtons.Count-1).Free;
FInputFileDlgButtons.Delete(FInputFileDlgButtons.Count-1);
end;
end;
procedure TInputFileDialog.CreateLabelComponents;
var
NewLabelList: TList;
LabelsAsText: TStringList;
ListIndex, i: integer;
NewLabel: TLabel;
begin
LabelsAsText:=TStringList.Create;
// add new TLabels
for ListIndex:=0 to FFileCount-1 do begin
// create TLabel list
if FInputLabels.Count<=ListIndex then begin
NewLabelList:=TList.Create;
FInputLabels.Add(NewLabelList);
end else
NewLabelList:=GetLabelList(ListIndex);
LabelsAsText.Text:=FFileDescs[ListIndex];
// create one TLabel for every line
for i:=0 to LabelsAsText.Count-1 do begin
// create TLabel
if NewLabelList.Count<=i then begin
NewLabel:=TLabel.Create(Self);
NewLabelList.Add(NewLabel);
end else
NewLabel:=GetLabel(ListIndex,i);
with NewLabel do begin
Name:='NewLabel'+IntToStr(ListIndex)+'_'+IntToStr(i);
Parent:=GetGroupBox(ListIndex);
Visible:=true;
end;
end;
// remove unused TLabels
while NewLabelList.Count>LabelsAsText.Count do begin
GetLabel(ListIndex,NewLabelList.Count-1).Free;
NewLabelList.Delete(NewLabelList.Count-1);
end;
end;
// remove unused LabelLists
while FInputLabels.Count>FFileCount do begin
DeleteLabelList(FInputLabels.Count-1);
end;
// update label text
for ListIndex:=0 to FInputLabels.Count-1 do begin
// split description into lines
LabelsAsText.Text:=FFileDescs[ListIndex];
for i:=0 to LabelListCount(ListIndex)-1 do begin
GetLabel(ListIndex,i).Text:=LabelsAsText[i];
end;
end;
LabelsAsText.Free;
end;
procedure TInputFileDialog.DeleteUnusedGroupBoxes;
var
i: integer;
begin
// remove old unused TGroupBoxes
while FInputGroupboxes.Count>FFileCount do begin
GetGroupBox(FInputGroupboxes.Count-1).Free;
FInputGroupboxes.Delete(FInputGroupboxes.Count-1);
end;
// update existing TGroupBoxes
for i:=0 to FInputGroupboxes.Count-1 do
GetGroupBox(i).Caption:=FFileTitles[i];
end;
procedure TInputFileDialog.DeleteLabelList(Index: integer);
var i: integer;
LabelList: TList;
begin
LabelList:=GetLabelList(Index);
for i:=LabelList.Count-1 downto 0 do begin
GetLabel(Index,i).Free;
LabelList.Delete(i);
end;
LabelList.Free;
FInputLabels.Delete(Index);
end;
procedure TInputFileDialog.ResizeComponents;
var
y, GroupBoxWidth, GroupBoxLeft, GroupBoxHeight, FileIndex,
LabelIndex, LabelLeft, LabelHeight, GroupBoxSpacing, LabelTop, LabelWidth,
ButtonWidth, ButtonHeight: integer;
CurLabel: TLabel;
CurEdit: TEdit;
CurButton: TButton;
begin
GroupBoxSpacing:=10;
GroupBoxLeft:=GroupBoxSpacing;
GroupBoxWidth:=ClientWidth-GroupBoxLeft*2;
y:=GroupBoxSpacing;
LabelHeight:=25;
// resize input components
for FileIndex:=0 to FileCount-1 do begin
GroupBoxHeight:=60+LabelListCount(FileIndex)*LabelHeight;
GetGroupBox(FileIndex).SetBounds(
GroupBoxLeft,y,GroupBoxWidth,GroupBoxHeight);
LabelTop:=7;
LabelLeft:=10;
LabelWidth:=GroupBoxWidth-LabelLeft*2;
for LabelIndex:=0 to LabelListCount(FileIndex)-1 do begin
CurLabel:=GetLabel(FileIndex,LabelIndex);
CurLabel.SetBounds(LabelLeft,LabelTop,LabelWidth,CurLabel.Height);
inc(LabelTop,LabelHeight);
end;
CurButton:=GetInputFileDlgButton(FileIndex);
ButtonWidth:=CurButton.Height;
ButtonHeight:=CurButton.Height;
CurEdit:=GetInputEdit(FileIndex);
CurEdit.SetBounds(LabelLeft,LabelTop,
LabelWidth-10-ButtonWidth,CurEdit.Height);
CurButton.SetBounds(CurEdit.Left+CurEdit.Width+3,LabelTop,
ButtonWidth,ButtonHeight);
inc(y,GroupBoxHeight+GroupBoxSpacing);
end;
inc(y,GroupBoxSpacing);
// resize ok and cancel button
OkButton.SetBounds(Max(GroupBoxLeft,GroupBoxLeft+GroupBoxWidth-250),y,
120,OkButton.Height);
CancelButton.SetBounds(OkButton.Left+OkButton.Width+10,OkButton.Top,
OkButton.Width,OkButton.Height);
inc(y,OkButton.Height+GroupBoxSpacing);
Height:=y;
end;
procedure TInputFileDialog.DeleteAllLabels;
var i: integer;
begin
for i:=FInputLabels.Count-1 downto 0 do
DeleteLabelList(i);
end;
constructor TInputFileDialog.Create(TheOwner: TComponent);
begin
inherited Create(TheOwner);
Position:=poScreenCenter;
Width:=500;
OnResize:=@FormResize;
OkButton:=TButton.Create(Self);
with OkButton do begin
Name:='OkButton';
Parent:=Self;
Caption:='OK';
OnClick:=@OkButtonClick;
Visible:=true;
end;
CancelButton:=TButton.Create(Self);
with CancelButton do begin
Name:='CancelButton';
Parent:=Self;
Caption:='Cancel';
OnClick:=@CancelButtonClick;
Visible:=true;
end;
FFileCount:=0;
FFileTitles:=TStringList.Create;
FFileDescs:=TStringList.Create;
FFileNames:=TStringList.Create;
FInputGroupboxes:=TList.Create;
FInputLabels:=TList.Create;
FInputDescs:=TStringList.Create;
FInputEdits:=TList.Create;
FInputFileDlgButtons:=TList.Create;
FUpdateCount:=0;
end;
destructor TInputFileDialog.Destroy;
begin
DeleteAllLabels;
FFileTitles.Free;
FFileDescs.Free;
FFileNames.Free;
if FFileFlags<>nil then FreeMem(FFileFlags);
FInputGroupboxes.Free;
FInputLabels.Free;
FInputDescs.Free;
FInputEdits.Free;
FInputFileDlgButtons.Free;
inherited Destroy;
end;
procedure TInputFileDialog.BeginUpdate;
begin
inc(FUpdateCount);
end;
procedure TInputFileDialog.EndUpdate;
begin
if FUpdateCount<=0 then exit;
dec(FUpdateCount);
if FUpdateCount=0 then
UpdateDlg;
end;
end.