Lazarus

Programming => Packages and Libraries => RichMemo => Topic started by: rick2691 on September 03, 2021, 01:34:47 pm

Title: CopyToClipboard
Post by: rick2691 on September 03, 2021, 01:34:47 pm
I am trying to use CopyToClipboard and PasteFromClipboard because they are the only way that I have found where text and formatting attributes can be transferred together. In particular I am wanting my Search and Replace functions to replace with both text and formatting.

What I have encountered is that CopyToClipboard can be hit, miss, and otherwise late on delivery. So I hear a horn warning, but the code keeps running without a proper execution.

Oddly, if I activate a showmessage('message'), just after CopyToClipboard, it performs correctly every time. But doing the same with sleep(1000), or at any value, it does not execute properly. So 'showmessage' is doing something different from 'sleep'.

Moreover, the hit and miss behavior is that the identical code in another 'begin ... end' section will have no problem at all. Yet if I use CopyToClipboard and PasteFromClipboard  in a 'replace every occurrence' routine it will miss all but the first instance.

However, the same routines with using PageMemo.SelText:=ReplaceBox.Lines.Text, instead of the clipboard functions is always faithful ... but I lose all of the formatting. Wherewith I have to do a CopyToClipboard as an independent function; then do a search; then activate an independent PasteFromClipboard again; in order to retain the formatting. Oddly, CopyToClipboard and PasteFromClipboard will always perform properly with that method.

So what's up with CopyToClipboard?

Title: Re: CopyToClipboard
Post by: skalogryz on September 04, 2021, 05:24:15 am
is it Windows? or Gtk?
---
I've just committed CopyRichText() function under RichMemoUtils.
You might want to try to use, instead of clipboard operations.

It should copy the text formatting, BUT it will not copy paragraph formatting (and this is something yet to be done)
Title: Re: CopyToClipboard
Post by: rick2691 on September 04, 2021, 10:38:40 am
Thank you much! I will try to find it.

I am using Windows 10.
Title: Re: CopyToClipboard
Post by: rick2691 on September 04, 2021, 12:33:27 pm
Code: Pascal  [Select][+][-]
  1. SearchBox.clear;  // RTF container
  2. CopySum:= CopyRichText(PageMemo, // RTF container
  3.                                          PageMemo.SelStart,
  4.                                          PageMemo.SelLength,
  5.                                          SearchBox, // RTF container
  6.                                          SearchBox.SelStart,
  7.                                          SearchBox.SelLength,
  8.                                          []);
  9.  

The above is my implementation. It worked perfectly. Thank you much!!

I have a couple of questions:
How might I employ CopySum?
What options can I add to []?
Title: Re: CopyToClipboard
Post by: skalogryz on September 08, 2021, 01:40:45 am
How might I employ CopySum?
what is CopySum?

What options can I add to []?
There's only one option available currently "coCopyBuf".
It forces the copy of the formatted text to be done via an intermediate buffer.

It is always used (even if not specified), if the source and destination of the copy is the same richmemo. Can be specified when the text is copied over from different richmemos.
Title: Re: CopyToClipboard
Post by: rick2691 on September 12, 2021, 01:48:47 pm
CopyRichText returns a lonint, so I assume that it is the length (sum) of what is copied. Since you ask the question, I now assume that it is something different. What is it, and how do I use it?
Title: Re: CopyToClipboard
Post by: skalogryz on September 13, 2021, 05:29:36 pm
CopyRichText() returns the number of characters copied over.
Usually it is expected to be equal to the number specified by SrcLen.
However, SrcLen can be set to -1 (meaning default whatever number of text is available). In this case the function returns the actual number of characters copied.
Title: Re: CopyToClipboard
Post by: rick2691 on September 14, 2021, 07:23:52 pm
I was testing what attributes can be copied. I found that the text comes through but the colors are hit and miss. I also found that superscript and subscript are copied as text, but not with the attributes.

Then it all crashed. RichMemo reverted to an older version without the RichMemoUtils. I also cannot reinstall the new RichMemo. It has problems with the QT files.

