Status of source code changes suggested in November 2014

HMG Unicode versions 3.1.x related

Moderator: Rathinagiri

User avatar
kcarmody
Posts: 152
Joined: Tue Oct 07, 2014 11:13 am
Contact:

Re: Status of source code changes suggested in November 2014

Post by kcarmody »

srvet_claudio wrote:
kcarmody wrote:For number 2, the function RichEditBox_HasUnicodeChars implements the HasUnicodeChars property. The purpose of this property is to detect whether the buffer has any non-ASCII characters. This is so we can warn the user if he tries to save non-ASCII characters to an ANSI file -- see demo.prg lines 961-965. The HMG_IsUtf8 function does not distinguish betweeen ASCII and non-ASCII. It only determines whether a string is in correct UTF-8 format, and pure ASCII is correct UTF-8. RichEditBox_GetText always returns correct UTF-8 text, so the function as you have written it will always return true.
Your original code only detect ASCII character (firsts 128 character of ANSI and Unicode character set) then is RichEditBox_HasOnlyASCII()
I think this function is unnecessary in RichEdit because it is very easy to write and only in very special cases is required. In addition is far from the characteristics of the Windows control which is mainly thinking for working with RTF files.
Sorry, I don't understand your first sentence. RichEditBox_HasUnicodeChars returns .F. if the buffer contains only ASCII characters and .T. if it contains one or more non-ASCII characters. I don't find any function named RichEditBox_HasOnlyASCII() and the sense of RichEditBox_HasUnicodeChars is to return true if the buffer has non-ASCII.

As to whether it is necessary, I agree it may not be necessary, but it can save certain users a lot of frustration. There may be more of these users than you think. For several years, I have been writing programs for processing Indic text (various scripts of India, usually Devanagari script). These scripts are Unicode-only. Typically the user will enter text that is completely in one of these scripts and is not clear about the difference between "ANSI text file" and "Unicode text file".

I do not want such a user to save to an ANSI file and then find out later that he has lost all his data, even though he saved the file! (When you write an ANSI file, Windows converts the non-ANSI characters to question marks.) Notepad displays the following warning if a user attempts such a thing:
This file contains characters in Unicode format which will be lost if you save this file as an ANSI encoded text file. To keep the Unicode information, click Cancel below and then select one of the Unicode options from the Encoding drop down list. Continue?
OK Cancel
Remember that there a billion people in India, another billion in China, etc. all using non-ASCII scripts to write their native languages.

I agree that the preferred file format for content in rich edit controls is RTF, but the Windows functions that read and write these files, and Notepad and Wordpad, support TXT also. So we have to think about users who want to use TXT and try to keep them from getting annoyed at us if we throw all their data away without warning.
srvet_claudio wrote:
kcarmody wrote:Numbers 3, 4, and 5 will work, but I would prefer to have the names as RTFTXT instead of RTF only. Before I started making these changes, HMG supported only RTF reading and writing to and from rich edit controls. The changes I am submitting will enable it to support both RTF and TXT files, and I would like the names to reflect that. The name RTFFILE_UTF8, for example, is confusing, because it is not a format of an RTF file, but a TXT file.


Then the right thing is RichEditBox_SaveFile() and RichEditBox_LoadFile(),
#define RICHEDITFILE_UTF8
OK, I'll make this change.

Kevin
User avatar
srvet_claudio
Posts: 2193
Joined: Thu Feb 25, 2010 8:43 pm
Location: Uruguay
Contact:

Re: Status of source code changes suggested in November 2014

Post by srvet_claudio »

The point is that you function RichEditBox_HasUnicodeChars() only detected ASCII characters, if I use an ANSI code page in my program and write a character bigger that 127 you function return .T. but is a valid ANSI (up to 255) character and not is a true Unicode character.
For this I called RichEditBox_HasUnicodeChars () as RichEditBox_HasOnlyASCII().
The Windows RichEdit control works internally always in Unicode but the text you get in HMG is ANSI or Unicode depends of the selected code page.
Best regards.
Dr. Claudio Soto
(from Uruguay)
http://srvet.blogspot.com
User avatar
kcarmody
Posts: 152
Joined: Tue Oct 07, 2014 11:13 am
Contact:

Re: Status of source code changes suggested in November 2014

Post by kcarmody »

srvet_claudio wrote:The point is that you function RichEditBox_HasUnicodeChars() only detected ASCII characters, if I use an ANSI code page in my program and write a character bigger that 127 you function return .T. but is a valid ANSI (up to 255) character and not is a true Unicode character.
For this I called RichEditBox_HasUnicodeChars () as RichEditBox_HasOnlyASCII().
The Windows RichEdit control works internally always in Unicode but the text you get in HMG is ANSI or Unicode depends of the selected code page.
Ah, I see now what you are saying. Yes, it is true that RichEditBox_HasUnicodeChars could be more accurately called RichEditBox_HasNonAsciiChars. However, this function calls RichEditBox_GetText to get the characters of the rich edit control in UTF-8. It does not look at the current code page. (This assumes a Unicode executable. I'm assuming that all HMG executables are Unicode now. Please correct me if I'm wrong.)

You are right that this does not pick up non-ASCII ANSI characters, which are in the ANSI range of 128-255 and can therefore be written to an ANSI file. The problem is that looking for these characters in a UTF-8 string is a time consuming process, because not all of these characters are in the Unicode range of 128-255. Some of them are elsewhere in Unicode. Here is a list of these characters:

Code: Select all

{ ;
  {0x80, 0x20AC}, ; // 1252 - EURO SIGN
  {0x82, 0x201A}, ; // 1252 - SINGLE LOW-9 QUOTATION MARK
  {0x83, 0x0192}, ; // 1252 - LATIN SMALL LETTER F WITH HOOK
  {0x84, 0x201E}, ; // 1252 - DOUBLE LOW-9 QUOTATION MARK
  {0x85, 0x2026}, ; // 1252 - HORIZONTAL ELLIPSIS
  {0x86, 0x2020}, ; // 1252 - DAGGER
  {0x87, 0x2021}, ; // 1252 - DOUBLE DAGGER
  {0x88, 0x02C6}, ; // 1252 - MODIFIER LETTER CIRCUMFLEX ACCENT
  {0x89, 0x2030}, ; // 1252 - PER MILLE SIGN
  {0x8A, 0x0160}, ; // 1252 - LATIN CAPITAL LETTER S WITH CARON
  {0x8B, 0x2039}, ; // 1252 - SINGLE LEFT-POINTING ANGLE QUOTATION MARK
  {0x8C, 0x0152}, ; // 1252 - LATIN CAPITAL LIGATURE OE
  {0x8E, 0x017D}, ; // 1252 - LATIN CAPITAL LETTER Z WITH CARON
  {0x91, 0x2018}, ; // 1252 - LEFT SINGLE QUOTATION MARK
  {0x92, 0x2019}, ; // 1252 - RIGHT SINGLE QUOTATION MARK
  {0x93, 0x201C}, ; // 1252 - LEFT DOUBLE QUOTATION MARK
  {0x94, 0x201D}, ; // 1252 - RIGHT DOUBLE QUOTATION MARK
  {0x95, 0x2022}, ; // 1252 - BULLET
  {0x96, 0x2013}, ; // 1252 - EN DASH
  {0x97, 0x2014}, ; // 1252 - EM DASH
  {0x98, 0x02DC}, ; // 1252 - SMALL TILDE
  {0x99, 0x2122}, ; // 1252 - TRADE MARK SIGN
  {0x9A, 0x0161}, ; // 1252 - LATIN SMALL LETTER S WITH CARON
  {0x9B, 0x203A}, ; // 1252 - SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
  {0x9C, 0x0153}, ; // 1252 - LATIN SMALL LIGATURE OE
  {0x9E, 0x017E}, ; // 1252 - LATIN SMALL LETTER Z WITH CARON
  {0x9F, 0x0178}  } // 1252 - LATIN CAPITAL LETTER Y WITH DIAERESIS
