Componentes.Terceros.DevExp.../official/x.30/ExpressEditors Library 5/Sources/cxRichEdit.pas
2007-12-16 17:06:54 +00:00

2996 lines
88 KiB
ObjectPascal

{********************************************************************}
{ }
{ Developer Express Visual Component Library }
{ ExpressEditors }
{ }
{ Copyright (c) 1998-2007 Developer Express Inc. }
{ ALL RIGHTS RESERVED }
{ }
{ The entire contents of this file is protected by U.S. and }
{ International Copyright Laws. Unauthorized reproduction, }
{ reverse-engineering, and distribution of all or any portion of }
{ the code contained in this file is strictly prohibited and may }
{ result in severe civil and criminal penalties and will be }
{ prosecuted to the maximum extent possible under the law. }
{ }
{ RESTRICTIONS }
{ }
{ THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES }
{ (DCU, OBJ, DLL, ETC.) ARE CONFIDENTIAL AND PROPRIETARY TRADE }
{ SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS }
{ LICENSED TO DISTRIBUTE THE EXPRESSEDITORS AND ALL }
{ ACCOMPANYING VCL CONTROLS AS PART OF AN EXECUTABLE PROGRAM ONLY. }
{ }
{ THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED }
{ FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE }
{ COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE }
{ AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT }
{ AND PERMISSION FROM DEVELOPER EXPRESS INC. }
{ }
{ CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON }
{ ADDITIONAL RESTRICTIONS. }
{ }
{********************************************************************}
unit cxRichEdit;
{$I cxVer.inc}
interface
uses
{$IFDEF DELPHI6}
Variants,
{$ENDIF}
Windows, Classes, ClipBrd, ComCtrls, Controls, Dialogs, Forms, Graphics,
Menus, Messages, RichEdit, StdCtrls, SysUtils, cxClasses, cxContainer,
cxControls, cxEdit, cxDrawTextUtils, cxGraphics, cxLookAndFeels, cxMemo,
cxScrollbar, cxTextEdit;
type
TcxCustomRichEditViewInfo = class(TcxCustomMemoViewInfo)
public
DrawBitmap: HBITMAP;
IsDrawBitmapDirty: Boolean;
PrevDrawBitmapSize: TSize;
constructor Create; override;
destructor Destroy; override;
procedure DrawNativeStyleEditBackground(ACanvas: TcxCanvas; ADrawBackground: Boolean;
ABackgroundStyle: TcxEditBackgroundPaintingStyle; ABackgroundBrush: TBrushHandle); override;
procedure DrawText(ACanvas: TcxCanvas); override;
function GetUpdateRegion(AViewInfo: TcxContainerViewInfo): TcxRegion; override;
function NeedShowHint(ACanvas: TcxCanvas; const P: TPoint;
const AVisibleBounds: TRect; out AText: TCaption;
out AIsMultiLine: Boolean; out ATextRect: TRect): Boolean; override;
procedure Paint(ACanvas: TcxCanvas); override;
end;
TcxCustomRichEditProperties = class;
TcxCustomRichEditViewData = class(TcxCustomMemoViewData)
private
function GetProperties: TcxCustomRichEditProperties;
protected
function InternalGetEditContentSize(ACanvas: TcxCanvas;
const AEditValue: TcxEditValue;
const AEditSizeProperties: TcxEditSizeProperties): TSize; override;
public
procedure Calculate(ACanvas: TcxCanvas; const ABounds: TRect; const P: TPoint;
Button: TcxMouseButton; Shift: TShiftState; AViewInfo: TcxCustomEditViewInfo;
AIsMouseEvent: Boolean); override;
property Properties: TcxCustomRichEditProperties read GetProperties;
end;
{ TcxCustomRichEditProperties }
TcxCustomRichEditProperties = class(TcxCustomMemoProperties)
private
FHideScrollBars: Boolean;
FMemoMode: Boolean;
FPlainText: Boolean;
FPlainTextChanged: Boolean;
FSelectionBar: Boolean;
FOnProtectChange: TRichEditProtectChange;
FOnResizeRequest: TRichEditResizeEvent;
FOnSaveClipboard: TRichEditSaveClipboard;
FOnSelectionChange: TNotifyEvent;
procedure SetHideScrollBars(Value: Boolean);
procedure SetMemoMode(Value: Boolean);
procedure SetPlainText(Value: Boolean);
procedure SetSelectionBar(Value: Boolean);
protected
function CanValidate: Boolean; override;
class function GetViewDataClass: TcxCustomEditViewDataClass; override;
property PlainTextChanged: Boolean read FPlainTextChanged;
public
constructor Create(AOwner: TPersistent); override;
procedure Assign(Source: TPersistent); override;
class function GetContainerClass: TcxContainerClass; override;
function GetDisplayText(const AEditValue: TcxEditValue;
AFullText: Boolean = False; AIsInplace: Boolean = True): WideString; override;
function GetSupportedOperations: TcxEditSupportedOperations; override;
class function GetViewInfoClass: TcxContainerViewInfoClass; override;
function IsResetEditClass: Boolean; override;
property PlainText: Boolean read FPlainText write SetPlainText default False;
// !!!
property HideScrollBars: Boolean read FHideScrollBars
write SetHideScrollBars default True;
property MemoMode: Boolean read FMemoMode write SetMemoMode default False;
property SelectionBar: Boolean read FSelectionBar write SetSelectionBar
default False;
property OnProtectChange: TRichEditProtectChange read FOnProtectChange
write FOnProtectChange;
property OnResizeRequest: TRichEditResizeEvent read FOnResizeRequest
write FOnResizeRequest;
property OnSaveClipboard: TRichEditSaveClipboard read FOnSaveClipboard
write FOnSaveClipboard;
property OnSelectionChange: TNotifyEvent read FOnSelectionChange
write FOnSelectionChange;
end;
{ TcxRichEditProperties }
TcxRichEditProperties = class(TcxCustomRichEditProperties)
published
property Alignment;
property AssignedValues;
property AutoSelect;
property ClearKey;
property HideScrollBars;
property HideSelection;
property ImeMode;
property ImeName;
property MaxLength;
property MemoMode;
property OEMConvert;
property PlainText;
property ReadOnly;
property ScrollBars;
property SelectionBar;
property VisibleLineCount;
property WantReturns;
property WantTabs;
property WordWrap;
property OnChange;
property OnEditValueChanged;
property OnProtectChange;
property OnResizeRequest;
property OnSaveClipboard;
property OnSelectionChange;
end;
TcxRichInnerEdit = class;
TcxCustomRichEdit = class;
TOnChange = procedure (Sender: TObject) of Object;
{ TcxCustomRichEdit }
TcxCustomRichEdit = class(TcxCustomMemo)
private
FEditPopupMenu: TComponent;
FIsNullEditValue: Boolean;
FPropertiesChange: Boolean;
procedure DoProtectChange(Sender: TObject; AStartPos, AEndPos: Integer;
var AAllowChange: Boolean);
procedure DoSaveClipboard(Sender: TObject; ANumObjects, ANumChars: Integer;
var ASaveClipboard: Boolean);
procedure EditPopupMenuClick(Sender: TObject);
function GetLines: TStrings;
function GetInnerRich: TcxRichInnerEdit;
procedure SetLines(Value: TStrings);
function GetActiveProperties: TcxCustomRichEditProperties;
function GetProperties: TcxCustomRichEditProperties;
procedure SetProperties(Value: TcxCustomRichEditProperties);
function GetCanUndo: Boolean;
function GetDefAttributes: TTextAttributes;
function GetDefaultConverter: TConversionClass;
function GetPageRect: TRect;
function GetParagraph: TParaAttributes;
function GetSelAttributes: TTextAttributes;
procedure RefreshScrollBars;
procedure SetDefAttributes(const Value: TTextAttributes);
procedure SetDefaultConverter(Value: TConversionClass);
procedure SetPageRect(const Value: TRect);
procedure SetSelAttributes(const Value: TTextAttributes);
procedure EMCanPaste(var Message: TMessage); message EM_CANPASTE;
procedure CMVisibleChanged(var Message: TMessage); message CM_VISIBLECHANGED;
protected
procedure AdjustInnerEdit; override;
function CanFocusOnClick: Boolean; override;
function CanKeyDownModifyEdit(Key: Word; Shift: TShiftState): Boolean; override;
procedure ContainerStyleChanged(Sender: TObject); override;
function DoShowPopupMenu(AMenu: TComponent; X, Y: Integer): Boolean; override;
function GetEditValue: TcxEditValue; override;
function GetInnerEditClass: TControlClass; override;
procedure ChangeHandler(Sender: TObject); override;
procedure Scroll(AScrollBarKind: TScrollBarKind; AScrollCode: TScrollCode;
var AScrollPos: Integer); override;
procedure Initialize; override;
procedure InternalSetEditValue(const Value: TcxEditValue;
AValidateEditValue: Boolean); override;
procedure InternalValidateDisplayValue(const ADisplayValue: TcxEditValue); override;
procedure PropertiesChanged(Sender: TObject); override;
procedure ResetEditValue; override;
procedure SetParent(AParent: TWinControl); override;
procedure SynchronizeDisplayValue; override;
procedure SynchronizeEditValue; override;
function UpdateContentOnFocusChanging: Boolean; override;
procedure UpdateScrollBars; override;
function CanDeleteSelection: Boolean;
procedure Changed(Sender: TObject);
procedure DoOnResizeRequest(const R: TRect);
procedure DoOnSelectionChange;
function GetEditPopupMenuInstance: TComponent; virtual;
function IsNavigationKey(Key: Word; Shift: TShiftState): Boolean; virtual;
procedure UpdateEditPopupMenuItems(APopupMenu: TComponent); virtual;
property EditPopupMenu: TComponent read FEditPopupMenu write FEditPopupMenu;
property InnerRich: TcxRichInnerEdit read GetInnerRich;
property PropertiesChange: Boolean read FPropertiesChange;
public
destructor Destroy; override;
procedure ClearSelection; override;
procedure CutToClipboard; override;
function FindTexT(const ASearchStr: string; AStartPos, ALength: Integer;
AOptions: TSearchTypes): Integer;
class function GetPropertiesClass: TcxCustomEditPropertiesClass; override;
procedure PasteFromClipboard; override;
procedure PrepareEditValue(const ADisplayValue: TcxEditValue;
out EditValue: TcxEditValue; AEditFocused: Boolean); override;
procedure Print(const Caption: string); virtual;
procedure Undo; override;
class procedure RegisterConversionFormat(const AExtension: string;
AConversionClass: TConversionClass);
property ActiveProperties: TcxCustomRichEditProperties
read GetActiveProperties;
property CanUndo: Boolean read GetCanUndo;
property DefAttributes: TTextAttributes read GetDefAttributes write SetDefAttributes;
property DefaultConverter: TConversionClass
read GetDefaultConverter write SetDefaultConverter;
property Lines: TStrings read GetLines write SetLines;
property PageRect: TRect read GetPageRect write SetPageRect;
property Paragraph: TParaAttributes read GetParagraph;
property Properties: TcxCustomRichEditProperties read GetProperties
write SetProperties;
property SelAttributes: TTextAttributes read GetSelAttributes write SetSelAttributes;
end;
{ TcxRichEdit }
TcxRichEdit = class(TcxCustomRichEdit)
private
function GetActiveProperties: TcxRichEditProperties;
function GetProperties: TcxRichEditProperties;
procedure SetProperties(Value: TcxRichEditProperties);
public
class function GetPropertiesClass: TcxCustomEditPropertiesClass; override;
property ActiveProperties: TcxRichEditProperties read GetActiveProperties;
published
property Align;
property Anchors;
property Constraints;
property DragCursor;
property DragKind;
property DragMode;
property Enabled;
property ImeMode;
property ImeName;
property ParentColor;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property Properties: TcxRichEditProperties read GetProperties
write SetProperties;
property Lines; // must be after Properties because of Properties.Alignment
property ShowHint;
property Style;
property StyleDisabled;
property StyleFocused;
property StyleHot;
property TabOrder;
property TabStop;
property Visible;
property OnClick;
property OnContextPopup;
property OnDblClick;
property OnDragDrop;
property OnDragOver;
property OnEditing;
property OnEndDock;
property OnEndDrag;
property OnEnter;
property OnExit;
property OnKeyDown;
property OnKeyPress;
property OnKeyUp;
property OnMouseDown;
property OnMouseEnter;
property OnMouseLeave;
property OnMouseMove;
property OnMouseUp;
property OnMouseWheel;
property OnMouseWheelDown;
property OnMouseWheelUp;
property OnStartDock;
property OnStartDrag;
end;
TcxRichInnerEditHelper = class(TcxInterfacedPersistent,
IcxContainerInnerControl, IcxCustomInnerEdit, IcxInnerTextEdit,
IcxInnerMemo)
private
FEdit: TcxRichInnerEdit;
protected
property Edit: TcxRichInnerEdit read FEdit;
public
constructor Create(AEdit: TcxRichInnerEdit); reintroduce; virtual;
// IcxContainerInnerControl
function GetControlContainer: TcxContainer;
function GetControl: TWinControl;
// IcxCustomInnerEdit
function CallDefWndProc(AMsg: UINT; WParam: WPARAM;
LParam: LPARAM): LRESULT;
function GetEditValue: TcxEditValue;
function GetOnChange: TNotifyEvent;
procedure LockBounds(ALock: Boolean);
procedure SafelySetFocus;
procedure SetEditValue(const Value: TcxEditValue);
procedure SetParent(Value: TWinControl);
procedure SetOnChange(Value: TNotifyEvent);
// IcxInnerTextEdit
procedure ClearSelection;
procedure CopyToClipboard;
function GetAlignment: TAlignment;
function GetAutoSelect: Boolean;
function GetCharCase: TEditCharCase;
function GetEchoMode: TcxEditEchoMode;
function GetHideSelection: Boolean;
function GetImeLastChar: Char;
function GetImeMode: TImeMode;
function GetImeName: TImeName;
function GetInternalUpdating: Boolean;
function GetMaxLength: Integer;
function GetMultiLine: Boolean;
function GetOEMConvert: Boolean;
function GetOnSelChange: TNotifyEvent;
function GetPasswordChar: TCaptionChar;
function GetReadOnly: Boolean;
function GetSelLength: Integer;
function GetSelStart: Integer;
function GetSelText: string;
procedure SelectAll;
procedure SetAlignment(Value: TAlignment);
procedure SetAutoSelect(Value: Boolean);
procedure SetCharCase(Value: TEditCharCase);
procedure SetEchoMode(Value: TcxEditEchoMode);
procedure SetHideSelection(Value: Boolean);
procedure SetInternalUpdating(Value: Boolean);
procedure SetImeMode(Value: TImeMode);
procedure SetImeName(const Value: TImeName);
procedure SetMaxLength(Value: Integer);
procedure SetOEMConvert(Value: Boolean);
procedure SetOnSelChange(Value: TNotifyEvent);
procedure SetPasswordChar(Value: TCaptionChar);
procedure SetReadOnly(Value: Boolean);
procedure SetSelLength(Value: Integer);
procedure SetSelStart(Value: Integer);
procedure SetSelText(Value: string);
// IcxInnerMemo
function GetCaretPos: TPoint;
function GetLines: TStrings;
function GetScrollBars: TScrollStyle;
function GetWantReturns: Boolean;
function GetWantTabs: Boolean;
function GetWordWrap: Boolean;
procedure SetCaretPos(const Value: TPoint);
procedure SetScrollBars(Value: TScrollStyle);
procedure SetWantReturns(Value: Boolean);
procedure SetWantTabs(Value: Boolean);
procedure SetWordWrap(Value: Boolean);
end;
{ TcxRichEditStrings }
TcxRichEditStreamOperation = (esoLoadFrom, esoSaveTo);
TcxRichEditStreamOperationInfo = record
EditStream: TEditStream;
StreamInfo: TRichEditStreamInfo;
TextType: Longint;
end;
TcxRichEditStrings = class(TStrings)
private
FConverter: TConversion;
FRichEdit: TcxRichInnerEdit;
FTextType: Longint;
protected
function Get(Index: Integer): string; override;
procedure InitConverter(const AFileName: string); virtual;
procedure InitStreamOperation(AStream: TStream;
var AStreamOperationInfo: TcxRichEditStreamOperationInfo;
AStreamOperation: TcxRichEditStreamOperation);
function GetCount: Integer; override;
procedure Put(Index: Integer; const S: string); override;
procedure SetUpdateState(Updating: Boolean); override;
procedure SetTextStr(const Value: string); override;
function GetLineBreakString: string; virtual;
property RichEdit: TcxRichInnerEdit read FRichEdit;
public
constructor Create(ARichEdit: TcxRichInnerEdit); virtual;
destructor Destroy; override;
procedure Clear; override;
procedure AddStrings(Strings: TStrings); override;
procedure Delete(Index: Integer); override;
procedure Insert(Index: Integer; const S: string); override;
procedure LoadFromFile(const FileName: string); override;
procedure LoadFromStream(Stream: TStream); override;
procedure SaveToFile(const FileName: string); override;
procedure SaveToStream(Stream: TStream); override;
end;
{ TcxRichInnerEdit }
TcxRichInnerEdit = class(TRichEdit, IUnknown,
IcxContainerInnerControl, IcxInnerEditHelper)
private
FAutoSelect: Boolean;
FEchoMode: TcxEditEchoMode;
FEscapePressed: Boolean;
FHelper: TcxRichInnerEditHelper;
FInternalUpdating: Boolean;
FIsEraseBackgroundLocked: Boolean;
FKeyPressProcessed: Boolean;
FLockBoundsCount: Integer;
FMemoMode: Boolean;
FRichVersion: Integer;
FSelectionBar: Boolean;
FSavedPlainText: Boolean;
FRichLines: TcxRichEditStrings;
FUseCRLF: Boolean;
// IcxContainerInnerControl
function GetControl: TWinControl;
function GetControlContainer: TcxContainer;
// IcxInnerEditHelper
function GetHelper: IcxCustomInnerEdit;
function GetContainer: TcxCustomRichEdit;
function GetLineCount: Integer;
function GetLineIndex(AIndex: Integer): Integer;
function GetLineLength(AIndex: Integer): Integer;
function GetRichLines: TcxRichEditStrings;
procedure InternalSetMemoMode;
procedure SetMemoMode(Value: Boolean);
procedure SetRichLines(
Value: TcxRichEditStrings);
procedure SetSelectionBar(Value: Boolean);
procedure WMChar(var Message: TWMChar); message WM_CHAR;
procedure WMClear(var Message: TMessage); message WM_CLEAR;
procedure WMCut(var Message: TMessage); message WM_CUT;
procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND;
procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE;
procedure WMKeyDown(var Message: TWMKeyDown); message WM_KEYDOWN;
procedure WMKillFocus(var Message: TWMKillFocus); message WM_KILLFOCUS;
procedure WMMButtonDown(var Message: TWMMButtonDown); message WM_MBUTTONDOWN;
procedure WMNCCalcSize(var Message: TWMNCCalcSize); message WM_NCCALCSIZE;
procedure WMNCPaint(var Message: TWMNCPaint); message WM_NCPAINT;
procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
procedure WMPaste(var Message: TMessage); message WM_PASTE;
procedure WMSetFocus(var Message: TWMSetFocus); message WM_SETFOCUS;
procedure WMSetFont(var Message: TWMSetFont); message WM_SETFONT;
procedure WMHScroll(var Message: TWMHScroll); message WM_HSCROLL;
procedure WMVScroll(var Message: TWMVScroll); message WM_VSCROLL;
procedure WMWindowPosChanged(var Message: TWMWindowPosChanged); message WM_WINDOWPOSCHANGED;
procedure WMWindowPosChanging(var Message: TWMWindowPosChanging); message WM_WINDOWPOSCHANGING;
procedure EMReplaceSel(var Message: TMessage); message EM_REPLACESEL;
procedure EMSetCharFormat(var Message: TMessage); message EM_SETCHARFORMAT;
procedure EMSetParaFormat(var Message: TMessage); message EM_SETPARAFORMAT;
procedure CMColorChanged(var Message: TMessage); message CM_COLORCHANGED;
procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
procedure CNCommand(var Message: TWMCommand); message CN_COMMAND;
procedure CNKeyDown(var Message: TWMKeyDown); message CN_KEYDOWN;
procedure WMGetText(var Message: TMessage); message WM_GETTEXT;
procedure WMGetTextLength(var Message: TWMGetTextLength); message WM_GETTEXTLENGTH;
procedure WMSetText(var Message: TWMSetText); message WM_SETTEXT;
procedure WMIMEComposition(var Message: TMessage); message WM_IME_COMPOSITION;
procedure EMExLineFromChar(var Message: TMessage); message EM_EXLINEFROMCHAR;
procedure EMLineLength(var Message: TMessage); message EM_LINELENGTH;
protected
procedure Click; override;
procedure CreateParams(var Params: TCreateParams); override;
procedure CreateWnd; override;
procedure DblClick; override;
procedure DestroyWnd; override;
procedure DoEnter; override;
procedure DragOver(Source: TObject; X, Y: Integer; State: TDragState;
var Accept: Boolean); override;
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
procedure KeyPress(var Key: Char); override;
procedure KeyUp(var Key: Word; Shift: TShiftState); override;
procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer); override;
procedure MouseLeave(AControl: TControl); dynamic;
procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer); override;
procedure RequestAlign; override;
procedure RequestSize(const Rect: TRect); override;
procedure RichCreateParams(var Params: TCreateParams;
out ARichVersion: Integer); virtual;
procedure SelectionChange; override;
procedure WndProc(var Message: TMessage); override;
function CanPaste: Boolean;
function GetSelection: TCharRange; virtual;
property AutoSelect: Boolean read FAutoSelect write FAutoSelect default False;
property Container: TcxCustomRichEdit read GetContainer;
property Helper: TcxRichInnerEditHelper read FHelper;
property MemoMode: Boolean read FMemoMode write SetMemoMode default False;
property RichVersion: Integer read FRichVersion write FRichVersion;
property SelectionBar: Boolean read FSelectionBar write SetSelectionBar
default False;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure DefaultHandler(var Message); override;
procedure DragDrop(Source: TObject; X, Y: Integer); override;
function ExecuteAction(Action: TBasicAction): Boolean; override;
function FindTexT(const ASearchStr: string;
AStartPos, ALength: Longint; AOptions: TSearchTypes): Integer;
procedure Print(const Caption: string); override;
procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override;
function UpdateAction(Action: TBasicAction): Boolean; override;
function CanFocus: Boolean; override;
function CanRedo: Boolean; virtual;
procedure Redo; virtual;
procedure Undo; virtual;
property RichLines: TcxRichEditStrings
read GetRichLines write SetRichLines;
end;
function AdjustRichLineBreaks(ADest, ASource: PChar; AShortBreak: Boolean = False): Integer;
procedure SetRichEditText(ARichEdit: TRichEdit;
const AEditValue: TcxEditValue);
implementation
uses
CommDlg, Printers, cxEditPaintUtils, cxEditUtils, cxExtEditConsts, cxVariants,
cxDWMAPI, dxUxTheme, dxThemeConsts, dxThemeManager;
type
TcxRichEditNames = array of string;
TStringsAccess = class(TStrings);
const
RTFConversionFormat: TConversionFormat = (
ConversionClass: TConversion;
Extension: 'rtf';
Next: nil
);
TextConversionFormat: TConversionFormat = (
ConversionClass: TConversion;
Extension: 'txt';
Next: @RTFConversionFormat
);
cxRichReadError = $0001;
cxRichWriteError = $0002;
cxRichNoError = $0000;
const
cxRichEditVersions: array[0..4] of Integer =
(100, 200, 300, 410, 500);
var
FRichEditLibrary: HMODULE = 0;
FRichRenderer, FRichConverter: TcxRichInnerEdit;
FConversionFormatList: PConversionFormat = @TextConversionFormat;
FRichEditDLLNames: TcxRichEditNames;
FRichEditClassNames: TcxRichEditNames;
function cxSendStructMessageEx(AHandle: THandle; AMsg: UINT; const AStructure; AParam: Integer; AStructureIsLParam: Boolean): LRESULT; overload;
begin
if AStructureIsLParam then
Result := SendMessage(AHandle, AMsg, AParam, Integer(@AStructure))
else
Result := SendMessage(AHandle, AMsg, Integer(@AStructure), AParam);
end;
function cxSendStructMessage(AHandle: THandle; AMsg: UINT; WParam: WPARAM; const LParam): LRESULT; overload;
begin
Result := cxSendStructMessageEx(AHandle, AMsg, LParam, WParam, True);
end;
function cxSendStructMessage(AHandle: THandle; AMsg: UINT; const WParam; LParam: LParam): LRESULT; overload;
begin
Result := cxSendStructMessageEx(AHandle, AMsg, WParam, LParam, False);
end;
function cxRichEditDLLNames: TcxRichEditNames;
procedure InitRichEditDLLNames;
const
cxRichEditDLLNamesCount = 3;
begin
SetLength(FRichEditDLLNames, cxRichEditDLLNamesCount);
FRichEditDLLNames[0] := 'Riched32.dll';
FRichEditDLLNames[1] := 'Riched20.dll';
FRichEditDLLNames[2] := 'Msftedit.dll';
end;
begin
if Length(FRichEditDLLNames) = 0 then
InitRichEditDLLNames;
Result := FRichEditDLLNames;
end;
function cxRichEditClassNames: TcxRichEditNames;
procedure InitRichEditClassNames;
const
cxRichEditClassNamesCount = 5;
begin
SetLength(FRichEditClassNames, cxRichEditClassNamesCount);
FRichEditClassNames[0] := 'RICHEDIT';
FRichEditClassNames[1] := 'RICHEDIT20';
FRichEditClassNames[2] := 'RICHEDIT30';
FRichEditClassNames[3] := 'RICHEDIT41';
FRichEditClassNames[4] := 'RICHEDIT50';
end;
begin
if Length(FRichEditClassNames) = 0 then
InitRichEditClassNames;
Result := FRichEditClassNames;
end;
function AdjustRichLineBreaks(ADest, ASource: PChar; AShortBreak: Boolean = False): Integer;
var
APrevDest: PChar;
begin
APrevDest := ADest;
repeat
if ASource^ in [#13, #10] then
begin
if AShortBreak then
ADest^ := #13
else
begin
PWord(ADest)^ := $0A0D;
Inc(ADest);
end;
if PWord(ASource)^ = $0A0D then
Inc(ASource);
end
else
ADest^ := ASource^;
Inc(ASource);
Inc(ADest);
until ASource^ = Char(0);
ADest^ := #0;
Result := ADest - APrevDest;
end;
function cxRichEditStreamLoad(dwCookie: Longint; pbBuff: PByte;
cb: Longint; var pcb: Longint): Longint; stdcall;
var
ABuffer, P: PChar;
AStreamInfo: PRichEditStreamInfo;
begin
Result := cxRichNoError;
AStreamInfo := PRichEditStreamInfo(Pointer(dwCookie));
ABuffer := StrAlloc(cb + 1);
try
cb := cb div 2;
pcb := 0;
P := ABuffer + cb;
try
if AStreamInfo^.Converter <> nil then
pcb := AStreamInfo^.Converter.ConvertReadStream(AStreamInfo^.Stream, P,
cb);
if pcb > 0 then
begin
P[pcb] := #0;
if P[pcb - 1] = #13 then
P[pcb - 1] := #0;
pcb := AdjustRichLineBreaks(ABuffer, P);
Move(ABuffer^, pbBuff^, pcb);
end;
except
Result := cxRichReadError;
end;
finally
StrDispose(ABuffer);
end;
end;
function cxRichEditStreamSave(dwCookie: Longint; pbBuff: PByte; cb: Longint;
var pcb: Longint): Longint; stdcall;
var
AStreamInfo: PRichEditStreamInfo;
begin
Result := cxRichNoError;
AStreamInfo := PRichEditStreamInfo(Pointer(dwCookie));
try
pcb := 0;
if AStreamInfo^.Converter <> nil then
pcb := AStreamInfo^.Converter.ConvertWriteStream(AStreamInfo^.Stream,
PChar(pbBuff), cb);
except
Result := cxRichWriteError;
end;
end;
function IsRichText(const AText: string): Boolean;
const
ARichPrefix = '{\rtf';
begin
Result := Copy(AText, 1, Length(ARichPrefix)) = ARichPrefix;
end;
procedure LoadRichFromString(ALines: TStrings; const S: string);
procedure PrepareStream(
AStream: TStringStream);
begin
end;
var
AStream: TStringStream;
begin
AStream := TStringStream.Create(S);
try
PrepareStream(AStream);
ALines.LoadFromStream(AStream);
finally
AStream.Free;
end;
end;
procedure ReleaseConversionFormatList;
var
AConversionFormatList: PConversionFormat;
begin
while FConversionFormatList <> @TextConversionFormat do
begin
AConversionFormatList := FConversionFormatList^.Next;
Dispose(FConversionFormatList);
FConversionFormatList := AConversionFormatList;
end;
end;
function CreateInnerRich: TcxRichInnerEdit;
begin
Result := nil;
if Application.Handle <> 0 then
begin
Result := TcxRichInnerEdit.Create(nil);
Result.ParentWindow := Application.Handle;
SendMessage(Result.Handle, EM_SETEVENTMASK, 0, 0);
end;
end;
function RichRenderer: TcxRichInnerEdit;
begin
if FRichRenderer = nil then
FRichRenderer := CreateInnerRich;
Result := FRichRenderer;
end;
function RichConverter: TcxRichInnerEdit;
begin
if FRichConverter = nil then
FRichConverter := CreateInnerRich;
Result := FRichConverter;
end;
procedure InternalSetRichEditText(ARichEdit: TRichEdit; const AText: string);
begin
if not ARichEdit.PlainText then
LoadRichFromString(ARichEdit.Lines, AText)
else
ARichEdit.Perform(WM_SETTEXT, 0, Longint(PChar(AText)));
end;
function ConvertRichText(const AText: string): string;
begin
InternalSetRichEditText(RichConverter, AText);
Result := RichConverter.Text;
end;
procedure SetRichDefAttributes(AEdit: TRichEdit; AFont: TFont; ATextColor: TColor);
begin
if not AEdit.HandleAllocated then
Exit;
AEdit.DefAttributes.Assign(AFont);
AEdit.DefAttributes.Color := ATextColor;
end;
procedure InitRichRenderer(AProperties: TcxCustomRichEditProperties;
AFont: TFont; AColor, ATextColor: TColor; const AText: string);
begin
RichRenderer.MemoMode := TcxCustomRichEditProperties(AProperties).MemoMode;
RichRenderer.PlainText := TcxCustomRichEditProperties(AProperties).PlainText;
RichRenderer.Alignment := TcxCustomRichEditProperties(AProperties).Alignment;
RichRenderer.HandleNeeded;
if not RichRenderer.MemoMode then
LoadRichFromString(RichRenderer.RichLines, AText)
else
RichRenderer.Text := AText;
if not IsRichText(AText) or RichRenderer.MemoMode or RichRenderer.PlainText then
SetRichDefAttributes(RichRenderer, AFont, ATextColor);
SendMessage(RichRenderer.Handle, EM_SETBKGNDCOLOR, 0, ColorToRGB(AColor));
end;
procedure DrawRichEdit(ADC: HDC; const ARect: TRect; const AText: string;
AProperties: TcxCustomRichEditProperties; AFont: TFont;
AColor, ATextColor: TColor; ACalculateHeight: Boolean; out AHeight: Integer);
const
TwipsPerInch = 1440;
var
AFormatRange: TFormatRange;
AStartIndex: Integer;
begin
if not ACalculateHeight then
FillRect(ADC, Rect(0, 0, ARect.Right - ARect.Left,
ARect.Bottom - ARect.Top), GetSolidBrush(AColor));
InitRichRenderer(AProperties, AFont, AColor, ATextColor, AText);
SendMessage(RichRenderer.Handle, EM_FORMATRANGE, 0, 0);
if ACalculateHeight then
AHeight := 0;
AFormatRange.hdc := ADC;
AFormatRange.hdcTarget := ADC;
AFormatRange.chrg.cpMin := 0;
AFormatRange.chrg.cpMax := -1;
repeat
AFormatRange.rc := cxEmptyRect;
AFormatRange.rc.Right := (ARect.Right - ARect.Left) * TwipsPerInch div GetDeviceCaps(ADC, LOGPIXELSX);
if ACalculateHeight then
AFormatRange.rc.Bottom := TwipsPerInch
else
AFormatRange.rc.Bottom := (ARect.Bottom - ARect.Top)(*65535*) * TwipsPerInch div GetDeviceCaps(ADC, LOGPIXELSY);
AFormatRange.rcPage := AFormatRange.rc;
AStartIndex := AFormatRange.chrg.cpMin;
AFormatRange.chrg.cpMin := cxSendStructMessage(RichRenderer.Handle, EM_FORMATRANGE,
WPARAM(not ACalculateHeight), AFormatRange);
if AFormatRange.chrg.cpMin <= AStartIndex then
Break;
if ACalculateHeight then
Inc(AHeight, AFormatRange.rc.Bottom - AFormatRange.rc.Top);
until not ACalculateHeight;
if ACalculateHeight then
AHeight := AHeight * GetDeviceCaps(ADC, LOGPIXELSY) div TwipsPerInch;
SendMessage(RichRenderer.Handle, EM_FORMATRANGE, 0, 0);
end;
procedure SetRichEditText(ARichEdit: TRichEdit; const AEditValue: TcxEditValue);
begin
InternalSetRichEditText(ARichEdit, VarToStr(AEditValue));
end;
{ TcxRichEdit }
class function TcxRichEdit.GetPropertiesClass: TcxCustomEditPropertiesClass;
begin
Result := TcxRichEditProperties;
end;
function TcxRichEdit.GetActiveProperties: TcxRichEditProperties;
begin
Result := TcxRichEditProperties(InternalGetActiveProperties);
end;
function TcxRichEdit.GetProperties: TcxRichEditProperties;
begin
Result := TcxRichEditProperties(FProperties);
end;
procedure TcxRichEdit.SetProperties(Value: TcxRichEditProperties);
begin
FProperties.Assign(Value);
end;
{ TcxRichInnerEditHelper }
constructor TcxRichInnerEditHelper.Create(AEdit: TcxRichInnerEdit);
begin
inherited Create(nil);
FEdit := AEdit;
FEdit.PlainText := False;
FEdit.WordWrap := False;
end;
function TcxRichInnerEditHelper.GetControl: TWinControl;
begin
Result := Edit;
end;
procedure TcxRichInnerEditHelper.LockBounds(ALock: Boolean);
begin
with Edit do
if ALock then
Inc(FLockBoundsCount)
else
if FLockBoundsCount > 0 then
Dec(FLockBoundsCount);
end;
function TcxRichInnerEditHelper.GetOnChange: TNotifyEvent;
begin
Result := Edit.OnChange;
end;
procedure TcxRichInnerEditHelper.SafelySetFocus;
var
APrevAutoSelect: Boolean;
begin
with Edit do
begin
APrevAutoSelect := AutoSelect;
AutoSelect := False;
SetFocus;
AutoSelect := APrevAutoSelect;
end;
end;
function TcxRichInnerEditHelper.CallDefWndProc(AMsg: UINT; WParam: WPARAM;
LParam: LPARAM): LRESULT;
begin
Result := CallWindowProc(Edit.DefWndProc, Edit.Handle, AMsg, WParam, LParam);
end;
function TcxRichInnerEditHelper.GetEditValue: TcxEditValue;
begin
with Edit do
Result := Text;
end;
procedure TcxRichInnerEditHelper.SetEditValue(const Value: TcxEditValue);
var
AContainer: TcxCustomRichEdit;
begin
AContainer := Edit.Container;
if AContainer.PropertiesChange then
Exit;
if AContainer.ActiveProperties.MemoMode or not CanAllocateHandle(Edit) then
Edit.Text := VarToStr(Value)
else
begin
Edit.Container.LockChangeEvents(True);
try
Edit.HandleNeeded;
LoadRichFromString(Edit.RichLines, VarToStr(Value));
finally
Edit.Container.LockChangeEvents(False);
end;
end;
end;
procedure TcxRichInnerEditHelper.SetParent(Value: TWinControl);
begin
Edit.Parent := Value;
end;
procedure TcxRichInnerEditHelper.SetOnChange(Value: TNotifyEvent);
begin
Edit.OnChange := Value;
end;
// IcxInnerTextEdit
procedure TcxRichInnerEditHelper.ClearSelection;
begin
Edit.ClearSelection;
end;
procedure TcxRichInnerEditHelper.CopyToClipboard;
begin
Edit.CopyToClipboard;
end;
function TcxRichInnerEditHelper.GetAlignment: TAlignment;
begin
Result := Edit.Alignment;
end;
function TcxRichInnerEditHelper.GetAutoSelect: Boolean;
begin
Result := Edit.AutoSelect;
end;
function TcxRichInnerEditHelper.GetCharCase: TEditCharCase;
begin
Result := Edit.CharCase;
end;
function TcxRichInnerEditHelper.GetEchoMode: TcxEditEchoMode;
begin
Result := eemNormal;
end;
function TcxRichInnerEditHelper.GetHideSelection: Boolean;
begin
Result := Edit.HideSelection;
end;
function TcxRichInnerEditHelper.GetInternalUpdating: Boolean;
begin
Result := Edit.FInternalUpdating;
end;
function TcxRichInnerEditHelper.GetMaxLength: Integer;
begin
Result := Edit.MaxLength;
end;
function TcxRichInnerEditHelper.GetMultiLine: Boolean;
begin
Result := True;
end;
function TcxRichInnerEditHelper.GetOEMConvert: Boolean;
begin
Result := Edit.OEMConvert;
end;
function TcxRichInnerEditHelper.GetOnSelChange: TNotifyEvent;
begin
Result := Edit.OnSelectionChange;
end;
function TcxRichInnerEditHelper.GetPasswordChar: TCaptionChar;
begin
Result := #0;
end;
function TcxRichInnerEditHelper.GetReadOnly: Boolean;
begin
Result := Edit.ReadOnly;
end;
function TcxRichInnerEditHelper.GetSelLength: Integer;
begin
Result := Edit.SelLength;
end;
function TcxRichInnerEditHelper.GetSelStart: Integer;
begin
Result := Edit.SelStart;
end;
function TcxRichInnerEditHelper.GetSelText: string;
begin
Result := Edit.SelText;
end;
procedure TcxRichInnerEditHelper.SelectAll;
begin
if not Edit.Container.IsInplace then
Edit.SelectAll;
end;
procedure TcxRichInnerEditHelper.SetAlignment(Value: TAlignment);
begin
Edit.Alignment := Value;
end;
procedure TcxRichInnerEditHelper.SetAutoSelect(Value: Boolean);
begin
Edit.AutoSelect := Value;
end;
procedure TcxRichInnerEditHelper.SetCharCase(Value: TEditCharCase);
begin
Edit.CharCase := Value;
end;
procedure TcxRichInnerEditHelper.SetEchoMode(Value: TcxEditEchoMode);
begin
end;
procedure TcxRichInnerEditHelper.SetHideSelection(Value: Boolean);
begin
if not Edit.Container.IsInplace then
Edit.HideSelection := Value;
end;
procedure TcxRichInnerEditHelper.SetInternalUpdating(Value: Boolean);
begin
Edit.FInternalUpdating := Value;
end;
procedure TcxRichInnerEditHelper.SetImeMode(Value: TImeMode);
begin
Edit.ImeMode := Value;
end;
procedure TcxRichInnerEditHelper.SetImeName(const Value: TImeName);
begin
Edit.ImeName := Value;
end;
procedure TcxRichInnerEditHelper.SetMaxLength(Value: Integer);
begin
Edit.MaxLength := Value;
end;
procedure TcxRichInnerEditHelper.SetOEMConvert(Value: Boolean);
begin
Edit.OEMConvert := Value;
end;
procedure TcxRichInnerEditHelper.SetOnSelChange(Value: TNotifyEvent);
begin
Edit.OnSelectionChange := Value;
end;
procedure TcxRichInnerEditHelper.SetPasswordChar(Value: TCaptionChar);
begin
end;
procedure TcxRichInnerEditHelper.SetReadOnly(Value: Boolean);
begin
Edit.ReadOnly := Value;
end;
procedure TcxRichInnerEditHelper.SetSelLength(Value: Integer);
begin
Edit.SelLength := Value;
end;
procedure TcxRichInnerEditHelper.SetSelStart(Value: Integer);
begin
with Edit do
SelStart := Value;
end;
procedure TcxRichInnerEditHelper.SetSelText(Value: string);
begin
Edit.SelText := Value;
end;
function TcxRichInnerEditHelper.GetImeLastChar: Char;
begin
Result := #0;
end;
function TcxRichInnerEditHelper.GetImeMode: TImeMode;
begin
Result := Edit.ImeMode;
end;
function TcxRichInnerEditHelper.GetImeName: TImeName;
begin
Result := Edit.ImeName;
end;
function TcxRichInnerEditHelper.GetControlContainer: TcxContainer;
begin
Result := Edit.Container;
end;
// IcxInnerMemo
function TcxRichInnerEditHelper.GetCaretPos: TPoint;
begin
Result := Edit.CaretPos;
end;
function TcxRichInnerEditHelper.GetLines: TStrings;
begin
Result := Edit.Lines;
end;
function TcxRichInnerEditHelper.GetScrollBars: TScrollStyle;
begin
Result := Edit.ScrollBars;
end;
function TcxRichInnerEditHelper.GetWantReturns: Boolean;
begin
Result := Edit.WantReturns;
end;
function TcxRichInnerEditHelper.GetWantTabs: Boolean;
begin
Result := Edit.WantTabs;
end;
function TcxRichInnerEditHelper.GetWordWrap: Boolean;
begin
Result := Edit.WordWrap;
end;
procedure TcxRichInnerEditHelper.SetCaretPos(const Value: TPoint);
begin
SetMemoCaretPos(Edit, Value);
end;
procedure TcxRichInnerEditHelper.SetScrollBars(Value: TScrollStyle);
begin
Edit.ScrollBars := Value;
end;
procedure TcxRichInnerEditHelper.SetWantReturns(Value: Boolean);
begin
Edit.WantReturns := Value;
end;
procedure TcxRichInnerEditHelper.SetWantTabs(Value: Boolean);
begin
Edit.WantTabs := Value;
end;
procedure TcxRichInnerEditHelper.SetWordWrap(Value: Boolean);
begin
Edit.WordWrap := Value;
end;
{ TcxRichEditStrings }
constructor TcxRichEditStrings.Create(ARichEdit: TcxRichInnerEdit);
begin
inherited Create;
FRichEdit := ARichEdit;
FTextType := SF_TEXT;
end;
destructor TcxRichEditStrings.Destroy;
begin
FreeAndNil(FConverter);
inherited Destroy;
end;
procedure TcxRichEditStrings.Clear;
begin
if Count > 0 then
RichEdit.Lines.Clear;
end;
procedure TcxRichEditStrings.AddStrings(Strings: TStrings);
var
APrevSelectionChange: TNotifyEvent;
begin
APrevSelectionChange := RichEdit.OnSelectionChange;
RichEdit.OnSelectionChange := nil;
try
inherited AddStrings(Strings);
finally
RichEdit.OnSelectionChange := APrevSelectionChange;
end;
end;
procedure TcxRichEditStrings.Delete(Index: Integer);
begin
FRichEdit.Lines.Delete(Index);
end;
procedure TcxRichEditStrings.Insert(Index: Integer; const S: string);
var
AFormat: string;
AStr: PChar;
ASelection: TCharRange;
begin
if (Index < 0) or (Index > Count) then
Exit;
ASelection.cpMin := FRichEdit.GetLineIndex(Index);
if ASelection.cpMin < 0 then
begin
ASelection.cpMin := FRichEdit.GetLineIndex(Index - 1);
if ASelection.cpMin < 0 then
ASelection.cpMin := 0
else
ASelection.cpMin := ASelection.cpMin + FRichEdit.GetLineLength(Index - 1);
AFormat := GetLineBreakString + '%s';
end
else
AFormat := '%s'+ GetLineBreakString;
ASelection.cpMax := ASelection.cpMin;
AStr := PChar(Format(AFormat, [S]));
cxSendStructMessage(FRichEdit.Handle, EM_EXSETSEL, 0, ASelection);
AdjustRichLineBreaks(AStr, PChar(Format(AFormat, [S])), Length(GetLineBreakString) = 1);
SendMessage(FRichEdit.Handle, EM_REPLACESEL, 0, LongInt(AStr));
if FRichEdit.SelStart <> (ASelection.cpMax + Length(WideString(AStr))) then
raise EOutOfResources.Create(
cxGetResourceString(@cxSEditRichEditLineInsertionError));
end;
procedure TcxRichEditStrings.LoadFromFile(const FileName: string);
begin
InitConverter(FileName);
inherited LoadFromFile(FileName);
FRichEdit.Container.EditModified := False
end;
procedure TcxRichEditStrings.LoadFromStream(Stream: TStream);
var
APos: Longint;
AStreamOperationInfo: TcxRichEditStreamOperationInfo;
begin
APos := Stream.Position;
try
InitStreamOperation(Stream, AStreamOperationInfo, esoLoadFrom);
with AStreamOperationInfo do
begin
SendMessage(RichEdit.Handle, EM_STREAMIN, TextType, Longint(@EditStream));
if (TextType = SF_RTF) and (EditStream.dwError <> 0) then
begin
Stream.Position := APos;
TextType := SF_TEXT;
cxSendStructMessage(RichEdit.Handle, EM_STREAMIN, TextType, EditStream);
end;
if EditStream.dwError <> 0 then
raise EOutOfResources.Create(cxGetResourceString(@cxSEditRichEditLoadFail));
FTextType := TextType;
end;
finally
if FConverter = nil then
FreeAndNil(AStreamOperationInfo.StreamInfo.Converter);
end;
with FRichEdit do
if Container <> nil then
Container.EditModified := False
end;
procedure TcxRichEditStrings.SaveToFile(const FileName: string);
begin
InitConverter(FileName);
inherited SaveToFile(FileName);
end;
procedure TcxRichEditStrings.SaveToStream(Stream: TStream);
var
AStreamOperationInfo: TcxRichEditStreamOperationInfo;
begin
try
InitStreamOperation(Stream, AStreamOperationInfo, esoSaveTo);
with AStreamOperationInfo do
begin
cxSendStructMessage(RichEdit.Handle, EM_STREAMOUT, TextType, EditStream);
if EditStream.dwError <> 0 then
raise EOutOfResources.Create(cxGetResourceString(@cxSEditRichEditSaveFail));
end;
finally
if FConverter = nil then
FreeAndNil(AStreamOperationInfo.StreamInfo.Converter);
end;
end;
function TcxRichEditStrings.Get(Index: Integer): string;
begin
Result := FRichEdit.Lines[Index];
while (Length(Result) > 0) and (Result[Length(Result)] in [#10, #13]) do
System.Delete(Result, Length(Result), 1);
end;
procedure TcxRichEditStrings.InitConverter(const AFileName: string);
var
AExtension: string;
AConversionFormat: PConversionFormat;
begin
AExtension := AnsiLowerCaseFileName(ExtractFileExt(AFilename));
System.Delete(AExtension, 1, 1);
AConversionFormat := FConversionFormatList;
while AConversionFormat <> nil do
with AConversionFormat^ do
if Extension <> AExtension then AConversionFormat := Next
else Break;
if AConversionFormat = nil then
AConversionFormat := @TextConversionFormat;
if (FConverter = nil) or
(FConverter.ClassType <> AConversionFormat^.ConversionClass) then
begin
FreeAndNil(FConverter);
FConverter := AConversionFormat^.ConversionClass.Create;
end;
end;
procedure TcxRichEditStrings.InitStreamOperation(AStream: TStream;
var AStreamOperationInfo: TcxRichEditStreamOperationInfo;
AStreamOperation: TcxRichEditStreamOperation);
var
AConverter: TConversion;
begin
if FConverter <> nil then
AConverter := FConverter
else
AConverter := RichEdit.DefaultConverter.Create;
with AStreamOperationInfo do
begin
StreamInfo.Converter := AConverter;
StreamInfo.Stream := AStream;
EditStream.dwCookie := Longint(Pointer(@StreamInfo));
if AStreamOperation = esoLoadFrom then
EditStream.pfnCallBack := @cxRichEditStreamLoad
else
EditStream.pfnCallBack := @cxRichEditStreamSave;
EditStream.dwError := 0;
if RichEdit.MemoMode or RichEdit.PlainText then
TextType := SF_TEXT
else
TextType := SF_RTF;
end;
end;
function TcxRichEditStrings.GetCount: Integer;
begin
Result := RichEdit.GetLineCount;
if (Result > 0) and (RichEdit.GetLineLength(Result - 1) = 0) then
Dec(Result);
end;
procedure TcxRichEditStrings.Put(Index: Integer; const S: string);
begin
TStringsAccess(FRichEdit.Lines).Put(Index, S);
end;
procedure TcxRichEditStrings.SetUpdateState(Updating: Boolean);
begin
TStringsAccess(FRichEdit.Lines).SetUpdateState(Updating);
end;
procedure TcxRichEditStrings.SetTextStr(const Value: string);
begin
FRichEdit.Container.Text := Value;
end;
function TcxRichEditStrings.GetLineBreakString: string;
begin
if FRichEdit.RichVersion >= 200 then
Result := #13
else
Result := #13#10
end;
{ TcxRichInnerEdit }
constructor TcxRichInnerEdit.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
ParentColor := True;
ParentFont := True;
FEchoMode := eemNormal;
FHelper := TcxRichInnerEditHelper.Create(Self);
FInternalUpdating := False;
FRichLines := TcxRichEditStrings.Create(Self);
FUseCRLF := True;
end;
destructor TcxRichInnerEdit.Destroy;
begin
FreeAndNil(FRichLines);
FreeAndNil(FHelper);
inherited Destroy;
end;
procedure TcxRichInnerEdit.DefaultHandler(var Message);
begin
if (Container = nil) or
not Container.InnerControlDefaultHandler(TMessage(Message)) then
inherited DefaultHandler(Message);
end;
procedure TcxRichInnerEdit.DragDrop(Source: TObject; X, Y: Integer);
begin
Container.DragDrop(Source, Left + X, Top + Y);
end;
function TcxRichInnerEdit.ExecuteAction(Action: TBasicAction): Boolean;
begin
Result := inherited ExecuteAction(Action) or (Container <> nil) and
Container.DataBinding.ExecuteAction(Action);
end;
function TcxRichInnerEdit.FindText(const ASearchStr: string;
AStartPos, ALength: Longint; AOptions: TSearchTypes): Integer;
var
AFindText: TFindText;
AFlags: Integer;
begin
with AFindText.chrg do
begin
cpMin := AStartPos;
cpMax := cpMin + ALength;
end;
AFlags := FR_DOWN;
if stWholeWord in AOptions then AFlags := AFlags or FT_WHOLEWORD;
if stMatchCase in AOptions then AFlags := AFlags or FT_MATCHCASE;
AFindText.lpstrText := PChar(ASearchStr);
Result := cxSendStructMessage(Handle, EM_FINDTEXT, AFlags, AFindText);
end;
procedure TcxRichInnerEdit.Print(const Caption: string);
var
AIsCRLFUsed: Boolean;
begin
AIsCRLFUsed := FUseCRLF;
FUseCRLF := False;
try
inherited;
finally
FUseCRLF := AIsCRLFUsed;
end;
end;
procedure TcxRichInnerEdit.Click;
begin
inherited Click;
_TcxContainerAccess.Click(Container);
end;
procedure TcxRichInnerEdit.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
RichCreateParams(Params, FRichVersion);
with Params.WindowClass do
style := style or CS_VREDRAW or CS_HREDRAW;
if SelectionBar then
Params.Style := Params.Style or ES_SELECTIONBAR;
end;
procedure TcxRichInnerEdit.CreateWnd;
begin
if Container <> nil then
begin
Alignment := Container.ActiveProperties.Alignment;
Container.ClearSavedChildControlRegions;
PlainText := FSavedPlainText;
end;
inherited CreateWnd;
if Container <> nil then
PlainText := Container.ActiveProperties.PlainText or Container.ActiveProperties.MemoMode;
SendMessage(Handle, EM_SETEVENTMASK, 0, ENM_CHANGE or ENM_SELCHANGE or
ENM_REQUESTRESIZE or ENM_PROTECTED or ENM_KEYEVENTS);
if MaxLength = 0 then
SendMessage(Handle, EM_EXLIMITTEXT, 0, MaxLongint);
InternalSetMemoMode;
end;
procedure TcxRichInnerEdit.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
begin
if FLockBoundsCount = 0 then
inherited SetBounds(ALeft, ATop, AWidth, AHeight);
end;
function TcxRichInnerEdit.UpdateAction(Action: TBasicAction): Boolean;
begin
Result := inherited UpdateAction(Action) or (Container <> nil) and
Container.DataBinding.UpdateAction(Action);
end;
function TcxRichInnerEdit.CanFocus: Boolean;
begin
if Container = nil then
Result := inherited CanFocus
else
Result := Container.CanFocusEx;
end;
function TcxRichInnerEdit.CanRedo: Boolean;
begin
Result := False;
if HandleAllocated then
Result := SendMessage(Handle, EM_CANREDO, 0, 0) <> 0;
end;
procedure TcxRichInnerEdit.Redo;
begin
if HandleAllocated then
SendMessage(Handle, EM_REDO, 0, 0);
end;
procedure TcxRichInnerEdit.Undo;
begin
if HandleAllocated then
SendMessage(Handle, EM_UNDO, 0, 0);
end;
procedure TcxRichInnerEdit.DblClick;
begin
inherited DblClick;
_TcxContainerAccess.DblClick(Container);
end;
procedure TcxRichInnerEdit.DestroyWnd;
begin
FSavedPlainText := PlainText;
inherited DestroyWnd;
end;
procedure TcxRichInnerEdit.DoEnter;
begin
inherited DoEnter;
if FAutoSelect then
SelectAll;
end;
procedure TcxRichInnerEdit.DragOver(Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
begin
_TcxContainerAccess.DragOver(Container, Source, Left + X, Top + Y, State, Accept);
end;
procedure TcxRichInnerEdit.KeyDown(var Key: Word; Shift: TShiftState);
begin
FInternalUpdating := False;
_TcxContainerAccess.KeyDown(Container, Key, Shift);
if Key = 0 then
FInternalUpdating := True
else
inherited KeyDown(Key, Shift);
if (RichVersion >= 200) and (Key = VK_RETURN) and not WantReturns and
not(ssCtrl in InternalGetShiftState) then
begin
Key := 0;
Exit;
end;
end;
procedure TcxRichInnerEdit.KeyPress(var Key: Char);
begin
FInternalUpdating := False;
// Ctrl+I calls KeyPress with Key = Char(VK_TAB). A tab must be inserted even when WantTabs = False
// if not WantTabs and (Key = Char(VK_TAB)) then
// Key := #0;
_TcxContainerAccess.KeyPress(Container, Key);
if Key = #0 then
FInternalUpdating := True
else
inherited KeyPress(Key);
end;
procedure TcxRichInnerEdit.KeyUp(var Key: Word; Shift: TShiftState);
begin
FInternalUpdating := False;
if not WantTabs and ((Key = VK_TAB)) then
Key := 0;
_TcxContainerAccess.KeyUp(Container, Key, Shift);
if Key = 0 then
FInternalUpdating := True
else
inherited KeyUp(Key, Shift);
end;
procedure TcxRichInnerEdit.MouseDown(Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
inherited MouseDown(Button, Shift, X, Y);
_TcxContainerAccess.MouseDown(Container, Button, Shift, X + Left, Y + Top);
end;
procedure TcxRichInnerEdit.MouseLeave(AControl: TControl);
begin
Container.ShortRefreshContainer(True);
end;
procedure TcxRichInnerEdit.MouseMove(Shift: TShiftState; X, Y: Integer);
begin
inherited MouseMove(Shift, X, Y);
_TcxContainerAccess.MouseMove(Container, Shift, X + Left, Y + Top);
end;
procedure TcxRichInnerEdit.MouseUp(Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
inherited MouseUp(Button, Shift, X, Y);
_TcxContainerAccess.MouseUp(Container, Button, Shift, X + Left, Y + Top);
end;
procedure TcxRichInnerEdit.RequestAlign;
begin
end;
procedure TcxRichInnerEdit.RequestSize(const Rect: TRect);
var
R: TRect;
begin
if Container <> nil then
begin
R := Rect;
Dec(R.Left, Left);
Dec(R.Top, Top);
Inc(R.Right, Container.Width - Width - Left);
Inc(R.Bottom, Container.Height - Height - Top);
OffsetRect(R, Container.Left, Container.Top);
Container.DoOnResizeRequest(R);
end;
end;
procedure TcxRichInnerEdit.RichCreateParams(var Params: TCreateParams;
out ARichVersion: Integer);
var
ARichClassName: string;
AWndClass: TWndClass;
I: Integer;
begin
if FRichEditLibrary = 0 then
for I := High(cxRichEditDLLNames) downto Low(cxRichEditDLLNames) do
begin
FRichEditLibrary := LoadLibrary(PChar(cxRichEditDLLNames[I]));
if FRichEditLibrary <> 0 then
Break;
end;
if FRichEditLibrary = 0 then
raise EcxEditError.Create(cxGetResourceString(@cxSEditRichEditLibraryError));
for I := High(cxRichEditClassNames) downto Low(cxRichEditClassNames) do
begin
// ARichClassName := cxRichEditClassNames[I] + 'W';
// if GetClassInfo(HInstance, PChar(ARichClassName), AWndClass) then
// Break;
ARichClassName := cxRichEditClassNames[I] + 'A';
if GetClassInfo(HInstance, PChar(ARichClassName), AWndClass) then
Break;
ARichClassName := cxRichEditClassNames[I];
if GetClassInfo(HInstance, PChar(ARichClassName), AWndClass) then
Break;
end;
if GetClassInfo(HInstance, PChar(ARichClassName), AWndClass) then
ARichVersion := cxRichEditVersions[I]
else
raise EcxEditError.Create(cxGetResourceString(@cxSEditRichEditLibraryError));
CreateSubClass(Params, PChar(ARichClassName));
end;
procedure TcxRichInnerEdit.SelectionChange;
begin
inherited SelectionChange;
if Container <> nil then
Container.DoOnSelectionChange;
end;
procedure TcxRichInnerEdit.WndProc(var Message: TMessage);
begin
if (Container <> nil) and Container.InnerControlMenuHandler(Message) then
Exit;
if ((Message.Msg = WM_LBUTTONDOWN) or (Message.Msg = WM_LBUTTONDBLCLK)) and
(Container.DragMode = dmAutomatic) and not Container.IsDesigning then
begin
_TcxContainerAccess.BeginAutoDrag(Container);
Exit;
end;
inherited WndProc(Message);
end;
function TcxRichInnerEdit.CanPaste: Boolean;
begin
Result := False;
if HandleAllocated then
Result := SendMessage(Handle, EM_CANPASTE, 0, 0) <> 0;
end;
function TcxRichInnerEdit.GetSelection: TCharRange;
begin
cxSendStructMessage(Handle, EM_EXGETSEL, 0, Result);
end;
//IcxContainerInnerControl
function TcxRichInnerEdit.GetControl: TWinControl;
begin
Result := Self;
end;
function TcxRichInnerEdit.GetControlContainer: TcxContainer;
begin
Result := Container;
end;
// IcxInnerEditHelper
function TcxRichInnerEdit.GetHelper: IcxCustomInnerEdit;
begin
Result := Helper;
end;
function TcxRichInnerEdit.GetContainer: TcxCustomRichEdit;
begin
if Parent is TcxCustomRichEdit then
Result := TcxCustomRichEdit(Parent)
else
Result := nil;
end;
function TcxRichInnerEdit.GetLineCount: Integer;
begin
Result := SendMessage(Handle, EM_GETLINECOUNT, 0, 0);
end;
function TcxRichInnerEdit.GetLineIndex(AIndex: Integer): Integer;
begin
Result := SendMessage(Handle, EM_LINEINDEX , AIndex, 0);
end;
function TcxRichInnerEdit.GetLineLength(AIndex: Integer): Integer;
begin
if GetLineIndex(AIndex) <> -1 then
Result := SendMessage(Handle, EM_LINELENGTH, GetLineIndex(AIndex), 0)
else
Result := 0;
end;
function TcxRichInnerEdit.GetRichLines: TcxRichEditStrings;
begin
Result := FRichLines;
end;
procedure TcxRichInnerEdit.InternalSetMemoMode;
var
AText: string;
ATextMode: LRESULT;
begin
if not HandleAllocated then
Exit;
ATextMode := SendMessage(Handle, EM_GETTEXTMODE, 0, 0);
if MemoMode and (ATextMode and TM_PLAINTEXT <> 0) or
not MemoMode and (ATextMode and TM_RICHTEXT <> 0) then
Exit;
AText := Text;
SendMessage(Handle, WM_SETTEXT, 0, 0);
if MemoMode then
ATextMode := ATextMode and not TM_RICHTEXT or TM_PLAINTEXT
else
ATextMode := ATextMode and not TM_PLAINTEXT or TM_RICHTEXT;
SendMessage(Handle, EM_SETTEXTMODE, ATextMode, 0);
Text := AText;
end;
procedure TcxRichInnerEdit.SetMemoMode(Value: Boolean);
begin
if Value <> FMemoMode then
begin
FMemoMode := Value;
RecreateWnd;
end;
end;
procedure TcxRichInnerEdit.SetRichLines(Value: TcxRichEditStrings);
begin
FRichLines.Assign(Value);
end;
procedure TcxRichInnerEdit.SetSelectionBar(Value: Boolean);
begin
if Value <> FSelectionBar then
begin
FSelectionBar := Value;
RecreateWnd;
end;
end;
procedure TcxRichInnerEdit.WMClear(var Message: TMessage);
begin
if (Self.SelLength > 0) and Container.DoEditing then
inherited;
end;
procedure TcxRichInnerEdit.WMCut(var Message: TMessage);
begin
if SelLength > 0 then
if Container.DoEditing then
inherited
else
Container.CopyToClipboard;
end;
procedure TcxRichInnerEdit.WMEraseBkgnd(var Message: TWMEraseBkgnd);
begin
if FIsEraseBackgroundLocked or (Container <> nil) and Container.IsInplace then
Message.Result := 1
else
CallWindowProc(DefWndProc, Handle, Message.Msg, Message.DC, 0);
end;
procedure TcxRichInnerEdit.WMGetDlgCode(var Message: TWMGetDlgCode);
begin
inherited;
if Container.TabsNeeded and (GetKeyState(VK_CONTROL) >= 0) then
Message.Result := Message.Result or DLGC_WANTTAB;
if FEscapePressed then
Message.Result := Message.Result and not DLGC_WANTALLKEYS;
end;
procedure TcxRichInnerEdit.WMKeyDown(var Message: TWMKeyDown);
var
AKey: Word;
APrevState: TcxCustomInnerTextEditPrevState;
AShiftState: TShiftState;
begin
if Message.CharCode <> VK_ESCAPE then
FKeyPressProcessed := True;
try
SaveTextEditState(Helper, False, APrevState);
FInternalUpdating := False;
inherited;
Container.SetScrollBarsParameters;
if FInternalUpdating then
Exit;
finally
FKeyPressProcessed := False;
end;
AShiftState := KeyDataToShiftState(Message.KeyData);
AKey := Message.CharCode;
if (AKey <> 0) and not Container.CanKeyDownModifyEdit(AKey, AShiftState) and
not CheckTextEditState(Helper, APrevState) and
not Container.IsNavigationKey(AKey, AShiftState) then
Container.DoAfterKeyDown(AKey, AShiftState);
Message.CharCode := AKey;
end;
procedure TcxRichInnerEdit.WMKillFocus(var Message: TWMKillFocus);
begin
inherited;
if not(csDestroying in ComponentState) then
Container.FocusChanged;
end;
procedure TcxRichInnerEdit.WMMButtonDown(var Message: TWMMButtonDown);
begin
Message.Result := 1;
SendMessage(Container.Handle, WM_MBUTTONDOWN, 0,
MakeLParam(Message.XPos + Left, Message.YPos + Top));
end;
procedure TcxRichInnerEdit.WMNCCalcSize(var Message: TWMNCCalcSize);
begin
inherited;
if (Container <> nil) and not Container.ScrollBarsCalculating then
Container.SetScrollBarsParameters;
end;
procedure TcxRichInnerEdit.WMNCPaint(var Message: TWMNCPaint);
procedure FillSizeGrip;
var
ABrush: HBRUSH;
DC: HDC;
begin
if Container.NeedsScrollBars and Container.HScrollBar.Visible and
Container.VScrollBar.Visible then
begin
DC := GetWindowDC(Handle);
ABrush := 0;
try
with Container.LookAndFeel do
ABrush := CreateSolidBrush(ColorToRGB(Painter.DefaultSizeGripAreaColor));
FillRect(DC, GetSizeGripRect(Self), ABrush);
finally
if ABrush <> 0 then
Windows.DeleteObject(ABrush);
ReleaseDC(Handle, DC);
end;
end;
end;
begin
inherited;
if (Container = nil) or not UsecxScrollBars then
Exit;
FillSizeGrip;
end;
procedure TcxRichInnerEdit.WMPaint(var Message: TWMPaint);
begin
if RichVersion >= 200 then
FIsEraseBackgroundLocked := True;
try
inherited;
finally
FIsEraseBackgroundLocked := False;
end;
end;
procedure TcxRichInnerEdit.WMPaste(var Message: TMessage);
begin
if (Clipboard.FormatCount > 0) and Container.DoEditing then
inherited;
end;
procedure TcxRichInnerEdit.WMSetFocus(var Message: TWMSetFocus);
begin
inherited;
if not(csDestroying in ComponentState) and (Message.FocusedWnd <> Container.Handle) then
Container.FocusChanged;
end;
procedure TcxRichInnerEdit.WMSetFont(var Message: TWMSetFont);
begin
if HandleAllocated and MemoMode then
begin
with TMessage(Message) do
Result := CallWindowProc(DefWndProc, Handle, Msg, WParam, LParam);
DefAttributes.Color := Font.Color;
end
else
inherited;
end;
procedure TcxRichInnerEdit.WMHScroll(var Message: TWMHScroll);
begin
inherited;
if not Focused then
Container.SetScrollBarsParameters;
end;
procedure TcxRichInnerEdit.WMVScroll(var Message: TWMVScroll);
begin
inherited;
if not Focused then
Container.SetScrollBarsParameters;
end;
procedure TcxRichInnerEdit.WMWindowPosChanged(var Message: TWMWindowPosChanged);
begin
if Container <> nil then
Container.SetScrollBarsParameters;
inherited;
end;
procedure TcxRichInnerEdit.WMWindowPosChanging(var Message: TWMWindowPosChanging);
var
ARgn: HRGN;
begin
inherited;
if (Container <> nil) and not(csDestroying in ComponentState) and
Container.NeedsScrollBars and Container.HScrollBar.Visible and Container.VScrollBar.Visible then
begin
ARgn := CreateRectRgnIndirect(GetSizeGripRect(Self));
SendMessage(Handle, WM_NCPAINT, ARgn, 0);
Windows.DeleteObject(ARgn);
end;
end;
procedure TcxRichInnerEdit.EMReplaceSel(var Message: TMessage);
begin
if (Container <> nil) and Container.Focused then
Container.DoEditing;
inherited;
end;
procedure TcxRichInnerEdit.EMSetCharFormat(var Message: TMessage);
begin
if Focused and (Message.WParam = SCF_SELECTION) and (SelLength > 0) then
Container.DoEditing;
inherited;
end;
procedure TcxRichInnerEdit.EMSetParaFormat(var Message: TMessage);
begin
if (Container <> nil) and not Container.IsDestroying and
(Container.ComponentState * [csLoading, csReading] = []) and Focused then
Container.DoEditing;
inherited;
end;
procedure TcxRichInnerEdit.CMColorChanged(var Message: TMessage);
begin
if (Container <> nil) and not Container.IsInplace then
inherited;
end;
procedure TcxRichInnerEdit.CMFontChanged(var Message: TMessage);
begin
if HandleAllocated and MemoMode then
Perform(WM_SETFONT, Font.Handle, 0)
else
if (Container <> nil) and not Container.IsInplace then
SetRichDefAttributes(Self, Font,
Container.ActiveStyle.GetVisibleFont.Color);
end;
procedure TcxRichInnerEdit.CMMouseLeave(var Message: TMessage);
begin
inherited;
if Message.lParam = 0 then
MouseLeave(Self)
else
MouseLeave(TControl(Message.lParam));
end;
procedure TcxRichInnerEdit.WMChar(var Message: TWMChar);
begin
if Message.CharCode <> VK_ESCAPE then
FKeyPressProcessed := True;
try
inherited;
finally
FKeyPressProcessed := False;
end;
end;
procedure TcxRichInnerEdit.CNCommand(var Message: TWMCommand);
begin
if Message.NotifyCode <> EN_CHANGE then
begin
inherited;
Exit;
end;
if (Container <> nil) and not Container.IsDestroying and
(Container.ComponentState * [csLoading, csReading] = []) and
Focused and FKeyPressProcessed then
Container.DoEditing;
inherited;
end;
procedure TcxRichInnerEdit.CNKeyDown(var Message: TWMKeyDown);
begin
if Message.CharCode = VK_ESCAPE then
FEscapePressed := True;
try
inherited;
finally
FEscapePressed := False;
end;
end;
const
AUseCRLFFlag: array[Boolean] of DWORD = (0, 1);
procedure TcxRichInnerEdit.WMGetText(var Message: TMessage);
var
ATextInfo: TGetTextEx;
begin
if (RichVersion >= 200) and HandleAllocated then
begin
ZeroMemory(@ATextInfo, SizeOf(ATextInfo));
ATextInfo.cb := Message.WParam;
ATextInfo.flags := AUseCRLFFlag[FUseCRLF];
Message.Result := cxSendStructMessage(Handle, EM_GETTEXTEX, ATextInfo, Message.LParam);
end
else
inherited;
end;
procedure TcxRichInnerEdit.WMGetTextLength(var Message: TWMGetTextLength);
var
ATextInfo: TGetTextLengthEx;
begin
if (RichVersion >= 200) and HandleAllocated then
begin
ZeroMemory(@ATextInfo, SizeOf(ATextInfo));
ATextInfo.flags := GTL_PRECISE or GTL_NUMCHARS or AUseCRLFFlag[FUseCRLF];
Message.Result := cxSendStructMessage(Handle, EM_GETTEXTLENGTHEX, ATextInfo, 0);
end
else
inherited;
end;
procedure TcxRichInnerEdit.WMSetText(var Message: TWMSetText);
begin
if MemoMode and IsRichText(Message.Text) then
Message.Text := PChar(ConvertRichText(Message.Text));
inherited;
end;
procedure TcxRichInnerEdit.WMIMEComposition(var Message: TMessage);
begin
if Container.DoEditing then
inherited;
end;
procedure TcxRichInnerEdit.EMExLineFromChar(var Message: TMessage);
begin
inherited;
if MemoMode then
begin
if GetLineIndex(Message.Result + 1) = Message.LParam then
Message.Result := Message.Result + 1;
end;
end;
procedure TcxRichInnerEdit.EMLineLength(var Message: TMessage);
var
ALineIndex: Integer;
begin
inherited;
if MemoMode then
begin
ALineIndex := SendMessage(Handle, EM_EXLINEFROMCHAR, 0, Message.WParam);
if (ALineIndex = GetLineCount - 1) and (Lines[ALineIndex] = '') then
Message.Result := 0;
end;
end;
{ TcxRichEdit }
destructor TcxCustomRichEdit.Destroy;
begin
FreeAndNil(FEditPopupMenu);
inherited Destroy;
end;
function TcxCustomRichEdit.GetInnerEditClass: TControlClass;
begin
Result := TcxRichInnerEdit;
end;
procedure TcxCustomRichEdit.DoProtectChange(Sender: TObject;
AStartPos, AEndPos: Integer; var AAllowChange: Boolean);
begin
with Properties do
if Assigned(OnProtectChange) then
OnProtectChange(Self, AStartPos, AEndPos, AAllowChange);
if RepositoryItem <> nil then
with ActiveProperties do
if Assigned(OnProtectChange) then
OnProtectChange(Self, AStartPos, AEndPos, AAllowChange);
end;
procedure TcxCustomRichEdit.DoSaveClipboard(Sender: TObject;
ANumObjects, ANumChars: Integer; var ASaveClipboard: Boolean);
begin
if IsDestroying then
Exit;
with Properties do
if Assigned(OnSaveClipboard) then
OnSaveClipboard(Self, ANumObjects, ANumChars, ASaveClipboard);
if RepositoryItem <> nil then
with ActiveProperties do
if Assigned(OnSaveClipboard) then
OnSaveClipboard(Self, ANumObjects, ANumChars, ASaveClipboard);
end;
procedure TcxCustomRichEdit.EditPopupMenuClick(Sender: TObject);
begin
case Integer(TMenuItem(Sender).Tag) of
-1: Undo;
-2: InnerRich.Redo;
-3: CutToClipboard;
-4: CopyToClipboard;
-5: PasteFromClipboard;
-6: ClearSelection;
-7: InnerRich.SelectAll;
end;
end;
function TcxCustomRichEdit.GetLines: TStrings;
begin
Result := InnerRich.RichLines;
end;
function TcxCustomRichEdit.GetInnerRich: TcxRichInnerEdit;
begin
Result := TcxRichInnerEdit(InnerControl);
end;
procedure TcxCustomRichEdit.SetLines(Value: TStrings);
begin
InnerRich.RichLines.Assign(Value);
end;
procedure TcxCustomRichEdit.ChangeHandler(Sender: TObject);
begin
FIsNullEditValue := False;
inherited ChangeHandler(Sender);
DoEditValueChanged;
end;
procedure TcxCustomRichEdit.Scroll(AScrollBarKind: TScrollBarKind;
AScrollCode: TScrollCode; var AScrollPos: Integer);
function GetScrollBarHandle(AScrollBarKind: TScrollBarKind): HWND;
var
AScrollBar: TcxScrollBar;
begin
Result := 0;
if AScrollBarKind = sbHorizontal then
AScrollBar := HScrollBar
else
AScrollBar := VScrollBar;
if AScrollBar <> nil then
Result := AScrollBar.Handle;
end;
const
ScrollBarIDs: array[TScrollBarKind] of Integer = (SB_HORZ, SB_VERT);
ScrollMessages: array[TScrollBarKind] of UINT = (WM_HSCROLL, WM_VSCROLL);
begin
with InnerRich do
begin
CallWindowProc(DefWndProc, Handle, ScrollMessages[AScrollBarKind],
Word(AScrollCode) + Word(AScrollPos) shl 16, GetScrollBarHandle(AScrollBarKind));
if AScrollCode <> scTrack then
AScrollPos := GetScrollPos(Handle, ScrollBarIDs[AScrollBarKind]);
end;
if AScrollCode <> scTrack then
SetScrollBarsParameters;
end;
procedure TcxCustomRichEdit.AdjustInnerEdit;
begin
if ActiveProperties.MemoMode then
inherited AdjustInnerEdit
else
begin
InnerRich.Color := ViewInfo.BackgroundColor;
InnerRich.Font := Style.GetVisibleFont;
end;
end;
function TcxCustomRichEdit.CanFocusOnClick: Boolean;
begin
Result := inherited CanFocusOnClick and
not(csLButtonDown in InnerRich.ControlState);
end;
function TcxCustomRichEdit.CanKeyDownModifyEdit(Key: Word; Shift: TShiftState): Boolean;
begin
Result := inherited CanKeyDownModifyEdit(Key, Shift) or
(((Key = VK_DELETE) or (Key = VK_INSERT)) and (ssShift in Shift)) or
(((Key = Ord('V')) or (Key = Ord('X')) and (ssCtrl in Shift))) and
(Clipboard.FormatCount > 0);
Result := Result or (Key = VK_BACK); // !!!
end;
procedure TcxCustomRichEdit.ContainerStyleChanged(Sender: TObject);
begin
inherited ContainerStyleChanged(Sender);
if not IsInplace and DataBinding.IDefaultValuesProvider.IsDataStorage and
not ActiveProperties.MemoMode and not ModifiedAfterEnter then
Reset;
end;
function TcxCustomRichEdit.DoShowPopupMenu(AMenu: TComponent; X, Y: Integer): Boolean;
begin
if Assigned(AMenu) then
Result := inherited DoShowPopupMenu(AMenu, X, Y)
else
begin
UpdateEditPopupMenuItems(GetEditPopupMenuInstance);
Result := inherited DoShowPopupMenu(GetEditPopupMenuInstance, X, Y);
EditingChanged;
end;
end;
function TcxCustomRichEdit.GetEditValue: TcxEditValue;
begin
if FIsNullEditValue then
Result := Null
else
PrepareEditValue('', Result, False);
end;
{ TcxCustomRichEditViewData }
procedure TcxCustomRichEditViewData.Calculate(ACanvas: TcxCanvas;
const ABounds: TRect; const P: TPoint; Button: TcxMouseButton;
Shift: TShiftState; AViewInfo: TcxCustomEditViewInfo;
AIsMouseEvent: Boolean);
begin
inherited Calculate(ACanvas, ABounds, P, Button, Shift, AViewInfo, AIsMouseEvent);
TcxCustomRichEditViewInfo(AViewInfo).IsDrawBitmapDirty := True;
end;
function TcxCustomRichEditViewData.InternalGetEditContentSize(
ACanvas: TcxCanvas; const AEditValue: TcxEditValue;
const AEditSizeProperties: TcxEditSizeProperties): TSize;
var
ADC: HDC;
AHeight: Integer;
begin
if (AEditSizeProperties.Width = -1) or (Properties.VisibleLineCount > 0) then
Result := inherited InternalGetEditContentSize(ACanvas, AEditValue,
AEditSizeProperties)
else
begin
ADC := CreateCompatibleDC(ACanvas.Handle);
try
Result.cx := AEditSizeProperties.Width;
DrawRichEdit(ADC, Rect(0, 0, AEditSizeProperties.Width, 0), VarToStr(AEditValue),
Properties, Style.Font, clWhite, clBlack, True, AHeight);
if AHeight > 0 then
Inc(AHeight, GetEditContentSizeCorrection.cy);
Result.cy := AHeight;
finally
DeleteDC(ADC);
end;
end;
end;
function TcxCustomRichEditViewData.GetProperties: TcxCustomRichEditProperties;
begin
Result := TcxCustomRichEditProperties(FProperties);
end;
{ TcxCustomRichEditProperties }
constructor TcxCustomRichEditProperties.Create(AOwner: TPersistent);
begin
inherited Create(AOwner);
FHideScrollBars := True;
end;
procedure TcxCustomRichEditProperties.Assign(Source: TPersistent);
begin
if Source is TcxCustomRichEditProperties then
begin
BeginUpdate;
try
inherited Assign(Source);
with Source as TcxCustomRichEditProperties do
begin
Self.HideScrollBars := HideScrollBars;
Self.MemoMode := MemoMode;
Self.PlainText := PlainText;
Self.SelectionBar := SelectionBar;
Self.OnProtectChange := OnProtectChange;
Self.OnResizeRequest := OnResizeRequest;
Self.OnSaveClipboard := OnSaveClipboard;
Self.OnSelectionChange := OnSelectionChange;
end;
finally
EndUpdate;
end
end
else
inherited Assign(Source);
end;
class function TcxCustomRichEditProperties.GetContainerClass: TcxContainerClass;
begin
Result := TcxRichEdit;
end;
function TcxCustomRichEditProperties.GetDisplayText(
const AEditValue: TcxEditValue; AFullText: Boolean = False;
AIsInplace: Boolean = True): WideString;
begin
if (MemoMode or not PlainText) and IsRichText(VarToStr(AEditValue)) then
Result := inherited GetDisplayText(ConvertRichText(VarToStr(AEditValue)), AFullText)
else
Result := inherited GetDisplayText(AEditValue, AFullText);
end;
function TcxCustomRichEditProperties.GetSupportedOperations: TcxEditSupportedOperations;
begin
Result := [esoAutoHeight, esoEditing, esoHorzAlignment];
end;
function TcxCustomRichEditProperties.CanValidate: Boolean;
begin
Result := False;
end;
class function TcxCustomRichEditProperties.GetViewDataClass: TcxCustomEditViewDataClass;
begin
Result := TcxCustomRichEditViewData;
end;
class function TcxCustomRichEditProperties.GetViewInfoClass: TcxContainerViewInfoClass;
begin
Result := TcxCustomRichEditViewInfo;
end;
function TcxCustomRichEditProperties.IsResetEditClass: Boolean;
begin
Result := False;
end;
procedure TcxCustomRichEditProperties.SetHideScrollBars(Value: Boolean);
begin
if Value <> FHideScrollBars then
begin
FHideScrollBars := Value;
Changed;
end;
end;
procedure TcxCustomRichEditProperties.SetMemoMode(Value: Boolean);
begin
if Value <> FMemoMode then
begin
FMemoMode := Value;
Changed;
end;
end;
procedure TcxCustomRichEditProperties.SetPlainText(Value: Boolean);
begin
if FPlainText <> Value then
begin
FPlainText := Value;
FPlainTextChanged := True;
try
Changed;
finally
FPlainTextChanged := False;
end;
end;
end;
procedure TcxCustomRichEditProperties.SetSelectionBar(Value: Boolean);
begin
if Value <> FSelectionBar then
begin
FSelectionBar := Value;
Changed;
end;
end;
{ TcxCustomRichEditViewInfo }
constructor TcxCustomRichEditViewInfo.Create;
begin
inherited Create;
PrevDrawBitmapSize.cx := -1;
PrevDrawBitmapSize.cy := -1;
end;
destructor TcxCustomRichEditViewInfo.Destroy;
begin
if DrawBitmap <> 0 then
DeleteObject(DrawBitmap);
inherited Destroy;
end;
procedure TcxCustomRichEditViewInfo.DrawNativeStyleEditBackground(ACanvas: TcxCanvas; ADrawBackground: Boolean;
ABackgroundStyle: TcxEditBackgroundPaintingStyle; ABackgroundBrush: TBrushHandle);
begin
if IsInplace or (BorderStyle = ebsNone) or not IsCompositionEnabled then
inherited DrawNativeStyleEditBackground(ACanvas, ADrawBackground, ABackgroundStyle, ABackgroundBrush)
else
DrawThemeBackground(OpenTheme(totEdit), ACanvas.Handle, EP_EDITTEXT, ETS_NORMAL, Bounds);
end;
procedure TcxCustomRichEditViewInfo.DrawText(ACanvas: TcxCanvas);
procedure PrepareDrawBitmap;
var
ADC: HDC;
APrevBitmap: HBITMAP;
ATempVar: Integer;
begin
if IsDrawBitmapDirty then
begin
if (DrawBitmap = 0) or (PrevDrawBitmapSize.cx <> TextRect.Right - TextRect.Left) or
(PrevDrawBitmapSize.cy <> TextRect.Bottom - TextRect.Top) then
begin
if DrawBitmap <> 0 then
DeleteObject(DrawBitmap);
DrawBitmap := CreateCompatibleBitmap(ACanvas.Handle,
TextRect.Right - TextRect.Left, TextRect.Bottom - TextRect.Top);
end;
ADC := CreateCompatibleDC(ACanvas.Handle);
APrevBitmap := 0;
try
APrevBitmap := SelectObject(ADC, DrawBitmap);
DrawRichEdit(ADC, TextRect, Text, TcxCustomRichEditProperties(EditProperties),
Font, BackgroundColor, TextColor, False, ATempVar);
finally
if APrevBitmap <> 0 then
SelectObject(ADC, APrevBitmap);
DeleteDC(ADC);
end;
IsDrawBitmapDirty := False;
end;
end;
var
ADC: HDC;
APrevBitmap: HBITMAP;
begin
PrepareDrawBitmap;
ADC := CreateCompatibleDC(ACanvas.Handle);
APrevBitmap := 0;
try
APrevBitmap := SelectObject(ADC, DrawBitmap);
with TextRect do
BitBlt(ACanvas.Handle, Left, Top, Right - Left, Bottom - Top, ADC, 0, 0, SRCCOPY);
finally
if APrevBitmap <> 0 then
SelectObject(ADC, APrevBitmap);
DeleteDC(ADC);
end;
end;
function TcxCustomRichEditViewInfo.GetUpdateRegion(AViewInfo: TcxContainerViewInfo): TcxRegion;
begin
Result := TcxRegion.Create(Self.Bounds);
end;
function TcxCustomRichEditViewInfo.NeedShowHint(ACanvas: TcxCanvas;
const P: TPoint; const AVisibleBounds: TRect; out AText: TCaption;
out AIsMultiLine: Boolean; out ATextRect: TRect): Boolean;
begin
Result := False;
end;
procedure TcxCustomRichEditViewInfo.Paint(ACanvas: TcxCanvas);
begin
ACanvas.Canvas.Lock;
try
if IsInplace and not Focused or IsDBEditPaintCopyDrawing then
begin
DrawText(ACanvas);
ACanvas.ExcludeClipRect(TextRect);
end;
DrawCustomEdit(ACanvas, Self, True, bpsComboListEdit);
finally
ACanvas.Canvas.Unlock;
end;
end;
function TcxCustomRichEdit.GetActiveProperties: TcxCustomRichEditProperties;
begin
Result := TcxCustomRichEditProperties(InternalGetActiveProperties);
end;
function TcxCustomRichEdit.GetProperties: TcxCustomRichEditProperties;
begin
Result := TcxCustomRichEditProperties(FProperties);
end;
procedure TcxCustomRichEdit.SetProperties(Value: TcxCustomRichEditProperties);
begin
FProperties.Assign(Value);
end;
function TcxCustomRichEdit.GetCanUndo: Boolean;
begin
Result := InnerRich.CanUndo;
end;
procedure TcxCustomRichEdit.Initialize;
begin
inherited Initialize;
InnerRich.OnProtectChange := DoProtectChange;
InnerRich.OnSaveClipboard := DoSaveClipboard;
Width := 185;
Height := 89;
FIsNullEditValue := True;
end;
procedure TcxCustomRichEdit.InternalSetEditValue(const Value: TcxEditValue;
AValidateEditValue: Boolean);
begin
LockChangeEvents(True);
try
SendMessage(InnerRich.Handle, WM_SETREDRAW, 0, 0);
try
SendMessage(InnerRich.Handle, WM_SETTEXT, 0, Integer(PChar('')));
InnerEdit.EditValue := Value;
EditModified := False;
FIsNullEditValue := VarIsNull(Value);
finally
SendMessage(InnerRich.Handle, WM_SETREDRAW, 1, 0);
InnerRich.Invalidate;
end;
finally
LockChangeEvents(False);
end;
end;
procedure TcxCustomRichEdit.InternalValidateDisplayValue(const ADisplayValue: TcxEditValue);
begin
end;
procedure TcxCustomRichEdit.PropertiesChanged(Sender: TObject);
begin
with InnerRich do
begin
HideScrollBars := ActiveProperties.HideScrollBars;
MemoMode := ActiveProperties.MemoMode;
PlainText := ActiveProperties.PlainText or MemoMode;
SelectionBar := ActiveProperties.SelectionBar;
end;
if not(IsInplace or IsDBEdit) then
FPropertiesChange := True;
try
inherited PropertiesChanged(Sender);
finally
FPropertiesChange := False;
end;
end;
procedure TcxCustomRichEdit.ResetEditValue;
begin
if not IsInplace and IsDBEdit then
Reset;
end;
procedure TcxCustomRichEdit.SetParent(AParent: TWinControl);
begin
inherited SetParent(AParent);
RefreshScrollBars;
end;
procedure TcxCustomRichEdit.SynchronizeDisplayValue;
begin
end;
procedure TcxCustomRichEdit.SynchronizeEditValue;
begin
end;
function TcxCustomRichEdit.GetDefAttributes: TTextAttributes;
begin
Result := InnerRich.DefAttributes;
end;
function TcxCustomRichEdit.GetDefaultConverter: TConversionClass;
begin
Result := InnerRich.DefaultConverter;
end;
function TcxCustomRichEdit.GetPageRect: TRect;
begin
Result := InnerRich.PageRect;
end;
function TcxCustomRichEdit.GetParagraph: TParaAttributes;
begin
Result := InnerRich.Paragraph;
end;
function TcxCustomRichEdit.GetSelAttributes: TTextAttributes;
begin
if ActiveProperties.MemoMode then
Result := InnerRich.DefAttributes
else
Result := InnerRich.SelAttributes;
end;
procedure TcxCustomRichEdit.RefreshScrollBars;
var
ARgn: HRGN;
begin
if HandleAllocated and NeedsScrollBars then
begin
ARgn := CreateRectRgnIndirect(GetControlRect(InnerRich));
SendMessage(InnerRich.Handle, WM_NCPAINT, ARgn, 0);
SetScrollBarsParameters;
VScrollBar.Invalidate;
HScrollBar.Invalidate;
DeleteObject(ARgn);
end;
end;
procedure TcxCustomRichEdit.SetDefAttributes(const Value: TTextAttributes);
begin
InnerRich.DefAttributes := Value;
end;
procedure TcxCustomRichEdit.SetDefaultConverter(Value: TConversionClass);
begin
InnerRich.DefaultConverter := Value;
end;
procedure TcxCustomRichEdit.SetPageRect(const Value: TRect);
begin
InnerRich.PageRect := Value;
end;
procedure TcxCustomRichEdit.SetSelAttributes(const Value: TTextAttributes);
begin
InnerRich.SelAttributes := Value;
end;
procedure TcxCustomRichEdit.EMCanPaste(var Message: TMessage);
begin
InnerRich.Dispatch(Message);
end;
procedure TcxCustomRichEdit.CMVisibleChanged(var Message: TMessage);
begin
inherited;
RefreshScrollBars;
end;
function TcxCustomRichEdit.UpdateContentOnFocusChanging: Boolean;
begin
Result := False;
end;
procedure TcxCustomRichEdit.UpdateScrollBars;
begin
end;
function TcxCustomRichEdit.CanDeleteSelection: Boolean;
begin
Result := (SelLength > 0) and CanModify;
end;
procedure TcxCustomRichEdit.Changed(Sender: TObject);
begin
DoEditing;
end;
procedure TcxCustomRichEdit.DoOnResizeRequest(const R: TRect);
begin
with Properties do
if Assigned(OnResizeRequest) then
OnResizeRequest(Self, R);
if RepositoryItem <> nil then
with ActiveProperties do
if Assigned(OnResizeRequest) then
OnResizeRequest(Self, R);
end;
procedure TcxCustomRichEdit.DoOnSelectionChange;
begin
with Properties do
if Assigned(OnSelectionChange) then
OnSelectionChange(Self);
if RepositoryItem <> nil then
with ActiveProperties do
if Assigned(OnSelectionChange) then
OnSelectionChange(Self);
end;
function TcxCustomRichEdit.GetEditPopupMenuInstance: TComponent;
function NewItem(const ACaption: string; ATag: Integer): TMenuItem;
begin
Result := TMenuItem.Create(Self);
with Result do
begin
Caption := ACaption;
Tag := ATag;
OnClick := EditPopupMenuClick;
end;
end;
var
APopupMenu: TPopupMenu;
begin
if Assigned(FEditPopupMenu) then
begin
Result := FEditPopupMenu;
Exit;
end;
APopupMenu := TPopupMenu.Create(Self);
FEditPopupMenu := APopupMenu;
APopupMenu.Items.Add(
NewItem(cxGetResourceString(@cxSEditRichEditUndoCaption), -1));
APopupMenu.Items.Add(
NewItem(cxGetResourceString(@cxSEditRichEditRedoCaption), -2));
APopupMenu.Items.Add(NewItem('-', MaxInt));
APopupMenu.Items.Add(
NewItem(cxGetResourceString(@cxSEditRichEditCutCaption), -3));
APopupMenu.Items.Add(
NewItem(cxGetResourceString(@cxSEditRichEditCopyCaption), -4));
APopupMenu.Items.Add(
NewItem(cxGetResourceString(@cxSEditRichEditPasteCaption), -5));
APopupMenu.Items.Add(
NewItem(cxGetResourceString(@cxSEditRichEditDeleteCaption), -6));
APopupMenu.Items.Add(NewItem('-', MaxInt));
APopupMenu.Items.Add(
NewItem(cxGetResourceString(@cxSEditRichEditSelectAllCaption), -7));
Result := APopupMenu;
end;
function TcxCustomRichEdit.IsNavigationKey(Key: Word;
Shift: TShiftState): Boolean;
begin
Result := (((Key = VK_UP) or (Key = VK_DOWN) or
(Key = VK_LEFT) or (Key = VK_RIGHT)) and (Shift = [])) or
(Key = VK_NEXT) or (Key = VK_PRIOR) or (Key = VK_HOME) or (Key = VK_END);
end;
procedure TcxCustomRichEdit.UpdateEditPopupMenuItems(APopupMenu: TComponent);
procedure UpdateItems(APopupMenu: TPopupMenu);
begin
APopupMenu.Items[0].Enabled := InnerRich.CanUndo;
APopupMenu.Items[1].Enabled := InnerRich.CanRedo;
APopupMenu.Items[3].Enabled := CanDeleteSelection;
APopupMenu.Items[4].Enabled := InnerRich.SelLength > 0;
APopupMenu.Items[5].Enabled := InnerRich.CanPaste;
APopupMenu.Items[6].Enabled := CanDeleteSelection;
APopupMenu.Items[8].Enabled := True;
end;
begin
if not (APopupMenu is TPopupMenu) then
Exit;
InnerRich.ReadOnly := inherited RealReadOnly;
UpdateItems(TPopupMenu(APopupMenu));
InnerRich.ReadOnly := RealReadOnly; // !!! ReadOnly must be True in DBRichEdit while DataSet is not in EditMode (for AddictSpellChecker)
end;
procedure TcxCustomRichEdit.ClearSelection;
begin
InnerRich.ClearSelection;
end;
procedure TcxCustomRichEdit.CutToClipboard;
begin
InnerRich.CutToClipboard;
end;
function TcxCustomRichEdit.FindText(const ASearchStr: string;
AStartPos, ALength: Integer; AOptions: TSearchTypes): Integer;
begin
Result := InnerRich.FindText(ASearchStr, AStartPos, ALength, AOptions);
end;
class function TcxCustomRichEdit.GetPropertiesClass: TcxCustomEditPropertiesClass;
begin
Result := TcxCustomRichEditProperties;
end;
procedure TcxCustomRichEdit.PasteFromClipboard;
begin
InnerRich.PasteFromClipboard;
end;
procedure TcxCustomRichEdit.PrepareEditValue(const ADisplayValue: TcxEditValue;
out EditValue: TcxEditValue; AEditFocused: Boolean);
var
AStream: TStringStream;
begin
if ActiveProperties.MemoMode or ActiveProperties.PlainText or
(Parent = nil) or not Parent.HandleAllocated then
EditValue := InnerRich.Text
else
begin
AStream := TStringStream.Create('');
try
Lines.SaveToStream(AStream);
EditValue := AStream.DataString;
finally
AStream.Free;
end;
end;
end;
procedure TcxCustomRichEdit.Print(const Caption: string);
begin
InnerRich.Print(Caption);
end;
procedure TcxCustomRichEdit.Undo;
begin
InnerRich.Undo;
end;
class procedure TcxCustomRichEdit.RegisterConversionFormat(
const AExtension: string; AConversionClass: TConversionClass);
var
AConversionFormat: PConversionFormat;
begin
New(AConversionFormat);
with AConversionFormat^ do
begin
Extension := AnsiLowerCaseFileName(AExtension);
ConversionClass := AConversionClass;
Next := FConversionFormatList;
end;
FConversionFormatList := AConversionFormat;
TCustomRichEdit.RegisterConversionFormat(AExtension, AConversionClass);
end;
initialization
GetRegisteredEditProperties.Register(TcxRichEditProperties,
cxGetResourceString(@scxSEditRepositoryRichEditItem));
finalization
FreeAndNil(FRichRenderer);
FreeAndNil(FRichConverter);
GetRegisteredEditProperties.Unregister(TcxRichEditProperties);
if FRichEditLibrary <> 0 then
FreeLibrary(FRichEditLibrary);
ReleaseConversionFormatList;
end.