Rick
Title: Re: CopyToClipboard
Post by: skalogryz on September 14, 2021, 07:45:39 pm
I was testing what attributes can be copied. I found that the text comes through but the colors are hit and miss. I also found that superscript and subscript are copied as text, but not with the attributes.
that is interesting. I presume you're trying richmemo with Qt5?

It has problems with the QT files.
what problem?
Title: Re: CopyToClipboard
Post by: rick2691 on September 14, 2021, 08:12:55 pm
No, I am not trying or using it. However, I reinstalled Lazarus, then I tried to reinstall RichMemo. It took several tries, but then I succeeded. Installing packages is not an intuitive process, and nobody (by what I have not found) has posted the rules.

Nevertheless, I am operating again. What stands is that "Size8, Size16, Size12, Strike, Italic, Bold, Underscore, and ColorRed" are being copied. Unfortunately, my RTF search box is also highlighting the import, and that is automatically turning all colors to the first color ... black. But nothing is highlighted (selected) with my RTF replace box, so it is keeping the color.

But superscript and subscript is being copied without the attributes ... and causing a crash. With this rebuild I am not even attempting to test them.

Rick
Title: Re: CopyToClipboard
Post by: skalogryz on September 14, 2021, 08:30:15 pm
are you using Win32 or Qt widgetset?
Title: Re: CopyToClipboard
Post by: rick2691 on September 15, 2021, 11:52:06 am
I am using Win32. The QT got activated because RichMemo was corrupted by the crash.
Title: Re: CopyToClipboard
Post by: rick2691 on September 15, 2021, 12:21:26 pm
I have updated my account signature.

I am attempting to RichCopy the following ...

Size8 Size16 Size12 Strike Italic Bold
Underscore ColorRed Superscript Subscript

... where each word describes its attribute.

If I copy Size8 through ColorRed it works perfectly.
If I copy Size8 through Superscript it works until it hits Superscript ... which has no attribute.
If I swap Superscript and Subscript it does the same on Subscript ... no attribute.
If I include both Superscript and Subscript it hangs, and I have to hit the STOP button to recover.

I may have hit the Windows TaskManager and EndTask for Laz when it had crashed.
Title: Re: CopyToClipboard
Post by: rick2691 on September 15, 2021, 05:20:44 pm
I am finding that when a plain-word is selected, and sent by CopyRichText to the Search box, it frequently converts it to italics. The following is my code to do so ...

Code: Pascal  [Select][+][-]
  1. PagePassive:= true;
  2.           PageMemoOn:= false;
  3.           SearchBoxOn:= true;
  4.           ReplaceBoxOn:= false;
  5.           FindActive:= false;
  6.           SearchPanel.Visible:= true;
  7.  
  8.           SearchBox.clear;
  9.           SearchBox.SelStart:= 1;
  10.           SearchBox.SelLength:= 0;
  11.  
  12.           ReplaceBox.clear;
  13.           ReplaceBox.SelStart:= 1;
  14.           ReplaceBox.SelLength:= 0;
  15.  
  16.           SentLength:= CopyRichText(PageMemo,        // substitute for CopyToClipboard & PasteFromClipboard
  17.                                     PageMemo.SelStart,
  18.                                     PageMemo.SelLength,
  19.                                     SearchBox,
  20.                                     SearchBox.SelStart,
  21.                                     SearchBox.SelLength,
  22.                                     []);  // option: coCopyBuf
  23.  
  24.           //The only option available is "coCopyBuf".
  25.           //It forces the copy of the formatted text to be done via an intermediate buffer.
  26.           //It is always used (even if not specified) when the source and destination are the same.
  27.           //It can also be specified when the text is copied from a different richmemo.
  28.  
  29.           SearchBox.SelectAll;
  30.           SentLength:= CopyRichText(SearchBox,
  31.                                     SearchBox.SelStart,
  32.                                     SearchBox.SelLength,
  33.                                     ReplaceBox,
  34.                                     ReplaceBox.SelStart,
  35.                                     ReplaceBox.SelLength,
  36.                                     []);  // option: coCopyBuf
  37.           SearchBox.SelStart:= 1;
  38.           SearchBox.SelLength:= 0;
  39.  
