lazarus-ccr/components/iphonelazext/project_iphone_options.pas

587 lines
16 KiB
ObjectPascal

{
*****************************************************************************
* *
* This file is part of the iPhone Laz Extension *
* *
* See the file COPYING.modifiedLGPL.txt, 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 project_iphone_options;
{$mode objfpc}{$H+}
interface
uses
Classes,SysUtils,FileUtil,LazFileUtils,LResources,Forms,StdCtrls,CheckLst,Buttons, Dialogs,
Menus,IDEOptionsIntf,ProjectIntf,LazIDEIntf,iPhoneExtStr,
iPhoneExtOptions, Controls, LazFilesUtils, XcodeUtils, newXibDialog, xibfile
,CompOptsIntf;
type
{ TiPhoneProjectOptionsEditor }
TiPhoneProjectOptionsEditor = class(TAbstractIDEOptionsEditor)
btnShowInFinder:TButton;
btnAddXib:TButton;
btnRemoveXib:TButton;
Label5:TLabel;
Label6: TLabel;
memResFiles: TMemo;
mnuDump:TMenuItem;
mnuOpenIB:TMenuItem;
nibFilesBox:TCheckListBox;
chkisPhone: TCheckBox;
cmbSDKs: TComboBox;
edtResDir: TEdit;
edtExclude: TEdit;
edtAppID: TEdit;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4:TLabel;
lblAppID: TLabel;
lblAppIDHint: TLabel;
lblSDKVer: TLabel;
nibsPopup:TPopupMenu;
procedure btnAddXibClick(Sender:TObject);
procedure btnRemoveXibClick(Sender:TObject);
procedure btnShowInFinderClick(Sender:TObject);
procedure Button1Click(Sender:TObject);
procedure chkisPhoneChange(Sender:TObject);
procedure cmbSDKsChange(Sender: TObject);
procedure edtExcludeChange(Sender: TObject);
procedure edtResDirChange(Sender:TObject);
procedure edtResDirExit(Sender:TObject);
procedure FrameClick(Sender: TObject);
procedure mnuDumpClick(Sender:TObject);
procedure mnuOpenIBClick(Sender:TObject);
procedure nibFilesBoxClickCheck(Sender:TObject);
procedure nibFilesBoxItemClick(Sender:TObject;Index:integer);
procedure nibFilesBoxMouseDown(Sender:TObject;Button:TMouseButton;Shift:
TShiftState;X,Y:Integer);
procedure nibFilesBoxMouseUp(Sender:TObject;Button:TMouseButton;Shift:
TShiftState;X,Y:Integer);
procedure nibsPopupPopup(Sender:TObject);
private
{ private declarations }
SelXibFile : String;
ResDirChanged : Boolean;
//fOnChanged : TNotifyEvent;
//procedure DoChanged;
procedure RefreshXIBList;
procedure SetControlsEnabled(AEnabled: Boolean);
procedure DumpClasses(const XibFileName: AnsiString; var PascalFileName: AnsiString);
public
{ public declarations }
class function SupportedOptionsClass: TAbstractIDEOptionsClass; override;
function GetTitle: String; override;
procedure Setup(ADialog: TAbstractOptionsEditorDialog); override;
procedure ReadSettings(AOptions: TAbstractIDEOptions); override;
procedure WriteSettings(AOptions: TAbstractIDEOptions); override;
//property OnChanged: TNotifyEvent read fOnChanged write fOnChanged;
end;
implementation
{$R *.lfm}
{ TiPhoneProjectOptionsEditor }
procedure TiPhoneProjectOptionsEditor.cmbSDKsChange(Sender: TObject);
begin
end;
procedure TiPhoneProjectOptionsEditor.btnShowInFinderClick(Sender:TObject);
var
path: AnsiString;
tmp : AnsiString;
begin
path:=Trim(edtResDir.Text);
path:=ResolveProjectPath(path);
ForceDirectoriesUTF8(path);
while (path<>'') and (not DirectoryExistsUTF8(path)) do begin
tmp:=path;
path:=ExtractFileDir(path);
if tmp=path then Break;
end;
if DirectoryExistsUTF8(path) then ExecCmdLineNoWait('open "'+path +'"');
end;
procedure TiPhoneProjectOptionsEditor.btnAddXibClick(Sender:TObject);
var
FileName : AnsiString;
SrcXib : AnsiString;
ResDir : AnsiString;
begin
newXibForm:=TnewXibForm.Create(Self);
ScanForXibTemplates(
XibTemplateDir( IncludeTrailingPathDelimiter(EnvOptions.PlatformsBaseDir)+iPhoneOSplatform),
@newXibForm.AddTemplate);
if (newXibForm.Execute(FileName, SrcXib)) and (SrcXib<>'')then begin
ResDir:=edtResDir.Text;
ResDir := ResolveProjectPath(ResDir);
ForceDirectoriesUTF8(ResDir);
if not CopyFile(SrcXib, ChangeFileExt(IncludeTrailingPathDelimiter(ResDir)+FileName,'.xib')) then
ShowMessage('Failed to create Nib file');
RefreshXIBList;
end;
newXibForm.Free;
newXibForm:=nil;
end;
procedure TiPhoneProjectOptionsEditor.btnRemoveXibClick(Sender:TObject);
var
XibName : AnsiString;
begin
if nibFilesBox.ItemIndex<0 then Exit;
XibName:=edtResDir.Text;
XibName := ResolveProjectPath(XibName);
XibName:=ChangeFileExt(IncludeTrailingPathDelimiter(XibName)+nibFilesBox.Items[nibFilesBox.ItemIndex],'.xib');
if FileExistsUTF8(XibName) then DeleteFileUTF8(XibName);
RefreshXIBList;
end;
procedure TiPhoneProjectOptionsEditor.Button1Click(Sender:TObject);
begin
end;
procedure TiPhoneProjectOptionsEditor.chkisPhoneChange(Sender:TObject);
begin
SetControlsEnabled(chkisPhone.Checked);
end;
procedure TiPhoneProjectOptionsEditor.edtExcludeChange(Sender: TObject);
begin
end;
procedure TiPhoneProjectOptionsEditor.edtResDirChange(Sender:TObject);
begin
ResDirChanged:=True;
end;
procedure TiPhoneProjectOptionsEditor.edtResDirExit(Sender:TObject);
var
s : AnsiString;
chk : AnsiString;
i : Integer;
begin
if not ResDirChanged then Exit;
ResDirChanged:=False;
// storing checked and selected items
for i:=0 to nibFilesBox.Count-1 do
if nibFilesBox.Checked[i] then
chk:=nibFilesBox.Items[i];
if nibFilesBox.ItemIndex>=0 then
s:=nibFilesBox.Items[nibFilesBox.ItemIndex]
else
s := '';
// refreshing the list
RefreshXIBList;
// restore selection and checked item
if s<>'' then nibFilesBox.ItemIndex:=nibFilesBox.Items.IndexOf(s);
i:=nibFilesBox.Items.IndexOf(chk);
nibFilesBox.Checked[i]:=True;
end;
procedure TiPhoneProjectOptionsEditor.FrameClick(Sender: TObject);
begin
end;
procedure TiPhoneProjectOptionsEditor.mnuDumpClick(Sender:TObject);
var
s : AnsiString;
pas : AnsiString;
p : TControl;
begin
if SelXibFile ='' then Exit;
s:=ChangeFileExt(IncludeTrailingPathDelimiter (edtResDir.Text) + SelXibFile,'.xib');
s := ResolveProjectPath(s);
DumpClasses(s, pas);
p:=Parent;
while Assigned(p) and (not (p is TForm)) do
p:=p.Parent;
if Assigned(p) then TForm(p).ModalResult:=mrOK;
LazarusIDE.DoOpenEditorFile(pas, -1,-1, [ofOnlyIfExists]);
end;
procedure TiPhoneProjectOptionsEditor.mnuOpenIBClick(Sender:TObject);
var
path : AnsiString;
begin
path:=ChangeFileExt(IncludeTrailingPathDelimiter(edtResDir.Text)+SelXibFile,'.xib');
path := ResolveProjectPath(path);
ExecCmdLineNoWait('open ' + path);
end;
procedure TiPhoneProjectOptionsEditor.nibFilesBoxClickCheck(Sender:TObject);
begin
end;
procedure TiPhoneProjectOptionsEditor.nibFilesBoxItemClick(Sender:TObject;Index: integer);
var
i, j : Integer;
begin
j:=-1;
for i:=0 to nibFilesBox.Count-1 do
if nibFilesBox.Checked[i] and (Index<>i) then begin
j:=i;
end;
if j>=0 then nibFilesBox.Checked[j]:=false;
end;
procedure TiPhoneProjectOptionsEditor.nibFilesBoxMouseDown(Sender:TObject;Button
:TMouseButton;Shift:TShiftState;X,Y:Integer);
var
i: Integer;
begin
i:=nibFilesBox.ItemAtPos(Point(X,Y), True);
if i>=0 then begin
nibFilesBox.ItemIndex:=i;
SelXibFile:=nibFilesBox.Items[i];
end else
SelXibFile:='';
end;
procedure TiPhoneProjectOptionsEditor.nibFilesBoxMouseUp(Sender:TObject;Button:
TMouseButton;Shift:TShiftState;X,Y:Integer);
begin
end;
procedure TiPhoneProjectOptionsEditor.nibsPopupPopup(Sender:TObject);
begin
mnuOpenIB.Enabled:=SelXibFile<>'';
if mnuOpenIB.Enabled then
mnuOpenIB.Caption:=Format(strOpenXibAtIB, [SelXibFile])
else
mnuOpenIB.Caption:=strOpenAtIB;
mnuDump.Enabled:=SelXibFile<>''
end;
//procedure TiPhoneProjectOptionsEditor.DoChanged;
//begin
//if Assigned(fOnChanged) then fOnChanged(Self);
//end;
procedure TiPhoneProjectOptionsEditor.RefreshXIBList;
var
path : AnsiString;
st : TStringList;
i : Integer;
AProjectFile: TLazProjectFile;
begin
path := ResolveProjectPath(trim(edtResDir.Text));
st:=TStringList.Create;
try
for i := 0 to LazarusIDE.ActiveProject.FileCount-1 do
begin
AProjectFile := LazarusIDE.ActiveProject.Files[i];
if (AProjectFile.IsPartOfProject) and FileExistsUTF8(ChangeFileExt(AProjectFile.filename,'.xib')) then
st.add(AProjectFile.filename);
end;
EnumFilesAtDir(path, '*.xib', st);
nibFilesBox.Clear;
for i:=0 to st.Count-1 do
nibFilesBox.Items.Add( ChangeFileExt( ExtractFileName(st[i]), ''));
finally
st.Free;
end;
end;
procedure TiPhoneProjectOptionsEditor.SetControlsEnabled(AEnabled:Boolean);
var
i : Integer;
begin
for i:=0 to ControlCount-1 do
if not (Controls[i] is TLabel) and (Controls[i]<>chkisPhone) then
Controls[i].Enabled:=AEnabled;
end;
function MethodName(const msg: AnsiString): String;
var
i : Integer;
begin
Result:=msg;
for i:=0 to length(Result) do if Result[i]=':' then Result[i]:='_';
end;
function ActionParams(const ActionName: AnsiString): String;
var
i : integer;
c : Integer;
begin
c:=0;
for i:=1 to length(ActionName) do if ActionName[i]=':' then inc(c);
case c of
1 : Result:=('(sender: id)');
2 : Result:=('(sender: id; keyEvent: SEL)');
end;
end;
function SetMethodName(const propName: AnsiString): String;
begin
if propName<>'' then
Result:='set'+AnsiUpperCase(propName[1])+Copy(propName, 2, length(propName)-1)
else
Result:='';
end;
procedure XibClassToInterface(cls: TXibClassDescr; intf: TStrings);
var
i : Integer;
begin
if not Assigned(cls) or not Assigned(intf) then Exit;
intf.Add(' { ' +cls.Name + ' }');
intf.Add('');
intf.Add(' ' +cls.Name + '=objcclass(NSObject)');
if length(cls.Outlets)>0 then begin
intf.Add(' private');
for i:=0 to length(cls.Outlets) - 1 do
intf.Add(' f'+cls.Outlets[i].Key+' : '+ cls.Outlets[i].Value+';');
end;
intf.Add(' public');
for i:=0 to length(cls.Actions) - 1 do
with cls.Actions[i] do
intf.Add(Format(' function %s%s: %s; message ''%s'';', [MethodName(Key), ActionParams(Key), Value, Key]));
for i:=0 to length(cls.Outlets) - 1 do
with cls.Outlets[i] do begin
intf.Add(Format(' function %s: %s; message ''%s'';', [Key, Value, Key]));
intf.Add(Format(' procedure %s(a%s: %s); message ''%s'';',
[SetMethodName(Key), Key, Value, SetMethodName(Key)+':']));
end;
if length(cls.Outlets) > 0 then
intf.Add(' procedure dealloc; override;');
intf.Add(' end;');
intf.Add('');
end;
procedure XibClassToImplementation(cls: TXibClassDescr; st: TStrings);
var
i : Integer;
begin
if not Assigned(cls) or not Assigned(st) then Exit;
if (length(cls.Actions)=0) and (length(cls.Outlets)=0) then exit;
st.Add(' { ' +cls.Name + ' }');
st.Add('');
for i:=0 to length(cls.Actions)-1 do
with cls.Actions[i] do begin
st.Add(Format('function %s.%s%s: %s;', [cls.Name, MethodName(Key), ActionParams(Key), Value]));
st.Add('begin');
st.Add(' // put action''s code here');
st.Add(' Result:=nil;');
st.Add('end;');
st.Add('');
end;
for i:=0 to length(cls.Outlets) - 1 do
with cls.Outlets[i] do begin
st.Add(Format('function %s.%s: %s;', [cls.Name, Key, Value]));
st.Add( 'begin');
st.Add(Format(' Result:=f%s;', [Key]));
st.Add( 'end;');
st.Add( '');
st.Add(Format('procedure %s.%s(a%s: %s);', [cls.Name, SetMethodName(Key), Key, Value]));
st.Add( 'begin');
st.Add(Format(' f%s:=a%s;', [Key, Key]));
st.Add(Format(' f%s.retain;', [Key]));
st.Add( 'end;');
st.Add( '');
end;
if length(cls.Outlets)>0 then begin
st.Add(Format('procedure %s.dealloc; ', [cls.Name]));
st.Add( 'begin');
for i:=0 to length(cls.Outlets) - 1 do
st.Add(Format(' f%s.release;',[cls.Outlets[i].Key]));
st.Add( ' inherited;');
st.Add( 'end;');
st.Add('');
end;
end;
procedure TiPhoneProjectOptionsEditor.DumpClasses(const XibFileName: AnsiString;
var PascalFileName: AnsiString);
var
unitNm : AnsiString;
fs : TFileStream;
xibcls : TList;
i : Integer;
intfPart : TStringList;
implPart : TStringList;
cls : TXibClassDescr;
const
le : Ansistring = LineEnding;
procedure wln(const s: AnsiString);
begin
if s <>'' then
fs.Write(s[1], length(s));
fs.Write(le[1], length(le));
end;
begin
if not FileExists(XibFileName) then Exit;
intfPart:=TStringList.Create;
implPart:=TStringList.Create;
xibcls:=TList.Create;
ListClassesDescr(XibFileName, xibcls);
for i:=0 to xibcls.Count-1 do begin
cls:=TXibClassDescr(xibcls[i]);
XibClassToInterface(cls, intfPart);
XibClassToImplementation(cls, implPart);
cls.Free;
end;
xibcls.Free;
unitNm:='dump'+ChangeFileExt(ExtractFileName(XibFileName),'');
PascalFileName:=ResolveProjectPath(unitNm+'.pas');
fs:=TFileStream.Create(PascalFileName, fmCreate);
wln('unit ' + unitNm+';');
wln('');
wln('{$mode objfpc}{$h+}');
wln('{$modeswitch objectivec1}');
wln('');
wln('interface');
wln('');
if intfPart.Count>0 then begin
wln('type');
for i:=0 to intfPart.Count-1 do wln(intfPart[i]);
end;
wln('');
wln('implementation');
wln('');
if implPart.Count>0 then
for i:=0 to implPart.Count-1 do wln(implPart[i]);
wln('');
wln('end.');
intfPart.Free;
implPart.Free;
fs.Free;
end;
function TiPhoneProjectOptionsEditor.GetTitle: String;
begin
Result:=strPrjOptTitle;
end;
procedure TiPhoneProjectOptionsEditor.Setup(ADialog: TAbstractOptionsEditorDialog);
begin
chkisPhone.Caption := strPrjOptIsiPhone;
lblSDKVer.Caption := strPrjOptSDKver;
lblAppID.Caption := strPtrOptAppID;
lblAppIDHint.Caption := strPtrOptAppIDHint;
end;
procedure TiPhoneProjectOptionsEditor.ReadSettings(AOptions: TAbstractIDEOptions);
var
i : Integer;
begin
with ProjOptions do
begin
Load;
chkisPhone.Checked:=isIPhoneApp;
EnvOptions.GetSDKVersions(cmbSDKs.Items);
i:=cmbSDKs.Items.IndexOf(SDK);
if (i<0) and (cmbSDKs.Items.Count>0) then
i:=cmbSDKs.Items.IndexOf(EnvOptions.DefaultSDK);
cmbSDKs.ItemIndex:=i;
edtAppID.Text:=AppID;
edtResDir.Text:=ResourceDir;
edtExclude.Text:=ExcludeMask;
memResFiles.Text:=ResFiles.Text;
end;
RefreshXIBList;
if ProjOptions.MainNib<>'' then begin
i:=nibFilesBox.Items.IndexOf(ProjOptions.MainNib);
if i>=0 then nibFilesBox.Checked[i]:=True;
end;
SetControlsEnabled(chkisPhone.Checked); // is iPhone project
end;
procedure TiPhoneProjectOptionsEditor.WriteSettings(AOptions: TAbstractIDEOptions);
var
amainnib : AnsiString;
i : integer;
begin
amainnib:='';
for i:=0 to nibFilesBox.Count-1 do
if nibFilesBox.Checked[i] then begin
amainnib:=nibFilesBox.Items[i];
Break;
end;
with ProjOptions do
begin
isIPhoneApp:=chkisPhone.Checked;
SDK:=cmbSDKs.Caption;
AppID:=edtAppID.Text;
ResourceDir:=edtResDir.Text;
ExcludeMask:=edtExclude.Text;
MainNib:=amainnib;
ResFiles.Text:=memResFiles.Text;
Save;
end;
DoOnChange;
end;
class function TiPhoneProjectOptionsEditor.SupportedOptionsClass: TAbstractIDEOptionsClass;
begin
//Result:=TiPhoneProjectOptions;
Result:=TLazCompilerOptions;
end;
const
iPhoneOptions = 10000; //todo: get it dynamically
initialization
//RegisterIDEOptionsEditor(iPhonePrjGroup, TiPhoneProjectOptionsEditor, iPhoneOptions);
RegisterIDEOptionsEditor(GroupProject, TiPhoneProjectOptionsEditor, iPhoneOptions);
finalization
end.