{ Copyright (C) 2006 Mattias Gaertner This source is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This code 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. See the GNU General Public License for more details. A copy of the GNU General Public License is available on the World Wide Web at . You can also obtain it by writing to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA. } unit H2PasDlg; {$mode objfpc}{$H+} interface uses Classes, SysUtils, LCLProc, LCLType, LResources, Forms, Controls, Graphics, Dialogs, ComCtrls, Buttons, StdCtrls, ExtCtrls, LazConfigStorage, LazFileUtils, LazFileCache, SynEdit, FileProcs, IDEMsgIntf, MenuIntf, IDECommands, BaseIDEIntf, IDEDialogs, LazIDEIntf, SrcEditorIntf, IDEExternToolIntf, CompOptsIntf, IDETextConverter, H2PasStrConsts, H2PasConvert, IDETextConvListEdit; type { TH2PasDialog } TH2PasDialog = class(TForm) MergeAllCHeadersExceptCurrentButton: TButton; MergeFileCheckBox: TCheckBox; FileInfoMemo: TMemo; FileStateImageList: TImageList; MoveFileDownButton: TButton; MoveFileUpButton: TButton; ConvertAndBuildButton: TButton; FileInfoGroupBox: TGroupBox; MainPageControl: TPageControl; AddIncludedCHeaderFilesButton: TButton; // c header files FilesTabSheet: TTabSheet; CHeaderFilesSplitter1: TSplitter; AddCHeadersButton: TButton; DisableAllCHeadersButton: TButton; EnableAllCHeadersButton: TButton; DeleteCHeadersButton: TButton; CHeaderFilesCheckTreeView: TTreeView; // pre h2pas PreH2PasTabSheet: TTabSheet; PreH2PasGroupBox: TGroupBox; PreH2PasEdit: TTextConvListEditor; // h2pas h2pasOptionsTabSheet: TTabSheet; h2pasOptionsCheckGroup: TCheckGroup; LibnameEdit: TEdit; LibNameLabel: TLabel; OutputExtEdit: TEdit; OutputExtLabel: TLabel; OutputDirEdit: TEdit; OutputDirLabel: TLabel; OutputDirBrowseButton: TButton; // post h2pas PostH2PasTabSheet: TTabSheet; PostH2PasGroupBox: TGroupBox; PostH2PasEdit: TTextConvListEditor; // settings SettingsTabSheet: TTabSheet; h2pasFilenameBrowseButton: TButton; H2PasFilenameEdit: TEdit; H2PasFilenameLabel: TLabel; NewSettingsButton: TButton; SaveSettingsAsButton: TButton; OpenLastProjectOnStartCheckBox: TCheckBox; // buttons at bottom OpenSettingsButton: TButton; SaveSettingsButton: TButton; ConvertButton: TButton; CloseButton: TButton; procedure AddCHeadersButtonClick(Sender: TObject); procedure AddIncludedCHeaderFilesButtonClick(Sender: TObject); procedure CHeaderFilesCheckTreeViewDblClick(Sender: TObject); procedure CHeaderFilesCheckTreeViewMouseDown(Sender: TOBject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure CHeaderFilesCheckTreeViewSelectionChanged(Sender: TObject); procedure CloseButtonClick(Sender: TObject); procedure ConvertAndBuildButtonClick(Sender: TObject); procedure ConvertButtonClick(Sender: TObject); procedure DeleteCHeadersButtonClick(Sender: TObject); procedure FormCloseQuery(Sender: TObject; var CanClose: boolean); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure H2PasFilenameEditEditingDone(Sender: TObject); procedure LibnameEditEditingDone(Sender: TObject); procedure MergeAllCHeadersExceptCurrentButtonClick(Sender: TObject); procedure MergeFileCheckBoxEditingDone(Sender: TObject); procedure MoveFileDownButtonClick(Sender: TObject); procedure MoveFileUpButtonClick(Sender: TObject); procedure NewSettingsButtonClick(Sender: TObject); procedure OpenLastProjectOnStartCheckBoxChange(Sender: TObject); procedure OpenSettingsButtonClick(Sender: TObject); procedure OutputDirBrowseButtonClick(Sender: TObject); procedure OutputDirEditEditingDone(Sender: TObject); procedure OutputExtEditEditingDone(Sender: TObject); procedure PostH2PasEditModified(Sender: TObject); procedure PreH2PasEditModified(Sender: TObject); procedure SaveSettingsAsButtonClick(Sender: TObject); procedure SaveSettingsButtonClick(Sender: TObject); procedure EnableAllCHeadersButtonClick(Sender: TObject); procedure DisableAllCHeadersButtonClick(Sender: TObject); procedure h2pasFilenameBrowseButtonClick(Sender: TObject); procedure h2pasOptionsCheckGroupItemClick(Sender: TObject; Index: LongInt); procedure OnShowSrcEditSection(Sender: TObject); procedure OnAddSearchAndReplaceBeforeH2PasClick(Sender: TObject); private FConverter: TH2PasConverter; FSrcEditAddSearchReplaceMenuItem: TIDEMenuCommand; FSrcEditSection: TIDEMenuSection; function GetProject: TH2PasProject; procedure UpdateAll(ScanIncludes: boolean); procedure UpdateProjectChanged(ScanIncludes: boolean); // show project settings procedure UpdateCaption; procedure UpdateFileInfo; procedure ClearMessages; procedure CreateLazarusMenuItems; function GetNodeFilename(Node: TTreeNode): string; function GetCurrentCHeaderFile: TH2PasFile; procedure MoveCurrentFile(Offset: integer); function GetFileNodeStateIndex(aFile: TH2PasFile): Integer; procedure MarkAllCHeadersExceptCurrentToMerge; // project settings procedure UpdateFilesPage(ScanIncludes: boolean); procedure UpdateH2PasPage; procedure UpdateConvertPage; // global settings procedure UpdateSettingsPage; function ShowSelectDirDialog(const Title: string; var ADirectory: string): boolean; function ShowOpenFileDialog(const Title: string; var AFilename: string): boolean; // IDE events function OnIDESavedAll(Sender: TObject): TModalResult; public function Convert: TModalResult; procedure ShowH2PasError; function SaveSettings: TModalResult; function SaveGlobalSettings: TModalResult; function LoadGlobalSettings: TModalResult; function SaveProject(const Filename: string; Flags: TSaveFlags): TModalResult; function OpenProject(const Filename: string; Flags: TOpenFlags): TModalResult; property Converter: TH2PasConverter read FConverter; property Project: TH2PasProject read GetProject; property SrcEditSection: TIDEMenuSection read FSrcEditSection; property SrcEditAddSearchReplaceMenuItem: TIDEMenuCommand read FSrcEditAddSearchReplaceMenuItem; end; var H2PasDialog: TH2PasDialog = nil; CmdH2PasTool: TIDECommand = nil; procedure ExecuteH2PasTool(Sender: TObject); procedure Register; implementation {$R h2pasdlg.lfm} procedure ExecuteH2PasTool(Sender: TObject); begin if H2PasDialog=nil then H2PasDialog:=TH2PasDialog.Create(Application); H2PasDialog.ShowOnTop; end; procedure Register; var Key: TIDEShortCut; Cat: TIDECommandCategory; begin // register IDE shortcut and menu item Key := IDEShortCut(VK_UNKNOWN,[],VK_UNKNOWN,[]); Cat:=IDECommandList.FindCategoryByName(CommandCategoryToolMenuName); CmdH2PasTool := RegisterIDECommand(Cat, 'H2Pas ...', h2pCreateUnitsFromCHeaderFiles, Key, nil, @ExecuteH2PasTool); RegisterIDEMenuCommand(itmSecondaryTools, 'H2PasTool', h2pH2Pas, nil, nil, CmdH2PasTool); // register text converter tools TextConverterToolClasses.RegisterClass(TPreH2PasTools); TextConverterToolClasses.RegisterClass(TRemoveCPlusPlusExternCTool); TextConverterToolClasses.RegisterClass(TRemoveEmptyCMacrosTool); TextConverterToolClasses.RegisterClass(TReplaceEdgedBracketPairWithStar); TextConverterToolClasses.RegisterClass(TReplaceMacro0PointerWithNULL); TextConverterToolClasses.RegisterClass(TConvertFunctionTypesToPointers); TextConverterToolClasses.RegisterClass(TConvertEnumsToTypeDef); TextConverterToolClasses.RegisterClass(TCommentComplexCMacros); TextConverterToolClasses.RegisterClass(TCommentComplexCFunctions); TextConverterToolClasses.RegisterClass(TAddMissingMacroBrackets); TextConverterToolClasses.RegisterClass(TPostH2PasTools); TextConverterToolClasses.RegisterClass(TReplaceUnitFilenameWithUnitName); TextConverterToolClasses.RegisterClass(TRemoveIncludeDirectives); TextConverterToolClasses.RegisterClass(TRemoveDoubleSemicolons); TextConverterToolClasses.RegisterClass(TRemoveSystemTypes); TextConverterToolClasses.RegisterClass(TRemoveRedefinedPointerTypes); TextConverterToolClasses.RegisterClass(TRemoveEmptyTypeVarConstSections); TextConverterToolClasses.RegisterClass(TFixH2PasMissingIFDEFsInUnit); TextConverterToolClasses.RegisterClass(TReduceCompilerDirectivesInUnit); TextConverterToolClasses.RegisterClass(TReplaceImplicitTypes); TextConverterToolClasses.RegisterClass(TFixArrayOfParameterType); TextConverterToolClasses.RegisterClass(TAddMissingPointerTypes); TextConverterToolClasses.RegisterClass(TRemoveRedefinitionsInUnit); TextConverterToolClasses.RegisterClass(TFixAliasDefinitionsInUnit); TextConverterToolClasses.RegisterClass(TReplaceConstFunctionsInUnit); TextConverterToolClasses.RegisterClass(TReplaceTypeCastFunctionsInUnit); TextConverterToolClasses.RegisterClass(TFixForwardDefinitions); TextConverterToolClasses.RegisterClass(TAddToUsesSection); // register h2pas output parser ExternalToolList.RegisterParser(TH2PasParser); end; { TH2PasDialog } procedure TH2PasDialog.FormCreate(Sender: TObject); begin Caption:=h2pCHeaderFileConverter; FilesTabSheet.Caption := h2pCHeaderFiles; AddCHeadersButton.Caption := h2pAddHFiles; DeleteCHeadersButton.Caption := h2pDeleteSelectedHFiles; EnableAllCHeadersButton.Caption := h2pEnableAllHFiles; DisableAllCHeadersButton.Caption := h2pDisableAllHFiles; MoveFileDownButton.Caption := h2pMoveFileDown; MoveFileUpButton.Caption := h2pMoveFileUp; FileInfoGroupBox.Caption := h2pFileInformation; AddIncludedCHeaderFilesButton.Caption := h2pAddIncludedHFiles; MergeAllCHeadersExceptCurrentButton.Caption := h2pMergeAllButThis; MergeFileCheckBox.Caption := h2pMergeFile; h2pasOptionsTabSheet.Caption := h2pH2pasOptions; h2pasOptionsCheckGroup.Caption := h2pOptions; with h2pasOptionsCheckGroup.Items do begin Add(h2pDUseExternalForAllProcedures); Add(h2pDUseExternalLibnameNameFunc__nameForFunctions); Add(h2pEConstantsInsteadOfEnumerationTypeForCEnums); Add(h2pCCompactOutputmodeLessSpacesAndEmptyLines); Add(h2pICreateAnIncludeFileInsteadOfAUnit); Add(h2pPUseLetterPForPointerTypesInsteadOf); Add(h2pPrPackAllRecords1ByteAlignment); Add(h2pPUseProcVarsForImports); Add(h2pSStripComments); Add(h2pSStripCommentsAndInfo); Add(h2pTPrependTypedefTypesWithT); Add(h2pTPrependTypedefTypesWithTAndRemove__); Add(h2pVReplacePointerParametersByVar); Add(h2pWHandleSpecialWin32Macros); Add(h2pXHandleSYS__TRAPOfThePalmOSHeaderFiles); Add(h2pCUseTypesInCtypesUnit); end; OutputExtLabel.Caption := h2pOutputExtensionOfNewFile; OutputDirLabel.Caption := h2pOutputDirectory; LibNameLabel.Caption := h2pLLibraryName; PreH2PasTabSheet.Caption := h2pBeforeH2pas; PreH2PasGroupBox.Caption := h2pConversionsBeforeRunningH2pas; PostH2PasTabSheet.Caption := h2pAfterH2pas; PostH2PasGroupBox.Caption := h2pConversionsAfterRunningH2pas; SettingsTabSheet.Caption := h2pSettings; H2PasFilenameLabel.Caption := h2pH2pasProgramPath; OpenLastProjectOnStartCheckBox.Caption := h2pOpenLastSettingsOnStart; SaveSettingsAsButton.Caption := h2pSaveSettingsAs; NewSettingsButton.Caption := h2pNewClearSettings; OpenSettingsButton.Caption := h2pOpenSettings; SaveSettingsButton.Caption := h2pSaveSettings; ConvertButton.Caption := h2pRunH2pas; ConvertAndBuildButton.Caption := h2pRunH2pasAndCompile; CloseButton.Caption := h2pClose; PreH2PasEdit:=TTextConvListEditor.Create(Self); with PreH2PasEdit do begin Name:='PreH2PasEdit'; Align:=alClient; OnModified:=@PreH2PasEditModified; Dock(PreH2PasGroupBox, Rect(0, 0, 0, 0)); Visible:=true;// Note: it's a form, and visible default is false end; PostH2PasEdit:=TTextConvListEditor.Create(Self); with PostH2PasEdit do begin Name:='PostH2PasEdit'; Align:=alClient; OnModified:=@PostH2PasEditModified; Dock(PostH2PasGroupBox, Rect(0, 0, 0, 0)); Visible:=true;// Note: it's a form, and visible default is false end; LazarusIDE.AddHandlerOnSavedAll(@OnIDESavedAll); CreateLazarusMenuItems; // create converter FConverter:=TH2PasConverter.Create; LoadGlobalSettings; // create project if Converter.AutoOpenLastProject and FileExistsUTF8(Converter.CurrentProjectFilename) then OpenProject(Converter.CurrentProjectFilename,[]); if Project=nil then begin Converter.Project:=TH2PasProject.Create; PreH2PasEdit.ListOfTools:=Project.PreH2PasTools; PostH2PasEdit.ListOfTools:=Project.PostH2PasTools; end; UpdateAll(false); end; procedure TH2PasDialog.FormCloseQuery(Sender: TObject; var CanClose: boolean); var DlgResult: TModalResult; begin //DebugLn(['TH2PasDialog.FormCloseQuery Converter.Modified=',Converter.Modified,' Project.Modified=',Project.Modified]); if Converter.Modified or ((Project<>nil) and (Project.Modified)) then begin DlgResult := QuestionDlg(h2pSaveChanges, h2pSaveSettings2, mtConfirmation, [mrYes, h2pSaveAndExit, mrNo, h2pDiscardChangesAndExit, mrCancel, h2pDoNotExit], 0); case DlgResult of mrYes: CanClose:=SaveSettings=mrOk; mrNo: ; else CanClose:=false; end; end; end; procedure TH2PasDialog.CloseButtonClick(Sender: TObject); begin Close; end; procedure TH2PasDialog.ConvertAndBuildButtonClick(Sender: TObject); begin if Convert=mrOk then LazarusIDE.DoBuildProject(crCompile,[]); end; procedure TH2PasDialog.ConvertButtonClick(Sender: TObject); begin Convert; end; procedure TH2PasDialog.DeleteCHeadersButtonClick(Sender: TObject); var DeleteFiles: TStringList; Node: TTreeNode; begin DeleteFiles:=TStringList.Create; Node:=CHeaderFilesCheckTreeView.GetFirstMultiSelected; while Node<>nil do begin if Node.Parent=nil then begin // top lvl node is a .h file DeleteFiles.Add(GetNodeFilename(Node)); end; Node:=Node.GetNextMultiSelected; end; if DeleteFiles.Count>0 then begin if QuestionDlg(h2pConfirmRemoval, Format(h2pDeleteTheseHFilesFromList, [#13, #13, DeleteFiles.Text]), mtConfirmation, [mrYes, h2pRemoveAllFiles, mrCancel], 0) = mrYes then begin Project.DeleteFiles(DeleteFiles); end; UpdateFilesPage(true); end; DeleteFiles.Free; end; procedure TH2PasDialog.AddCHeadersButtonClick(Sender: TObject); var OpenDialog: TOpenDialog; begin OpenDialog:=TOpenDialog.Create(nil); try InitIDEFileDialog(OpenDialog); OpenDialog.Title := h2pAddHFiles2; OpenDialog.Options:=OpenDialog.Options+[ofAllowMultiSelect,ofFileMustExist]; OpenDialog.Filter := Format(h2pCHeaderFileHHAllFiles, [FileMask]); if OpenDialog.Execute then begin Project.AddFiles(OpenDialog.Files); UpdateFilesPage(true); end; finally StoreIDEFileDialog(OpenDialog); OpenDialog.Free; end; end; procedure TH2PasDialog.CHeaderFilesCheckTreeViewMouseDown(Sender: TOBject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var Node: TTreeNode; StateIconLeft: LongInt; AFilename: String; CurFile: TH2PasFile; begin if (Button=mbLeft) and (Shift=[]) then ; Node:=CHeaderFilesCheckTreeView.GetNodeAt(X,Y); if (Node=nil) or (Node.Parent<>nil) then exit; StateIconLeft:=Node.DisplayStateIconLeft; if (x>=StateIconLeft) and (xnil then continue; // .h file not yet in project j:=sl.Count-1; while (j>=0) and (CompareFilenames(CurFilename,sl[j])<>0) do dec(j); if j>=0 then continue; // .h file not yet in list sl.Add(CurFilename); end; if sl.Count>0 then begin s:=''; for i:=0 to sl.Count-1 do begin CurFilename:=Project.ShortenFilename(sl[i]); s:=s+#13+CurFilename; end; if QuestionDlg(h2pAddHFiles3, Format(h2pAddTheseHFilesToH2pasProject, [#13, s, #13]), mtConfirmation,[mrYes,mrNo],0)=mrYes then begin Project.AddFiles(sl); Project.ReadAllCIncludes(true); UpdateFilesPage(false); end; end; finally sl.Free; end; end; procedure TH2PasDialog.CHeaderFilesCheckTreeViewDblClick(Sender: TObject); var CurFile: TH2PasFile; begin CurFile:=GetCurrentCHeaderFile; if CurFile<>nil then LazarusIDE.DoOpenEditorFile(CurFile.Filename,-1, -1,[]); end; procedure TH2PasDialog.CHeaderFilesCheckTreeViewSelectionChanged(Sender: TObject); begin UpdateFileInfo; end; procedure TH2PasDialog.FormDestroy(Sender: TObject); begin PreH2PasEdit.ListOfTools:=nil; PostH2PasEdit.ListOfTools:=nil; FreeAndNil(FConverter); end; procedure TH2PasDialog.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if (Key=VK_ESCAPE) and (Shift=[]) then begin ModalResult:=mrCancel; Key:=VK_UNKNOWN; end; if (Key=VK_S) and (Shift=[ssCtrl]) then begin SaveSettings; Key:=VK_UNKNOWN; end; end; procedure TH2PasDialog.H2PasFilenameEditEditingDone(Sender: TObject); begin Converter.h2pasFilename:=H2PasFilenameEdit.Text; end; procedure TH2PasDialog.LibnameEditEditingDone(Sender: TObject); begin if Project<>nil then Project.Libname:=LibnameEdit.Text; end; procedure TH2PasDialog.MergeAllCHeadersExceptCurrentButtonClick(Sender: TObject); begin MarkAllCHeadersExceptCurrentToMerge; end; procedure TH2PasDialog.MergeFileCheckBoxEditingDone(Sender: TObject); var CurFile: TH2PasFile; begin if Project=nil then exit; CurFile:=GetCurrentCHeaderFile; if CurFile=nil then exit; CurFile.Merge:=MergeFileCheckBox.Checked; UpdateFileInfo; end; procedure TH2PasDialog.MoveFileDownButtonClick(Sender: TObject); begin MoveCurrentFile(1); end; procedure TH2PasDialog.MoveFileUpButtonClick(Sender: TObject); begin MoveCurrentFile(-1); end; procedure TH2PasDialog.NewSettingsButtonClick(Sender: TObject); begin Project.Filename:=''; Project.Clear(true); UpdateAll(true); end; procedure TH2PasDialog.OpenLastProjectOnStartCheckBoxChange(Sender: TObject); begin Converter.AutoOpenLastProject:=OpenLastProjectOnStartCheckBox.Checked; end; procedure TH2PasDialog.OpenSettingsButtonClick(Sender: TObject); var OpenDialog: TOpenDialog; begin OpenDialog:=TOpenDialog.Create(nil); try InitIDEFileDialog(OpenDialog); OpenDialog.Title := h2pOpenProjectH2p; OpenDialog.Options:=OpenDialog.Options+[ofFileMustExist]; OpenDialog.Filter := Format(h2pH2pasProjectH2pH2pAllFiles, [FileMask]); if OpenDialog.Execute then begin OpenProject(OpenDialog.FileName,[]); end; finally StoreIDEFileDialog(OpenDialog); OpenDialog.Free; end; end; procedure TH2PasDialog.OutputDirBrowseButtonClick(Sender: TObject); var ADirectory: String; begin ADirectory:=OutputDirEdit.Text; if not ShowSelectDirDialog(h2pOutputDirectory, ADirectory) then exit; Project.OutputDirectory:=Project.ShortenFilename(ADirectory); OutputDirEdit.Text:=Project.OutputDirectory; end; procedure TH2PasDialog.OutputDirEditEditingDone(Sender: TObject); begin Project.OutputDirectory:=OutputDirEdit.Text; end; procedure TH2PasDialog.OutputExtEditEditingDone(Sender: TObject); begin Project.OutputExt:=OutputExtEdit.Text; end; procedure TH2PasDialog.PostH2PasEditModified(Sender: TObject); begin Project.Modified:=true; end; procedure TH2PasDialog.PreH2PasEditModified(Sender: TObject); begin Project.Modified:=true; end; procedure TH2PasDialog.SaveSettingsAsButtonClick(Sender: TObject); begin SaveProject('',[sfSaveAs]); end; procedure TH2PasDialog.SaveSettingsButtonClick(Sender: TObject); begin SaveProject('',[]); end; procedure TH2PasDialog.EnableAllCHeadersButtonClick(Sender: TObject); var i: Integer; begin CHeaderFilesCheckTreeView.BeginUpdate; for i:=0 to CHeaderFilesCheckTreeView.Items.TopLvlCount-1 do CHeaderFilesCheckTreeView.Items.TopLvlItems[i].StateIndex:=1; for i:=0 to Project.CHeaderFileCount-1 do Project.CHeaderFiles[i].Enabled:=true; CHeaderFilesCheckTreeView.EndUpdate; UpdateFileInfo; end; procedure TH2PasDialog.DisableAllCHeadersButtonClick(Sender: TObject); var i: Integer; begin CHeaderFilesCheckTreeView.BeginUpdate; for i:=0 to CHeaderFilesCheckTreeView.Items.TopLvlCount-1 do CHeaderFilesCheckTreeView.Items.TopLvlItems[i].StateIndex:=0; for i:=0 to Project.CHeaderFileCount-1 do Project.CHeaderFiles[i].Enabled:=false; CHeaderFilesCheckTreeView.EndUpdate; UpdateFileInfo; end; procedure TH2PasDialog.h2pasFilenameBrowseButtonClick(Sender: TObject); var AFilename: String; begin AFilename:=H2PasFilenameEdit.Text; if not ShowOpenFileDialog(h2pFilenameOfH2pasProgram, AFilename) then exit; Converter.h2pasFilename:=AFilename; H2PasFilenameEdit.Text:=Converter.h2pasFilename; end; procedure TH2PasDialog.h2pasOptionsCheckGroupItemClick(Sender: TObject; Index: LongInt); var s: string; p: Integer; OptionStr: String; NewValue: boolean; begin if Index<0 then exit; NewValue:=h2pasOptionsCheckGroup.Checked[Index]; s:=h2pasOptionsCheckGroup.Items[Index]; p:=2; while (p<=length(s)) and (s[p]<>' ') do inc(p); OptionStr:=copy(s,2,p-2); if length(OptionStr)=1 then begin case OptionStr[1] of 'd': Project.UseExternal:=NewValue; 'D': Project.UseExternalLibname:=NewValue; 'e': Project.ConstantsInsteadOfEnums:=NewValue; 'c': Project.CompactOutputmode:=NewValue; 'i': Project.CreateIncludeFile:=NewValue; 'p': Project.PforPointers:=NewValue; 'P': Project.UseProcVarsForImport:=NewValue; 's': Project.StripComments:=NewValue; 'S': Project.StripCommentsAndInfo:=NewValue; 't': Project.TforTypedefs:=NewValue; 'T': Project.TforTypedefsRemoveUnderscore:=NewValue; 'v': Project.VarParams:=NewValue; 'w': Project.Win32Header:=NewValue; 'x': Project.PalmOSSYSTrap:=NewValue; 'C': Project.UseCTypes:=NewValue; else raise Exception.Create(Format(h2pTH2PasDialogH2pasOptionsCheckGroupItemClickUnknown, [OptionStr])); end; end else begin if OptionStr='pr' then Project.PackAllRecords:=NewValue; end; end; procedure TH2PasDialog.OnShowSrcEditSection(Sender: TObject); var SrcEdit: TSourceEditorInterface; begin SrcEdit:=SourceEditorManagerIntf.ActiveEditor; SrcEditSection.Visible:=(SrcEdit<>nil) and Converter.FileIsRelated(SrcEdit.FileName); //DebugLn(['TH2PasDialog.OnShowSrcEditSection ',SrcEditSection.Visible]); end; procedure TH2PasDialog.OnAddSearchAndReplaceBeforeH2PasClick(Sender: TObject); var Tool: TCustomTextConverterTool; SrcEdit: TSourceEditorInterface; s: String; begin //DebugLn(['TH2PasDialog.OnAddSearchAndReplaceBeforeH2PasClick']); SrcEdit:=SourceEditorManagerIntf.ActiveEditor; if SrcEdit=nil then exit; MainPageControl.ActivePage:=PreH2PasTabSheet; ShowOnTop; // get current source editor selection or line s:=SrcEdit.Selection; if s='' then s:=SrcEdit.CurrentLineText; // add a search and replace tool Tool:=PreH2PasEdit.CreateTool(TTextReplaceTool); TTextReplaceTool(Tool).SearchFor:=s; if (System.Pos(#10,s)>0) or (System.Pos(#13,s)>0) then TTextReplaceTool(Tool).Options:=TTextReplaceTool(Tool).Options+[trtMultiLine]; PreH2PasEdit.PropertyGrid.RefreshPropertyValues; //DebugLn(['TH2PasDialog.OnAddSearchAndReplaceBeforeH2PasClick ',s]); end; function TH2PasDialog.GetProject: TH2PasProject; begin Result:=Converter.Project; end; procedure TH2PasDialog.UpdateAll(ScanIncludes: boolean); begin UpdateCaption; UpdateFilesPage(ScanIncludes); UpdateH2PasPage; UpdateConvertPage; UpdateSettingsPage; end; procedure TH2PasDialog.UpdateProjectChanged(ScanIncludes: boolean); begin UpdateCaption; UpdateFilesPage(ScanIncludes); UpdateH2PasPage; UpdateConvertPage; end; procedure TH2PasDialog.UpdateCaption; var s: String; begin s:=h2pCHeaderFileConverter; if Project<>nil then s:=s+' - '+ExtractFileNameOnly(Project.Filename); Caption:=s; end; procedure TH2PasDialog.UpdateFileInfo; var AFile: TH2PasFile; s: String; Filename: String; OutputFilename: String; i: Integer; IncFile: TH2PasFileCInclude; begin AFile:=GetCurrentCHeaderFile; if AFile<>nil then begin Filename:=AFile.Filename; s := Format(h2pFile, [Filename]); if not FileExistsCached(Filename) then s := s + #13 + h2pERRORFileNotFound2; if AFile.MergedBy<>nil then begin OutputFilename:=AFile.MergedBy.GetOutputFilename; s := s + #13 + Format(h2pMergedInto, [OutputFilename]); end else begin OutputFilename:=AFile.GetOutputFilename; s := s + #13 + Format(h2pOutput, [OutputFilename]); end; AFile.ReadCIncludes(false); if AFile.CIncludeCount>0 then begin s := s + #13#13 + h2pIncludes; for i:=0 to AFile.CIncludeCount-1 do begin IncFile:=AFile.CIncludes[i]; s:=s+#13+Project.ShortenFilename(IncFile.Filename)+':'+IntToStr(IncFile.SrcPos.Y); end; AddIncludedCHeaderFilesButton.Enabled:=true; end else begin AddIncludedCHeaderFilesButton.Enabled:=false; end; if AFile.CIncludedByCount>0 then begin s := s + #13#13 + h2pIncludedBy; for i:=0 to AFile.CIncludedByCount-1 do begin IncFile:=AFile.CIncludedBy[i]; s:=s+#13+Project.ShortenFilename(IncFile.Owner.Filename)+':'+IntToStr(IncFile.SrcPos.Y); end; end; FileInfoMemo.Caption:=s; MergeFileCheckBox.Checked:=AFile.Merge; MergeFileCheckBox.Enabled:=true; end else begin FileInfoMemo.Caption := h2pNoFileSelected; MergeFileCheckBox.Enabled:=false; AddIncludedCHeaderFilesButton.Enabled:=false; end; end; procedure TH2PasDialog.ClearMessages; begin IDEMessagesWindow.Clear; end; procedure TH2PasDialog.CreateLazarusMenuItems; begin // add a context menu to the source editor. It will be freed by ide automatically fSrcEditSection:=RegisterIDESubMenu(SrcEditMenuSectionFirstStatic, h2pH2pasProject, 'h2pas', nil, nil); fSrcEditSection.AddHandlerOnShow(@OnShowSrcEditSection); // add a menu item to easily create a Search and replace from the current // selection or line of the source editor. fSrcEditAddSearchReplaceMenuItem:=RegisterIDEMenuCommand(SrcEditSection, 'Add "search and replace" tool before H2Pas', h2pAddSearchAndReplaceToolBeforeH2pas, @OnAddSearchAndReplaceBeforeH2PasClick); end; function TH2PasDialog.GetNodeFilename(Node: TTreeNode): string; var p: LongInt; begin Result:=Node.Text; p:=System.Pos('(',Result); if p>0 then Result:=copy(Result,1,p-2); Result:=Project.LongenFilename(Result); end; function TH2PasDialog.GetCurrentCHeaderFile: TH2PasFile; var AFilename: String; Node: TTreeNode; begin Result:=nil; Node:=CHeaderFilesCheckTreeView.Selected; if (Node=nil) or (Node.Parent<>nil) then exit; AFilename:=GetNodeFilename(Node); Result:=Project.CHeaderFileWithFilename(AFilename); end; procedure TH2PasDialog.MoveCurrentFile(Offset: integer); var Index: LongInt; AFilename: String; NewIndex: Integer; Node: TTreeNode; begin if Offset=0 then begin DebugLn(['TH2PasDialog.MoveCurrentFile Offset=0']); exit; end; Node:=CHeaderFilesCheckTreeView.Selected; if (Node=nil) or (Node.Parent<>nil) then exit; AFilename:=GetNodeFilename(Node); Index:=Project.CHeaderFileIndexWithFilename(AFilename); if Index<0 then begin DebugLn(['TH2PasDialog.MoveCurrentFile not found: Filename=',AFilename]); exit; end; NewIndex:=Index+Offset; if (NewIndex<0) or (NewIndex>=Project.CHeaderFileCount) then begin DebugLn(['TH2PasDialog.MoveCurrentFile out of bounds: NewIndex=',NewIndex]); exit; end; Project.CHeaderFileMove(Index,NewIndex); CHeaderFilesCheckTreeView.ConsistencyCheck; Node.Index:=NewIndex; CHeaderFilesCheckTreeView.ConsistencyCheck; end; function TH2PasDialog.GetFileNodeStateIndex(aFile: TH2PasFile): Integer; begin if aFile=nil then Result:=0 else if aFile.Enabled then Result:=1 else Result:=0; end; procedure TH2PasDialog.MarkAllCHeadersExceptCurrentToMerge; var CurFile: TH2PasFile; i: Integer; OtherFile: TH2PasFile; begin if Project=nil then exit; CurFile:=GetCurrentCHeaderFile; if CurFile=nil then exit; for i:=0 to Project.CHeaderFileCount-1 do begin OtherFile:=Project.CHeaderFiles[i]; OtherFile.Merge:=OtherFile<>CurFile; end; UpdateFileInfo; end; procedure TH2PasDialog.UpdateFilesPage(ScanIncludes: boolean); var i: Integer; CurFile: TH2PasFile; OldSelection: TStringList; s: String; OldExpandedState: TTreeNodeExpandedState; Node: TTreeNode; OldSelected: String; j: Integer; begin if ScanIncludes and (Project<>nil) then Project.ReadAllCIncludes(false); CHeaderFilesCheckTreeView.BeginUpdate; OldSelection:=nil; OldExpandedState:=TTreeNodeExpandedState.Create(CHeaderFilesCheckTreeView); try // remember old selection OldSelected:=''; if CHeaderFilesCheckTreeView.Selected<>nil then OldSelected:=CHeaderFilesCheckTreeView.Selected.Text; OldSelection:=TStringList.Create; Node:=CHeaderFilesCheckTreeView.GetFirstMultiSelected; while Node<>nil do begin //DebugLn(['TH2PasDialog.UpdateFilesPage Node.Text="',Node.Text,'" Index=',Node.Index]); OldSelection.Add(Node.GetTextPath); Node:=Node.GetNextMultiSelected; end; // clear CHeaderFilesCheckTreeView.Items.Clear; // fill for i:=0 to Project.CHeaderFileCount-1 do begin CurFile:=Project.CHeaderFiles[i]; s:=Project.ShortenFilename(CurFile.Filename); if CurFile.CIncludedByCount>0 then s := Format(h2pIncludedBy2, [s, IntToStr(CurFile.CIncludedByCount)]); Node:=CHeaderFilesCheckTreeView.Items.Add(nil,s); Node.MultiSelected:=OldSelection.IndexOf(Node.GetTextPath)>=0; Node.Selected:=Node.Text=OldSelected; Node.StateIndex:=GetFileNodeStateIndex(CurFile); for j:=0 to CurFile.CIncludeCount-1 do begin end; end; // restore expanded state OldExpandedState.Apply(CHeaderFilesCheckTreeView); finally OldExpandedState.Free; OldSelection.Free; CHeaderFilesCheckTreeView.EndUpdate; end; UpdateFileInfo; end; procedure TH2PasDialog.UpdateH2PasPage; procedure Check(const Option: string; NewValue: boolean); var i: Integer; s: string; begin for i:=0 to h2pasOptionsCheckGroup.Items.Count-1 do begin s:=h2pasOptionsCheckGroup.Items[i]; if copy(s,1,length(Option)+1)=Option+' ' then h2pasOptionsCheckGroup.Checked[i]:=NewValue; end; end; begin Check('-d',Project.UseExternal); Check('-D',Project.UseExternalLibname); Check('-e',Project.ConstantsInsteadOfEnums); Check('-c',Project.CompactOutputmode); Check('-i',Project.CreateIncludeFile); Check('-p',Project.PforPointers); Check('-pr',Project.PackAllRecords); Check('-P',Project.UseProcVarsForImport); Check('-s',Project.StripComments); Check('-S',Project.StripCommentsAndInfo); Check('-t',Project.TforTypedefs); Check('-T',Project.TforTypedefsRemoveUnderscore); Check('-v',Project.VarParams); Check('-w',Project.Win32Header); Check('-x',Project.PalmOSSYSTrap); Check('-C',Project.UseCTypes); LibnameEdit.Text:=Project.Libname; OutputExtEdit.Text:=Project.OutputExt; OutputDirEdit.Text:=Project.OutputDirectory; end; procedure TH2PasDialog.UpdateConvertPage; begin ClearMessages; PreH2PasEdit.ListOfTools:=Project.PreH2PasTools; PreH2PasEdit.UpdateAll; PostH2PasEdit.ListOfTools:=Project.PostH2PasTools; PostH2PasEdit.UpdateAll; //DebugLn(['TH2PasDialog.UpdateConvertPage PreH2PasEdit.ListOfTools=',PreH2PasEdit.ListOfTools.COmponentCount]); end; procedure TH2PasDialog.UpdateSettingsPage; begin H2PasFilenameEdit.Text:=Converter.h2pasFilename; OpenLastProjectOnStartCheckBox.Checked:=Converter.AutoOpenLastProject; end; function TH2PasDialog.ShowSelectDirDialog(const Title: string; var ADirectory: string): boolean; var SelectDirDialog: TSelectDirectoryDialog; begin Result:=false; SelectDirDialog:=TSelectDirectoryDialog.Create(nil); try InitIDEFileDialog(SelectDirDialog); SelectDirDialog.Title:=Title; if (ADirectory<>'') and (FilenameIsAbsolute(ADirectory)) then SelectDirDialog.InitialDir:=ADirectory; if SelectDirDialog.Execute then begin ADirectory:=SelectDirDialog.FileName; Result:=true; end; finally StoreIDEFileDialog(SelectDirDialog); SelectDirDialog.Free; end; end; function TH2PasDialog.ShowOpenFileDialog(const Title: string; var AFilename: string): boolean; var OpenDialog: TOpenDialog; begin Result:=false; OpenDialog:=TOpenDialog.Create(nil); try InitIDEFileDialog(OpenDialog); OpenDialog.Title:=Title; if (AFilename<>'') and (FilenameIsAbsolute(AFilename)) then OpenDialog.InitialDir:=ExtractFilePath(AFilename); if AFilename<>'' then OpenDialog.Filename:=ExtractFileName(AFilename); if OpenDialog.Execute then begin AFilename:=OpenDialog.FileName; Result:=true; end; finally StoreIDEFileDialog(OpenDialog); OpenDialog.Free; end; end; function TH2PasDialog.OnIDESavedAll(Sender: TObject): TModalResult; begin Result:=SaveSettings; end; function TH2PasDialog.Convert: TModalResult; begin Result:=mrCancel; if not Project.HasEnabledFiles then begin IDEMessageDialog(h2pNothingToDo, h2pPleaseEnableAtLeastOneCHeaderFileThatIsNotMerged, mtInformation,[mbOk],''); Result:=mrOK; exit; end; // save settings if SaveSettings<>mrOk then begin DebugLn(['TH2PasDialog.Convert SaveSettings failed']); exit; end; // save IDE files if LazarusIDE.DoSaveProject([])<>mrOK then begin DebugLn(['TH2PasDialog.Convert LazarusIDE.DoSaveProject failed']); exit; end; LazarusIDE.SaveSourceEditorChangesToCodeCache(nil); Result:=Converter.Execute; if Result<>mrOk then begin ShowH2PasError; end; end; procedure TH2PasDialog.ShowH2PasError; begin LazarusIDE.DoJumpToCompilerMessage(true); end; function TH2PasDialog.SaveSettings: TModalResult; begin Result:=SaveGlobalSettings; if Result<>mrOk then exit; if (Project<>nil) and Project.Modified then Result:=SaveProject('',[]); end; function TH2PasDialog.SaveGlobalSettings: TModalResult; var Config: TConfigStorage; begin Result:=mrCancel; try Config:=GetIDEConfigStorage('h2pastool.xml',false); try Converter.WindowBounds:=BoundsRect; Converter.Save(Config); Config.WriteToDisk; finally Config.Free; end; Result:=mrOk; except on E: Exception do begin MessageDlg(h2pWriteError, Format(h2pErrorWritingGlobalConfig, [#13, E.Message]), mtError, [mbCancel], 0); end; end; end; function TH2PasDialog.LoadGlobalSettings: TModalResult; var Config: TConfigStorage; begin Result:=mrCancel; try Config:=GetIDEConfigStorage('h2pastool.xml',true); try Converter.Load(Config); if (Converter.WindowBounds.Left>-10) and (Converter.WindowBounds.Right-10) and (Converter.WindowBounds.Bottom100) and (Converter.WindowBounds.Bottom-Converter.WindowBounds.Top>50) then BoundsRect:=Converter.WindowBounds; UpdateSettingsPage; finally Config.Free; end; Result:=mrOk; except on E: Exception do begin MessageDlg(h2pReadError, Format(h2pErrorReadingGlobalConfig, [#13, E.Message]), mtError, [mbCancel], 0); end; end; end; function TH2PasDialog.SaveProject(const Filename: string; Flags: TSaveFlags ): TModalResult; var NewFilename: String; SaveDialog: TSaveDialog; NewPath: String; begin Result:=mrCancel; if Project=nil then exit(mrOk); NewFilename:=Filename; if NewFilename='' then NewFilename:=Project.Filename; // choose a filename if (not FilenameIsAbsolute(NewFilename)) or (sfSaveAs in Flags) then begin SaveDialog:=TSaveDialog.Create(nil); try InitIDEFileDialog(SaveDialog); SaveDialog.Title := h2pSaveProjectAsH2p; //choose a nice default name if NewFilename='' then NewFilename:='project1.h2p'; SaveDialog.FileName:=NewFilename; SaveDialog.Filter := Format(h2pH2pasProjectH2pH2pAllFiles, [FileMask]); NewPath:=ExtractFilePath(NewFilename); if NewPath<>'' then SaveDialog.InitialDir:=NewPath; if (not SaveDialog.Execute) then exit; NewFilename:=SaveDialog.FileName; if NewFilename='' then exit; // append default file extension if ExtractFileExt(NewFilename)='' then NewFilename:=NewFilename+'.h2p'; // warn if overwriting if FileExistsUTF8(NewFilename) then begin if QuestionDlg(h2pReplaceFile, Format(h2pTheFileAlreadyExists, [NewFilename, #13]), mtConfirmation, [mrOk, h2pOverwrite, mrCancel, h2pCancel], 0) <> mrOk then exit; end; finally StoreIDEFileDialog(SaveDialog); SaveDialog.Free; end; end; // save try DebugLn(['TH2PasDialog.SaveProject saving project']); Converter.SaveProject(NewFilename); Result:=mrOk; except on E: Exception do begin MessageDlg(h2pWriteError, Format(h2pErrorWritingGlobalConfig, [#13, E.Message]), mtError, [mbCancel], 0); end; end; UpdateCaption; end; function TH2PasDialog.OpenProject(const Filename: string; Flags: TOpenFlags ): TModalResult; var NewFilename: String; begin Result:=mrCancel; NewFilename:=ExpandFileNameUTF8(TrimFilename(Filename)); if not FileExistsUTF8(NewFilename) then begin if ofOnlyIfExists in Flags then begin MessageDlg(h2pFileNotFound, Format(h2pFileNotFound2, [NewFilename]), mtError, [mbCancel], 0); exit; end; end; // create new project if Project=nil then Converter.Project:=TH2PasProject.Create; if FileExistsUTF8(NewFilename) then begin // load try Converter.LoadProject(NewFilename); Result:=mrOk; except on E: Exception do begin MessageDlg(h2pReadError, Format(h2pErrorReadingProjectFromFile, [#13, NewFilename, #13, #13, E.Message]), mtError, [mbCancel], 0); end; end; end else begin // new project Project.Clear(true); Converter.CurrentProjectFilename:=NewFilename; Project.Filename:=NewFilename; end; UpdateProjectChanged(true); end; end.