In each row, the first number is the ANSI code point and the second is the Unicode code point. 1252 is the Windows code page number for ANSI.

To test a UTF-8 string for non-ASCII ANSI characters, we first have to get a Unicode code point for each UTF-8 sequence, and then test whether it is in the range 0-0x7F or 0xA0-0xFF, or is one of the numbers in the second column of this table, or is one of the values within 0x80-0x9F that is not in the first column of the table. Obviously, this can be done, but it seems inefficient to me. If you think it is worth doing, then I can put it into RichEditBox_HasUnicodeChars. I could make the detailed test optional. Or we could have a separate property HasNonAsciiChars.

Please let me know what you think.

Kevin
User avatar
srvet_claudio
Posts: 2193
Joined: Thu Feb 25, 2010 8:43 pm
Location: Uruguay
Contact:

Re: Status of source code changes suggested in November 2014

Post by srvet_claudio »

The best way for detect Unicode characters is with an adequate algorithm, insert this code:

Code: Select all

ON KEY F5 ACTION MsgDebug( HMG_IsUTF8( Form_1.RichEditBox_1.VALUE ) )
in demo C:\hmg.3.4.1\SAMPLES\Controls\RichEditBox and test it with UTF-8 and with different ANSI code page.
Best regards.
Dr. Claudio Soto
(from Uruguay)
http://srvet.blogspot.com
User avatar
kcarmody
Posts: 152
Joined: Tue Oct 07, 2014 11:13 am
Contact:

Re: Status of source code changes suggested in November 2014

Post by kcarmody »

srvet_claudio wrote:The best way for detect Unicode characters is with an adequate algorithm, insert this code:

Code: Select all

ON KEY F5 ACTION MsgDebug( HMG_IsUTF8( Form_1.RichEditBox_1.VALUE ) )
in demo C:\hmg.3.4.1\SAMPLES\Controls\RichEditBox and test it with UTF-8 and with different ANSI code page.
OK, I tried this. With no code page set in demo.prg (which I believe defaults the code page to UTF-8), I found that HMG_IsUtf8 returns .F. on pure ASCII and .T. if the buffer contains one or more non-ASCII characters. It did not matter if the non-ASCII characters were ANSI or not. So it works the same as HasUnicodeChars.

With the code page set to ES850, HMG_IsUtf8 returns .F. on all text, no matter what it contains.

I found that HMG_IsUtf8 works the same as the Harbour function HB_STRISUTF8 (\src\rtl\strutf8.c in the Harbour source code), both with and without a code page set, so I don't understand why HMG_IsUtf8 is needed.

Both of these functions are misnamed, since pure ASCII is valid UTF-8. That is why UTF-8 has become so popular -- pure ASCII from old software does not need to be modified to be UTF-8.

However, you were right that HMG_IsUtf8 can be used to implement HasUnicodeChars in its current implementation. I did not think this would work, because I assumed that HMG_IsUtf8 would return .T. on pure ASCII text.

So it looks like we are still looking for a quick way to determine whether the buffer contains only ANSI text.

Kevin
User avatar
srvet_claudio
Posts: 2193
Joined: Thu Feb 25, 2010 8:43 pm
Location: Uruguay
Contact:

Re: Status of source code changes suggested in November 2014

Post by srvet_claudio »

kcarmody wrote:I found that HMG_IsUtf8 works the same as the Harbour function HB_STRISUTF8 (\src\rtl\strutf8.c in the Harbour source code), both with and without a code page set, so I don't understand why HMG_IsUtf8 is needed.
It is a new function of Harbour that I did not know that exist, when I introduced HMG_ISUTF8 in HMG did not exist HB_STRISUTF8 in Harbour.
Best regards.
Dr. Claudio Soto
(from Uruguay)
http://srvet.blogspot.com
User avatar
kcarmody
Posts: 152
Joined: Tue Oct 07, 2014 11:13 am
Contact:

Re: Status of source code changes suggested in November 2014

Post by kcarmody »

I've been looking at the functions in \SOURCE\h_UNICODE_String.prg. There is one simple function there that looks to me like it has a bug. Here is the code:

Code: Select all

FUNCTION HMG_UTF8InsertBOM ( cString )
   IF HMG_IsUTF8WithBOM (cString) == .F.
      cString := UTF8_BOM + HB_BCHAR (0x2F) + cString
   ENDIF
RETURN cString
The BOM defined in \INCLUDE\i_UNICODE.ch:

Code: Select all

#xtranslate UTF8_BOM => (HB_BCHAR (0xEF) + HB_BCHAR (0xBB) + HB_BCHAR (0xBF))
This is the correct UTF-8 BOM, but the function adds a "/" character (HB_BCHAR(0x2F)) between the BOM and the text. This does not seem necessary or desirable. This function is not used anywhere in HMG now, as far as I can see. Shouldn't this "/" be deleted from this function?
User avatar
srvet_claudio
Posts: 2193
Joined: Thu Feb 25, 2010 8:43 pm
Location: Uruguay
Contact:

Re: Status of source code changes suggested in November 2014

Post by srvet_claudio »

kcarmody wrote:I've been looking at the functions in \SOURCE\h_UNICODE_String.prg. There is one simple function there that looks to me like it has a bug. Here is the code:

Code: Select all

FUNCTION HMG_UTF8InsertBOM ( cString )
   IF HMG_IsUTF8WithBOM (cString) == .F.
      cString := UTF8_BOM + HB_BCHAR (0x2F) + cString
   ENDIF
RETURN cString
The BOM defined in \INCLUDE\i_UNICODE.ch:

Code: Select all

#xtranslate UTF8_BOM => (HB_BCHAR (0xEF) + HB_BCHAR (0xBB) + HB_BCHAR (0xBF))
This is the correct UTF-8 BOM, but the function adds a "/" character (HB_BCHAR(0x2F)) between the BOM and the text. This does not seem necessary or desirable. This function is not used anywhere in HMG now, as far as I can see. Shouldn't this "/" be deleted from this function?
Yes, you are right.
Done!
Best regards.
Dr. Claudio Soto
(from Uruguay)
http://srvet.blogspot.com
User avatar
kcarmody
Posts: 152
Joined: Tue Oct 07, 2014 11:13 am
Contact:

