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: