{ ***************************************************************************** See the file COPYING.modifiedLGPL.txt, included in this distribution, for details about the license. ***************************************************************************** Author: Mattias Gaertner Abstract: Installs a HTML control in the IDE using TIpHtmlPanel. } unit IPIDEHTMLControl; {$mode objfpc}{$H+} interface uses Classes, SysUtils, LCLProc, Forms, Graphics, Controls, Dialogs, ExtCtrls, Menus, IpMsg, Ipfilebroker, IpHtml, IDEHelpIntf, LazHelpIntf, LazIDEIntf; type TLazIPHtmlControl = class; { TLazIpHtmlDataProvider } TLazIpHtmlDataProvider = class(TIpHtmlDataProvider) private FControl: TLazIPHtmlControl; protected function DoGetStream(const URL: string): TStream; override; public property Control: TLazIPHtmlControl read FControl; end; { TLazIPHtmlControl } TLazIPHtmlControl = class(TCustomPanel,TIDEHTMLControlIntf) function DataProviderCanHandle(Sender: TObject; const {%H-}URL: string): Boolean; procedure DataProviderCheckURL(Sender: TObject; const {%H-}URL: string; var Available: Boolean; var ContentType: string); procedure DataProviderGetHtml(Sender: TObject; const {%H-}URL: string; const {%H-}aPostData: TIpFormDataEntity; var Stream: TStream); procedure DataProviderGetImage(Sender: TIpHtmlNode; const URL: string; var Picture: TPicture); procedure DataProviderLeave(Sender: TIpHtml); procedure DataProviderReportReference(Sender: TObject; const {%H-}URL: string); procedure IPHTMLPanelHotClick(Sender: TObject); private FIDEProvider: TAbstractIDEHTMLProvider; FIPHTMLPanel: TIpHtmlPanel; FURL: string; procedure SetIDEProvider(const AValue: TAbstractIDEHTMLProvider); protected procedure Notification(AComponent: TComponent; Operation: TOperation); override; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; function GetURL: string; procedure SetURL(const AValue: string); property IDEProvider: TAbstractIDEHTMLProvider read FIDEProvider write SetIDEProvider; procedure SetHTMLContent(Stream: TStream; const NewURL: string); procedure GetPreferredControlSize(out AWidth, AHeight: integer); property IPHTMLPanel: TIpHtmlPanel read FIPHTMLPanel; end; { TLazIPHtmlControlClipboardPopup } TLazIPHtmlControlClipboardPopup = class(TPopupMenu) private FCopy, FSelectAll: TMenuItem; FPanel: TLazIPHtmlControl; procedure DoCopy(Sender: TObject); procedure DoSelectAll(Sender: TObject); protected procedure DoPopup(Sender: TObject); override; public constructor Create(AOwner: TComponent; APanel: TLazIPHtmlControl); reintroduce; end; function IPCreateLazIDEHTMLControl(Owner: TComponent; var Provider: TAbstractIDEHTMLProvider; {%H-}Flags: TIDEHTMLControlFlags = []): TControl; procedure Register; implementation resourcestring ipdCopy = '&Copy'; ipdSelectAll = 'Select &all'; procedure Register; begin CreateIDEHTMLControl:=@IPCreateLazIDEHTMLControl; end; function IPCreateLazIDEHTMLControl(Owner: TComponent; var Provider: TAbstractIDEHTMLProvider; Flags: TIDEHTMLControlFlags = []): TControl; var HTMLControl: TLazIPHtmlControl; begin //debugln(['IPCreateLazIDEHTMLControl ']); HTMLControl:=TLazIPHtmlControl.Create(Owner); Result:=HTMLControl; if Provider=nil then Provider:=CreateIDEHTMLProvider(HTMLControl); //debugln(['IPCreateLazIDEHTMLControl Provider=',DbgSName(Provider)]); HTMLControl.IDEProvider:=Provider; if ihcWithClipboardMenu in Flags then TLazIPHtmlControlClipboardPopup.Create(Owner, HTMLControl); end; { TLazIPHtmlControlClipboardPopup } procedure TLazIPHtmlControlClipboardPopup.DoCopy(Sender: TObject); begin if FPanel.IPHTMLPanel <> nil then FPanel.IPHTMLPanel.CopyToClipboard; end; procedure TLazIPHtmlControlClipboardPopup.DoSelectAll(Sender: TObject); begin if FPanel.IPHTMLPanel <> nil then FPanel.IPHTMLPanel.SelectAll; end; procedure TLazIPHtmlControlClipboardPopup.DoPopup(Sender: TObject); begin if FPanel.IPHTMLPanel <> nil then FCopy.Enabled := FPanel.IPHTMLPanel.HaveSelection; inherited DoPopup(Sender); end; constructor TLazIPHtmlControlClipboardPopup.Create(AOwner: TComponent; APanel: TLazIPHtmlControl); begin inherited Create(AOwner); FPanel := APanel; AutoPopup := True; FCopy := TMenuItem.Create(Owner); FCopy.Caption := ipdCopy; FCopy.ShortCut := ShortCut(ord('C'), [ssCtrl]); FCopy.OnClick := @DoCopy; Items.Add(FCopy); FSelectAll := TMenuItem.Create(Owner); FSelectAll.Caption := ipdSelectAll; FSelectAll.ShortCut := ShortCut(ord('A'), [ssCtrl]); FSelectAll.OnClick := @DoSelectAll; Items.Add(FSelectAll); TControl(Owner).PopupMenu := Self; end; { TLazIpHtmlDataProvider } function TLazIpHtmlDataProvider.DoGetStream(const URL: string): TStream; begin //debugln(['TLazIpHtmlDataProvider.DoGetStream ',URL,' ',DbgSName(Control.IDEProvider)]); Result:=Control.IDEProvider.GetStream(URL,false); end; { TLazIPHtmlControl } function TLazIPHtmlControl.DataProviderCanHandle(Sender: TObject; const URL: string): Boolean; begin //debugln(['TLazIPHtmlControl.DataProviderCanHandle URL=',URL]); Result:=false; end; procedure TLazIPHtmlControl.DataProviderCheckURL(Sender: TObject; const URL: string; var Available: Boolean; var ContentType: string); begin //debugln(['TLazIPHtmlControl.DataProviderCheckURL URL=',URL]); Available:=false; ContentType:=''; end; procedure TLazIPHtmlControl.DataProviderGetHtml(Sender: TObject; const URL: string; const aPostData: TIpFormDataEntity; var Stream: TStream); begin //debugln(['TLazIPHtmlControl.DataProviderGetHtml URL=',URL]); Stream:=nil; end; procedure TLazIPHtmlControl.DataProviderGetImage(Sender: TIpHtmlNode; const URL: string; var Picture: TPicture); var URLType: string; URLPath: string; URLParams: string; Filename: String; Ext: String; Stream: TStream; NewURL: String; begin //DebugLn(['TIPLazHtmlControl.HTMLGetImageX URL=',URL]); if IDEProvider=nil then exit; NewURL:=IDEProvider.MakeURLAbsolute(IDEProvider.BaseURL,URL); //DebugLn(['TIPLazHtmlControl.HTMLGetImageX NewURL=',NewURL,' Provider.BaseURL=',IDEProvider.BaseURL,' URL=',URL]); Picture:=nil; Stream:=nil; try try SplitURL(NewURL,URLType,URLPath,URLParams); if URLPath='' then URLPath:=NewURL; Filename:=URLPathToFilename(URLPath); Ext:=ExtractFileExt(Filename); //DebugLn(['TIPLazHtmlControl.HTMLGetImageX URLPath=',URLPath,' Filename=',Filename,' Ext=',Ext]); Picture:=TPicture.Create; // quick check if file format is supported (raises an exception) Picture.FindGraphicClassWithFileExt(Ext); // get stream Stream:=IDEProvider.GetStream(NewURL,true); // load picture Picture.LoadFromStreamWithFileExt(Stream,Ext); finally if Stream<>nil then IDEProvider.ReleaseStream(NewURL); end; except on E: Exception do begin FreeAndNil(Picture); DebugLn(['TIPLazHtmlControl.HTMLGetImageX ERROR: ',E.Message]); end; end; end; procedure TLazIPHtmlControl.DataProviderLeave(Sender: TIpHtml); begin //debugln(['TLazIPHtmlControl.DataProviderLeave ']); end; procedure TLazIPHtmlControl.DataProviderReportReference(Sender: TObject; const URL: string); begin //debugln(['TLazIPHtmlControl.DataProviderReportReference URL=',URL]); end; procedure TLazIPHtmlControl.IPHTMLPanelHotClick(Sender: TObject); var HotNode: TIpHtmlNode; HRef: String; //Target: String; begin HotNode:=FIPHTMLPanel.HotNode; if HotNode is TIpHtmlNodeA then begin HRef := TIpHtmlNodeA(HotNode).HRef; //Target := TIpHtmlNodeA(HotNode).Target; end else begin HRef := TIpHtmlNodeAREA(HotNode).HRef; //Target := TIpHtmlNodeAREA(HotNode).Target; end; //debugln(['TLazIPHtmlControl.IPHTMLPanelHotClick HRef="',HRef,'" Target="',Target,'"']); IDEProvider.OpenURLAsync(HRef); end; procedure TLazIPHtmlControl.SetIDEProvider( const AValue: TAbstractIDEHTMLProvider); begin if FIDEProvider=AValue then exit; //debugln(['TLazIPHtmlControl.SetIDEProvider Old=',DbgSName(FIDEProvider),' New=',DbgSName(FIDEProvider)]); if FIDEProvider<>nil then begin IDEProvider.ControlIntf:=nil; end; FIDEProvider:=AValue; if FIDEProvider<>nil then begin FreeNotification(FIDEProvider); IDEProvider.ControlIntf:=Self; end; end; procedure TLazIPHtmlControl.Notification(AComponent: TComponent; Operation: TOperation); begin inherited Notification(AComponent, Operation); if Operation=opRemove then begin if IDEProvider=AComponent then begin if IDEProvider.ControlIntf=TIDEHTMLControlIntf(Self) then IDEProvider.ControlIntf:=nil; IDEProvider:=nil; end; end; end; constructor TLazIPHtmlControl.Create(AOwner: TComponent); begin inherited Create(AOwner); FIPHTMLPanel:=TIpHtmlPanel.Create(Self); with FIPHTMLPanel do begin Name:='TLazIPHtmlControl_IPHTMLPanel'; Align:=alClient; DefaultFontSize:=8; MarginHeight:=2; MarginWidth:=2; Parent:=Self; WantTabs := False; OnHotClick:=@IPHTMLPanelHotClick; end; FIPHTMLPanel.DataProvider:=TLazIpHtmlDataProvider.Create(FIPHTMLPanel); with TLazIpHtmlDataProvider(FIPHTMLPanel.DataProvider) do begin FControl:=Self; Name:='TLazIPHtmlControl_DataProvider'; OnCanHandle:=@DataProviderCanHandle; OnGetHtml:=@DataProviderGetHtml; OnGetImage:=@DataProviderGetImage; OnLeave:=@DataProviderLeave; OnCheckURL:=@DataProviderCheckURL; OnReportReference:=@DataProviderReportReference; end; Caption:=''; BevelInner:=bvLowered; end; destructor TLazIPHtmlControl.Destroy; begin //debugln(['TLazIPHtmlControl.Destroy ',DbgSName(Self),' ',dbgs(Pointer(Self))]); FreeAndNil(FIDEProvider); inherited Destroy; end; function TLazIPHtmlControl.GetURL: string; begin Result:=FURL; end; procedure TLazIPHtmlControl.SetURL(const AValue: string); var Stream: TStream; NewHTML: TIpHtml; NewURL: String; begin if IDEProvider=nil then raise Exception.Create('TIPLazHtmlControl.SetURL missing Provider'); if FURL=AValue then exit; NewURL:=IDEProvider.MakeURLAbsolute(IDEProvider.BaseURL,AValue); if FURL=NewURL then exit; FURL:=NewURL; try Stream:=IDEProvider.GetStream(FURL,true); try NewHTML:=TIpHtml.Create; // Beware: Will be freed automatically TIpHtmlPanel FIPHTMLPanel.SetHtml(NewHTML); NewHTML.LoadFromStream(Stream); finally IDEProvider.ReleaseStream(FURL); end; except on E: Exception do begin MessageDlg('Unable to open HTML file', 'URL: '+FURL+#13 +'Error: '+E.Message,mtError,[mbCancel],0); end; end; end; procedure TLazIPHtmlControl.SetHTMLContent(Stream: TStream; const NewURL: string ); var NewHTML: TIpHtml; begin FURL:=NewURL; try NewHTML:=TIpHtml.Create; // Beware: Will be freed automatically TIpHtmlPanel FIPHTMLPanel.SetHtml(NewHTML); NewHTML.LoadFromStream(Stream); except on E: Exception do begin MessageDlg('Unable to load HTML stream', 'URL: '+FURL+#13 +'Error: '+E.Message,mtError,[mbCancel],0); end; end; end; procedure TLazIPHtmlControl.GetPreferredControlSize(out AWidth, AHeight: integer); begin AWidth:=0; AHeight:=0; inherited GetPreferredSize(AWidth, AHeight); end; end.