Re: Status of source code changes suggested in November 2014

Post by kcarmody »

Incorporating the changes recently suggested by Claudio, I'm again submitting the following changes, almost all of which relate to the RichEditBox control. I've developed a patch, based on Claudio's current patch (patch 6), which incorporates these changes. My patch should be installed on top of Claudio's patch.

Individual modified source files are at http://kevincarmody.com/hmg/, and a zip of files in the patch is at http://kevincarmody.com/hmg/HmgChangeProposal.zip.

This patch includes an overhauled Rich Edit demo, which uses all the source code changes (except for the HasNonAnsiChars property and the SelPasteSpecial method). The new Rich Edit demo is at http://kevincarmody.com/hmg/SAMPLES/Con ... chEditBox/, including the executable at http://kevincarmody.com/hmg/SAMPLES/Con ... x/demo.exe.

New function GetRichEditFileType( cFile, lUtf8Test ) --> nFileType

This function returns a file type (RTF, ANSI, UTF-16, UTF-8) which can be used in RichEditLoadFile and RichEditSaveFile methods of RichEditBox control.

http://kevincarmody.com/hmg/SOURCE/h_richeditbox.prg - lines 52, 512-578

Code: Select all

// Following line added by Kevin Carmody, September 2015
#include "fileio.ch"

Code: Select all

// Following function added by Kevin Carmody, September 2015

*-----------------------------------------------------------------------------*
FUNCTION GetRichEditFileType ( cFile, lUtf8Test )
*-----------------------------------------------------------------------------*

LOCAL hFile    := FOPEN( cFile, FO_READ )
LOCAL cBuffer  := SPACE( 5 )
LOCAL nBufRead := 0
LOCAL nType    := 0

/*
  The following code block tests whether an umnarked text file contains
  valid UTF-8 text with non-ASCII characters.
*/

LOCAL bIsUtf8NonAscii := {||
   LOCAL lUtf8NonAscii := .N.
   LOCAL cPartial := ''
      cBuffer  := SPACE( 0x400 )
      nBufRead := 1
      BEGIN SEQUENCE
         WHILE nBufRead > 0
            nBufRead := FREAD( hFile, @cBuffer, 0x400 )
            IF nBufRead > 0 .AND. HMG_IsUtf8( cPartial + cBuffer, .N., .Y., @cPartial )
               lUtf8NonAscii := .Y.
               BREAK
            ENDIF
         ENDDO
         IF ! EMPTY( cPartial )
            lUtf8NonAscii := .N.
         ENDIF
      END SEQUENCE
   RETURN lUtf8NonAscii
   }

   BEGIN SEQUENCE

      IF hFile < 0
         BREAK
      ENDIF
      nBufRead := FREAD( hFile, @cBuffer, 5 )
      DO CASE
      CASE nBufRead >= 5 .AND. LEFT( cBuffer, 5 ) == "{\rtf"
         nType := RICHEDITFILE_RTF
      CASE nBufRead >= 3 .AND. LEFT( cBuffer, 3 ) == E"\xEF\xBB\xBF"
         nType := RICHEDITFILE_UTF8
      CASE nBufRead >= 2 .AND. LEFT( cBuffer, 2 ) == E"\xFF\xFE"
         nType := RICHEDITFILE_UTF16LE
      CASE nBufRead >= 2 .AND. LEFT( cBuffer, 2 ) == E"\xFE\xFF"
         nType := RICHEDITFILE_UTF16BE
      CASE ! EMPTY( lUtf8Test ) .AND. bIsUtf8NonAscii:EVAL( )
         nType := RICHEDITFILE_UTF8
      OTHERWISE
         nType := RICHEDITFILE_ANSI
      ENDCASE

   END SEQUENCE

   FCLOSE( hFile )

RETURN nType   
This function is used in http://kevincarmody.com/hmg/SAMPLES/Con ... x/demo.prg - line 880

Code: Select all

   LOCAL nFormat        := GETRICHEDITFILETYPE(cFileName, .Y.)
New function Utf16ByteSwap( cInFile, cOutFile )

This function supports the UTF-16 BE (big endian) file type for the RichEditLoadFile and RichEditSaveFile methods of RichEditBox control.

http://kevincarmody.com/hmg/SOURCE/h_richeditbox.prg - lines 52, 583-627

Code: Select all

// Following line added by Kevin Carmody, September 2015
#include "fileio.ch"

Code: Select all

// Following function added by Kevin Carmody, September 2015

*-----------------------------------------------------------------------------*
FUNCTION Utf16ByteSwap( cInFile, cOutFile )
*-----------------------------------------------------------------------------*

LOCAL hInFile   := FOPEN( cInFile , FO_READ )
LOCAL hOutFile  := FCREATE( cOutFile )
LOCAL cInBuffer := SPACE( 0x400 )
LOCAL nBufRead  := 1
LOCAL lSuccess  := .N.
LOCAL cOutBuffer, cBytePair, nBufWrite, nByte

BEGIN SEQUENCE

   IF hInFile < 0
      BREAK
   ENDIF
   IF hOutFile < 0
      BREAK
   ENDIF
   WHILE nBufRead > 0
      cOutBuffer := ""
      nBufRead   := FREAD( hInFile, @cInBuffer, 0x400 )
      IF nBufRead > 0
         FOR nByte := 1 TO nBufRead STEP 2
            cBytePair  := SUBSTR( cInBuffer, nByte, 2 )
            cOutBuffer += RIGHT( cBytePair, 1 ) + LEFT( cBytePair, 1 )
         NEXT
         nBufWrite := FWRITE( hOutFile, cOutBuffer )
         IF nBufWrite < nBufRead
            BREAK
         ENDIF
      ENDIF
   ENDDO
   lSuccess := .Y.
    
END SEQUENCE

FCLOSE( hInFile )
FCLOSE( hOutFile )

RETURN lSuccess
This function is used in RichEditBox_RichEditLoadFile() and RichEditBox_RichEditSaveFile() - see below.

New function HMG_IsNonASCII( cString )

This function determines whether a string contains any non-ASCII characters.

http://kevincarmody.com/hmg/SOURCE/h_UNICODE_String.prg - lines 262-280

Code: Select all

// Following function added by Kevin Carmody, September 2015

FUNCTION HMG_IsNonASCII( cString )
/*
   This function determines whether a string contains one or more
   non-ASCII characters.
*/

LOCAL lNonASCII := .F.
LOCAL cChar

   BEGIN SEQUENCE
      FOR EACH cChar IN cString
         IF cChar >= CHR( 0x80 )
            lNonASCII := .T.
            BREAK
         ENDIF
      NEXT
   END SEQUENCE

