You've already forked lazarus-ccr
20070415 revision of XDev Toolkit - initial commit to SVN.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@179 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
282
components/xdev_toolkit/CvtHelp.pas
Normal file
282
components/xdev_toolkit/CvtHelp.pas
Normal file
@@ -0,0 +1,282 @@
|
|||||||
|
program CvtHelp;
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
Input files: HTML file created from WinHelp .rtf file by saving it
|
||||||
|
in Word's "Web Page, Filtered" format. Also looks for WinHelp .hpj
|
||||||
|
file with same name as HTML input file.
|
||||||
|
|
||||||
|
Output file: HTML file that can be used with LCL apps that use
|
||||||
|
HelpUtil unit's THelpUtilManager class.
|
||||||
|
|
||||||
|
Author: Phil Hess.
|
||||||
|
Copyright: Copyright (C) 2007 Phil Hess. All rights reserved.
|
||||||
|
License: Modified LGPL.
|
||||||
|
}
|
||||||
|
|
||||||
|
uses
|
||||||
|
SysUtils,
|
||||||
|
Classes;
|
||||||
|
|
||||||
|
const
|
||||||
|
ProgramName = 'CvtHelp';
|
||||||
|
ProgramVersion = '0.01';
|
||||||
|
|
||||||
|
var
|
||||||
|
OldFileName : string;
|
||||||
|
HpjFileName : string;
|
||||||
|
NewFileName : string;
|
||||||
|
OldFileVar : TextFile;
|
||||||
|
HpjFileVar : TextFile;
|
||||||
|
NewFileVar : TextFile;
|
||||||
|
{$IFNDEF FPC}
|
||||||
|
MatchFound : TFilenameCaseMatch;
|
||||||
|
{$ENDIF}
|
||||||
|
MapSection : TStringList;
|
||||||
|
TitleStr : string;
|
||||||
|
CopyrightStr: string;
|
||||||
|
Footnotes : TStringList;
|
||||||
|
InStr : string;
|
||||||
|
FnStr : string;
|
||||||
|
FnPos : Integer;
|
||||||
|
FnRef : string;
|
||||||
|
PrevInStr : string;
|
||||||
|
TopicStr : string;
|
||||||
|
TopicMapped : Boolean;
|
||||||
|
FootIdx : Integer;
|
||||||
|
LinkPos : Integer;
|
||||||
|
UnlinkPos : Integer;
|
||||||
|
|
||||||
|
begin
|
||||||
|
|
||||||
|
if ParamCount < 2 then {List program useage?}
|
||||||
|
begin
|
||||||
|
WriteLn(ProgramName, ', version ', ProgramVersion,
|
||||||
|
' - converts WinHelp/RTF-based HTML file to help HTML file.');
|
||||||
|
WriteLn('Usage: ', ProgramName, ' infile outfile');
|
||||||
|
Halt;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{Get name of HTML file to convert from command line}
|
||||||
|
OldFileName := ParamStr(1);
|
||||||
|
{$IFNDEF FPC}
|
||||||
|
OldFileName := ExpandFileNameCase(OldFileName, MatchFound);
|
||||||
|
{$ELSE}
|
||||||
|
OldFileName := ExpandFileName(OldFileName);
|
||||||
|
{$ENDIF}
|
||||||
|
|
||||||
|
HpjFileName := ChangeFileExt(OldFileName, '.hpj');
|
||||||
|
|
||||||
|
{Get name of HTML file to create from command line}
|
||||||
|
NewFileName := ParamStr(2);
|
||||||
|
{$IFNDEF FPC}
|
||||||
|
NewFileName := ExpandFileNameCase(NewFileName, MatchFound);
|
||||||
|
{$ELSE}
|
||||||
|
NewFileName := ExpandFileName(NewFileName);
|
||||||
|
{$ENDIF}
|
||||||
|
|
||||||
|
if (OldFileName = NewFileName) or
|
||||||
|
(HpjFileName = NewFileName) then
|
||||||
|
begin
|
||||||
|
WriteLn('Can''t use input file name for output file');
|
||||||
|
Halt;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{Open input HTML file}
|
||||||
|
AssignFile(OldFileVar, OldFileName);
|
||||||
|
try
|
||||||
|
Reset(OldFileVar);
|
||||||
|
except
|
||||||
|
on EInOutError do
|
||||||
|
begin
|
||||||
|
WriteLn('Can''t open input file ', OldFileName);
|
||||||
|
Halt;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{Open WinHelp project file}
|
||||||
|
AssignFile(HpjFileVar, HpjFileName);
|
||||||
|
try
|
||||||
|
Reset(HpjFileVar);
|
||||||
|
except
|
||||||
|
on EInOutError do
|
||||||
|
begin
|
||||||
|
WriteLn('Can''t open WinHelp project file ', HpjFileName);
|
||||||
|
Halt;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
MapSection := TStringList.Create;
|
||||||
|
while not Eof(HpjFileVar) do
|
||||||
|
begin
|
||||||
|
ReadLn(HpjFileVar, InStr);
|
||||||
|
if CompareText(InStr, '[OPTIONS]') = 0 then
|
||||||
|
begin
|
||||||
|
repeat
|
||||||
|
ReadLn(HpjFileVar, InStr);
|
||||||
|
if CompareText(Copy(InStr, 1, 6), 'TITLE=') = 0 then
|
||||||
|
TitleStr := Copy(InStr, 7, MaxInt)
|
||||||
|
else if CompareText(Copy(InStr, 1, 10), 'COPYRIGHT=') = 0 then
|
||||||
|
CopyrightStr := Copy(InStr, 11, MaxInt);
|
||||||
|
until Copy(InStr, 1, 1) = '[';
|
||||||
|
end
|
||||||
|
else if CompareText(InStr, '[MAP]') = 0 then
|
||||||
|
begin
|
||||||
|
repeat
|
||||||
|
ReadLn(HpjFileVar, InStr);
|
||||||
|
if (InStr <> '') and (Copy(InStr, 1, 1) <> '[') then
|
||||||
|
MapSection.Add(Copy(InStr, 1, Pos(' ', InStr)-1) + '=' +
|
||||||
|
Trim(Copy(InStr, Pos(' ', InStr), MaxInt)));
|
||||||
|
until Eof(HpjFileVar) or (Copy(InStr, 1, 1) = '[');
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
CloseFile(HpjFileVar);
|
||||||
|
|
||||||
|
{Create output HTML file}
|
||||||
|
AssignFile(NewFileVar, NewFileName);
|
||||||
|
try
|
||||||
|
Rewrite(NewFileVar);
|
||||||
|
except
|
||||||
|
on EInOutError do
|
||||||
|
begin
|
||||||
|
WriteLn('Can''t create output file ', NewFileName);
|
||||||
|
Halt;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Footnotes := TStringList.Create;
|
||||||
|
|
||||||
|
{Read through entire file, saving footnote topic references and names}
|
||||||
|
while not Eof(OldFileVar) do
|
||||||
|
begin
|
||||||
|
ReadLn(OldFileVar, InStr);
|
||||||
|
if CompareText(InStr, '<div><br clear=all>') = 0 then {Found footnotes?}
|
||||||
|
begin
|
||||||
|
while not Eof(OldFileVar) do
|
||||||
|
begin
|
||||||
|
ReadLn(OldFileVar, InStr);
|
||||||
|
if Pos('MsoFootnoteText', InStr) > 0 then {Found a footnote?}
|
||||||
|
begin
|
||||||
|
FnStr := InStr;
|
||||||
|
repeat
|
||||||
|
ReadLn(OldFileVar, InStr);
|
||||||
|
if InStr <> '' then
|
||||||
|
FnStr := FnStr + ' ' + InStr;
|
||||||
|
until InStr = '';
|
||||||
|
TopicStr := Copy(FnStr, Pos('</a>', FnStr) + 5, MaxInt);
|
||||||
|
TopicStr := Copy(TopicStr, 1, Length(TopicStr)-4);
|
||||||
|
if Pos('_', TopicStr) > 0 then
|
||||||
|
begin
|
||||||
|
FnPos := Pos('name=', FnStr) + 6;
|
||||||
|
FnRef := '';
|
||||||
|
repeat
|
||||||
|
FnRef := FnRef + FnStr[FnPos];
|
||||||
|
Inc(FnPos);
|
||||||
|
until FnStr[FnPos] = '"';
|
||||||
|
Footnotes.Add(FnRef + '=' + TopicStr);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Reset(OldFileVar);
|
||||||
|
{Process input file}
|
||||||
|
while not Eof(OldFileVar) do
|
||||||
|
begin
|
||||||
|
ReadLn(OldFileVar, InStr);
|
||||||
|
if CompareText(Copy(InStr, 1, 7), '<title>') = 0 then {Found title?}
|
||||||
|
begin {Replace with title from .hpj file}
|
||||||
|
WriteLn(NewFileVar, '<title>', TitleStr, '</title>');
|
||||||
|
{Include AppleTitle line so file can be registered as help book on OS X.}
|
||||||
|
Write(NewFileVar, '<meta name="AppleTitle" content="');
|
||||||
|
if CompareText(Copy(TitleStr, Length(TitleStr)-4, 5), ' Help') = 0 then
|
||||||
|
Write(NewFileVar, Copy(TitleStr, 1, Length(TitleStr)-5)) {Don't include}
|
||||||
|
else
|
||||||
|
Write(NewFileVar, TitleStr);
|
||||||
|
WriteLn(NewFileVar, '">');
|
||||||
|
{Include copyright statement from .hpj file}
|
||||||
|
WriteLn(NewFileVar, '<!--');
|
||||||
|
WriteLn(NewFileVar, CopyrightStr);
|
||||||
|
WriteLn(NewFileVar, '-->');
|
||||||
|
end
|
||||||
|
|
||||||
|
else if Pos('class=Topictitle', InStr) > 0 then {Found a topic?}
|
||||||
|
begin
|
||||||
|
{Get footnote number _ftnXX}
|
||||||
|
FnPos := Pos('#_', InStr) + 1;
|
||||||
|
FnRef := '';
|
||||||
|
repeat
|
||||||
|
FnRef := FnRef + InStr[FnPos];
|
||||||
|
Inc(FnPos);
|
||||||
|
until InStr[FnPos] = '"';
|
||||||
|
{Insert anchor}
|
||||||
|
TopicStr := Footnotes.Values[FnRef];
|
||||||
|
if TopicStr <> '' then
|
||||||
|
begin
|
||||||
|
TopicMapped := False;
|
||||||
|
if MapSection.Values[TopicStr] <> '' then
|
||||||
|
begin
|
||||||
|
WriteLn(NewFileVar, '<a name="', MapSection.Values[TopicStr],
|
||||||
|
'"></a>');
|
||||||
|
TopicMapped := True;
|
||||||
|
end;
|
||||||
|
if not TopicMapped then {No mapping in project file for topic?}
|
||||||
|
begin {Just use topic name in anchor}
|
||||||
|
Write(NewFileVar, '<a name="', TopicStr, '"></a>');
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
Write(NewFileVar, Copy(InStr, 1, 20)); {Save part of 1st topic line}
|
||||||
|
repeat {Skip over rest of topic lines}
|
||||||
|
PrevInStr := InStr;
|
||||||
|
ReadLn(OldFileVar, InStr);
|
||||||
|
until InStr = '';
|
||||||
|
WriteLn(NewFileVar, Copy(PrevInStr, 36, MaxInt)); {Save part of last topic line}
|
||||||
|
end
|
||||||
|
|
||||||
|
else if CompareText(InStr, '<div><br clear=all>') = 0 then {Found footnotes?}
|
||||||
|
begin
|
||||||
|
repeat {Skip over footnotes}
|
||||||
|
ReadLn(OldFileVar, InStr);
|
||||||
|
until CompareText(InStr, '</body>') = 0;
|
||||||
|
WriteLn(NewFileVar, InStr);
|
||||||
|
end
|
||||||
|
|
||||||
|
else {Found normal line}
|
||||||
|
begin {See if it contains link to topic}
|
||||||
|
LinkPos := Pos('<u>', InStr);
|
||||||
|
if LinkPos > 0 then {Line contains link?}
|
||||||
|
begin
|
||||||
|
PrevInStr := InStr;
|
||||||
|
ReadLn(OldFileVar, InStr); {Get next line too}
|
||||||
|
InStr := PrevInStr + ' ' + InStr; {Combine}
|
||||||
|
for FootIdx := 0 to Footnotes.Count -1 do
|
||||||
|
begin
|
||||||
|
TopicStr := Footnotes.ValueFromIndex[FootIdx];
|
||||||
|
if Pos(TopicStr, InStr) > 0 then
|
||||||
|
begin
|
||||||
|
UnlinkPos := Pos('</u>', InStr);
|
||||||
|
Write(NewFileVar, Copy(InStr, 1, LinkPos-1),
|
||||||
|
'<a href="#');
|
||||||
|
if MapSection.Values[TopicStr] <> '' then
|
||||||
|
Write(NewFileVar, MapSection.Values[TopicStr])
|
||||||
|
else
|
||||||
|
Write(NewFileVar, TopicStr);
|
||||||
|
WriteLn(NewFileVar, '">',
|
||||||
|
Copy(InStr, LinkPos+3, UnlinkPos-LinkPos-3), '</a>',
|
||||||
|
Copy(InStr, UnlinkPos+4, MaxInt));
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
WriteLn(NewFileVar, InStr);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
MapSection.Free;
|
||||||
|
Footnotes.Free;
|
||||||
|
CloseFile(OldFileVar);
|
||||||
|
CloseFile(NewFileVar);
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
107
components/xdev_toolkit/DfmToLfm.ini
Normal file
107
components/xdev_toolkit/DfmToLfm.ini
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
|
||||||
|
; DfmToLfm program configuration file.
|
||||||
|
; Be sure to add "=" after each key you add. The key's value can be omitted
|
||||||
|
; as it has no meaning to DfmToLfm.
|
||||||
|
|
||||||
|
; DfmToLfm deletes these .dfm properties when creating .lfm file.
|
||||||
|
; Note: If no class is specified, deletes that property from all classes.
|
||||||
|
|
||||||
|
[DeleteProps]
|
||||||
|
IsControl=
|
||||||
|
;NumGlyphs=
|
||||||
|
OldCreateOrder=
|
||||||
|
WantReturns=
|
||||||
|
Ctl3D=
|
||||||
|
ParentCtl3D=
|
||||||
|
OnClickCheck=
|
||||||
|
Flat=
|
||||||
|
IntegralHeight=
|
||||||
|
DesignSize=
|
||||||
|
AutoSelect=
|
||||||
|
BiDiMode=
|
||||||
|
ParentBiDiMode=
|
||||||
|
HideSelection=
|
||||||
|
ImeMode=
|
||||||
|
ImeName=
|
||||||
|
OEMConvert=
|
||||||
|
TRadioGroup.TabOrder=
|
||||||
|
TBitBtn.ParentFont=
|
||||||
|
TCheckBox.Font.Charset=
|
||||||
|
TCheckBox.Font.Color=
|
||||||
|
TCheckBox.Font.Height=
|
||||||
|
TCheckBox.Font.Name=
|
||||||
|
TCheckBox.Font.Style=
|
||||||
|
TCheckBox.ParentFont=
|
||||||
|
TCheckGroup.Font.Charset=
|
||||||
|
TCheckGroup.Font.Color=
|
||||||
|
TCheckGroup.Font.Height=
|
||||||
|
TCheckGroup.Font.Name=
|
||||||
|
TCheckGroup.Font.Style=
|
||||||
|
TCheckGroup.ParentFont=
|
||||||
|
TCheckListBox.Font.Charset=
|
||||||
|
TCheckListBox.Font.Color=
|
||||||
|
TCheckListBox.Font.Height=
|
||||||
|
TCheckListBox.Font.Name=
|
||||||
|
TCheckListBox.Font.Style=
|
||||||
|
TCheckListBox.ParentFont=
|
||||||
|
TRadioButton.Font.Charset=
|
||||||
|
TRadioButton.Font.Color=
|
||||||
|
TRadioButton.Font.Height=
|
||||||
|
TRadioButton.Font.Name=
|
||||||
|
TRadioButton.Font.Style=
|
||||||
|
TRadioButton.ParentFont=
|
||||||
|
TRadioGroup.Font.Charset=
|
||||||
|
TRadioGroup.Font.Color=
|
||||||
|
TRadioGroup.Font.Height=
|
||||||
|
TRadioGroup.Font.Name=
|
||||||
|
TRadioGroup.Font.Style=
|
||||||
|
TRadioGroup.ParentFont=
|
||||||
|
TBevel.Font.Charset=
|
||||||
|
TBevel.Font.Color=
|
||||||
|
TBevel.Font.Height=
|
||||||
|
TBevel.Font.Name=
|
||||||
|
TBevel.Font.Style=
|
||||||
|
TTabSheet.Font.Charset=
|
||||||
|
TTabSheet.Font.Color=
|
||||||
|
TTabSheet.Font.Height=
|
||||||
|
TTabSheet.Font.Name=
|
||||||
|
TTabSheet.Font.Style=
|
||||||
|
TNotebook.Font.Charset=
|
||||||
|
TNotebook.Font.Color=
|
||||||
|
TNotebook.Font.Height=
|
||||||
|
TNotebook.Font.Name=
|
||||||
|
TNotebook.Font.Style=
|
||||||
|
TNotebook.ParentFont=
|
||||||
|
TLabeledEdit.Font.Charset=
|
||||||
|
TLabeledEdit.Font.Color=
|
||||||
|
TLabeledEdit.Font.Height=
|
||||||
|
TLabeledEdit.Font.Name=
|
||||||
|
TLabeledEdit.Font.Style=
|
||||||
|
|
||||||
|
|
||||||
|
; When -p switch is used with DfmToLfm, don't try to add parent's font
|
||||||
|
; properties to these classes since they don't have font in LCL.
|
||||||
|
|
||||||
|
[NoFont]
|
||||||
|
TMainMenu=
|
||||||
|
TMenuItem=
|
||||||
|
TScrollBar=
|
||||||
|
TImage=
|
||||||
|
TTabSheet=
|
||||||
|
TCheckBox=
|
||||||
|
TCheckGroup=
|
||||||
|
TCheckListBox=
|
||||||
|
TRadioButton=
|
||||||
|
TRadioGroup=
|
||||||
|
TActionList=
|
||||||
|
TShape=
|
||||||
|
TBevel=
|
||||||
|
TNotebook=
|
||||||
|
TLabeledEdit=
|
||||||
|
TSplitter=
|
||||||
|
TOvcController=
|
||||||
|
TOvcSpinner=
|
||||||
|
TOvcTCCheckBox=
|
||||||
|
TOvcTCBitmap=
|
||||||
|
TOvcTCGlyphs=
|
||||||
|
TOvcTCIcon=
|
318
components/xdev_toolkit/DfmToLfm.pas
Normal file
318
components/xdev_toolkit/DfmToLfm.pas
Normal file
@@ -0,0 +1,318 @@
|
|||||||
|
program DfmToLfm;
|
||||||
|
|
||||||
|
{
|
||||||
|
Converts Delphi form design file to a Lazarus form file by
|
||||||
|
deleting properties that are not supported by LCL and
|
||||||
|
optionally making changes to font properties. The resulting
|
||||||
|
Lazarus form file can then be converted to a Lazarus resource
|
||||||
|
file with LazRes.
|
||||||
|
Note that the Delphi form file must be a text file.
|
||||||
|
List of properties to delete and other configuration settings
|
||||||
|
are read from DfmToLfm.ini.
|
||||||
|
This utility (and Lazarus LazRes) can be used whenever design
|
||||||
|
changes are made to the form in Delphi.
|
||||||
|
Note: Use MakePasX to make the form's code file cross-platform
|
||||||
|
(a one-time conversion).
|
||||||
|
|
||||||
|
Author: Phil Hess.
|
||||||
|
Copyright: Copyright (C) 2007 Phil Hess. All rights reserved.
|
||||||
|
License: Modified LGPL.
|
||||||
|
}
|
||||||
|
|
||||||
|
uses
|
||||||
|
SysUtils,
|
||||||
|
IniFiles;
|
||||||
|
|
||||||
|
const
|
||||||
|
ProgramName = 'DfmToLfm';
|
||||||
|
ProgramVersion = '0.01';
|
||||||
|
|
||||||
|
DfmFileExt = '.dfm'; {Delphi form file extension}
|
||||||
|
LfmFileExt = '.lfm'; {Lazarus form file extension}
|
||||||
|
CfgFileExt = '.ini'; {Extension for file with same name as program
|
||||||
|
containing configuration settings}
|
||||||
|
|
||||||
|
NoFontChanges = 0; {No font switch on command line}
|
||||||
|
UseParentFont = 1; {-p font switch on command line}
|
||||||
|
DeleteFontName = 2; {-d font switch on command line}
|
||||||
|
|
||||||
|
MaxNestedObjs = 20; {Maximum depth of nested controls on form}
|
||||||
|
MaxFontProps = 5; {Maximum font properties that can be saved}
|
||||||
|
|
||||||
|
type
|
||||||
|
TStackRec = record {Info about form objects}
|
||||||
|
ClassName : string;
|
||||||
|
FontPropCnt : Integer;
|
||||||
|
FontAdded : Boolean;
|
||||||
|
FontProps : array [1..MaxFontProps] of string;
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
CfgFileName : string;
|
||||||
|
{$IFNDEF FPC}
|
||||||
|
MatchFound : TFilenameCaseMatch;
|
||||||
|
{$ENDIF}
|
||||||
|
FontSwitch : Integer;
|
||||||
|
CfgFileObj : TMemIniFile;
|
||||||
|
DfmFileName : string;
|
||||||
|
LfmFileName : string;
|
||||||
|
DfmFileVar : TextFile;
|
||||||
|
LfmFileVar : TextFile;
|
||||||
|
StackLevel : Integer;
|
||||||
|
StackRec : array [1..MaxNestedObjs] of TStackRec;
|
||||||
|
DeleteLine : Boolean;
|
||||||
|
InStr : string;
|
||||||
|
StripStr : string;
|
||||||
|
SkipStr : string;
|
||||||
|
ParentLevel : Integer;
|
||||||
|
FontPropNum : Integer;
|
||||||
|
|
||||||
|
begin
|
||||||
|
|
||||||
|
{Base configuration file name on program file location and program name}
|
||||||
|
CfgFileName := ExtractFilePath(ParamStr(0)) + ProgramName + CfgFileExt;
|
||||||
|
{$IFNDEF FPC}
|
||||||
|
CfgFileName := ExpandFileNameCase(CfgFileName, MatchFound);
|
||||||
|
{$ENDIF}
|
||||||
|
|
||||||
|
if ParamCount = 0 then {List program syntax and exit?}
|
||||||
|
begin
|
||||||
|
WriteLn(ProgramName, ', version ', ProgramVersion,
|
||||||
|
' - converts a Delphi form file to a Lazarus form file.');
|
||||||
|
WriteLn('Usage: ', ProgramName, ' filename', DfmFileExt, ' [-p|-d]');
|
||||||
|
WriteLn('Switches:');
|
||||||
|
WriteLn(' -p Add parent''s font to controls with no font ',
|
||||||
|
'(useful with Windows).');
|
||||||
|
WriteLn(' -d Delete font name from controls ',
|
||||||
|
'(useful with OS X and Linux).');
|
||||||
|
WriteLn('Looks for configuration data in file ', CfgFileName);
|
||||||
|
Halt;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{Check for command line switches}
|
||||||
|
FontSwitch := NoFontChanges;
|
||||||
|
if FindCmdLineSwitch('p', ['-'], True) then
|
||||||
|
FontSwitch := UseParentFont
|
||||||
|
else if FindCmdLineSwitch('d', ['-'], True) then
|
||||||
|
FontSwitch := DeleteFontName;
|
||||||
|
|
||||||
|
{Load configuration file}
|
||||||
|
if not FileExists(CfgFileName) then
|
||||||
|
begin
|
||||||
|
WriteLn('Can''t load program configuration file ', CfgFileName);
|
||||||
|
Halt;
|
||||||
|
end;
|
||||||
|
CfgFileObj := TMemIniFile.Create(CfgFileName);
|
||||||
|
|
||||||
|
{Get name of Delphi form file from command line}
|
||||||
|
DfmFileName := ParamStr(1);
|
||||||
|
if ExtractFileExt(DfmFileName) = '' then
|
||||||
|
DfmFileName := DfmFileName + DfmFileExt;
|
||||||
|
{$IFNDEF FPC}
|
||||||
|
DfmFileName := ExpandFileNameCase(DfmFileName, MatchFound);
|
||||||
|
{$ELSE}
|
||||||
|
DfmFileName := ExpandFileName(DfmFileName);
|
||||||
|
{$ENDIF}
|
||||||
|
|
||||||
|
{Base Lazarus form file name on Delphi form file name}
|
||||||
|
LfmFileName := ChangeFileExt(DfmFileName, LfmFileExt);
|
||||||
|
|
||||||
|
{Open Delphi form file}
|
||||||
|
AssignFile(DfmFileVar, DfmFileName);
|
||||||
|
try
|
||||||
|
Reset(DfmFileVar);
|
||||||
|
except
|
||||||
|
on EInOutError do
|
||||||
|
begin
|
||||||
|
WriteLn('Can''t open Delphi form file ', DfmFileName);
|
||||||
|
Halt;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{Create Lazarus form file}
|
||||||
|
AssignFile(LfmFileVar, LfmFileName);
|
||||||
|
try
|
||||||
|
Rewrite(LfmFileVar);
|
||||||
|
except
|
||||||
|
on EInOutError do
|
||||||
|
begin
|
||||||
|
WriteLn('Can''t create Lazarus form file ', LfmFileName);
|
||||||
|
Halt;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
StackLevel := 0;
|
||||||
|
while not Eof(DfmFileVar) do {Read and process Delphi form file}
|
||||||
|
begin
|
||||||
|
DeleteLine := False;
|
||||||
|
ReadLn(DfmFileVar, InStr); {Read property from form file}
|
||||||
|
StripStr := StringReplace(InStr, ' ', '', [rfReplaceAll]); {Strip spaces}
|
||||||
|
|
||||||
|
if ((CompareText('object ', Copy(Trim(InStr), 1, 7)) = 0) or
|
||||||
|
(CompareText('end', StripStr) = 0)) and {End of object's props reached?}
|
||||||
|
(StackLevel > 1) and {Object is nested?}
|
||||||
|
(not CfgFileObj.ValueExists(
|
||||||
|
'NoFont', StackRec[StackLevel].ClassName)) and {Class has font?}
|
||||||
|
(StackRec[StackLevel].FontPropCnt = 0) and {Object has no font?}
|
||||||
|
(FontSwitch = UseParentFont) and {Okay to insert parent font in object?}
|
||||||
|
(not StackRec[StackLevel].FontAdded) then {Font not inserted yet?}
|
||||||
|
begin
|
||||||
|
ParentLevel := StackLevel;
|
||||||
|
repeat
|
||||||
|
Dec(ParentLevel);
|
||||||
|
until (ParentLevel = 0) or
|
||||||
|
(StackRec[ParentLevel].FontPropCnt > 0);
|
||||||
|
if ParentLevel > 0 then {A parent has font?}
|
||||||
|
begin {Add font properties to current object}
|
||||||
|
for FontPropNum := 1 to StackRec[ParentLevel].FontPropCnt do
|
||||||
|
begin
|
||||||
|
WriteLn(LfmFileVar, StringOfChar(' ', (StackLevel-ParentLevel)*2),
|
||||||
|
StackRec[ParentLevel].FontProps[FontPropNum]);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
StackRec[StackLevel].FontAdded := True;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if CompareText('object ', Copy(Trim(InStr), 1, 7)) = 0 then
|
||||||
|
begin {Push object's class name on stack}
|
||||||
|
Inc(StackLevel);
|
||||||
|
if Pos(': ', InStr) > 0 then {Named control?}
|
||||||
|
StackRec[StackLevel].ClassName :=
|
||||||
|
Trim(Copy(InStr, Pos(': ', InStr)+2, MaxInt))
|
||||||
|
else {Unnamed control}
|
||||||
|
StackRec[StackLevel].ClassName := Trim(Copy(Trim(InStr), 7, MaxInt));
|
||||||
|
StackRec[StackLevel].FontPropCnt := 0;
|
||||||
|
StackRec[StackLevel].FontAdded := False;
|
||||||
|
end
|
||||||
|
|
||||||
|
else if CompareText('end', StripStr) = 0 then
|
||||||
|
begin {Pop current class from stack}
|
||||||
|
Dec(StackLevel);
|
||||||
|
end
|
||||||
|
|
||||||
|
else if CompareText('font.', Copy(Trim(InStr), 1, 5)) = 0 then
|
||||||
|
begin {Font property}
|
||||||
|
if FontSwitch <> NoFontChanges then
|
||||||
|
begin
|
||||||
|
if FontSwitch = UseParentFont then
|
||||||
|
begin {Save font property in case need it for child objects}
|
||||||
|
if StackRec[StackLevel].FontPropCnt < MaxFontProps then
|
||||||
|
begin
|
||||||
|
Inc(StackRec[StackLevel].FontPropCnt);
|
||||||
|
StackRec[StackLevel].FontProps[StackRec[StackLevel].FontPropCnt] :=
|
||||||
|
InStr;
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
else {FontSwitch = DeleteFontName}
|
||||||
|
begin
|
||||||
|
if CompareText('font.name', Copy(Trim(InStr), 1, 9)) = 0 then
|
||||||
|
DeleteLine := True;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
{Check if font property should be deleted from current object}
|
||||||
|
if CfgFileObj.ValueExists('DeleteProps',
|
||||||
|
StackRec[StackLevel].ClassName + '.' +
|
||||||
|
Copy(StripStr, 1, Pos('=', StripStr)-1)) then
|
||||||
|
DeleteLine := True;
|
||||||
|
end
|
||||||
|
|
||||||
|
else {Other property}
|
||||||
|
begin {Check if property should be deleted from current object}
|
||||||
|
if CfgFileObj.ValueExists('DeleteProps',
|
||||||
|
Copy(StripStr, 1, Pos('=', StripStr)-1)) or
|
||||||
|
CfgFileObj.ValueExists('DeleteProps',
|
||||||
|
StackRec[StackLevel].ClassName + '.' +
|
||||||
|
Copy(StripStr, 1, Pos('=', StripStr)-1)) then
|
||||||
|
begin {Property or class.property in list of props to delete?}
|
||||||
|
DeleteLine := True;
|
||||||
|
if Copy(StripStr, Length(StripStr), 1) = '(' then {Delete > 1 line?}
|
||||||
|
begin
|
||||||
|
repeat
|
||||||
|
ReadLn(DfmFileVar, SkipStr);
|
||||||
|
SkipStr := Trim(SkipStr);
|
||||||
|
until Copy(SkipStr, Length(SkipStr), 1) = ')';
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if not DeleteLine then {Include line in Lazarus form file?}
|
||||||
|
begin
|
||||||
|
try
|
||||||
|
{If Delphi form file does have Height and Width, reduce
|
||||||
|
to size of its ClientHeight or ClientWidth.}
|
||||||
|
if ((StackLevel = 1) and
|
||||||
|
(CompareText('Height=', Copy(StripStr, 1, 7)) = 0)) then
|
||||||
|
WriteLn(LfmFileVar,
|
||||||
|
' Height = ',
|
||||||
|
IntToStr(StrToInt(Copy(StripStr, 8, MaxInt)) - 34))
|
||||||
|
else if ((StackLevel = 1) and
|
||||||
|
(CompareText('Width=', Copy(StripStr, 1, 6)) = 0)) then
|
||||||
|
WriteLn(LfmFileVar,
|
||||||
|
' Width = ',
|
||||||
|
IntToStr(StrToInt(Copy(StripStr, 7, MaxInt)) - 8))
|
||||||
|
|
||||||
|
{LCL TGroupBox child controls' Top measures from a lower position
|
||||||
|
within group box than with VCL, so reduce Top value}
|
||||||
|
else if (StackLevel > 1) and
|
||||||
|
(CompareText('Top=', Copy(StripStr, 1, 4)) = 0) and
|
||||||
|
(CompareText('TGroupBox',
|
||||||
|
StackRec[Pred(StackLevel)].ClassName) = 0) then
|
||||||
|
WriteLn(LfmFileVar,
|
||||||
|
Copy(InStr, 1, Succ(Pos('=', InStr))),
|
||||||
|
IntToStr(StrToInt(Copy(StripStr, 5, MaxInt)) - 16))
|
||||||
|
|
||||||
|
{Lazarus IDE appears to swap Top and Left properties for non-visual
|
||||||
|
controls, so swap them for Orpheus table cell controls.}
|
||||||
|
else if ((CompareText('Top=', Copy(StripStr, 1, 4)) = 0) or
|
||||||
|
(CompareText('Left=', Copy(StripStr, 1, 5)) = 0)) and
|
||||||
|
((CompareText('TOvcTC',
|
||||||
|
Copy(StackRec[StackLevel].ClassName, 1, 6)) = 0) or
|
||||||
|
(CompareText('TO32TC',
|
||||||
|
Copy(StackRec[StackLevel].ClassName, 1, 6)) = 0) or
|
||||||
|
(CompareText('TOvcController',
|
||||||
|
StackRec[StackLevel].ClassName) = 0)) then
|
||||||
|
begin
|
||||||
|
if CompareText('Top=', Copy(StripStr, 1, 4)) = 0 then
|
||||||
|
WriteLn(LfmFileVar,
|
||||||
|
StringReplace(InStr, 'Top', 'Left', [rfIgnoreCase]))
|
||||||
|
else
|
||||||
|
WriteLn(LfmFileVar,
|
||||||
|
StringReplace(InStr, 'Left', 'Top', [rfIgnoreCase]));
|
||||||
|
end
|
||||||
|
|
||||||
|
else {No change to property}
|
||||||
|
WriteLn(LfmFileVar, InStr);
|
||||||
|
|
||||||
|
{Delphi form files don't always include Height or Width properties,
|
||||||
|
which are required by Lazarus, so add them based on ClientHeight
|
||||||
|
and ClientWidth properties, which apparently act the same as
|
||||||
|
Height and Width in Lazarus (unlike Delphi).}
|
||||||
|
if (CompareText('ClientHeight=', Copy(StripStr, 1, 13)) = 0) or
|
||||||
|
(CompareText('ClientWidth=', Copy(StripStr, 1, 12)) = 0) then
|
||||||
|
WriteLn(LfmFileVar,
|
||||||
|
StringReplace(InStr, 'Client', '', [rfIgnoreCase]));
|
||||||
|
except
|
||||||
|
on EInOutError do
|
||||||
|
begin
|
||||||
|
WriteLn('Can''t write to Lazarus form file ', LfmFileName);
|
||||||
|
Halt;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end; {while not Eof}
|
||||||
|
|
||||||
|
CloseFile(DfmFileVar);
|
||||||
|
try
|
||||||
|
CloseFile(LfmFileVar);
|
||||||
|
except
|
||||||
|
on EInOutError do
|
||||||
|
begin
|
||||||
|
WriteLn('Can''t close Lazarus form file ', LfmFileName);
|
||||||
|
Halt;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
CfgFileObj.Free;
|
||||||
|
WriteLn(LfmFileName, ' successfully created');
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
154
components/xdev_toolkit/HelpUtil.pas
Normal file
154
components/xdev_toolkit/HelpUtil.pas
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
unit HelpUtil;
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
Isolates platform-specific help access for Lazarus LCL.
|
||||||
|
|
||||||
|
Assumes Application.HelpFile is set.
|
||||||
|
|
||||||
|
Create THelpUtilManager object in main form's FormCreate handler and
|
||||||
|
call its Free method in main form's FormDestroy handler.
|
||||||
|
|
||||||
|
Display help topic by calling Application.HelpContext.
|
||||||
|
|
||||||
|
Author: Phil Hess.
|
||||||
|
Copyright: Copyright (C) 2007 Phil Hess. All rights reserved.
|
||||||
|
License: Modified LGPL. This means you can link your code to this
|
||||||
|
compiled unit (statically in a standalone executable or
|
||||||
|
dynamically in a library) without releasing your code. Only
|
||||||
|
changes to this unit need to be made publicly available.
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
SysUtils,
|
||||||
|
{$IFDEF MSWINDOWS}
|
||||||
|
Windows,
|
||||||
|
{$ELSE}
|
||||||
|
Unix,
|
||||||
|
{$ENDIF}
|
||||||
|
{$IFDEF LINUX}
|
||||||
|
FileUtil,
|
||||||
|
{$ENDIF}
|
||||||
|
Forms,
|
||||||
|
Dialogs,
|
||||||
|
HelpIntfs;
|
||||||
|
|
||||||
|
type
|
||||||
|
THelpUtilManager = class(THelpManager)
|
||||||
|
destructor Destroy; override;
|
||||||
|
procedure ShowError( ShowResult : TShowHelpResult;
|
||||||
|
const ErrMsg : string); override;
|
||||||
|
function ShowHelpForQuery( Query : THelpQuery;
|
||||||
|
AutoFreeQuery : Boolean;
|
||||||
|
var ErrMsg : string): TShowHelpResult; override;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
|
||||||
|
const
|
||||||
|
HELP_CONTEXT = 1;
|
||||||
|
HELP_QUIT = 2;
|
||||||
|
|
||||||
|
function DoHelpCommand(Command : Word;
|
||||||
|
Data : LongInt) : Boolean;
|
||||||
|
begin
|
||||||
|
{$IFDEF MSWINDOWS} {LCL doesn't have TApplication.HelpCommand, so call Win API}
|
||||||
|
Result := WinHelp(Application.MainForm.Handle,
|
||||||
|
PChar(Application.HelpFile),
|
||||||
|
Command, Data);
|
||||||
|
{$ENDIF}
|
||||||
|
end; {DoHelpCommand}
|
||||||
|
|
||||||
|
|
||||||
|
{THelpUtilManager}
|
||||||
|
|
||||||
|
destructor THelpUtilManager.Destroy;
|
||||||
|
begin
|
||||||
|
{$IFDEF MSWINDOWS}
|
||||||
|
DoHelpCommand(HELP_QUIT, 0);
|
||||||
|
{Shut down help application if running and not in use
|
||||||
|
by another instance of program}
|
||||||
|
{$ENDIF}
|
||||||
|
inherited Destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure THelpUtilManager.ShowError( ShowResult : TShowHelpResult;
|
||||||
|
const ErrMsg : string);
|
||||||
|
begin
|
||||||
|
if ShowResult = shrHelpNotFound then
|
||||||
|
MessageDlg('Help not implemented.', mtError, [mbOK], 0)
|
||||||
|
else if ShowResult = shrViewerNotFound then
|
||||||
|
MessageDlg('Help viewer not found.', mtError, [mbOK], 0)
|
||||||
|
else if ShowResult = shrViewerError then
|
||||||
|
MessageDlg('Unable to start help viewer.', mtError, [mbOK], 0)
|
||||||
|
else if ShowResult <> shrSuccess then
|
||||||
|
MessageDlg(ErrMsg, mtError, [mbOK], 0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function THelpUtilManager.ShowHelpForQuery( Query : THelpQuery;
|
||||||
|
AutoFreeQuery : Boolean;
|
||||||
|
var ErrMsg : string): TShowHelpResult;
|
||||||
|
{$IFDEF LINUX}
|
||||||
|
function SearchForBrowser(const BrowserFileName : string) : string;
|
||||||
|
begin
|
||||||
|
Result :=
|
||||||
|
SearchFileInPath(BrowserFileName, '', GetEnvironmentVariable('PATH'),
|
||||||
|
PathSeparator, [sffDontSearchInBasePath]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetBrowserPath : string;
|
||||||
|
begin
|
||||||
|
Result := SearchForBrowser('firefox');
|
||||||
|
if Result = '' then
|
||||||
|
Result := SearchForBrowser('konqueror'); {KDE browser}
|
||||||
|
if Result = '' then
|
||||||
|
Result := SearchForBrowser('epiphany'); {GNOME browser}
|
||||||
|
if Result = '' then
|
||||||
|
Result := SearchForBrowser('mozilla');
|
||||||
|
if Result = '' then
|
||||||
|
Result := SearchForBrowser('opera');
|
||||||
|
end;
|
||||||
|
{$ENDIF}
|
||||||
|
|
||||||
|
begin
|
||||||
|
if Query is THelpQueryContext then {Is a help context request?}
|
||||||
|
begin
|
||||||
|
{$IFDEF MSWINDOWS}
|
||||||
|
DoHelpCommand(HELP_CONTEXT, THelpQueryContext(Query).Context);
|
||||||
|
Result := shrSuccess;
|
||||||
|
{$ELSE}
|
||||||
|
{$IFDEF DARWIN}
|
||||||
|
if Shell('Open -a "Help Viewer" "' + Application.HelpFile + '"') = 127 then
|
||||||
|
// Note: With OS X earlier than 10.4 (Tiger), if connected to network
|
||||||
|
// but not connected to Internet, takes Help Viewer 1-2 minutes to
|
||||||
|
// recover and turn off rotating ball! Can comment out previous Shell
|
||||||
|
// and uncomment next line to use default browser instead.
|
||||||
|
// if Shell('Open "' + Application.HelpFile + '"') = 127 then
|
||||||
|
Result := shrViewerError
|
||||||
|
else
|
||||||
|
Result := shrSuccess;
|
||||||
|
{$ELSE} {For now, shell to first browser found, passing help file name}
|
||||||
|
if GetBrowserPath <> '' then {Found a browser?}
|
||||||
|
begin
|
||||||
|
if Shell(GetBrowserPath + ' ' + Application.HelpFile) = 127 then
|
||||||
|
Result := shrViewerError
|
||||||
|
else
|
||||||
|
Result := shrSuccess;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Result := shrViewerNotFound;
|
||||||
|
{$ENDIF}
|
||||||
|
{$ENDIF}
|
||||||
|
end
|
||||||
|
else {Not a help context request?}
|
||||||
|
Result := inherited ShowHelpForQuery(Query, AutoFreeQuery, ErrMsg);
|
||||||
|
end; {THelpUtilManager.ShowHelpForQuery}
|
||||||
|
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
220
components/xdev_toolkit/MakePasX.pas
Normal file
220
components/xdev_toolkit/MakePasX.pas
Normal file
@@ -0,0 +1,220 @@
|
|||||||
|
program MakePasX;
|
||||||
|
|
||||||
|
{
|
||||||
|
Makes Delphi form code file or project file cross-platform
|
||||||
|
so it can be compiled by both Delphi and Lazarus/FPC.
|
||||||
|
Note that this is a one-time conversion.
|
||||||
|
Note: Use DfmToLfm to convert form's design file to LCL
|
||||||
|
whenever changes are made to form in Delphi.
|
||||||
|
|
||||||
|
Author: Phil Hess.
|
||||||
|
Copyright: Copyright (C) 2007 Phil Hess. All rights reserved.
|
||||||
|
License: Modified LGPL.
|
||||||
|
}
|
||||||
|
|
||||||
|
uses
|
||||||
|
SysUtils;
|
||||||
|
|
||||||
|
const
|
||||||
|
ProgramName = 'MakePasX';
|
||||||
|
ProgramVersion = '0.01';
|
||||||
|
|
||||||
|
PasFileExt = '.pas'; {Pascal code file extension}
|
||||||
|
DelProjFileExt = '.dpr'; {Delphi project file extension}
|
||||||
|
TmpFileExt = '.tmp'; {Create converted file with this extension}
|
||||||
|
BakFileExt = '.bak'; {Rename original file with this extension}
|
||||||
|
|
||||||
|
var
|
||||||
|
OldFileName : string;
|
||||||
|
NewFileName : string;
|
||||||
|
OldFileVar : TextFile;
|
||||||
|
NewFileVar : TextFile;
|
||||||
|
{$IFNDEF FPC}
|
||||||
|
MatchFound : TFilenameCaseMatch;
|
||||||
|
{$ENDIF}
|
||||||
|
IsProject : Boolean;
|
||||||
|
InStr : string;
|
||||||
|
FoundUses : Boolean;
|
||||||
|
Done : Boolean;
|
||||||
|
UnitPos : Integer;
|
||||||
|
HasAppInit : Boolean;
|
||||||
|
HasForm : Boolean;
|
||||||
|
|
||||||
|
begin
|
||||||
|
|
||||||
|
if ParamCount = 0 then {List program useage?}
|
||||||
|
begin
|
||||||
|
WriteLn(ProgramName, ', version ', ProgramVersion,
|
||||||
|
' - makes Delphi code file cross-platform.');
|
||||||
|
WriteLn('Usage: ', ProgramName, ' filename[', PasFileExt, '|',
|
||||||
|
DelProjFileExt, ']');
|
||||||
|
Halt;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{Get name of Pascal code file to convert from command line}
|
||||||
|
OldFileName := ParamStr(1);
|
||||||
|
if ExtractFileExt(OldFileName) = '' then {No extension?}
|
||||||
|
OldFileName := OldFileName + PasFileExt; {Assume it's not a project file}
|
||||||
|
{$IFNDEF FPC}
|
||||||
|
OldFileName := ExpandFileNameCase(OldFileName, MatchFound);
|
||||||
|
{$ELSE}
|
||||||
|
OldFileName := ExpandFileName(OldFileName);
|
||||||
|
{$ENDIF}
|
||||||
|
|
||||||
|
IsProject := CompareText(ExtractFileExt(OldFileName), DelProjFileExt) = 0;
|
||||||
|
|
||||||
|
NewFileName := ChangeFileExt(OldFileName, TmpFileExt);
|
||||||
|
|
||||||
|
{Open code file}
|
||||||
|
AssignFile(OldFileVar, OldFileName);
|
||||||
|
try
|
||||||
|
Reset(OldFileVar);
|
||||||
|
except
|
||||||
|
on EInOutError do
|
||||||
|
begin
|
||||||
|
WriteLn('Can''t open Pascal code file ', OldFileName);
|
||||||
|
Halt;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{Create new code file}
|
||||||
|
AssignFile(NewFileVar, NewFileName);
|
||||||
|
try
|
||||||
|
Rewrite(NewFileVar);
|
||||||
|
except
|
||||||
|
on EInOutError do
|
||||||
|
begin
|
||||||
|
WriteLn('Can''t create new code file ', NewFileName);
|
||||||
|
Halt;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
FoundUses := False;
|
||||||
|
HasAppInit := False;
|
||||||
|
HasForm := False;
|
||||||
|
while not Eof(OldFileVar) do {Read and convert Pascal code file}
|
||||||
|
begin
|
||||||
|
ReadLn(OldFileVar, InStr); {Read line of code}
|
||||||
|
|
||||||
|
if not IsProject then {Form code file?}
|
||||||
|
begin
|
||||||
|
if (CompareText(InStr, 'uses') = 0) and {Found uses section?}
|
||||||
|
(not FoundUses) then {And in interface section?}
|
||||||
|
begin {Note assumes "uses" appears on separate line from list of units}
|
||||||
|
FoundUses := True;
|
||||||
|
WriteLn(NewFileVar, InStr);
|
||||||
|
WriteLn(NewFileVar,
|
||||||
|
' {$IFNDEF LCL} Windows, Messages, ',
|
||||||
|
'{$ELSE} LclIntf, LMessages, LclType, LResources, {$ENDIF}');
|
||||||
|
ReadLn(OldFileVar, InStr);
|
||||||
|
repeat
|
||||||
|
UnitPos := Pos('WINDOWS,', UpperCase(InStr));
|
||||||
|
if UnitPos > 0 then
|
||||||
|
Delete(InStr, UnitPos, 8);
|
||||||
|
if Copy(InStr, UnitPos, 1) = ' ' then
|
||||||
|
Delete(InStr, UnitPos, 1);
|
||||||
|
UnitPos := Pos('MESSAGES,', UpperCase(InStr));
|
||||||
|
if UnitPos > 0 then
|
||||||
|
Delete(InStr, UnitPos, 9);
|
||||||
|
if Copy(InStr, UnitPos, 1) = ' ' then
|
||||||
|
Delete(InStr, UnitPos, 1);
|
||||||
|
UnitPos := Pos('WINTYPES,', UpperCase(InStr)); {Synonym for Windows}
|
||||||
|
if UnitPos > 0 then
|
||||||
|
Delete(InStr, UnitPos, 9);
|
||||||
|
if Copy(InStr, UnitPos, 1) = ' ' then
|
||||||
|
Delete(InStr, UnitPos, 1);
|
||||||
|
UnitPos := Pos('WINPROCS,', UpperCase(InStr)); {Synonym for Windows}
|
||||||
|
if UnitPos > 0 then
|
||||||
|
Delete(InStr, UnitPos, 9);
|
||||||
|
if Copy(InStr, UnitPos, 1) = ' ' then
|
||||||
|
Delete(InStr, UnitPos, 1);
|
||||||
|
WriteLn(NewFileVar, InStr);
|
||||||
|
Done := Pos(';', InStr) > 0;
|
||||||
|
if not Done then
|
||||||
|
ReadLn(OldFileVar, InStr);
|
||||||
|
until Done;
|
||||||
|
end {uses section}
|
||||||
|
|
||||||
|
else if CompareText(Copy(Trim(InStr), 1, 10),
|
||||||
|
'{$R *.dfm}') = 0 then {Form's resource file?}
|
||||||
|
begin
|
||||||
|
WriteLn(NewFileVar, '{$IFNDEF LCL}');
|
||||||
|
WriteLn(NewFileVar, InStr);
|
||||||
|
WriteLn(NewFileVar, '{$ENDIF}');
|
||||||
|
HasForm := True;
|
||||||
|
end
|
||||||
|
|
||||||
|
else if (CompareText(InStr, 'end.') = 0) and HasForm then {End of unit?}
|
||||||
|
begin
|
||||||
|
{Note: Make sure IFDEF goes after initialization since Delphi
|
||||||
|
inserts new event handlers immediately before initialization line.}
|
||||||
|
WriteLn(NewFileVar, 'initialization');
|
||||||
|
WriteLn(NewFileVar, '{$IFDEF LCL}');
|
||||||
|
WriteLn(NewFileVar, '{$I ', ChangeFileExt(ExtractFileName(OldFileName),
|
||||||
|
'.lrs} {Include form''s resource file}'));
|
||||||
|
WriteLn(NewFileVar, '{$ENDIF}');
|
||||||
|
WriteLn(NewFileVar);
|
||||||
|
WriteLn(NewFileVar, InStr);
|
||||||
|
end
|
||||||
|
|
||||||
|
else {Nothing to change with this line}
|
||||||
|
WriteLn(NewFileVar, InStr);
|
||||||
|
end
|
||||||
|
|
||||||
|
else {Delphi project file}
|
||||||
|
begin
|
||||||
|
if (CompareText(InStr, 'uses') = 0) and {Found uses section?}
|
||||||
|
(not FoundUses) then {And in interface section?}
|
||||||
|
begin {Note assumes "uses" appears on separate line from list of units}
|
||||||
|
FoundUses := True;
|
||||||
|
WriteLn(NewFileVar, InStr);
|
||||||
|
WriteLn(NewFileVar, '{$IFDEF LCL}');
|
||||||
|
WriteLn(NewFileVar, ' Interfaces,');
|
||||||
|
WriteLn(NewFileVar, '{$ENDIF}');
|
||||||
|
end
|
||||||
|
else if (CompareText(Copy(Trim(InStr), 1, 10), '{$R *.res}') = 0) or
|
||||||
|
(CompareText(Copy(Trim(InStr), 1, 10), '{$R *.r32}') = 0) or
|
||||||
|
(CompareText(Copy(Trim(InStr), 1, 10), '{$R *.r16}') = 0) then
|
||||||
|
begin {Program's resource file}
|
||||||
|
WriteLn(NewFileVar, '{$IFDEF MSWINDOWS}');
|
||||||
|
WriteLn(NewFileVar, InStr);
|
||||||
|
WriteLn(NewFileVar, '{$ENDIF}');
|
||||||
|
end
|
||||||
|
else if CompareText(Copy(Trim(InStr), 1, 3), '{$R') = 0 then
|
||||||
|
begin {Might be a type library or XP manifest resource file}
|
||||||
|
WriteLn(NewFileVar, '{$IFNDEF FPC}');
|
||||||
|
WriteLn(NewFileVar, InStr);
|
||||||
|
WriteLn(NewFileVar, '{$ENDIF}');
|
||||||
|
end
|
||||||
|
else if Pos('APPLICATION.INITIALIZE', UpperCase(InStr)) > 0 then
|
||||||
|
begin
|
||||||
|
HasAppInit := True;
|
||||||
|
WriteLn(NewFileVar, InStr);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
if (not HasAppInit) and
|
||||||
|
((Pos('APPLICATION.CREATEFORM', UpperCase(InStr)) > 0) or
|
||||||
|
(Pos('APPLICATION.RUN', UpperCase(InStr)) > 0)) then
|
||||||
|
begin
|
||||||
|
WriteLn(NewFileVar, ' Application.Initialize;'); {Laz needs this}
|
||||||
|
HasAppInit := True;
|
||||||
|
end;
|
||||||
|
WriteLn(NewFileVar, InStr);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end; {while not Eof}
|
||||||
|
|
||||||
|
DeleteFile(ChangeFileExt(OldFileName, BakFileExt));
|
||||||
|
CloseFile(OldFileVar);
|
||||||
|
RenameFile(OldFileName, ChangeFileExt(OldFileName, BakFileExt));
|
||||||
|
CloseFile(NewFileVar);
|
||||||
|
if not IsProject then
|
||||||
|
RenameFile(NewFileName, ChangeFileExt(NewFileName, PasFileExt))
|
||||||
|
else
|
||||||
|
RenameFile(NewFileName, ChangeFileExt(NewFileName, DelProjFileExt));
|
||||||
|
WriteLn(OldFileName, ' successfully converted.');
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
79
components/xdev_toolkit/MakeVer.pas
Normal file
79
components/xdev_toolkit/MakeVer.pas
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
program MakeVer;
|
||||||
|
|
||||||
|
{
|
||||||
|
Makes INI-style version file from Delphi .dof file.
|
||||||
|
|
||||||
|
Author: Phil Hess.
|
||||||
|
Copyright: Copyright (C) 2007 Phil Hess. All rights reserved.
|
||||||
|
License: Modified LGPL.
|
||||||
|
}
|
||||||
|
|
||||||
|
uses
|
||||||
|
SysUtils,
|
||||||
|
Classes,
|
||||||
|
IniFiles;
|
||||||
|
|
||||||
|
const
|
||||||
|
ProgramName = 'MakeVer';
|
||||||
|
ProgramVersion = '0.01';
|
||||||
|
|
||||||
|
DofFileExt = '.dof'; {Delphi project options file extension}
|
||||||
|
VerFileExt = '.version'; {Linux/Mac version info file extension}
|
||||||
|
|
||||||
|
VersionSection = 'Version Info Keys';
|
||||||
|
|
||||||
|
var
|
||||||
|
DofFileName : string;
|
||||||
|
VerFileName : string;
|
||||||
|
DofIniFile : TIniFile;
|
||||||
|
VerIniFile : TIniFile;
|
||||||
|
VerStrList : TStringList;
|
||||||
|
{$IFNDEF FPC}
|
||||||
|
MatchFound : TFilenameCaseMatch;
|
||||||
|
{$ENDIF}
|
||||||
|
ItemNum : Integer;
|
||||||
|
|
||||||
|
begin
|
||||||
|
|
||||||
|
if ParamCount = 0 then {List program useage?}
|
||||||
|
begin
|
||||||
|
WriteLn(ProgramName, ', version ', ProgramVersion,
|
||||||
|
' - makes INI-style version file from Delphi .dof file.');
|
||||||
|
WriteLn('Usage: ', ProgramName, ' filename', DofFileExt);
|
||||||
|
Halt;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{Get name of Delphi project options file from command line}
|
||||||
|
DofFileName := ParamStr(1);
|
||||||
|
if ExtractFileExt(DofFileName) = '' then
|
||||||
|
DofFileName := DofFileName + DofFileExt;
|
||||||
|
{$IFNDEF FPC}
|
||||||
|
DofFileName := ExpandFileNameCase(DofFileName, MatchFound);
|
||||||
|
{$ELSE}
|
||||||
|
DofFileName := ExpandFileName(DofFileName);
|
||||||
|
{$ENDIF}
|
||||||
|
|
||||||
|
VerFileName := ChangeFileExt(DofFileName, VerFileExt);
|
||||||
|
|
||||||
|
if not FileExists(DofFileName) then
|
||||||
|
begin
|
||||||
|
WriteLn(DofFileName, ' does not exist');
|
||||||
|
Halt;
|
||||||
|
end;
|
||||||
|
|
||||||
|
DofIniFile := TIniFile.Create(DofFileName);
|
||||||
|
VerStrList := TStringList.Create;
|
||||||
|
DofIniFile.ReadSectionValues(VersionSection, VerStrList); {Load vers strings}
|
||||||
|
VerIniFile := TIniFile.Create(VerFileName);
|
||||||
|
for ItemNum := 0 to Pred(VerStrList.Count) do {Write to version file}
|
||||||
|
begin
|
||||||
|
VerIniFile.WriteString(VersionSection, VerStrList.Names[ItemNum],
|
||||||
|
VerStrList.Values[VerStrList.Names[ItemNum]]);
|
||||||
|
end;
|
||||||
|
VerIniFile.UpdateFile; {Save to file}
|
||||||
|
VerIniFile.Free;
|
||||||
|
DofIniFile.Free;
|
||||||
|
WriteLn(VerFileName, ' successfully created');
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
5
components/xdev_toolkit/ReadMe.txt
Normal file
5
components/xdev_toolkit/ReadMe.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
This is the XDev Toolkit.
|
||||||
|
|
||||||
|
See XDevStatus.html for more information.
|
||||||
|
|
256
components/xdev_toolkit/RtfDoc.pas
Normal file
256
components/xdev_toolkit/RtfDoc.pas
Normal file
@@ -0,0 +1,256 @@
|
|||||||
|
unit RtfDoc;
|
||||||
|
|
||||||
|
{
|
||||||
|
Class for creating RTF document.
|
||||||
|
|
||||||
|
Author: Phil Hess.
|
||||||
|
Copyright: Copyright (C) 2007 Phil Hess. All rights reserved.
|
||||||
|
License: Modified LGPL. This means you can link your code to this
|
||||||
|
compiled unit (statically in a standalone executable or
|
||||||
|
dynamically in a library) without releasing your code. Only
|
||||||
|
changes to this unit need to be made publicly available.
|
||||||
|
}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
SysUtils,
|
||||||
|
RtfPars;
|
||||||
|
|
||||||
|
type
|
||||||
|
TRtfDoc = class(TObject)
|
||||||
|
private
|
||||||
|
FParser : TRTFParser;
|
||||||
|
procedure DoGroup;
|
||||||
|
procedure DoCtrl;
|
||||||
|
procedure DoText;
|
||||||
|
{$IFDEF FPC}
|
||||||
|
procedure HandleError(s : ShortString);
|
||||||
|
{$ELSE} {Delphi}
|
||||||
|
procedure HandleError(s : string);
|
||||||
|
{$ENDIF}
|
||||||
|
protected
|
||||||
|
FFileName : string;
|
||||||
|
FFileVar : TextFile;
|
||||||
|
public
|
||||||
|
constructor Create;
|
||||||
|
destructor Destroy; override;
|
||||||
|
property Parser : TRTFParser read FParser;
|
||||||
|
property FileName : string read FFileName;
|
||||||
|
procedure Start(const FileName : string); virtual;
|
||||||
|
procedure Done; virtual;
|
||||||
|
procedure OutDefaultFontTable(DefFont : Integer); virtual;
|
||||||
|
procedure OutToken( AClass : Integer;
|
||||||
|
Major : Integer;
|
||||||
|
Minor : Integer;
|
||||||
|
Param : Integer;
|
||||||
|
const Text : string); virtual;
|
||||||
|
procedure OutCtrl(Major : Integer;
|
||||||
|
Minor : Integer;
|
||||||
|
Param : Integer); virtual;
|
||||||
|
procedure OutText(const Text : string); virtual;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
constructor TRtfDoc.Create;
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
FParser := TRTFParser.Create(nil);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
destructor TRtfDoc.Destroy;
|
||||||
|
begin
|
||||||
|
Parser.Free;
|
||||||
|
inherited Destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TRtfDoc.Start(const FileName : string);
|
||||||
|
var
|
||||||
|
CurYear : Word;
|
||||||
|
CurMonth : Word;
|
||||||
|
CurDay : Word;
|
||||||
|
CurHour : Word;
|
||||||
|
CurMinute : Word;
|
||||||
|
CurSecond : Word;
|
||||||
|
CurSec100 : Word;
|
||||||
|
begin
|
||||||
|
FFileName := FileName;
|
||||||
|
AssignFile(FFileVar, FFileName);
|
||||||
|
Rewrite(FFileVar);
|
||||||
|
|
||||||
|
Parser.ResetParser;
|
||||||
|
|
||||||
|
Parser.ClassCallbacks[rtfGroup] := DoGroup;
|
||||||
|
Parser.ClassCallbacks[rtfText] := DoText;
|
||||||
|
Parser.ClassCallbacks[rtfControl] := DoCtrl;
|
||||||
|
Parser.DestinationCallbacks[rtfFontTbl] := nil;
|
||||||
|
Parser.DestinationCallbacks[rtfColorTbl] := nil;
|
||||||
|
Parser.DestinationCallbacks[rtfInfo] := nil;
|
||||||
|
Parser.OnRTFError := HandleError;
|
||||||
|
|
||||||
|
OutToken(rtfGroup, rtfBeginGroup, -1, rtfNoParam, '');
|
||||||
|
OutCtrl(rtfVersion, -1, 1);
|
||||||
|
OutCtrl(rtfCharSet, rtfAnsiCharSet, rtfNoParam);
|
||||||
|
|
||||||
|
{Output document creation date and time}
|
||||||
|
DecodeDate(Now, CurYear, CurMonth, CurDay);
|
||||||
|
DecodeTime(Now, CurHour, CurMinute, CurSecond, CurSec100);
|
||||||
|
OutToken(rtfGroup, rtfBeginGroup, -1, rtfNoParam, '');
|
||||||
|
OutCtrl(rtfDestination, rtfInfo, rtfNoParam);
|
||||||
|
OutToken(rtfGroup, rtfBeginGroup, -1, rtfNoParam, '');
|
||||||
|
OutCtrl(rtfSpecialChar, rtfICreateTime, rtfNoParam);
|
||||||
|
OutCtrl(rtfSpecialChar, rtfIYear, CurYear);
|
||||||
|
OutCtrl(rtfSpecialChar, rtfIMonth, CurMonth);
|
||||||
|
OutCtrl(rtfSpecialChar, rtfIDay, CurDay);
|
||||||
|
OutCtrl(rtfSpecialChar, rtfIHour, CurHour);
|
||||||
|
OutCtrl(rtfSpecialChar, rtfIMinute, CurMinute);
|
||||||
|
OutToken(rtfGroup, rtfEndGroup, -1, rtfNoParam, '');
|
||||||
|
OutToken(rtfGroup, rtfEndGroup, -1, rtfNoParam, '');
|
||||||
|
WriteLn(FFileVar);
|
||||||
|
|
||||||
|
end; {TRtfDoc.Start}
|
||||||
|
|
||||||
|
|
||||||
|
procedure TRtfDoc.OutDefaultFontTable(DefFont : Integer);
|
||||||
|
begin
|
||||||
|
{Output default font number}
|
||||||
|
OutCtrl(rtfDefFont, -1, DefFont);
|
||||||
|
{Output font table}
|
||||||
|
OutToken(rtfGroup, rtfBeginGroup, -1, rtfNoParam, '');
|
||||||
|
OutCtrl(rtfDestination, rtfFontTbl, rtfNoParam);
|
||||||
|
OutToken(rtfGroup, rtfBeginGroup, -1, rtfNoParam, '');
|
||||||
|
OutCtrl(rtfCharAttr, rtfFontNum, 0);
|
||||||
|
OutToken(rtfControl, rtfFontFamily, rtfFFModern, rtfNoParam,
|
||||||
|
'Courier New;');
|
||||||
|
OutToken(rtfGroup, rtfEndGroup, -1, rtfNoParam, '');
|
||||||
|
OutToken(rtfGroup, rtfBeginGroup, -1, rtfNoParam, '');
|
||||||
|
OutCtrl(rtfCharAttr, rtfFontNum, 1);
|
||||||
|
OutToken(rtfControl, rtfFontFamily, rtfFFRoman, rtfNoParam,
|
||||||
|
'Times New Roman;');
|
||||||
|
OutToken(rtfGroup, rtfEndGroup, -1, rtfNoParam, '');
|
||||||
|
OutToken(rtfGroup, rtfBeginGroup, -1, rtfNoParam, '');
|
||||||
|
OutCtrl(rtfCharAttr, rtfFontNum, 2);
|
||||||
|
OutToken(rtfControl, rtfFontFamily, rtfFFSwiss, rtfNoParam,
|
||||||
|
'Arial;');
|
||||||
|
OutToken(rtfGroup, rtfEndGroup, -1, rtfNoParam, '');
|
||||||
|
OutToken(rtfGroup, rtfEndGroup, -1, rtfNoParam, '');
|
||||||
|
WriteLn(FFileVar);
|
||||||
|
end; {TRtfDoc.OutDefaultFontTable}
|
||||||
|
|
||||||
|
|
||||||
|
procedure TRtfDoc.Done;
|
||||||
|
begin
|
||||||
|
WriteLn(FFileVar);
|
||||||
|
OutToken(rtfGroup, rtfEndGroup, -1, rtfNoParam, '');
|
||||||
|
CloseFile(FFileVar);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TRtfDoc.OutToken( AClass : Integer;
|
||||||
|
Major : Integer;
|
||||||
|
Minor : Integer;
|
||||||
|
Param : Integer;
|
||||||
|
const Text : string);
|
||||||
|
begin
|
||||||
|
Parser.SetToken(AClass, Major, Minor, Param, Text);
|
||||||
|
Parser.RouteToken;
|
||||||
|
if Text <> '' then
|
||||||
|
Write(FFileVar, Text);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TRtfDoc.OutCtrl(Major : Integer;
|
||||||
|
Minor : Integer;
|
||||||
|
Param : Integer);
|
||||||
|
begin
|
||||||
|
OutToken(rtfControl, Major, Minor, Param, '');
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TRtfDoc.OutText(const Text : string);
|
||||||
|
var
|
||||||
|
CharNum : Integer;
|
||||||
|
begin
|
||||||
|
for CharNum := 1 to Length(Text) do
|
||||||
|
OutToken(rtfText, Ord(Text[CharNum]), 0, rtfNoParam, '');
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TRtfDoc.DoGroup;
|
||||||
|
begin
|
||||||
|
if Parser.rtfMajor = rtfBeginGroup then
|
||||||
|
Write(FFileVar, '{')
|
||||||
|
else
|
||||||
|
Write(FFileVar, '}');
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TRtfDoc.DoCtrl;
|
||||||
|
var
|
||||||
|
RtfIdx : Integer;
|
||||||
|
begin
|
||||||
|
if (Parser.rtfMajor = rtfSpecialChar) and
|
||||||
|
(Parser.rtfMinor = rtfPar) then
|
||||||
|
WriteLn(FFileVar); {Make RTF file more human readable}
|
||||||
|
RtfIdx := 0;
|
||||||
|
while rtfKey[RtfIdx].rtfKStr <> '' do
|
||||||
|
begin
|
||||||
|
if (Parser.rtfMajor = rtfKey[RtfIdx].rtfKMajor) and
|
||||||
|
(Parser.rtfMinor = rtfKey[RtfIdx].rtfKMinor) then
|
||||||
|
begin
|
||||||
|
Write(FFileVar, '\');
|
||||||
|
Write(FFileVar, rtfKey[RtfIdx].rtfKStr);
|
||||||
|
if Parser.rtfParam <> rtfNoParam then
|
||||||
|
Write(FFileVar, IntToStr(Parser.rtfParam));
|
||||||
|
if rtfKey[RtfIdx].rtfKStr <> '*' then
|
||||||
|
Write(FFileVar, ' ');
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
Inc(RtfIdx);
|
||||||
|
end;
|
||||||
|
end; {TRtfDoc.DoCtrl}
|
||||||
|
|
||||||
|
|
||||||
|
procedure TRtfDoc.DoText;
|
||||||
|
var
|
||||||
|
AChar : Char;
|
||||||
|
begin
|
||||||
|
{rtfMajor contains the character ASCII code,
|
||||||
|
so just output it for now, preceded by \
|
||||||
|
if special char.}
|
||||||
|
AChar := Chr(Parser.rtfMajor);
|
||||||
|
case AChar of
|
||||||
|
'\' : Write(FFileVar, '\\');
|
||||||
|
'{' : Write(FFileVar, '\{');
|
||||||
|
'}' : Write(FFileVar, '\}');
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
if AChar > #127 then {8-bit ANSI character?}
|
||||||
|
Write(FFileVar, '\''' + IntToHex(Ord(AChar), 2)) {Encode using 7-bit chars}
|
||||||
|
else {7-bit ANSI character}
|
||||||
|
Write(FFileVar, AChar);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end; {TRtfDoc.DoText}
|
||||||
|
|
||||||
|
|
||||||
|
{$IFDEF FPC}
|
||||||
|
procedure TRtfDoc.HandleError(s : ShortString);
|
||||||
|
begin
|
||||||
|
WriteLn(StdErr, s);
|
||||||
|
end;
|
||||||
|
{$ELSE} {Delphi}
|
||||||
|
procedure TRtfDoc.HandleError(s : string);
|
||||||
|
begin
|
||||||
|
WriteLn(ErrOutput, S);
|
||||||
|
end;
|
||||||
|
{$ENDIF}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
45
components/xdev_toolkit/TestRtfDoc.pas
Normal file
45
components/xdev_toolkit/TestRtfDoc.pas
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
program TestRtfDoc;
|
||||||
|
|
||||||
|
{
|
||||||
|
Test program for RtfDoc unit.
|
||||||
|
}
|
||||||
|
|
||||||
|
uses
|
||||||
|
SysUtils,
|
||||||
|
RtfPars, {Free Pascal unit with TRtfParser class and rtf constants}
|
||||||
|
RtfDoc; {Descendant class used in this program}
|
||||||
|
|
||||||
|
begin
|
||||||
|
|
||||||
|
with TRtfDoc.Create do {Create TRtfDoc object}
|
||||||
|
begin
|
||||||
|
try
|
||||||
|
|
||||||
|
try
|
||||||
|
Start('test.rtf'); {Create RTF file}
|
||||||
|
except
|
||||||
|
on EInOutError do {File read-only or some other I/O error}
|
||||||
|
begin
|
||||||
|
WriteLn('Can''t create file');
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
OutDefaultFontTable(2); {Select font 2 (Arial) as default}
|
||||||
|
|
||||||
|
OutCtrl(rtfParAttr, rtfQuadCenter, rtfNoParam); {Center line}
|
||||||
|
OutCtrl(rtfCharAttr, rtfBold, 1); {Turn on bolding}
|
||||||
|
OutText('Hello'); {Output some text}
|
||||||
|
OutCtrl(rtfCharAttr, rtfBold, 0); {Turn off bolding}
|
||||||
|
OutText(' there!'); {Output some more text}
|
||||||
|
OutCtrl(rtfSpecialChar, rtfPar, rtfNoParam); {End of paragraph}
|
||||||
|
|
||||||
|
Done; {Close RTF file}
|
||||||
|
|
||||||
|
finally
|
||||||
|
Free; {Free TRtfDoc object}
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
391
components/xdev_toolkit/ViewDoc.pas
Normal file
391
components/xdev_toolkit/ViewDoc.pas
Normal file
@@ -0,0 +1,391 @@
|
|||||||
|
unit ViewDoc;
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
Unit of functions for viewing documents with a word processor.
|
||||||
|
|
||||||
|
Author: Phil Hess.
|
||||||
|
Copyright: Copyright (C) 2007 Phil Hess. All rights reserved.
|
||||||
|
License: Modified LGPL. This means you can link your code to this
|
||||||
|
compiled unit (statically in a standalone executable or
|
||||||
|
dynamically in a library) without releasing your code. Only
|
||||||
|
changes to this unit need to be made publicly available.
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
SysUtils,
|
||||||
|
Classes,
|
||||||
|
{$IFDEF MSWINDOWS}
|
||||||
|
Windows,
|
||||||
|
Registry,
|
||||||
|
ShellApi;
|
||||||
|
{$ENDIF}
|
||||||
|
{$IFDEF DARWIN} {OS X}
|
||||||
|
BaseUnix,
|
||||||
|
Unix;
|
||||||
|
{$ENDIF}
|
||||||
|
{$IFDEF LINUX}
|
||||||
|
FileUtil,
|
||||||
|
Unix;
|
||||||
|
{$ENDIF}
|
||||||
|
|
||||||
|
type
|
||||||
|
TViewerOptions = set of (ovwUseAsTemplate, ovwAddToDeleteList);
|
||||||
|
|
||||||
|
function GetViewerCount : Integer;
|
||||||
|
|
||||||
|
function GetViewerName(Viewer : Integer) : string;
|
||||||
|
|
||||||
|
function ViewDocument(const FileName : string;
|
||||||
|
Viewer : Integer;
|
||||||
|
Options : TViewerOptions;
|
||||||
|
var ErrorMsg : string) : Boolean;
|
||||||
|
|
||||||
|
function DeleteViewedDocs : Boolean;
|
||||||
|
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
const
|
||||||
|
{$IFDEF MSWINDOWS}
|
||||||
|
MaxViewers = 3; {Number of supported word processors}
|
||||||
|
|
||||||
|
{Names of word processors}
|
||||||
|
ViewerName : array [1..MaxViewers] of string =
|
||||||
|
('Microsoft Word',
|
||||||
|
'OpenOffice',
|
||||||
|
'AbiWord');
|
||||||
|
|
||||||
|
{Executable files}
|
||||||
|
ViewerExe : array [1..MaxViewers] of string =
|
||||||
|
('WINWORD.EXE',
|
||||||
|
'SOFFICE.EXE',
|
||||||
|
'AbiWord.exe');
|
||||||
|
|
||||||
|
{Command line startup switches.
|
||||||
|
If non-blank, start word processor with a new document
|
||||||
|
based on the specified template. If blank, open document
|
||||||
|
read-only to force user to save under different name.}
|
||||||
|
ViewerSwitch : array [1..MaxViewers] of string =
|
||||||
|
('/t',
|
||||||
|
'-n ',
|
||||||
|
'');
|
||||||
|
|
||||||
|
ViewerRegKey : array [1..MaxViewers] of string =
|
||||||
|
('',
|
||||||
|
'',
|
||||||
|
'SOFTWARE\Classes\AbiSuite.AbiWord\shell\open\command');
|
||||||
|
{$ENDIF}
|
||||||
|
|
||||||
|
{$IFDEF DARWIN} {OS X}
|
||||||
|
MaxViewers = 4;
|
||||||
|
|
||||||
|
ViewerName : array [1..MaxViewers] of string =
|
||||||
|
('Microsoft Word',
|
||||||
|
'Pages',
|
||||||
|
'NeoOffice',
|
||||||
|
'AbiWord');
|
||||||
|
|
||||||
|
{OS X Open command doesn't support passing switches to app}
|
||||||
|
ViewerSwitch : array [1..MaxViewers] of string =
|
||||||
|
('',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'');
|
||||||
|
|
||||||
|
MaxViewerFolders = 7;
|
||||||
|
|
||||||
|
ViewerFolders : array [1..MaxViewerFolders] of string =
|
||||||
|
('Microsoft Word',
|
||||||
|
'Microsoft Office 2004/Microsoft Word',
|
||||||
|
'Microsoft Office X/Microsoft Word',
|
||||||
|
'Pages.app',
|
||||||
|
'iWork ''06/Pages.app',
|
||||||
|
'NeoOffice.app',
|
||||||
|
'AbiWord.app');
|
||||||
|
{$ENDIF}
|
||||||
|
|
||||||
|
{$IFDEF LINUX}
|
||||||
|
MaxViewers = 2;
|
||||||
|
|
||||||
|
ViewerName : array [1..MaxViewers] of string =
|
||||||
|
('OpenOffice',
|
||||||
|
'AbiWord');
|
||||||
|
|
||||||
|
ViewerExe : array [1..MaxViewers] of string =
|
||||||
|
('soffice.bin',
|
||||||
|
'abiword');
|
||||||
|
|
||||||
|
ViewerSwitch : array [1..MaxViewers] of string =
|
||||||
|
('-n ',
|
||||||
|
'');
|
||||||
|
{$ENDIF}
|
||||||
|
|
||||||
|
|
||||||
|
var
|
||||||
|
DeleteList : TStringList; {List of files to delete when program exits;
|
||||||
|
object is created and destroyed in unit's
|
||||||
|
initialization and finalization sections}
|
||||||
|
|
||||||
|
|
||||||
|
function GetViewerCount : Integer;
|
||||||
|
{Return number of viewers defined.}
|
||||||
|
begin
|
||||||
|
Result := MaxViewers;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function GetViewerName(Viewer : Integer) : string;
|
||||||
|
{Return viewer's name.}
|
||||||
|
begin
|
||||||
|
Result := ViewerName[Viewer];
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function LocateViewer(Viewer : Integer) : string;
|
||||||
|
{Return path to viewer's executable file,
|
||||||
|
or blank string if can't locate viewer.}
|
||||||
|
{$IFDEF MSWINDOWS}
|
||||||
|
var
|
||||||
|
Reg : TRegistry;
|
||||||
|
begin
|
||||||
|
Result := '';
|
||||||
|
{With Windows, installed programs usually have Registry entries
|
||||||
|
under the App Paths section, including complete path to program.}
|
||||||
|
Reg := TRegistry.Create;
|
||||||
|
try
|
||||||
|
Reg.RootKey := HKEY_LOCAL_MACHINE;
|
||||||
|
if ViewerRegKey[Viewer] = '' then
|
||||||
|
begin
|
||||||
|
if Reg.OpenKeyReadOnly(
|
||||||
|
'\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\' +
|
||||||
|
ViewerExe[Viewer]) then
|
||||||
|
begin {Found key, so assume program is installed}
|
||||||
|
try
|
||||||
|
if Reg.ReadString('') <> '' then {Key has (Default) registry entry?}
|
||||||
|
Result := Reg.ReadString('');
|
||||||
|
except {Trap exception if registry entry does not contain a string}
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
else {Non-standard registry key}
|
||||||
|
begin
|
||||||
|
if Reg.OpenKeyReadOnly(ViewerRegKey[Viewer]) then
|
||||||
|
begin {Found key, so assume program is installed}
|
||||||
|
try
|
||||||
|
if Reg.ReadString('') <> '' then {Key as (Default) registry entry?}
|
||||||
|
begin
|
||||||
|
Result := Reg.ReadString('');
|
||||||
|
if Copy(Result, 1, 1) = '"' then {Strip first quoted item?}
|
||||||
|
Result := Copy(Result, 2, Pos('"', Copy(Result, 2, MaxInt))-1);
|
||||||
|
end;
|
||||||
|
except
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
Reg.Free;
|
||||||
|
end;
|
||||||
|
{$ENDIF}
|
||||||
|
|
||||||
|
{$IFDEF DARWIN} //TODO: Search for app like OS X LaunchServices does.
|
||||||
|
var
|
||||||
|
FolderIdx : Integer;
|
||||||
|
LocIdx : Integer;
|
||||||
|
PathPrefix : string;
|
||||||
|
begin
|
||||||
|
Result := '';
|
||||||
|
FolderIdx := 0;
|
||||||
|
while (FolderIdx < MaxViewerFolders) and (Result = '') do
|
||||||
|
begin
|
||||||
|
Inc(FolderIdx);
|
||||||
|
if Pos(LowerCase(ViewerName[Viewer]),
|
||||||
|
LowerCase(ViewerFolders[FolderIdx])) > 0 then
|
||||||
|
begin
|
||||||
|
LocIdx := 0;
|
||||||
|
while (LocIdx < 4) and (Result = '') do
|
||||||
|
begin
|
||||||
|
Inc(LocIdx);
|
||||||
|
case LocIdx of
|
||||||
|
1 : PathPrefix := '/Applications/';
|
||||||
|
2 : PathPrefix := '~/Applications/';
|
||||||
|
3 : PathPrefix := '~/Desktop/';
|
||||||
|
4 : PathPrefix := '~/'
|
||||||
|
end;
|
||||||
|
if FileExists(PathPrefix + ViewerFolders[FolderIdx]) then
|
||||||
|
Result := PathPrefix + ViewerFolders[FolderIdx];
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
{$ENDIF}
|
||||||
|
|
||||||
|
{$IFDEF LINUX}
|
||||||
|
begin
|
||||||
|
{Search path for specified file name, returning its
|
||||||
|
expanded file name that includes path to it.}
|
||||||
|
Result := SearchFileInPath(
|
||||||
|
ViewerExe[Viewer], '', GetEnvironmentVariable('PATH'),
|
||||||
|
PathSeparator, [sffDontSearchInBasePath]);
|
||||||
|
{$ENDIF}
|
||||||
|
end; {LocateViewer}
|
||||||
|
|
||||||
|
|
||||||
|
function LaunchViewer(const ProgPath : string;
|
||||||
|
const Params : string;
|
||||||
|
const DefaultDir : string) : Integer;
|
||||||
|
{Start viewer program with specified command line parameters
|
||||||
|
by shelling to it, returning shell's code.}
|
||||||
|
{$IFDEF MSWINDOWS}
|
||||||
|
var
|
||||||
|
ProgPathBuf : array [0..MAX_PATH] of Char;
|
||||||
|
ParamsBuf : array [0..MAX_PATH] of Char;
|
||||||
|
DefaultDirBuf : array [0..MAX_PATH] of Char;
|
||||||
|
begin
|
||||||
|
StrPCopy(ProgPathBuf, ProgPath);
|
||||||
|
StrPCopy(ParamsBuf, Params);
|
||||||
|
StrPCopy(DefaultDirBuf, DefaultDir);
|
||||||
|
Result := ShellExecute(0, nil, ProgPathBuf, ParamsBuf, DefaultDirBuf,
|
||||||
|
SW_SHOWNORMAL);
|
||||||
|
{$ENDIF}
|
||||||
|
|
||||||
|
{$IFDEF DARWIN}
|
||||||
|
begin
|
||||||
|
Result := Shell('Open -a ' + ProgPath + ' ' + Params);
|
||||||
|
{$ENDIF}
|
||||||
|
|
||||||
|
{$IFDEF LINUX}
|
||||||
|
begin
|
||||||
|
Result := Shell(ProgPath + ' ' + Params);
|
||||||
|
{$ENDIF}
|
||||||
|
end; {LaunchViewer}
|
||||||
|
|
||||||
|
|
||||||
|
function ViewDocument(const FileName : string;
|
||||||
|
Viewer : Integer;
|
||||||
|
Options : TViewerOptions;
|
||||||
|
var ErrorMsg : string) : Boolean;
|
||||||
|
{View FileName with Viewer. If successful, return True; if
|
||||||
|
error, return False and error message in ErrorMsg.}
|
||||||
|
var
|
||||||
|
ProgPath : string;
|
||||||
|
Switches : string;
|
||||||
|
ShellStatus : Integer;
|
||||||
|
{$IFDEF DARWIN}
|
||||||
|
FileInfo : Stat;
|
||||||
|
{$ENDIF}
|
||||||
|
begin
|
||||||
|
Result := False;
|
||||||
|
ErrorMsg := 'Unexpected error';
|
||||||
|
|
||||||
|
if not FileExists(FileName) then
|
||||||
|
begin
|
||||||
|
ErrorMsg := 'File does not exist.';
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if ovwAddToDeleteList in Options then
|
||||||
|
DeleteList.Add(FileName);
|
||||||
|
|
||||||
|
if Viewer = 0 then {Use first word processor found?}
|
||||||
|
begin
|
||||||
|
ProgPath := '';
|
||||||
|
while (Viewer < MaxViewers) and (ProgPath = '') do
|
||||||
|
begin
|
||||||
|
Inc(Viewer);
|
||||||
|
ProgPath := LocateViewer(Viewer);
|
||||||
|
end;
|
||||||
|
if ProgPath = '' then
|
||||||
|
begin
|
||||||
|
ErrorMsg := 'Unable to locate a word processor.';
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
else {Use specified word processor}
|
||||||
|
begin
|
||||||
|
ProgPath := LocateViewer(Viewer);
|
||||||
|
if ProgPath = '' then
|
||||||
|
begin
|
||||||
|
ErrorMsg := ViewerName[Viewer] + ' does not appear to be installed.';
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Switches := '';
|
||||||
|
if ovwUseAsTemplate in Options then
|
||||||
|
begin
|
||||||
|
Switches := ViewerSwitch[Viewer];
|
||||||
|
if Switches = '' then {No "template" switch to pass?}
|
||||||
|
{Set file read-only so user has to save under different name}
|
||||||
|
{$IFDEF MSWINDOWS}
|
||||||
|
FileSetAttr(FileName, faReadOnly);
|
||||||
|
{$ELSE} {OS X and Linux}
|
||||||
|
begin
|
||||||
|
FpStat(FileName, FileInfo);
|
||||||
|
FpChmod(FileName, FileInfo.st_mode and ($FFFF XOR S_IWUSR));
|
||||||
|
end;
|
||||||
|
{$ENDIF}
|
||||||
|
end;
|
||||||
|
|
||||||
|
ShellStatus := LaunchViewer('"' + ProgPath + '"',
|
||||||
|
Switches + '"' + FileName + '"', '');
|
||||||
|
{$IFDEF MSWINDOWS}
|
||||||
|
if ShellStatus <= 32 then {Windows shell error?}
|
||||||
|
{$ELSE}
|
||||||
|
if ShellStatus = 127 then {Unix shell error?}
|
||||||
|
{$ENDIF}
|
||||||
|
begin
|
||||||
|
ErrorMsg := 'Shell error ' + IntToStr(ShellStatus) +
|
||||||
|
' attempting to start ' + ViewerName[Viewer] + '.';
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
ErrorMsg := '';
|
||||||
|
Result := True;
|
||||||
|
end; {ViewDocument}
|
||||||
|
|
||||||
|
|
||||||
|
function DeleteViewedDocs : Boolean;
|
||||||
|
{Attempt to delete documents in deletion list, returning
|
||||||
|
True if all documents deleted or False if unable to
|
||||||
|
delete all documents.}
|
||||||
|
var
|
||||||
|
DocNum : Integer;
|
||||||
|
{$IFDEF DARWIN}
|
||||||
|
FileInfo : Stat;
|
||||||
|
{$ENDIF}
|
||||||
|
begin
|
||||||
|
Result := True;
|
||||||
|
for DocNum := DeleteList.Count - 1 downto 0 do
|
||||||
|
begin
|
||||||
|
if FileExists(DeleteList.Strings[DocNum]) then
|
||||||
|
begin
|
||||||
|
{$IFDEF MSWINDOWS}
|
||||||
|
if (FileGetAttr(DeleteList.Strings[DocNum]) and faReadOnly) <> 0 then
|
||||||
|
FileSetAttr(DeleteList.Strings[DocNum],
|
||||||
|
FileGetAttr(DeleteList.Strings[DocNum]) - faReadOnly);
|
||||||
|
{$ELSE} {OS X and Linux}
|
||||||
|
FpStat(DeleteList.Strings[DocNum], FileInfo);
|
||||||
|
if (FileInfo.st_Mode or S_IWUSR) = 0 then {File read-only?}
|
||||||
|
FpChmod(DeleteList.Strings[DocNum], FileInfo.st_Mode or S_IWUSR);
|
||||||
|
{$ENDIF}
|
||||||
|
if SysUtils.DeleteFile(DeleteList.Strings[DocNum]) then
|
||||||
|
DeleteList.Delete(DocNum)
|
||||||
|
else
|
||||||
|
Result := False; {At least one doc not deleted}
|
||||||
|
end;
|
||||||
|
end; {for DocNum}
|
||||||
|
end; {DeleteViewedDocs}
|
||||||
|
|
||||||
|
|
||||||
|
initialization
|
||||||
|
DeleteList := TStringList.Create;
|
||||||
|
|
||||||
|
finalization
|
||||||
|
DeleteViewedDocs;
|
||||||
|
DeleteList.Free;
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
66
components/xdev_toolkit/ViewWith.pas
Normal file
66
components/xdev_toolkit/ViewWith.pas
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
program ViewWith;
|
||||||
|
|
||||||
|
{
|
||||||
|
Test program for ViewDoc unit.
|
||||||
|
}
|
||||||
|
|
||||||
|
uses
|
||||||
|
SysUtils,
|
||||||
|
ViewDoc;
|
||||||
|
|
||||||
|
var
|
||||||
|
VwrIdx : Integer;
|
||||||
|
Viewer : Integer;
|
||||||
|
Options : TViewerOptions;
|
||||||
|
InStr : string;
|
||||||
|
ErrorMsg : string;
|
||||||
|
Done : Boolean;
|
||||||
|
|
||||||
|
begin
|
||||||
|
|
||||||
|
if ParamCount < 2 then
|
||||||
|
begin
|
||||||
|
WriteLn('Usage: ViewWith viewername docfilename [-t] [-d]');
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Viewer := 0;
|
||||||
|
for VwrIdx := 1 to GetViewerCount do
|
||||||
|
begin
|
||||||
|
if SameText(ParamStr(1), GetViewerName(VwrIdx)) then
|
||||||
|
Viewer := VwrIdx;
|
||||||
|
end;
|
||||||
|
if Viewer = 0 then
|
||||||
|
WriteLn('Specified viewer not supported - using first viewer found');
|
||||||
|
|
||||||
|
Options := [];
|
||||||
|
if FindCmdLineSwitch('t', ['-'], True) then {Treat file as template?}
|
||||||
|
Options := Options + [ovwUseAsTemplate];
|
||||||
|
|
||||||
|
if FindCmdLineSwitch('d', ['-'], True) then {Delete file before exiting?}
|
||||||
|
begin
|
||||||
|
Options := Options + [ovwAddToDeleteList];
|
||||||
|
Write('File will be deleted when done viewing - is this okay (Y/N)? ');
|
||||||
|
ReadLn(InStr);
|
||||||
|
if CompareText(InStr, 'y') <> 0 then
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if not ViewDocument(ParamStr(2), Viewer, Options, ErrorMsg) then
|
||||||
|
begin
|
||||||
|
WriteLn(ErrorMsg);
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if FindCmdLineSwitch('d', ['-'], True) and FileExists(ParamStr(2)) then
|
||||||
|
begin
|
||||||
|
repeat
|
||||||
|
Write('Press Enter when ready to delete file (or Ctrl+C to exit): ');
|
||||||
|
ReadLn(InStr);
|
||||||
|
Done := DeleteViewedDocs;
|
||||||
|
if not Done then
|
||||||
|
WriteLn(' Unable to delete file - may still be open in viewer');
|
||||||
|
until Done;
|
||||||
|
end;
|
||||||
|
end.
|
||||||
|
|
286
components/xdev_toolkit/XDevStatus.html
Normal file
286
components/xdev_toolkit/XDevStatus.html
Normal file
@@ -0,0 +1,286 @@
|
|||||||
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
|
||||||
|
<!--Copyright 2007 Phil Hess-->
|
||||||
|
<HTML>
|
||||||
|
|
||||||
|
<HEAD>
|
||||||
|
|
||||||
|
<TITLE>Status of XDev Toolkit</TITLE>
|
||||||
|
|
||||||
|
<META NAME="AUTHOR" CONTENT="Phil Hess">
|
||||||
|
</HEAD>
|
||||||
|
|
||||||
|
<BODY>
|
||||||
|
|
||||||
|
<CENTER>
|
||||||
|
<H1>Status of XDev Toolkit</H1>
|
||||||
|
</CENTER>
|
||||||
|
|
||||||
|
<HR>
|
||||||
|
<H3>Contents</H3>
|
||||||
|
<A HREF="#Introduction">Introduction</A><BR>
|
||||||
|
<A HREF="#Installation">Installation</A><BR>
|
||||||
|
<A HREF="#CodeConverters">MakePasX & DfmToLfm: Delphi converters</A><BR>
|
||||||
|
<A HREF="#VersionInfo">MakeVer: Create a version info file</A><BR>
|
||||||
|
<A HREF="#HelpConverter">CvtHelp & HelpUtil: Convert WinHelp RTF to HTML</A><BR>
|
||||||
|
<A HREF="#OSXscripts">OS X scripts: Create an app bundle</A><BR>
|
||||||
|
<A HREF="#RTF">RtfDoc & ViewDoc: RTF document creation and viewing</A><BR>
|
||||||
|
<A HREF="#To_Do">To Do</A><BR>
|
||||||
|
<A HREF="#Other_Resources">Other Resources</A><P>
|
||||||
|
|
||||||
|
<HR>
|
||||||
|
<A name="Introduction"></A><H3>Introduction</H3>
|
||||||
|
|
||||||
|
These notes describe the status of the XDev Toolkit, a set of utilities for
|
||||||
|
cross-platform development with <A HREF="http://www.lazarus.freepascal.org">Lazarus</A>
|
||||||
|
and <A HREF="http://www.freepascal.org">Free Pascal</A>. Please send your bug
|
||||||
|
reports, suggestions and comments to:<P>
|
||||||
|
|
||||||
|
MacPgmr (at) fastermac (dot) net<P>
|
||||||
|
|
||||||
|
<I>Note:</I> You can also post to the Lazarus forum if you want your bug reports
|
||||||
|
and suggestions to be seen by the entire Lazarus community.<P>
|
||||||
|
|
||||||
|
The XDev Toolkit source code is here: <A HREF="http://web.fastermac.net/~MacPgmr/XDev/downloads">http://web.fastermac.net/~MacPgmr/XDev/downloads</A><P>
|
||||||
|
|
||||||
|
All source code included in the XDev Toolkit is released under the Modified LGPL license.
|
||||||
|
|
||||||
|
<HR>
|
||||||
|
<A name="Installation"></A><H3>Installation</H3>
|
||||||
|
|
||||||
|
<OL>
|
||||||
|
<LI>Unzip the source files into their own folder.<P>
|
||||||
|
<LI>Open a terminal window and compile each utility and test program with FPC.
|
||||||
|
For example:<P>
|
||||||
|
|
||||||
|
fpc -Sd DfmToLfm.pas
|
||||||
|
|
||||||
|
<LI>To see a utility's syntax, simply run it in a terminal window
|
||||||
|
without any parameters or switches. For example:<P>
|
||||||
|
|
||||||
|
dfmtolfm
|
||||||
|
|
||||||
|
</OL>
|
||||||
|
|
||||||
|
<HR>
|
||||||
|
<A name="CodeConverters"></A><H3>MakePasX & DfmToLfm: Delphi converters</H3>
|
||||||
|
|
||||||
|
These two utilities are provided for converting Delphi projects to Lazarus
|
||||||
|
and optionally maintaining the project's forms on both Delphi and Lazarus.
|
||||||
|
The MakePasX utility is used to make Delphi code files cross-platform (.dpr
|
||||||
|
and .pas). The DfmToLfm utility is used to create Lazarus form design files
|
||||||
|
(.lfm) from Delphi form design files (.dfm).<p>
|
||||||
|
|
||||||
|
Once you've converted a Delphi app to Lazarus you can continue to
|
||||||
|
develop the app with Delphi on Windows and use Lazarus to compile
|
||||||
|
the app on other platforms. This type of app can provide the best of both
|
||||||
|
worlds: taking advantage of the Windows-specific features of Delphi while
|
||||||
|
utilizing Free Pascal and Lazarus to add cross-platform capability to the app.
|
||||||
|
|
||||||
|
<OL>
|
||||||
|
<LI>Use the MakePasX utility to make the Delphi project file (.dpr) and form
|
||||||
|
code files (.pas) cross-platform. This is a one-time conversion that results
|
||||||
|
in a set of source files that can be compiled by both Delphi and Lazarus.<P>
|
||||||
|
<LI>Use the DfmToLfm utility to create Lazarus form files (.lfm) from the Delphi
|
||||||
|
form files (.dfm).<P>
|
||||||
|
<LI>Use the Lazarus lazres utility to create the Lazarus resource file (.lrs)
|
||||||
|
from the form file (.lfm) Repeat steps 2 and 3 whenever you make changes
|
||||||
|
to the Delphi form files. If your project has a number of forms, run these
|
||||||
|
utilities for each form in a batch or shell file to automate the conversion.<P>
|
||||||
|
<LI>Compile the resulting files with Lazarus on Windows
|
||||||
|
to test the converted code and form files.<P>
|
||||||
|
<LI>Move the Lazarus project's files over to OS X or Linux and compile and
|
||||||
|
test them there with that platform's version of Lazarus.
|
||||||
|
</OL>
|
||||||
|
|
||||||
|
|
||||||
|
<HR>
|
||||||
|
<A name="VersionInfo"></A><H3>MakeVer: Create a version info file</H3>
|
||||||
|
|
||||||
|
This simple utility extracts version information from a Delphi .dof file and
|
||||||
|
creates an INI-style .version file that can be distributed with a Lazarus app.<BR><BR>
|
||||||
|
|
||||||
|
<HR>
|
||||||
|
<A name="HelpConverter"></A><H3>CvtHelp & HelpUtil: Convert WinHelp RTF to HTML</H3>
|
||||||
|
|
||||||
|
The CvtHelp utility can be used to convert a WinHelp RTF help file
|
||||||
|
to an HTML file that can be used in a Lazarus app that uses the HelpUtil unit.
|
||||||
|
|
||||||
|
<OL>
|
||||||
|
<LI>Use Word to save the WinHelp RTF file to a "Web Page, Filtered" HTML file.
|
||||||
|
For example, open myapp.rtf and save it as myapp.htm.<P>
|
||||||
|
<LI>Run CvtHelp on the resulting HTML file and the WinHelp help project (.hpj)
|
||||||
|
file. For example:<P>
|
||||||
|
cvthelp myapp.htm myapp.html
|
||||||
|
<LI>Add the HelpUtil unit to the uses section of your Lazarus app's main form.<P>
|
||||||
|
<LI>In your main form's FormCreate handler:<P>
|
||||||
|
Application.HelpFile := ChangeFileExt(ParamStr(0), '.html');<P>
|
||||||
|
HelpManager := THelpUtilManager.Create;
|
||||||
|
<LI>In your main form's FormDestroy handler:<P>
|
||||||
|
HelpManager.Free;
|
||||||
|
<LI>To invoke help, add something like this to a menu command or button OnClick
|
||||||
|
handler:<P>
|
||||||
|
Application.HelpContext(1);
|
||||||
|
</OL>
|
||||||
|
|
||||||
|
For more information, refer to the CvtHelp and HelpUtil source code.<BR><BR>
|
||||||
|
|
||||||
|
<HR>
|
||||||
|
<A name="OSXscripts"></A><H3>OS X scripts: Create an app bundle</H3>
|
||||||
|
|
||||||
|
This script (create_app_mac.sh) creates an .app bundle (folder) for an executable
|
||||||
|
created with Lazarus and its Carbon widgetset so you can double-click the app
|
||||||
|
to start it or drag and drop the app on the dock.<P>
|
||||||
|
|
||||||
|
<UL>
|
||||||
|
<LI>Before using this script, make sure you've made it executable:<P>
|
||||||
|
|
||||||
|
chmod +x create_app_mac.sh<P>
|
||||||
|
|
||||||
|
<LI>Example: Your executable is file myapp and you want to create an .app bundle
|
||||||
|
for it named My Application.app:<P>
|
||||||
|
|
||||||
|
./create_app_mac.sh myapp "My Application"<P>
|
||||||
|
</UL>
|
||||||
|
|
||||||
|
For more information or to customize this script for a specific app,
|
||||||
|
open it in a text editor and read the comments.<P>
|
||||||
|
|
||||||
|
<HR>
|
||||||
|
<A name="RTF"></A><H3>RtfDoc & ViewDoc: RTF document creation and viewing</H3>
|
||||||
|
|
||||||
|
With Delphi, you can use a TRichEdit control to create, display and allow the
|
||||||
|
user to edit simple documents in Rich Text Format (RTF). TRichEdit is a wrapper
|
||||||
|
around the Windows RICHED32.DLL library that's also used by Windows WordPad
|
||||||
|
to create and edit RTF files. RTF is a well-documented text format that's
|
||||||
|
fully supported by Microsoft Word and OpenOffice.org.<P>
|
||||||
|
|
||||||
|
TRichEdit is a handy control for creating or displaying simple reports,
|
||||||
|
but if you try to use it for more than that you will be quickly disappointed
|
||||||
|
because TRichEdit has serious limitations. For one thing, Borland never added
|
||||||
|
support to TRichEdit for newer versions of the Rich Edit library (RICHED20.DLL).
|
||||||
|
And although it's possible to hack the Delphi ComCtrls unit to add support
|
||||||
|
for RICHED20.DLL, Microsoft never fixed some of the bugs in this library
|
||||||
|
or supported more than just a subset of RTF.<P>
|
||||||
|
|
||||||
|
Since Lazarus is a cross-platform tool, it doesn't provide a TRichEdit control.
|
||||||
|
And even if it did, this type of control might not meet your needs. After all,
|
||||||
|
TRichEdit is trying to be a word processor, something the creators of Word
|
||||||
|
and OpenOffice.org have spent many years developing. Wouldn't it make more
|
||||||
|
sense just to use an actual word processor to create and display reports?
|
||||||
|
|
||||||
|
<H4>Using TRtfParser to create RTF documents</H4>
|
||||||
|
|
||||||
|
With Windows, the easiest way to control a word processor externally from
|
||||||
|
another program is to start the Word or OpenOffice.org Automation server
|
||||||
|
and use the server to create, manipulate and display documents. But this
|
||||||
|
is a Windows-only solution; OS X and Linux don't have an equivalent to
|
||||||
|
Windows Automation.<P>
|
||||||
|
|
||||||
|
Fortunately Free Pascal includes a unit named RtfPars that includes the
|
||||||
|
TRtfParser class. While this class was designed to parse and proof existing
|
||||||
|
RTF documents, you can also run it "backwards" to create RTF documents as well.<P>
|
||||||
|
|
||||||
|
To simplify use of the TRtfParser class, the XDev Toolkit includes unit RtfDoc,
|
||||||
|
which introduces a TRtfParser descendant, TRtfDoc, which can be used
|
||||||
|
to create RTF files without knowing how TRtfParser works. For information
|
||||||
|
on how to use it, look at the RtfDoc.pas file and TestRtfDoc.pas example
|
||||||
|
program. You'll also want to look at the Free Pascal rtfdata.inc file for
|
||||||
|
a list of constants that you'll need to use with TRtfDoc.<P>
|
||||||
|
|
||||||
|
For more information on the RTF specification, refer to Microsoft's documentation.<P>
|
||||||
|
|
||||||
|
<H4>Using Word and OpenOffice.org to display RTF documents</H4>
|
||||||
|
|
||||||
|
Assuming you can create your RTF report document as described in the previous
|
||||||
|
section, you now need a way to display it with a word processor. With Windows,
|
||||||
|
you would probably start the Word or OpenOffice.org Automation server, load
|
||||||
|
the report document, then make the program visible so the user can browse,
|
||||||
|
edit, print or save the report. To do this in a cross-platform way, you can
|
||||||
|
instead shell to the word processor and pass the report file name on the
|
||||||
|
command line. Here are the steps:
|
||||||
|
|
||||||
|
<UL>
|
||||||
|
<LI>Determine that the word processor exists and the location of its executable.
|
||||||
|
<LI>Start the word processor by shelling to it, passing it the name of the RTF
|
||||||
|
report document.
|
||||||
|
<LI>Clean up.
|
||||||
|
</UL>
|
||||||
|
|
||||||
|
The XDev Toolkit includes unit ViewDoc, which takes care of most of the details.
|
||||||
|
The first two steps are handled by its ViewDocument function, to which you pass
|
||||||
|
the document name and which word processor to use (Word or OO) and let it
|
||||||
|
determine the word processor's location and launch it. The clean-up step is
|
||||||
|
handled by the unit's DeleteViewedDocs function. For more information on how
|
||||||
|
to use these functions, look at file ViewDoc.pas and ViewWith.pas, a test
|
||||||
|
program that uses the ViewDoc unit.<P>
|
||||||
|
|
||||||
|
Why would you need to clean up after launching the word processor? Usually
|
||||||
|
this step is necessary because the report document will be a temporary file
|
||||||
|
that you'll want to delete. You probably shouldn't require your users to name
|
||||||
|
each report document that your program creates. This will quickly annoy them;
|
||||||
|
it also forces your users to clean up the clutter of saved report documents.
|
||||||
|
Instead, you should use the GetTempFilename function (in the Lazarus FileUtil
|
||||||
|
unit) to get a file name to use for your temporary file, then delete this file
|
||||||
|
yourself at some point after launching the word processor. (Don't use the same
|
||||||
|
file name for all reports since this will restrict your users to viewing only
|
||||||
|
one report at a time.)<P>
|
||||||
|
|
||||||
|
But how can you delete a file if it's open in another program? Remember, your
|
||||||
|
word processor is running externally to your program and locks the file as
|
||||||
|
long as it's open. The file and the word processor won't be closed until the
|
||||||
|
user decides to close them. And even if the file has already been closed,
|
||||||
|
are you sure you want to delete it? What if your user made changes to the
|
||||||
|
report and saved it?<P>
|
||||||
|
|
||||||
|
The solution that ViewDocument uses is to start the word processor with
|
||||||
|
a switch that tells it to create a new document based on the report file
|
||||||
|
(that is, using it as a template). ViewDocument can also add the report file
|
||||||
|
to a list of temporary files to be deleted when your program shuts down. Even
|
||||||
|
though your program still can't delete the temporary file as long as the new
|
||||||
|
document based on it is open in the word processor, this does mean that if
|
||||||
|
the user saves the new document, it won't be with the report file's name.<P>
|
||||||
|
|
||||||
|
To delete the temporary files created by your program, call the DeleteViewedDocs
|
||||||
|
function in your main form's FormCloseQuery handler. If DeleteViewedDocs
|
||||||
|
returns False, you can remind your user to save or close any reports still
|
||||||
|
open in the word processor. DeleteViewedDocs is also called by the ViewDoc
|
||||||
|
unit's finalization code to clean up whatever it can when the program finally
|
||||||
|
does shut down.<P>
|
||||||
|
|
||||||
|
One final note: With OS X, the normal way to start a program from a terminal
|
||||||
|
command line or when shelling is to use the Open command. Unfortunately, the
|
||||||
|
only parameter that Open passes along to the program is the name of the file
|
||||||
|
to open, so there's no way to pass any switches to Word or NeoOffice. With OS X,
|
||||||
|
ViewDocument instead sets the temporary report file to read-only, thus forcing
|
||||||
|
the user to use a different name when saving the report. A disadvantage of this
|
||||||
|
approach is that the word processor shows the name of the temporary file in
|
||||||
|
the title bar (for example, rpt1.tmp) rather than Document1 or Untitled1 as it
|
||||||
|
normally does with a new document. ViewDocument also uses this approach with
|
||||||
|
AbiWord, which doesn't appear to support a command line template switch.
|
||||||
|
|
||||||
|
<HR>
|
||||||
|
<A name="To_Do"></A><H3>To Do</H3>
|
||||||
|
<OL>
|
||||||
|
<LI>Generalize MakeVer so it can use a Delphi .bdsproj file as input and
|
||||||
|
also be able to output version information to a Lazarus .lpi file.<P>
|
||||||
|
<LI>Review Free Pascal's rtfdata.inc file for additional bugs.
|
||||||
|
</OL>
|
||||||
|
|
||||||
|
<HR>
|
||||||
|
<A name="Other_Resources"></A><H3>Other Resources</H3>
|
||||||
|
|
||||||
|
<A HREF="http://wiki.lazarus.freepascal.org/The_Power_of_Proper_Planning_and_Practices">http://wiki.lazarus.freepascal.org/The_Power_of_Proper_Planning_and_Practices</A><P>
|
||||||
|
|
||||||
|
<A HREF="http://wiki.lazarus.freepascal.org/Multiplatform_Programming_Guide">http://wiki.lazarus.freepascal.org/Multiplatform_Programming_Guide</A><P>
|
||||||
|
|
||||||
|
<A HREF="http://wiki.lazarus.freepascal.org/OS_X_Programming_Tips">http://wiki.lazarus.freepascal.org/OS_X_Programming_Tips</A><P>
|
||||||
|
|
||||||
|
<A HREF="http://wiki.lazarus.freepascal.org/Deploying_Your_Application">http://wiki.lazarus.freepascal.org/Deploying_Your_Application</A><P>
|
||||||
|
<P>
|
||||||
|
<HR>
|
||||||
|
Last updated: April 15, 2007
|
||||||
|
<P>
|
||||||
|
|
||||||
|
</BODY>
|
||||||
|
|
||||||
|
</HTML>
|
83
components/xdev_toolkit/create_app_mac.sh
Executable file
83
components/xdev_toolkit/create_app_mac.sh
Executable file
@@ -0,0 +1,83 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Force Bourne shell in case tcsh is default.
|
||||||
|
#
|
||||||
|
# Author: Phil Hess
|
||||||
|
# Revisions: 2007-03-17 - initial release.
|
||||||
|
# 2007-04-09 - added support for .icns file.
|
||||||
|
#
|
||||||
|
exename=$1
|
||||||
|
appname=$2
|
||||||
|
if [ "$appname" = "" ]
|
||||||
|
then
|
||||||
|
appname=$exename
|
||||||
|
fi
|
||||||
|
appfolder=$appname.app
|
||||||
|
plistfile=$appfolder/Contents/Info.plist
|
||||||
|
#
|
||||||
|
if [ "$exename" = "" ]
|
||||||
|
then
|
||||||
|
echo "Usage: $0 executable_file [app_name]"
|
||||||
|
echo "Creates .app bundle (folder) for specified executable file"
|
||||||
|
elif ! [ -e $exename ]
|
||||||
|
then
|
||||||
|
echo "$exename does not exist"
|
||||||
|
elif [ -e "$appfolder" ]
|
||||||
|
then
|
||||||
|
echo "$appfolder already exists"
|
||||||
|
else
|
||||||
|
echo "Creating $appfolder..."
|
||||||
|
mkdir "$appfolder"
|
||||||
|
mkdir "$appfolder/Contents"
|
||||||
|
mkdir "$appfolder/Contents/MacOS"
|
||||||
|
mkdir "$appfolder/Contents/Resources"
|
||||||
|
#
|
||||||
|
# Instead of copying executable into .app folder after each compile,
|
||||||
|
# simply create a symbolic link to executable.
|
||||||
|
# Tip: When you're ready to distribute your .app, delete the link
|
||||||
|
# and copy the executable into the .app folder.
|
||||||
|
ln -s ../../../$exename "$appfolder/Contents/MacOS/$exename"
|
||||||
|
#
|
||||||
|
# Create PkgInfo file using first 4 chars of application name.
|
||||||
|
echo "APPL"${appname:0:4} >$appfolder/Contents/PkgInfo
|
||||||
|
#
|
||||||
|
# If it exists, copy icons file with same name.
|
||||||
|
if [ -e "$exename.icns" ]
|
||||||
|
then
|
||||||
|
cp -p $exename.icns "$appfolder/Contents/Resources"
|
||||||
|
fi
|
||||||
|
#
|
||||||
|
# Create information property list file (Info.plist).
|
||||||
|
# Tip: By customizing this script for a specific app, you can set
|
||||||
|
# additional properties such as CFBundleGetInfoString for copyright
|
||||||
|
# info, CFBundleIconFile for name of icon file (.icns) in Resources,
|
||||||
|
# and CFBundleIdentifier (example: com.myorganization.myapp), as well
|
||||||
|
# as more precise CFBundleSignature (change PkgInfo file too) and
|
||||||
|
# CFBundleVersion strings.
|
||||||
|
echo '<?xml version="1.0" encoding="UTF-8"?>' >$plistfile
|
||||||
|
echo '<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">' >>$plistfile
|
||||||
|
echo '<plist version="1.0">' >>$plistfile
|
||||||
|
echo '<dict>' >>$plistfile
|
||||||
|
echo ' <key>CFBundleDevelopmentRegion</key>' >>$plistfile
|
||||||
|
echo ' <string>English</string>' >>$plistfile
|
||||||
|
echo ' <key>CFBundleExecutable</key>' >>$plistfile
|
||||||
|
echo ' <string>'$exename'</string>' >>$plistfile
|
||||||
|
if [ -e "$exename.icns" ]
|
||||||
|
then
|
||||||
|
echo ' <key>CFBundleIconFile</key>' >>$plistfile
|
||||||
|
echo ' <string>'$exename'.icns</string>' >>$plistfile
|
||||||
|
fi
|
||||||
|
echo ' <key>CFBundleInfoDictionaryVersion</key>' >>$plistfile
|
||||||
|
echo ' <string>6.0</string>' >>$plistfile
|
||||||
|
echo ' <key>CFBundleName</key>' >>$plistfile
|
||||||
|
echo ' <string>'$appname'</string>' >>$plistfile
|
||||||
|
echo ' <key>CFBundlePackageType</key>' >>$plistfile
|
||||||
|
echo ' <string>APPL</string>' >>$plistfile
|
||||||
|
echo ' <key>CFBundleSignature</key>' >>$plistfile
|
||||||
|
echo ' <string>'${appname:0:4}'</string>' >>$plistfile
|
||||||
|
echo ' <key>CFBundleVersion</key>' >>$plistfile
|
||||||
|
echo ' <string>1.0</string>' >>$plistfile
|
||||||
|
echo ' <key>CSResourcesFileMapped</key>' >>$plistfile
|
||||||
|
echo ' <true/>' >>$plistfile
|
||||||
|
echo '</dict>' >>$plistfile
|
||||||
|
echo '</plist>' >>$plistfile
|
||||||
|
fi
|
Reference in New Issue
Block a user