Title: Re: CopyToClipboard
Post by: rick2691 on September 16, 2021, 01:43:23 pm
I have noticed that it may not go italic if more than one word is selected (though not a reliable rule). It also happens with one word or letter within a range of positions (ie. 28 thru 74) on each line of a paragraph; though the range varies by a few characters.

Then I created a paragraph with no attributes at all. The ranging changed considerably, but it was still converting to italics when sent to CopyRichText, and doing so within ranges.
Title: Re: CopyToClipboard
Post by: rick2691 on October 14, 2021, 04:28:34 pm
I have been trying to get rid of the erratic italics problem, but with no success.

So I looked in RichMemoUtils for the CopyRichText functions ...

I have questions about the following:

_CopyDirect ... variables: ofs, ln, fnt  ...do not appear to be initialized.

I see that GetTextAttributes conditionally sets ofs & ln, but I haven't noticed anything for when they are outside the condition.

I also don't see how InitFontParams is assigning anything to variable fnt, and it doesn't appear to be initialized before going to the function.

Rick
Title: Re: CopyToClipboard
Post by: rick2691 on December 23, 2021, 04:40:49 pm
I have tried every option to make CopyRichText work for my needs. With no more response from anyone I started researching things on my own.

I found the following code on a forum. I think it was for RichEdit and Delphi, so I tweaked it.

It has two methods: GetRTFselection and PutRTFselection.

I also found some code on this forum by "typo". He used TMemoryStream, and that made everything work. Before finding that, it was not working on account of using TStringStream.

I have been testing it all, and have not found any failures yet.

Rick