RETURN lNonASCII
This function is used in RichEditBox_HasNonAsciiChars() - see below.

New function HMG_UTF8IsNonANSI( cUtf8Str )

This function determines whether a UTF-8 string contains any non-ANSI characters.

http://kevincarmody.com/hmg/SOURCE/h_UNICODE_String.prg - lines 285-369

Code: Select all

// Following function added by Kevin Carmody, September 2015

FUNCTION HMG_UTF8IsNonANSI( cUtf8Str )
/*
   This function determines whether a UTF-8 string contains one or more
   non-ANSI characters.  It does not check whether the string is valid UTF-8.
*/

LOCAL aAnsiTrans := { ;
   0x20AC, ; // ANSI 0x80 - EURO SIGN
   0x201A, ; // ANSI 0x82 - SINGLE LOW-9 QUOTATION MARK
   0x0192, ; // ANSI 0x83 - LATIN SMALL LETTER F WITH HOOK
   0x201E, ; // ANSI 0x84 - DOUBLE LOW-9 QUOTATION MARK
   0x2026, ; // ANSI 0x85 - HORIZONTAL ELLIPSIS
   0x2020, ; // ANSI 0x86 - DAGGER
   0x2021, ; // ANSI 0x87 - DOUBLE DAGGER
   0x02C6, ; // ANSI 0x88 - MODIFIER LETTER CIRCUMFLEX ACCENT
   0x2030, ; // ANSI 0x89 - PER MILLE SIGN
   0x0160, ; // ANSI 0x8A - LATIN CAPITAL LETTER S WITH CARON
   0x2039, ; // ANSI 0x8B - SINGLE LEFT-POINTING ANGLE QUOTATION MARK
   0x0152, ; // ANSI 0x8C - LATIN CAPITAL LIGATURE OE
   0x017D, ; // ANSI 0x8E - LATIN CAPITAL LETTER Z WITH CARON
   0x2018, ; // ANSI 0x91 - LEFT SINGLE QUOTATION MARK
   0x2019, ; // ANSI 0x92 - RIGHT SINGLE QUOTATION MARK
   0x201C, ; // ANSI 0x93 - LEFT DOUBLE QUOTATION MARK
   0x201D, ; // ANSI 0x94 - RIGHT DOUBLE QUOTATION MARK
   0x2022, ; // ANSI 0x95 - BULLET
   0x2013, ; // ANSI 0x96 - EN DASH
   0x2014, ; // ANSI 0x97 - EM DASH
   0x02DC, ; // ANSI 0x98 - SMALL TILDE
   0x2122, ; // ANSI 0x99 - TRADE MARK SIGN
   0x0161, ; // ANSI 0x9A - LATIN SMALL LETTER S WITH CARON
   0x203A, ; // ANSI 0x9B - SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
   0x0153, ; // ANSI 0x9C - LATIN SMALL LIGATURE OE
   0x017E, ; // ANSI 0x9E - LATIN SMALL LETTER Z WITH CARON
   0x0178  } // ANSI 0x9F - LATIN CAPITAL LETTER Y WITH DIAERESIS
LOCAL aAnsiSkip  := { ;
   0x81, ;
   0x8D, ;
   0x8F, ;
   0x90, ;
   0x9D  }

LOCAL lNonANSI := .F.
LOCAL nOctets  := 0
LOCAL cChar, nChar, nCode

   BEGIN SEQUENCE

      FOR EACH cChar IN cUtf8Str

         nChar := HB_BCODE( cChar )

         IF nOctets != 0

            --nOctets
            nCode := HB_BITOR( HB_BITSHIFT( nCode, 6 ), HB_BITAND( nChar, 0x3F ) )
            IF nOctets == 0
               DO CASE
               CASE nCode >= 0x100
                  IF ASCAN( aAnsiTrans, nCode ) == 0
                     lNonANSI := .T.
                  ENDIF
               CASE nCode >= 0xA0
               CASE nCode >= 0x80
                  IF ASCAN( aAnsiSkip, nCode ) == 0
                     lNonANSI := .T.
                  ENDIF                  
               ENDCASE
            ENDIF

         ELSEIF HB_BITAND( nChar, 0x80 ) != 0

            DO WHILE HB_BITAND( nChar, 0x80 ) != 0
               nChar := HB_BITAND( HB_BITSHIFT ( nChar, 1 ), 0xFF )
               ++nOctets
            ENDDO
            --nOctets
            nCode := HB_BITAND( HB_BCODE( cChar ), HB_BITSHIFT( 1, nOctets ) - 1 )

         ENDIF

      NEXT

   END SEQUENCE

RETURN lNonANSI
This function is used in RichEditBox_HasNonAnsiChars() - see below.

Enhanced function DoMethod ( Arg1 , Arg2 , Arg3 , Arg4 , Arg5 , Arg6 , Arg7 , Arg8 , Arg9 )

Enabled this function to return a value from a RichEditBox method.

http://kevincarmody.com/hmg/SOURCE/h_controlmisc.prg - line 8869

Code: Select all

Function DoMethod ( Arg1 , Arg2 , Arg3 , Arg4 , Arg5 , Arg6 , Arg7 , Arg8 , Arg9 )
// Following line modified by Kevin Carmody, September 2015
Local xData, i, hWnd
http://kevincarmody.com/hmg/SOURCE/h_controlmisc.prg - lines 8881-8882

Code: Select all

// Following 2 lines modified by Kevin Carmody, September 2015
IF _RichEditBox_DoMethod ( @xData, Arg1 , Arg2 , Arg3 , Arg4 , Arg5 , Arg6 , Arg7 , Arg8 , Arg9 ) == .T.
   Return xData
ENDIF
http://kevincarmody.com/hmg/SOURCE/h_controlmisc.prg - line 10422

Code: Select all

// Following line modified by Kevin Carmody, September 2015
Function _RichEditBox_DoMethod ( xData, Arg1 , Arg2 , Arg3 , Arg4 , Arg5 , Arg6 , Arg7 , Arg8 , Arg9 )
The return value is used in http://kevincarmody.com/hmg/SAMPLES/Con ... x/demo.prg - lines 906

Code: Select all

      IF ! wMain.ebDoc.RICHEDITLOADFILE(cFileName, .N., nFormat)
The return value is used in http://kevincarmody.com/hmg/SAMPLES/Con ... x/demo.prg - lines 993

Code: Select all

      IF ! wMain.ebDoc.RICHEDITSAVEFILE(cFileName, .N., nFormat)
Enhanced function HMG_IsUTF8( cString, lAllowASCII, lAllowPartial, cPartial )

This function now has three optional arguments:
  • lAllowASCII allows the input string to be all ASCII
  • lAllowPartial allows the input string to end with an incomplete UTF-8 sequence
  • cPartial (passed by reference) is set to the incomplete UTF-8 sequence at the end of the input string, or the empty string
The last two arguments are useful when the string is an input file buffer.

http://kevincarmody.com/hmg/SOURCE/h_UNICODE_String.prg - lines 175-257

