lazarus/lcl/include/clipbrd.inc

909 lines
25 KiB
PHP

{%MainUnit ../clipbrd.pp}
{******************************************************************************
TClipBoard
******************************************************************************
*****************************************************************************
This file is part of the Lazarus Component Library (LCL)
See the file COPYING.modifiedLGPL.txt, included in this distribution,
for details about the license.
*****************************************************************************
The clipboard is able to work with the windows and gtk behaviour/features.
}
{$I clipbrd_html.inc}
{ TClipboard }
constructor TClipboard.Create;
begin
// default: create a normal Clipboard
Create(ctClipboard);
end;
constructor TClipboard.Create(AClipboardType: TClipboardType);
begin
//DebugLn('[TClipboard.Create] A ',ClipboardTypeName[AClipboardType],' Self=',DbgS(Self));
inherited Create;
FClipboardType:=AClipboardType;
end;
destructor TClipboard.Destroy;
begin
//DebugLn('[TClipboard.Destroy] A ',ClipboardTypeName[ClipboardType],' Self=',DbgS(Self));
OnRequest:=nil; // this will notify the owner
if FAllocated then begin
ClipboardGetOwnership(ClipboardType,nil,0,nil);
FAllocated:=false;
end;
Clear;
inherited Destroy;
//DebugLn('[TClipboard.Destroy] END ',ClipboardTypeName[ClipboardType]);
end;
function TClipboard.IndexOfCachedFormatID(FormatID: TClipboardFormat;
CreateIfNotExists: boolean): integer;
var
NewSize: integer;
FormatAdded: Boolean;
begin
//DebugLn('[TClipboard.IndexOfCachedFormatID] A ',ClipboardTypeName[ClipboardType]
//,' Format=',FormatID,' CreateIfNotExists=',CreateIfNotExists);
if FormatID=0 then begin
Result:=-1;
if CreateIfNotExists then
raise Exception.Create(
'IndexOfCachedFormatID: Internal Error: invalid FormatID 0 for '+
ClipboardTypeName[ClipboardType]);
end;
Result:=FCount-1;
while (Result>=0) and (FData[Result].FormatID<>FormatID) do
dec(Result);
FormatAdded:=false;
if (Result<0) and CreateIfNotExists then begin
// add new format
inc(FCount);
NewSize:=SizeOf(TClipboardData)*FCount;
ReallocMem(FData,NewSize);
Result:=FCount-1;
FData[Result].FormatID:=FormatID;
FData[Result].Stream:=TMemoryStream.Create;
FSupportedFormatsChanged:=true;
FormatAdded:=true;
end;
if not IsUpdating then begin
// CreateIfNotExists = true means changing the clipboard
// => we need OwnerShip for that
if CreateIfNotExists and (not GetOwnerShip) then begin
// getting ownership failed
if FormatAdded then begin
// undo: remove added format
// Note: This creates a little overhead in case of an error, but reduces
// overhead in case of everything works
FData[Result].Stream.Free;
NewSize:=SizeOf(TClipboardData)*FCount;
ReallocMem(FData,NewSize);
end;
Result:=-1;
raise Exception.Create('Unable to get clipboard ownership for '+
ClipboardTypeName[ClipboardType]);
end;
end;
//DebugLn('[TClipboard.IndexOfCachedFormatID] END ',ClipboardTypeName[ClipboardType]
//,' Format=',FormatID,' CreateIfNotExists=',CreateIfNotExists,' Result=',Result);
end;
function TClipboard.AddFormat(FormatID: TClipboardFormat;
Stream: TStream): Boolean;
// copy Stream to a MemoryStream, add it to cache and tell the interface object
var
OldPosition: TStreamSeekType;
i: integer;
begin
//DebugLn('[TClipboard.AddFormat - Stream] A ',ClipboardTypeName[ClipboardType],' Format=',FormatID);
Result:=false;
BeginUpdate;
try
i:=IndexOfCachedFormatID(FormatID,true);
if i<0 then exit;
if FData[i].Stream<>Stream then begin
if Stream<>nil then begin
OldPosition:=Stream.Position;
FData[i].Stream.LoadFromStream(Stream);
Stream.Position:=OldPosition;
end else
FData[i].Stream.Clear;
FSupportedFormatsChanged:=true;
end;
finally
Result:=EndUpdate;
end;
end;
function TClipboard.AddFormat(FormatID: TClipboardFormat;
var Buffer; Size: Integer): Boolean;
var i: integer;
begin
//DebugLn('[TClipboard.AddFormat - Buffer] A ',ClipboardTypeName[ClipboardType],' Format=',FormatID,' Size=',Size);
Result:=false;
BeginUpdate;
try
i:=IndexOfCachedFormatID(FormatID,true);
if i<0 then exit;
FData[i].Stream.Clear;
if Size>0 then
FData[i].Stream.Write(Buffer,Size);
finally
Result:=EndUpdate;
end;
end;
function TClipboard.SetFormat(FormatID: TClipboardFormat;
Stream: TStream): Boolean;
// copy Stream to a MemoryStream, set the cache and tell the interface object
begin
BeginUpdate;
try
Clear;
AddFormat(FormatID,Stream);
finally
Result:=EndUpdate;
end;
end;
procedure TClipboard.Clear;
var i: integer;
begin
//DebugLn('[TClipboard.Clear] A ',ClipboardTypeName[ClipboardType]);
if FData<>nil then begin
for i:=0 to FCount-1 do
FData[i].Stream.Free;
FreeMem(FData,SizeOf(TClipboardData)*FCount);
FData:=nil;
end;
FCount:=0;
//DebugLn('[TClipboard.Clear] END ',ClipboardTypeName[ClipboardType]);
end;
procedure TClipboard.Open;
// Open and Closed must be balanced.
// When the Clipboard is Open, it will not read/write from/to the interface.
// Instead it will collect all changes until Close is called.
// It will then try to commit all changes as one block.
begin
BeginUpdate;
end;
procedure TClipboard.Close;
begin
EndUpdate;
end;
procedure TClipboard.InternalOnRequest(
const RequestedFormatID: TClipboardFormat; AStream: TStream);
begin
//DebugLn('[TClipboard.InternalOnRequest] A ',ClipboardTypeName[ClipboardType]
//,' RequestedFormatID=',RequestedFormatID,' AStream=',AStream<>nil,' Allocated=',FAllocated);
if not FAllocated then exit;
if (RequestedFormatID=0) then begin
// loosing ownership
FAllocated:=false;
if Assigned(FOnRequest) then FOnRequest(RequestedFormatID,AStream);
FOnRequest:=nil;
end else begin
GetFormat(RequestedFormatID,AStream);
end;
end;
function TClipboard.GetOwnerShip: boolean;
var
FormatList: PClipboardFormat;
i: integer;
begin
if (not FAllocated) or FSupportedFormatsChanged then begin
GetMem(FormatList,SizeOf(TClipboardFormat)*FCount);
for i:=0 to FCount-1 do
FormatList[i]:=FData[i].FormatID;
//DebugLn(['[TClipboard.GetOwnerShip] A ',ClipboardTypeName[ClipboardType],' Allocated=',FAllocated]);
FAllocated:=true;
if not ClipboardGetOwnerShip(ClipboardType,@InternalOnRequest,FCount,
FormatList)
then
FAllocated:=false;
FreeMem(FormatList);
FSupportedFormatsChanged:=false;
end;
Result:=FAllocated;
//DebugLn('[TClipboard.GetOwnerShip] END ',ClipboardTypeName[ClipboardType],' Allocated=',FAllocated);
end;
procedure TClipboard.SetOnRequest(AnOnRequest: TClipboardRequestEvent);
begin
if Assigned(FOnRequest) then
// tell the old owner, that it lost the ownership
FOnRequest(0,nil);
FOnRequest:=AnOnRequest;
end;
procedure TClipboard.BeginUpdate;
begin
Inc(FOpenRefCount);
end;
function TClipboard.EndUpdate: Boolean;
begin
if FOpenRefCount = 0 then
RaiseGDBException('TClipboard.EndUpdate');
Result:=true;
Dec(FOpenRefCount);
if FOpenRefCount = 0 then begin
if FSupportedFormatsChanged then begin
Result:=GetOwnerShip;
if not Result then
Clear;
end;
end;
end;
function TClipboard.IsUpdating: Boolean;
begin
Result:=FOpenRefCount>0;
end;
function TClipboard.CanReadFromInterface: Boolean;
begin
Result:=FAllocated and (not IsUpdating);
end;
function TClipboard.CanReadFromCache: Boolean;
begin
Result:=FAllocated or IsUpdating;
end;
procedure TClipboard.OnDefaultFindClass(Reader: TReader;
const AClassName: string; var ComponentClass: TComponentClass);
var
PersistentClass: TPersistentClass;
begin
if Reader=nil then ;
PersistentClass:=FindClass(AClassName);
if (PersistentClass<>nil) and (PersistentClass.InheritsFrom(TComponent)) then
ComponentClass:=TComponentClass(PersistentClass);
end;
function TClipboard.GetFormat(FormatID: TClipboardFormat;
Stream: TStream): Boolean;
// request data from interface object or copy cached data to Stream
var i: integer;
begin
//DebugLn('[TClipboard.GetFormat] A ',ClipboardTypeName[ClipboardType],' FormatID=',FormatID,' ',ClipboardFormatToMimeType(FormatID),' Allocated=',fAllocated);
Result:=false;
if Stream=nil then exit;
if FormatID=0 then exit;
if CanReadFromCache then begin
if Assigned(FOnRequest) then begin
FOnRequest(FormatID,Stream);
Result:=true;
end else begin
i:=IndexOfCachedFormatID(FormatID,false);
if i<0 then
Result:=false
else begin
FData[i].Stream.Position:=0;
if Stream is TMemoryStream then
TMemoryStream(Stream).SetSize(Stream.Position+FData[i].Stream.Size);
Stream.CopyFrom(FData[i].Stream,FData[i].Stream.Size);
Result:=true;
end;
end;
end else begin
// not the clipboard owner -> request data
Result:=ClipboardGetData(ClipboardType,FormatID,Stream);
end;
//DebugLn('[TClipboard.GetFormat] END ',ClipboardTypeName[ClipboardType],' FormatID=',FormatID,' Result=',Result);
end;
function TClipboard.SetComponent(Component: TComponent): Boolean;
var
i: integer;
s: TMemoryStream;
begin
BeginUpdate;
try
i:=IndexOfCachedFormatID(PredefinedClipboardFormat(pcfComponent),true);
s:=FData[i].Stream;
s.Clear;
WriteComponentAsBinaryToStream(s,Component);
s.Position:=0;
FSupportedFormatsChanged:=true;
finally
Result:=EndUpdate;
end;
end;
function TClipboard.SetComponentAsText(Component: TComponent): Boolean;
var
MemStream: TMemoryStream;
s: string;
begin
BeginUpdate;
MemStream:=nil;
try
MemStream:=TMemoryStream.Create;
WriteComponentAsTextToStream(MemStream,Component);
SetLength(s,MemStream.Size);
MemStream.Position:=0;
if s<>'' then
MemStream.Read(s[1],length(s));
AsText:=s;
finally
MemStream.Free;
Result:=EndUpdate;
end;
end;
function TClipboard.GetComponent(Owner, Parent: TComponent): TComponent;
begin
Result:=nil;
GetComponent(Result,@OnDefaultFindClass,Owner,Parent);
end;
procedure TClipboard.GetComponent(var RootComponent: TComponent;
OnFindComponentClass: TFindComponentClassEvent; Owner: TComponent;
Parent: TComponent);
var
MemStream: TMemoryStream;
begin
MemStream:=TMemoryStream.Create;
try
if GetFormat(PredefinedClipboardFormat(pcfComponent),MemStream) then begin
MemStream.Position := 0;
ReadComponentFromBinaryStream(MemStream,RootComponent,
OnFindComponentClass,Owner,Parent);
end;
finally
MemStream.Free;
end;
end;
procedure TClipboard.GetComponentAsText(var RootComponent: TComponent;
OnFindComponentClass: TFindComponentClassEvent; Owner: TComponent;
Parent: TComponent);
var
s: String;
MemStream: TMemoryStream;
begin
MemStream:=nil;
try
MemStream:=TMemoryStream.Create;
s:=AsText;
if s<>'' then
MemStream.Write(s[1],length(s));
MemStream.Position:=0;
ReadComponentFromTextStream(MemStream,RootComponent,OnFindComponentClass,
Owner,Parent);
finally
MemStream.Free;
end;
end;
function TClipboard.SetBuffer(FormatID: TClipboardFormat;
var Buffer; Size: Integer): Boolean;
var i: integer;
begin
BeginUpdate;
try
i:=IndexOfCachedFormatID(FormatID,true);
FData[i].Stream.Clear;
if Size>0 then begin
FData[i].Stream.Write(Buffer,Size);
FData[i].Stream.Position:=0;
end;
FSupportedFormatsChanged:=true;
finally
Result:=EndUpdate;
end;
end;
procedure TClipboard.SetTextBuf(Buffer: PChar);
begin
if Buffer=nil then Buffer:=#0;
SetBuffer(PredefinedClipboardFormat(pcfText),Buffer^,StrLen(Buffer)+1);
end;
function TClipboard.GetTextBuf(Buffer: PChar; BufSize: Integer): Integer;
var MemStream: TMemoryStream;
begin
Result:=0;
if (Buffer=nil) or (BufSize=0) then exit;
MemStream:=TMemoryStream.Create;
try
if GetFormat(PredefinedClipboardFormat(pcfText),MemStream) then begin
MemStream.Position:=0;
Result:=BufSize;
if Result>MemStream.Size then Result:=integer(MemStream.Size);
if Result>0 then
MemStream.Read(Buffer^,Result);
Buffer[Result]:=#0;
Result:=StrLen(Buffer);
end;
finally
MemStream.Free;
end;
end;
procedure TClipboard.SetAsText(const Value: string);
var s: string;
i: Integer;
begin
//DebugLn('[TClipboard.SetAsText] A ',ClipboardTypeName[ClipboardType],' "',Value,'"');
if Assigned(FOnRequest) then exit;
if Value<>'' then
s:=Value
else
s:=#0;
Clear;
i := Length(Value);
if ClipboardFormatNeedsNullByte(pcfText) then
i := i + 1;
SetBuffer(PredefinedClipboardFormat(pcfText),s[1],i);
//DebugLn('[TClipboard.SetAsText] END ',ClipboardTypeName[ClipboardType],' "',Value,'"');
end;
function TClipboard.GetAsText: string;
var
MemStream: TMemoryStream;
ASize: int64;
begin
//DebugLn('[TClipboard.GetAsText] A ',ClipboardTypeName[ClipboardType]);
Result:='';
MemStream:=TMemoryStream.Create;
try
if GetFormat(PredefinedClipboardFormat(pcfText),MemStream) then begin
ASize:=MemStream.Size;
if (ASize>0) and (pchar(MemStream.Memory)[ASize-1]=#0) then
Dec(ASize);
MemStream.Position:=0;
SetLength(Result,ASize);
if ASize>0 then
MemStream.Read(Result[1],ASize);
end;
finally
MemStream.Free;
end;
//DebugLn('[TClipboard.GetAsText] END ',ClipboardTypeName[ClipboardType],' "',dbgstr(Result),'"');
end;
procedure TClipboard.SupportedFormats(List: TStrings);
var cnt, i: integer;
FormatList: PClipboardFormat;
begin
//DebugLn('[TClipboard.SupportedFormats]');
List.Clear;
if CanReadFromCache then begin
for i:=0 to FCount-1 do
List.Add(ClipboardFormatToMimeType(FData[i].FormatID));
end else begin
FormatList:=nil;
if ClipboardGetFormats(ClipboardType,cnt,FormatList) then begin
for i:=0 to cnt-1 do
List.Add(ClipboardFormatToMimeType(FormatList[i]));
end;
if FormatList<>nil then FreeMem(FormatList);
end;
end;
procedure TClipboard.SupportedFormats(var AFormatCount: integer;
var FormatList: PClipboardFormat);
var i: integer;
begin
AFormatCount:=0;
FormatList:=nil;
if CanReadFromCache then begin
if (FCount>0) then begin
GetMem(FormatList,SizeOf(TClipBoardFormat)*FCount);
for i:=0 to FCount-1 do
FormatList[i]:=FData[i].FormatID;
AFormatCount:=FCount;
end;
end else begin
ClipboardGetFormats(ClipboardType,AFormatCount,FormatList);
end;
end;
function TClipboard.SetSupportedFormats(AFormatCount: integer;
FormatList: PClipboardFormat): Boolean;
var i: integer;
begin
BeginUpdate;
try
Clear;
FCount:=AFormatCount;
GetMem(FData,SizeOf(TClipboardData)*FCount);
for i:=0 to FCount-1 do begin
FData[i].FormatID:=FormatList[i];
FData[i].Stream:=TMemoryStream.Create;
end;
FSupportedFormatsChanged:=true;
finally
Result:=EndUpdate;
end;
end;
function TClipboard.FindPictureFormatID: TClipboardFormat;
var
List: PClipboardFormat;
cnt, i: integer;
begin
//DebugLn('[TClipboard.FindPictureFormatID]');
List:=nil;
Result:=0;
cnt:=0;
try
if not CanReadFromCache then begin
if not ClipboardGetFormats(ClipboardType,cnt,List) then
exit;
for i:=0 to cnt-1 do begin
Result:=List[i];
if TPicture.SupportsClipboardFormat(Result) then
exit;
end;
end else begin
for i:=FCount-1 downto 0 do begin
Result:=FData[i].FormatID;
if TPicture.SupportsClipboardFormat(Result) then
exit;
end;
end;
finally
if List<>nil then FreeMem(List);
end;
Result:=0;
end;
function TClipboard.FindFormatID(const FormatName: string): TClipboardFormat;
var
List: PClipboardFormat;
cnt, i: integer;
begin
//DebugLn('[TClipboard.FindPictureFormatID]');
List:=nil;
Result:=0;
cnt:=0;
try
if not CanReadFromCache then begin
if not ClipboardGetFormats(ClipboardType,cnt,List) then
exit;
for i:=0 to cnt-1 do begin
Result:=List[i];
if CompareText(ClipboardFormatToMimeType(Result),FormatName)=0 then
exit;
end;
end else begin
for i:=FCount-1 downto 0 do begin
Result:=FData[i].FormatID;
if CompareText(ClipboardFormatToMimeType(Result),FormatName)=0 then
exit;
end;
end;
finally
if List<>nil then FreeMem(List);
end;
Result:=0;
end;
function TClipboard.HasPictureFormat: boolean;
begin
Result:=FindPictureFormatID<>0;
end;
function TClipboard.HasFormat(FormatID: TClipboardFormat): Boolean;
// ask widgetset
var List: PClipboardFormat;
cnt, i: integer;
begin
//DebugLn('[TClipboard.HasFormat] A ',ClipboardTypeName[ClipboardType],' Allocated=',FAllocated);
if FormatID<>0 then begin
if CanReadFromCache then
Result := (IndexOfCachedFormatID(FormatID,false)>=0)
else begin
if not ClipboardGetFormats(ClipboardType,cnt,List) then begin
Result:=false;
exit;
end;
i:=0;
//for i:=0 to cnt-1 do
//DebugLn('[TClipboard.HasFormat] ',FormatID,' ',List[i]);
while (i<cnt) and (List[i]<>FormatID) do inc(i);
Result := i<cnt;
if List<>nil then FreeMem(List);
end;
if not Result then begin
Result := (PredefinedClipboardFormat(pcfPicture)=FormatID) and (HasPictureFormat);
end;
end else
Result:=false;
//DebugLn('[TClipboard.HasFormat] END ',ClipboardTypeName[ClipboardType],' FormatID=',FormatID,' Result=',Result);
end;
function TClipboard.HasFormatName(const FormatName: string): Boolean;
begin
Result:=FindFormatID(FormatName)<>0;
end;
procedure TClipboard.AssignToPicture(Dest: TPicture);
var
FormatID: TClipboardFormat;
begin
FormatID:=FindPictureFormatID;
if FormatID=0 then exit;
Dest.LoadFromClipboardFormatID(ClipboardType,FormatID);
end;
procedure TClipboard.AssignPicture(Source: TPicture);
begin
AssignGraphic(Source.Graphic);
end;
function TClipboard.AssignToGraphic(Dest: TGraphic): boolean;
var
MimeTypes: TStringList;
i: Integer;
GraphicFormatID: TClipboardFormat;
begin
Result:=false;
MimeTypes:=TStringList.Create;
try
Dest.GetSupportedSourceMimeTypes(MimeTypes);
for i:=0 to MimeTypes.Count-1 do begin
GraphicFormatID:=FindFormatID(MimeTypes[i]);
if GraphicFormatID<>0 then begin
AssignToGraphic(Dest,GraphicFormatID);
Result:=true;
exit;
end;
end;
finally
MimeTypes.Free;
end;
end;
function TClipboard.AssignToGraphic(Dest: TGraphic; FormatID: TClipboardFormat
): boolean;
var
MemStream: TMemoryStream;
begin
Result:=false;
if FormatID=0 then exit;
MemStream:=TMemoryStream.Create;
try
if not GetFormat(FormatID,MemStream) then exit;
MemStream.Position:=0;
Dest.LoadFromMimeStream(MemStream,ClipboardFormatToMimeType(FormatID));
finally
MemStream.Free;
end;
Result:=true;
end;
procedure TClipboard.AssignGraphic(Source: TGraphic);
var
MimeType: String;
FormatID: TClipboardFormat;
begin
MimeType := Source.MimeType;
FormatID:=ClipboardRegisterFormat(MimeType);
if FormatID<>0 then
AssignGraphic(Source,FormatID);
end;
procedure TClipboard.AssignGraphic(Source: TGraphic; FormatID: TClipboardFormat);
var
MemStream: TMemoryStream;
begin
MemStream:=TMemoryStream.Create;
try
Source.SaveToStream(MemStream);
MemStream.Position:=0;
SetFormat(FormatID,MemStream);
finally
MemStream.Free;
end;
end;
procedure TClipboard.Assign(Source: TPersistent);
begin
if Source is TPicture then
AssignPicture(TPicture(Source))
else if Source is TGraphic then
AssignGraphic(TGraphic(Source))
else
inherited Assign(Source);
end;
procedure TClipboard.AssignTo(Dest: TPersistent);
begin
if Dest is TPicture then
AssignToPicture(TPicture(Dest))
else if Dest is TGraphic then
AssignToGraphic(TGraphic(Dest))
else
inherited AssignTo(Dest);
end;
function TClipboard.GetFormatCount: Integer;
// ask widgetset
var List: PClipboardFormat;
begin
//DebugLn('[TClipboard.GetFormatCount]');
if CanReadFromCache then
Result:=FCount
else begin
Result:=0;
if ClipboardGetFormats(ClipboardType,Result,List) then begin
if List<>nil then FreeMem(List);
end else
Result:=0;
end;
end;
function TClipboard.GetFormats(Index: Integer): TClipboardFormat;
var
List: PClipboardFormat;
cnt: integer;
begin
//DebugLn('[TClipboard.GetFormats] Index=',Index);
if CanReadFromCache then begin
if (Index<0) or (Index>=FCount) then
raise Exception.Create('TClipboard.GetFormats: Index out of bounds: Index='
+IntToStr(Index)+' Count='+IntToStr(FCount));
Result:=FData[Index].FormatID;
end else begin
if ClipboardGetFormats(ClipboardType,cnt,List) then begin
if (Index>=0) and (Index<cnt) then
Result:=List[Index]
else
Result:=0;
if List<>nil then FreeMem(List);
end else
Result:=0;
end;
end;
{ Retrieves html formatted text from the clipboard. If ExtractFragmentOnly is
true then only the relevant html fragment is returned, the rest of the html
string is dropped. The Office applications in Windows and Linux write the
full html code which can be retrieved with ExtractFragmentOnly = false.
In case of Windows, the MS header is automatically removed.}
function TClipboard.GetAsHtml(ExtractFragmentOnly: Boolean): String;
var
Stream: TMemoryStream;
bom: TBOM;
US: UnicodeString;
begin
//debugln(['TClipboard.GetAsHtml: ExtractFragmentOnly = ',ExtractFragmentOnly]);
Result := '';
if (CF_HTML = 0) or not HasFormat(CF_HTML) then
begin
//debugln(['TClipboard.GetAsHtml: CF_HTML= ',CF_HTML,' HasFormat(CF_HTML) = ',HasFormat(CF_HTML)]);
exit;
end;
Stream := TMemoryStream.Create;
try
if not GetFormat(CF_HTML, Stream) then
begin
//debugln(['TClipboard.GetAsHtml: GetFormat(CF_HTML, stream) = False']);
exit;
end;
Stream.Write(#0#0, Length(#0#0));
bom := GetBomFromStream(Stream);
case Bom of
bomUtf8:
begin
Stream.Position := 3;
SetLength(Result, Stream.Size - 3);
Stream.Read(Result, Stream.Size - 3);
//ClipBoard may return a larger Stream than the size of the string
//this gets rid of it, since the string will end in a #0 (wide)char
Result := PAnsiChar(Result);
//debugln(['TClipboard.GetAsHtml: Found bomUtf8']);
end;
bomUTF16LE:
begin
Stream.Position := 2;
SetLength(US, Stream.Size - 2);
Stream.Read(US[1], Stream.Size - 2);
//ClipBoard may return a larger Stream than the size of the string
//this gets rid of it, since the string will end in a #0 (wide)char
US := PWideChar(US);
Result := Utf16ToUtf8(US);
//debugln(['TClipboard.GetAsHtml: FoundbomUtf16LE']);
end;
bomUtf16BE:
begin
//this may need swapping of WideChars????
Stream.Position := 2;
SetLength(US, Stream.Size - 2);
Stream.Read(US[1], Stream.Size - 2);
//ClipBoard may return a larger Stream than the size of the string
//this gets rid of it, since the string will end in a #0 (wide)char
US := PWideChar(US);
Result := Utf16ToUtf8(US);
//debugln(['TClipboard.GetAsHtml: Found bomUtf16BE']);
end;
bomUndefined:
begin
//assume the first byte is part of the string and it is some AnsiString
//CF_HTML returns a string encoded as UTF-8 on Windows
Result := PAnsiChar(Stream.Memory);
//debugln(['TClipboard.GetAsHtml: Found bomUndefined']);
end;
end;
if (Result <> '') then begin
if ExtractFragmentOnly then
Result := ExtractHtmlFragmentFromClipBoardHtml(Result)
{$IFDEF WINDOWS}
else
Result := ExtractHtmlFromClipboardHtml(Result);
{$ENDIF}
end;
finally
Stream.Free;
end;
end;
{ Adds html-formatted text to the clipboard. The main Office applications in
Windows and Linux require a valid and complete html text (i.e. with <html>
and <body> tags), therefore we insert them if they are not present.
In case of Windows, a specific header will be added,
otherwise the format will not be recognized by the clipboard.
}
procedure TClipboard.SetAsHtml(Html: String; const PlainText: String);
var
Stream: TStream;
IsValid: Boolean;
begin
if CF_HTML = 0 then
exit;
//If the HTML does not have correct <html><body> and closing </body></html> insert them
MaybeInsertHtmlAndBodyTags(HTML, IsValid);
if not IsValid then
exit;
{$IFDEF WINDOWS}
Stream := TStringStream.Create(InsertClipHeader(Html), DefaultSystemCodePage);
{$ELSE}
Stream := TStringStream.Create(Html);
{$ENDIF}
try
Stream.Position := 0;
Clipboard.AddFormat(CF_HTML, Stream);
if (PlainText <> '') then
begin
Stream.Size := 0;
Stream.Position := 0;
Stream.WriteBuffer(Pointer(PlainText)^, Length(PlainText)+1); //Also write terminating zero
Stream.Position := 0;
ClipBoard.AddFormat(CF_TEXT, Stream);
end;
finally
Stream.Free;
end;
end;
procedure TClipboard.SetAsHtml(Html: String);
begin
SetAsHtml(Html, '');
end;