Code: Pascal  [Select][+][-]
  1. //======================== begin: stream callback for Get/PutRTFselection
  2. // (this code section must precede any use of Get/PutRTFselection)
  3.  
  4. // by Peter Below (TeamB)  < 100113.1...@compuserve.com >
  5.  
  6. // Stream Callback function
  7. type
  8.   TEditStreamCallBack = function(dwCookie: Longint; pbBuff: PByte;
  9.                                  cb: Longint; var pcb: Longint
  10.                                 ): DWORD; stdcall;
  11.   TEditStream = record
  12.                 dwCookie: Longint;
  13.                 dwError: Longint;
  14.                 pfnCallback: TEditStreamCallBack;
  15.                 end;
  16.  
  17. // EditStreamOutCallback callback function
  18. function EditStreamOutCallback(dwCookie: Longint; pbBuff: PByte;
  19.                                cb: Longint; var pcb: Longint
  20.                               ): DWORD; stdcall;
  21. var theStream: TStream;
  22. begin
  23.   theStream:= TStream(dwCookie);
  24.   with theStream do
  25.        begin
  26.        If cb > 0 Then
  27.           begin
  28.           pcb:= Write(pbBuff^, cb);
  29.           Result:= pcb;
  30.           end else Result:= 0;
  31.        end;
  32. end;
  33.  
  34. // EditStreamInCallback callback function
  35. function EditStreamInCallback(dwCookie: Longint; pbBuff: PByte;
  36.                               cb: Longint; var pcb: Longint
  37.                              ): DWORD; stdcall;
  38. var
  39.   theStream: TStream;
  40.   dataAvail: LongInt;
  41. begin
  42.   theStream:= TStream(dwCookie);
  43.   with theStream do // open theStream attributes for access; ie. theStream.size
  44.        begin
  45.          dataAvail:= Size - Position; // size & position are attributes of "theStream"; ie. theStream.size
  46.          Result:= 0;
  47.          if dataAvail<=cb then
  48.             begin
  49.               pcb:= read(pbBuff^, dataAvail);
  50.               if pcb<>dataAvail then Result:= UINT(E_FAIL);
  51.             end
  52.             else
  53.             begin
  54.               pcb:= read(pbBuff^, cb);
  55.               if pcb<>cb then Result:= UINT(E_FAIL);
  56.             end;
  57.        end;
  58. end;
  59.  
  60. // copyout Stream from RichEdit: uses stream callback above
  61. Procedure GetRTFSelection(Amemo: TRichMemo; IntoStream: TStream);
  62. Var editstream: TEditStream;
  63. Begin
  64.   with editstream Do
  65.        Begin
  66.        dwCookie:= Longint(IntoStream);
  67.        dwError:= 0;
  68.        pfnCallback:= @EditStreamOutCallBack;
  69.        end;
  70.   Amemo.Perform(EM_STREAMOUT, SF_RTF or SFF_SELECTION, longint(@EditStream));
  71. End;
  72.  
  73. // Insert Stream into RichEdit: uses stream callback above
  74. procedure PutRTFSelection(Amemo: TRichMemo; SourceStream: TStream);
  75. var EditStream: TEditStream;
  76. begin
  77.   with EditStream do
  78.        begin
  79.        dwCookie:= Longint(SourceStream);
  80.        dwError:= 0;
  81.        pfnCallback:= @EditStreamInCallBack;
  82.        end;
  83.   Amemo.Perform(EM_STREAMIN, SF_RTF or SFF_SELECTION, Longint(@EditStream));
  84. end;
  85.  
  86. //=================================== end: stream callback for Get/PutRTFselection
  87.  
  88.  
  89.  
  90. //=========== begin: my application of the functions
  91.  
  92. procedure TCmdForm.CopyPageMemo;  // PageMemo to SearchBox & ReplaceBox
  93. var MS: TMemoryStream; { TMemoryStream use by typo;
  94.                          https://forum.lazarus.freepascal.org/index.php?topic=26425.45 }
  95. begin
  96.   SearchBox.Clear;
  97.   // PageMemo section already selected
  98.   MS:= TMemoryStream.Create;  { TMemoryStream use by Author: typo }
  99.   try
  100.     GetRTFSelection(PageMemo,MS);  // PageMemo is an RTF container
  101.     MS.Position:= 0;          { TMemoryStream use by Author: typo }
  102.     PutRTFSelection(SearchBox,MS);  // SearchBox is an RTF container
  103.   finally
  104.     MS.Free;
  105.     PageMemo.SelLength:= 0;
  106.   end;
  107. end;
  108.  
  109. //=========== end: my application of the functions  
  110.  
Title: Re: CopyToClipboard
Post by: rick2691 on March 03, 2022, 02:23:55 pm
I just discovered that the previous codes for GetRTFselection and PutRTFselection have a disfunction when you have an image seleted or the selection is otherwise too long.

I have also found that others have had similar problems ... and they have posted the following:

Code: Pascal  [Select][+][-]
  1. //=================================== begin: stream callback for Get/PutRTFselection
  2.  
  3. // by Peter Below (TeamB)  < 100113.1...@compuserve.com >
  4.  
  5. // Stream Callback function
  6. type
  7.   TEditStreamCallBack = function(dwCookie: Longint; pbBuff: PByte;
  8.                                  cb: Longint; var pcb: Longint
  9.                                 ): DWORD; stdcall;  //  DWORD was Longint
  10.   TEditStream = record
  11.                 dwCookie: Longint;
  12.                 dwError: Longint;
  13.                 pfnCallback: TEditStreamCallBack;
  14.                 end;  
  15.  
  16. // Callback function for EM_STREAMOUT ... by the TEAM (who are co-workers with Peter Below)
  17. //
  18. function EditStreamOutCallback(dwCookie: Longint; pbBuff: PByte;
  19.                                cb: Longint; var pcb: Longint): DWORD; stdcall;
  20. begin                          //  DWORD was Longint
  21.   // This will write the contents of the RichEdit to a TMemoryStream field.
  22.   //
  23.   // dwCookie is Application-defined, so we're passing the blob stream.
  24.   //
  25.   pcb:= TMemoryStream(dwCookie).Write(pbBuff^, cb);
  26.   Result:= 0;
  27. end;
  28.  
  29. // Callback function for EM_STREAMIN
  30. //
  31. function EditStreamInCallback(dwCookie: Longint; pbBuff: PByte;
  32.                               cb: Longint; var pcb: Longint): DWORD; stdcall;
  33. var                           //  DWORD was Longint
  34.   theStream: TMemoryStream;  // use TMemoryStream instead of TStream.
  35. begin
  36.   // This will write the contents of a TMemoryStream field to a RichEdit.
  37.   //
  38.   // dwCookie is Application-defined, so we're passing the stream containing
  39.   // the formatted text to be added.
  40.   //
  41.   theStream:= TMemoryStream(dwCookie);
  42.   Result:= 0;
  43.  
  44.   with theStream do
  45.        begin
  46.        if (Size - Position) <= cb then
  47.            begin
  48.            pcb:= Size;
  49.            Read(pbBuff^, Size);
  50.            end
  51.            else begin
  52.                 pcb:= cb;
  53.                 Read(pbBuff^, cb);
  54.                 end;
  55.        end;
  56. end;
  57.  
  58. // copyout Stream from RichEdit: uses stream callback above
  59. Procedure GetRTFSelection(Amemo: TRichMemo; IntoStream: TMemoryStream);  // TStream);
  60. Var EditStream: TEditStream;
  61. Begin
  62.   with EditStream Do
  63.        Begin
  64.        dwCookie:= Longint(IntoStream);
  65.        dwError:= 0;
  66.        pfnCallback:= @EditStreamOutCallBack;
  67.        end;
  68.   Amemo.Perform(EM_STREAMOUT, SF_RTF or SFF_SELECTION, longint(@EditStream));
  69. End;
  70.  
  71. // Insert Stream into RichEdit: uses stream callback above
  72. procedure PutRTFSelection(Amemo: TRichMemo; SourceStream: TMemoryStream);  // TStream);
  73. var EditStream: TEditStream;
  74. begin
  75.   with EditStream do
  76.        begin
  77.        dwCookie:= Longint(SourceStream);
  78.        dwError:= 0;
  79.        pfnCallback:= @EditStreamInCallBack;
  80.        end;
  81.   Amemo.Perform(EM_STREAMIN, SF_RTF or SFF_SELECTION, Longint(@EditStream));
  82. end;
  83.  

The above replacement codes work perfectly. I have been able to copy a 100 page RTF document to another RTF container that also had unicode fonts and a dozen JPG images.
Title: Re: CopyToClipboard
Post by: Thaddy on March 03, 2022, 02:31:55 pm
As long as RTF is registered as a clipboard format (default in Windows) you should not have those issues. As you already discovered, a stringsteam is NOT suitable for RTF, because an RTF can contain binary data. (that is programmer error)
A memorystream or filestream will work.
Title: Re: CopyToClipboard
Post by: rick2691 on March 03, 2022, 02:39:25 pm
Thaddy,

Please note that I added some codes to what I just posted while you were responding.

OK, you lost me on registering. How is that done?

However, the above codes are functioning without that apparent registration. Unless I have forgotten that I did it at some point long ago.

Rick
Title: Re: CopyToClipboard
Post by: rick2691 on March 03, 2022, 02:48:30 pm
Thaddy,

My browser was going crazy, so I had missed your comment about TStringStream. Changing to TMemoryStream had not fixed the problem. But I have left it in because it is safer than TStringStream.

What was bad was the code for EditStreamInCallback and EditStreamOutCallback.

Rick
Title: Re: CopyToClipboard
Post by: rick2691 on March 11, 2022, 12:46:02 pm
This thread was carried further with
https://forum.lazarus.freepascal.org/index.php?topic=58536.0
With which it was resolved.

Rick
TinyPortal © 2005-2018