Code: Select all

// Following function modified by Kevin Carmody, September 2015

FUNCTION HMG_IsUTF8( cString, lAllowASCII, lAllowPartial, cPartial ) // code from Harbour Project
/* 
  Modeled after HB_STRISUTF8 in \src\rtl\strutf8.c in Harbour source.
  This Harbour code has two bugs:
    - does not allow input to be all ASCII
    - allows code point above 0x10FFFF
  This function corrects these bugs.
  This function returns .F. if cString contains any invalid UTF-8.
  If the optional argument lAllowASCII is .T., cString may be all ASCII.
     Otherwise cString must contain one or more non-ASCII chars.
  If the optional argument lAllowPartial is .T., cString may end with an 
     unfinished UTF-8 byte sequence, which is passed back through cPartial, 
     which is otherwise set to the empty string. This is useful when cString 
     is a file buffer.
*/
LOCAL lASCII  := .T.
LOCAL lUTF8   := .T.
LOCAL nOctets := 0
LOCAL cChar, nChar, nCode

   IF lAllowASCII == NIL
      lAllowASCII := .F.
   ENDIF
   IF lAllowPartial == NIL
      lAllowPartial := .F.
   ENDIF

   BEGIN SEQUENCE

      FOR EACH cChar IN cString

         nChar := HB_BCODE( cChar )

         IF nOctets != 0

            IF HB_BITAND( nChar, 0xC0 ) != 0x80
               lUTF8 := .F.
               BREAK
            ENDIF
            --nOctets
            nCode := HB_BITOR( HB_BITSHIFT( nCode, 6 ), HB_BITAND( nChar, 0x3F ) )
            IF nOctets == 0 .AND. nCode > 0x10FFFF
               lUTF8 := .F.
               BREAK
            ENDIF

         ELSEIF HB_BITAND( nChar, 0x80 ) != 0

            lASCII := .F.
            DO WHILE HB_BITAND( nChar, 0x80 ) != 0
               nChar := HB_BITAND( HB_BITSHIFT ( nChar, 1 ), 0xFF )
               ++nOctets
            ENDDO
            --nOctets
            IF nOctets == 0
               lUTF8 := .F.
               BREAK
            ENDIF
            nCode := HB_BITAND( HB_BCODE( cChar ), HB_BITSHIFT( 1, nOctets ) - 1 )

         ENDIF

      NEXT

   END SEQUENCE

   IF nOctets > 0
      IF lAllowPartial
         cPartial := RIGHT( cString, nOctets )
      ELSE
         lUTF8 := .F.
      ENDIF
   ELSE
      IF lAllowPartial
         cPartial := ''
      ENDIF
   ENDIF

   IF ! lAllowASCII .AND. lASCII
      lUTF8 := .F.
   ENDIF

RETURN lUTF8
This function is used in http://kevincarmody.com/hmg/SOURCE/h_richeditbox.prg - see above.

Code: Select all

            IF nBufRead > 0 .AND. HMG_IsUtf8( cPartial + cBuffer, .N., .Y., @cPartial )
Fixed RichEditBox_StreamIn( hWndControl, cFileName, lSelection, nDataFormat ) --> lSuccess

This function now skips over a byte order mark (BOM) in a Unicode text file if one is present.

http://kevincarmody.com/hmg/SOURCE/c_richeditbox.c - lines 190-192, 199-203, 216-233

Code: Select all

//        RichEditBox_StreamIn ( hWndControl, cFileName, lSelection, nDataFormat ) --> return lSuccess
HB_FUNC ( RICHEDITBOX_STREAMIN )
{
   HWND       hWndControl = (HWND)   HMG_parnl (1);
   TCHAR     *cFileName   = (TCHAR*) HMG_parc (2);
   BOOL       lSelection  = (BOOL)   hb_parl  (3);
   LONG       nDataFormat = (LONG)   hb_parnl (4);
   HANDLE     hFile;
   // Following 3 lines added by Kevin Carmody, September 2015
   BYTE       bUtf8Bom[3]; 
   BYTE       bUtf16Bom[2]; 
   DWORD      dwRead;
   EDITSTREAM es;
   LONG       Format;

   switch( nDataFormat )
   {
   // Comments in this switch block modified by Kevin Carmody, September 2015
      case 1:   Format = SF_TEXT; break; // ANSI or UTF-8 with BOM or mixed (UTF-8 BOM removed, overlong UTF-8 accepted, invalid UTF-8 read as ANSI)
      case 2:   Format = ( CP_UTF8 << 16 ) | SF_USECODEPAGE | SF_TEXT; break; // UTF-8 without BOM (BOM not removed)
      case 3:   Format = SF_TEXT | SF_UNICODE; break; // UTF-16 LE without BOM (BOM not removed)
      case 4:   Format = SF_RTF;  break;
      // case 5, UTF-8 RTF, removed by Kevin Carmody, September 2015, because it can never occur
      default:  Format = SF_RTF; break;
   }

   if ( lSelection )
        Format = Format | SFF_SELECTION;

   if( ( hFile = CreateFile (cFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL )) == INVALID_HANDLE_VALUE )
   {   hb_retl (FALSE);
       return;
   }

   // Following switch block added by Kevin Carmody, September 2015
   switch( nDataFormat )
   {
      case 1:   break;
      case 2:   
         if ( ! ReadFile (hFile, bUtf8Bom, 3, &dwRead, NULL) ) // read past BOM if present
            hb_retl (FALSE);
         if ( ! ( dwRead == 3 && bUtf8Bom[0] == 0xEF && bUtf8Bom[1] == 0xBB && bUtf8Bom[2] == 0xBF ) )
            SetFilePointer (hFile, 0, 0, FILE_BEGIN);
         break;
      case 3:
         if ( ! ReadFile (hFile, bUtf16Bom, 2, &dwRead, NULL) ) // read past BOM if present
            hb_retl (FALSE);
         if ( ! ( dwRead == 2 && bUtf16Bom[0] == 0xFF && bUtf16Bom[1] == 0xFE ) )
            SetFilePointer (hFile, 0, 0, FILE_BEGIN);
         break;
      case 4:   break;
      default:  break;
   }
   es.pfnCallback = EditStreamCallbackRead;
   es.dwCookie    = (DWORD_PTR) hFile;
   es.dwError     = 0;

   SendMessage ( hWndControl, EM_STREAMIN, (WPARAM) Format, (LPARAM) &es );

   CloseHandle (hFile);

   if( es.dwError )
      hb_retl (FALSE);
   else
      hb_retl (TRUE);
}
This function is called by RichEditBox_RtfTxtLoadFile() - see below.

Fixed RichEditBox_StreamOut( hWndControl, cFileName, lSelection, nDataFormat ) --> lSuccess

This function now writes a byte order mark (BOM) to a Unicode text file.

http://kevincarmody.com/hmg/SOURCE/c_richeditbox.c - lines 269-271, 278-282, 295-302

Code: Select all

//        RichEditBox_StreamOut ( hWndControl, cFileName, lSelection, nDataFormat ) --> return lSuccess
HB_FUNC ( RICHEDITBOX_STREAMOUT )
{
   HWND       hWndControl = (HWND)   HMG_parnl (1);
   TCHAR     *cFileName   = (TCHAR*) HMG_parc (2);
   BOOL       lSelection  = (BOOL)   hb_parl  (3);
   LONG       nDataFormat = (LONG)   hb_parnl (4);
   HANDLE     hFile;
   // Following 3 lines added by Kevin Carmody, September 2015
   BYTE       bUtf8Bom[3]  = {0xEF, 0xBB, 0xBF};
   BYTE       bUtf16Bom[2] = {0xFF, 0xFE}; 
   DWORD      dwWritten;
   EDITSTREAM es;
   LONG       Format;

   switch( nDataFormat )
   {
   // Comments in this switch block modified by Kevin Carmody, September 2015
      case 1:   Format = SF_TEXT; break; // ANSI (non-ANSI characters converted to question marks)
      case 2:   Format = ( CP_UTF8 << 16 ) | SF_USECODEPAGE | SF_TEXT; break; // UTF-8 without BOM
      case 3:   Format = SF_TEXT | SF_UNICODE; break; // UTF-16 LE without BOM
      case 4:   Format = SF_RTF;  break;
      // case 5, UTF-8 RTF, removed by Kevin Carmody, September 2015, because it can never occur
      default:  Format = SF_RTF; break;
   }

   if ( lSelection )
        Format = Format | SFF_SELECTION;

   if( ( hFile = CreateFile (cFileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL )) == INVALID_HANDLE_VALUE )
   {   hb_retl (FALSE);
       return;
   }

   // Following switch block added by Kevin Carmody, September 2015
   switch( nDataFormat )
   {
      case 1:   break;
      case 2:   WriteFile( hFile, bUtf8Bom, 3, &dwWritten, NULL ); break; // write UTF-8 BOM at head of file
      case 3:   WriteFile( hFile, bUtf16Bom, 2, &dwWritten, NULL ); break; // write UTF-16 LE BOM at head of file
      case 4:   break;
      default:  break;
   }
   es.pfnCallback = EditStreamCallbackWrite;
   es.dwCookie    = (DWORD_PTR) hFile;
   es.dwError     = 0;

   SendMessage ( hWndControl, EM_STREAMOUT, (WPARAM) Format, (LPARAM) &es );
   
   CloseHandle (hFile);

   if( es.dwError )
      hb_retl (FALSE);
   else
      hb_retl (TRUE);
}
This function is used in RichEditBox_RtfTxtSaveFile() - see below.

Fixed HMG_UTF8InsertBOM ( cString )

Deleted spurious insertion of '/' between BOM and text.

http://kevincarmody.com/hmg/SOURCE/h_UNICODE_String.prg - line 167

Code: Select all

// Following function modified by Kevin Carmody, September 2015

FUNCTION HMG_UTF8InsertBOM ( cString )
   IF HMG_IsUTF8WithBOM (cString) == .F.
      cString := UTF8_BOM + cString
   ENDIF
RETURN cString
New constants RICHEDITFILE_ANSI etc.

These constants are RTF and TXT file types returned by the new function GetRichEditFileType() and can be used by the RichEditLoadFile and RichEditSaveFile methods of the RichEditBox control.

http://kevincarmody.com/hmg/INCLUDE/i_richeditbox.ch - lines 161-169

Code: Select all

// Following 5 #defines added by Kevin Carmody, September 2015

*****************
*   File type   *
*****************

#define RICHEDITFILE_ANSI      1   // ANSI text file
#define RICHEDITFILE_UTF8      2   // UTF-8 text file
#define RICHEDITFILE_UTF16LE   3   // UTF-16 LE (little endian) text file
#define RICHEDITFILE_RTF       4   // RTF file
#define RICHEDITFILE_UTF16BE   5   // UTF-16 BE (big endian) text file
These constants are also used in the Rich Edit demo - http://kevincarmody.com/hmg/SAMPLES/Con ... x/demo.prg - lines 883-904 and lines 976-992.

New RichEditBox property HasNonAsciiChars (read only)

This property detects whether a rich edit control contains non-ASCII Unicode characters.

http://kevincarmody.com/hmg/SOURCE/h_controlmisc.prg - lines 10266-10268, at end of _RichEditBox_GetProperty()

Code: Select all

   // Following case added by Kevin Carmody, September 2015
   CASE Arg3 == "HASNONASCIICHARS"
        xData  := RichEditBox_HasNonAsciiChars ( hWndControl )
        RetVal := .T.
http://kevincarmody.com/hmg/INCLUDE/i_window.ch - line 164

Code: Select all

;; // Following line modified by Kevin Carmody, September 2015
#xtranslate <w>. \<c\> . \<p:RTFTextMode,AutoURLDetect,Zoom,SelectRange,CaretPos,Value,GetSelectText,GetTextLength,ViewRect,HasNonAsciiChars,HasNonAnsiChars\> => GetProperty ( <"w">, \<"c"\> , \<"p"\> ) ;;
http://kevincarmody.com/hmg/SOURCE/h_richeditbox.prg - lines 424-430

Code: Select all

// Following function added by Kevin Carmody, September 2015

/*
  The following function tests for the presence of non-ASCII characters in 
  a rich edit control.  It would be better to know if the control contained
  non-ANSI characters, but since some ANSI characters are not in the Latin-1 
  Supplement, testing for non-ANSI characters is inefficient for large 
  documents.
*/

*-----------------------------------------------------------------------------*
FUNCTION RichEditBox_HasNonAsciiChars( hWndControl )
*-----------------------------------------------------------------------------*

LOCAL cBuffer := RichEditBox_GetText( hWndControl, .N. )

RETURN HMG_IsNonASCII( cBuffer, .N. )
This property is used in http://kevincarmody.com/hmg/SAMPLES/Con ... x/demo.prg - line 945

Code: Select all

   LOCAL lUnicode := wMain.ebDoc.HASNONASCIICHARS
New RichEditBox property HasNonAnsiChars (read only)

This property detects whether a rich edit control contains non-ANSI Unicode characters.

http://kevincarmody.com/hmg/SOURCE/h_controlmisc.prg - lines 10266-10268, at end of _RichEditBox_GetProperty()

Code: Select all

   // Following case added by Kevin Carmody, September 2015
   CASE Arg3 == "HASNONANSICHARS"
        xData  := RichEditBox_HasNonAnsiChars ( hWndControl )
        RetVal := .T.
http://kevincarmody.com/hmg/INCLUDE/i_window.ch - line 164

Code: Select all

;; // Following line modified by Kevin Carmody, September 2015
#xtranslate <w>. \<c\> . \<p:RTFTextMode,AutoURLDetect,Zoom,SelectRange,CaretPos,Value,GetSelectText,GetTextLength,ViewRect,HasNonAsciiChars,HasNonAnsiChars\> => GetProperty ( <"w">, \<"c"\> , \<"p"\> ) ;;
http://kevincarmody.com/hmg/SOURCE/h_richeditbox.prg - lines 424-430

Code: Select all

// Following function added by Kevin Carmody, September 2015

/*
  The following function tests for the presence of non-ANSI characters in 
  a rich edit control.  It is slower than RichEditBox_HasNonAsciiChars
  but does not reject any Unicode characters that are in ANSI.
*/

*-----------------------------------------------------------------------------*
FUNCTION RichEditBox_HasNonAnsiChars( hWndControl )
*-----------------------------------------------------------------------------*

LOCAL cBuffer := RichEditBox_GetText( hWndControl, .N. )

RETURN HMG_UTF8IsNonANSI( cBuffer )
This property is not used in http://kevincarmody.com/hmg/SAMPLES/Con ... x/demo.prg, but could be used on line 945 in place of HASNONASCIICHARS. In this case, it would be slower but would catch non-ASCII ANSI characters that could be successfully written to an ANSI file.

Code: Select all

   LOCAL lUnicode := wMain.ebDoc.HASNONANSICHARS
New RichEditBox method RichEditLoadFile( cFile, lSelection, nType ) --> lSuccess

This method is a synonym for the RtfLoadFile method. It now uses the file type returned by GetRichEditFileType(). It skips over a byte order mark in a Unicode text file, and it supports UTF-16 BE (big endian Unicode text file).

http://kevincarmody.com/hmg/SOURCE/h_controlmisc.prg - lines 10445-10446

Code: Select all

   // Following case modified by Kevin Carmody, September 2015
   CASE Arg3 == "RTFLOADFILE" .OR. Arg3 == "RICHEDITLOADFILE"
        xData := RichEditBox_RichEditLoadFile ( hWndControl, Arg4, Arg5, Arg6 )   // by default save in SF_RTF format
        RetVal := .T.
http://kevincarmody.com/hmg/INCLUDE/i_window.ch - lines 172-173, 175

Code: Select all

;; // Following 2 lines modified by Kevin Carmody, September 2015
#xtranslate <w>. \<c\> . \<p:RTFLoadFile,RTFSaveFile,RichEditLoadFile,RichEditSaveFile\> (\<arg1\>,\<arg2\>,\<arg3\>) => DoMethod ( <"w">, \<"c"\> , \<"p"\> , \<arg1\> , \<arg2\>, \<arg3\> ) ;;
#xtranslate <w>. \<c\> . \<p:RTFLoadFile,RTFSaveFile,RichEditLoadFile,RichEditSaveFile\> (\<arg1\>,\<arg2\>) => DoMethod ( <"w">, \<"c"\> , \<"p"\> , \<arg1\> , \<arg2\> ) ;;
;; // Following line added by Kevin Carmody, September 2015
#xtranslate <w>. \<c\> . \<p:RTFLoadFile,RTFSaveFile,RichEditLoadFile,RichEditSaveFile\> (\<arg1\>) => DoMethod ( <"w">, \<"c"\> , \<"p"\> , \<arg1\> ) ;;
http://kevincarmody.com/hmg/SOURCE/h_richeditbox.prg - lines 452-484

Code: Select all

// Following function added by Kevin Carmody, September 2015

*-----------------------------------------------------------------------------*
FUNCTION RichEditBox_RichEditLoadFile( hWndControl, cFile, lSelection, nType )
*-----------------------------------------------------------------------------*

LOCAL lSuccess := .N.
LOCAL cTempFile

   IF ! HB_ISLOGICAL( lSelection )
      lSelection := .N.
   ENDIF
   IF ! HB_ISNUMERIC( nType )
      nType := RICHEDITFILE_RTF
   ENDIF

   IF lSelection
      RichEditBox_UnSelectAll( hWndControl )
   ENDIF
   IF RichEditBox_RTFLoadResourceFile( hWndControl, cFile, lSelection )
      lSuccess := .T.
   ELSE
      IF nType == RICHEDITFILE_UTF16BE
         cTempFile := GETTEMPFOLDER() + "_RichEditLoadFile.txt"
         lSuccess  := Utf16ByteSwap( cFile, cTempFile )
         IF lSuccess
            lSuccess := RichEditBox_StreamIn( hWndControl, cTempFile, lSelection, RICHEDITFILE_UTF16LE )
         ENDIF
         DELETE FILE ( cTempFile )
      ELSE
         lSuccess := RichEditBox_StreamIn( hWndControl, cFile, lSelection, nType )
      ENDIF
   ENDIF

RETURN lSuccess
This method is used in http://kevincarmody.com/hmg/SAMPLES/Con ... x/demo.prg - line 906

Code: Select all

      IF ! wMain.ebDoc.RICHEDITLOADFILE(cFileName, .N., nFormat)
New RichEditBox method RichEditSaveFile( cFile, lSelection, nType ) --> lSuccess

This method is a synonym for the RtfSaveFile method. It now uses the file type returned by GetRichEditFileType(), writes a byte order mark to a Unicode text file, and supports UTF-16 BE (big endian Unicode text file).

http://kevincarmody.com/hmg/SOURCE/h_controlmisc.prg - lines 10450-10451

Code: Select all

   // Following case modified by Kevin Carmody, September 2015
   CASE Arg3 == "RTFSAVEFILE" .OR. Arg3 == "RICHEDITSAVEFILE"
        xData := RichEditBox_RichEditSaveFile ( hWndControl, Arg4, Arg5, Arg6 )   // by default save in SF_RTF format
        RetVal := .T.
http://kevincarmody.com/hmg/INCLUDE/i_window.ch - lines 172-173, 175

Code: Select all

;; // Following 2 lines modified by Kevin Carmody, September 2015
#xtranslate <w>. \<c\> . \<p:RTFLoadFile,RTFSaveFile,RichEditLoadFile,RichEditSaveFile\> (\<arg1\>,\<arg2\>,\<arg3\>) => DoMethod ( <"w">, \<"c"\> , \<"p"\> , \<arg1\> , \<arg2\>, \<arg3\> ) ;;
#xtranslate <w>. \<c\> . \<p:RTFLoadFile,RTFSaveFile,RichEditLoadFile,RichEditSaveFile\> (\<arg1\>,\<arg2\>) => DoMethod ( <"w">, \<"c"\> , \<"p"\> , \<arg1\> , \<arg2\> ) ;;
;; // Following line added by Kevin Carmody, September 2015
#xtranslate <w>. \<c\> . \<p:RTFLoadFile,RTFSaveFile,RichEditLoadFile,RichEditSaveFile\> (\<arg1\>) => DoMethod ( <"w">, \<"c"\> , \<"p"\> , \<arg1\> ) ;;
http://kevincarmody.com/hmg/SOURCE/h_richeditbox.prg - lines 482-507

Code: Select all

// Following function added by Kevin Carmody, September 2015

*-----------------------------------------------------------------------------*
FUNCTION RichEditBox_RichEditSaveFile( hWndControl, cFile, lSelection, nType )
*-----------------------------------------------------------------------------*

LOCAL lSuccess := .N.
LOCAL cTempFile

   IF ! HB_ISLOGICAL( lSelection )
      lSelection := .N.
   ENDIF
   IF ! HB_ISNUMERIC( nType )
      nType := RICHEDITFILE_RTF
   ENDIF

   IF nType == RICHEDITFILE_UTF16BE
      cTempFile := GETTEMPFOLDER() + "_RichEditLoadFile.txt"
      lSuccess := RichEditBox_StreamOut( hWndControl, cTempFile, lSelection, RICHEDITFILE_UTF16LE )
      IF lSuccess
         lSuccess  := Utf16ByteSwap( cTempFile, cFile )
      ENDIF
      DELETE FILE ( cTempFile )
   ELSE
      lSuccess := RichEditBox_StreamOut( hWndControl, cFile, lSelection, nType )
   ENDIF

RETURN lSuccess
This method is used in http://kevincarmody.com/hmg/SAMPLES/Con ... x/demo.prg - line 993

Code: Select all

      IF ! wMain.ebDoc.RICHEDITSAVEFILE(cFileName, .N., nFormat)
New RichEditBox method SelPasteSpecial

Paste special - needs documentation of clipboard format argument.

http://kevincarmody.com/hmg/SOURCE/h_controlmisc.prg - lines 10463-10465

Code: Select all

   // Following case added by Kevin Carmody, September 2015
   CASE Arg3 == HMG_UPPER ("SelPasteSpecial")
        RichEditBox_PasteSpecial ( hWndControl, Arg4 )
        RetVal := .T.
http://kevincarmody.com/hmg/INCLUDE/i_window.ch - line 179

Code: Select all

;; // Following line added by Kevin Carmody, September 2015
#xtranslate <w>. \<c\> . \<p:SelPasteSpecial\> (\<arg1\>) => DoMethod ( <"w">, \<"c"\> , \<"p"\> , \<arg1\> ) ;;
This method is not used in the Rich Edit demo.

Enhanced RichEditBox method RtfLoadFile( cFile, lSelection, nType ) --> lSuccess

This method is a synonym for the RichEditLoadFile method described above.

http://kevincarmody.com/hmg/SOURCE/h_controlmisc.prg - lines 10445-10446

Code: Select all

   // Following case modified by Kevin Carmody, September 2015
   CASE Arg3 == "RTFLOADFILE" .OR. Arg3 == "RICHEDITLOADFILE"
        xData := RichEditBox_RichEditLoadFile ( hWndControl, Arg4, Arg5, Arg6 )   // by default save in SF_RTF format
        RetVal := .T.
http://kevincarmody.com/hmg/INCLUDE/i_window.ch - lines 172-173, 175

Code: Select all

;; // Following 2 lines modified by Kevin Carmody, September 2015
#xtranslate <w>. \<c\> . \<p:RTFLoadFile,RTFSaveFile,RichEditLoadFile,RichEditSaveFile\> (\<arg1\>,\<arg2\>,\<arg3\>) => DoMethod ( <"w">, \<"c"\> , \<"p"\> , \<arg1\> , \<arg2\>, \<arg3\> ) ;;
#xtranslate <w>. \<c\> . \<p:RTFLoadFile,RTFSaveFile,RichEditLoadFile,RichEditSaveFile\> (\<arg1\>,\<arg2\>) => DoMethod ( <"w">, \<"c"\> , \<"p"\> , \<arg1\> , \<arg2\> ) ;;
;; // Following line added by Kevin Carmody, September 2015
#xtranslate <w>. \<c\> . \<p:RTFLoadFile,RTFSaveFile,RichEditLoadFile,RichEditSaveFile\> (\<arg1\>) => DoMethod ( <"w">, \<"c"\> , \<"p"\> , \<arg1\> ) ;;
This method is not used in the Rich Edit demo.

Enhanced RichEditBox method RtfSaveFile( cFile, lSelection, nType ) --> lSuccess

This method is a synonym for the RichEditSaveFile method described above.

http://kevincarmody.com/hmg/SOURCE/h_controlmisc.prg - lines 10445-10447

Code: Select all

   // Following case modified by Kevin Carmody, September 2015
   CASE Arg3 == "RTFSAVEFILE" .OR. Arg3 == "RICHEDITSAVEFILE"
        xData := RichEditBox_RichEditSaveFile ( hWndControl, Arg4, Arg5, Arg6 )   // by default save in SF_RTF format
        RetVal := .T.
http://kevincarmody.com/hmg/INCLUDE/i_window.ch - lines 172-173, 175

Code: Select all

// Following 2 lines modified by Kevin Carmody, September 2015
#xtranslate <w>. \<c\> . \<p:RTFLoadFile,RTFSaveFile,RichEditLoadFile,RichEditSaveFile\> (\<arg1\>,\<arg2\>,\<arg3\>) => DoMethod ( <"w">, \<"c"\> , \<"p"\> , \<arg1\> , \<arg2\>, \<arg3\> ) ;;
#xtranslate <w>. \<c\> . \<p:RTFLoadFile,RTFSaveFile,RichEditLoadFile,RichEditSaveFile\> (\<arg1\>,\<arg2\>) => DoMethod ( <"w">, \<"c"\> , \<"p"\> , \<arg1\> , \<arg2\> ) ;;
;; // Following line added by Kevin Carmody, September 2015
#xtranslate <w>. \<c\> . \<p:RTFLoadFile,RTFSaveFile,RichEditLoadFile,RichEditSaveFile\> (\<arg1\>) => DoMethod ( <"w">, \<"c"\> , \<"p"\> , \<arg1\> ) ;;
This method is not used in the Rich Edit demo.

Overhauled the Rich Edit demo

The rich edit demo now has the following features:
  • Main menu
  • List of recently used files
  • Resizable windows
  • Ctrl-B, Ctrl-I, Ctrl-U supported
  • File name in title, file name and page in status bar
  • Modified flag, caps lock, num lock, insert status on status bar
  • Window size, font name and size, file locations, file filters, recently used file names stored in registry
  • Paragraph numbering
  • Read and write text files
  • Many other enhancements
The compiled executable is at http://kevincarmody.com/hmg/SAMPLES/Con ... x/demo.exe.

The rich edit demo uses all the enhancements described above (except the HasNonAnsiChars property, SelPasteSpecial method, and HMG_UTF8InsertBOM function).

Source files changed: Source files added: Source files deleted:
User avatar
srvet_claudio
Posts: 2193
Joined: Thu Feb 25, 2010 8:43 pm
Location: Uruguay
Contact:

Re: Status of source code changes suggested in November 2014

Post by srvet_claudio »

Thanks Kevin.
Best regards.
Dr. Claudio Soto
(from Uruguay)
http://srvet.blogspot.com
Post Reply