Remove global variables from the richedit control.
This commit is contained in:
parent
04279d18cd
commit
0dc42208b5
File diff suppressed because it is too large
Load Diff
|
@ -52,6 +52,7 @@ HANDLE RICHED32_hHeap = NULL;
|
|||
, \
|
||||
hwnd, (UINT)wParam, (UINT)lParam)
|
||||
|
||||
LPVOID* WINAPI CreateIRichEditOle();
|
||||
|
||||
/***********************************************************************
|
||||
* DllMain [Internal] Initializes the internal 'RICHED32.DLL'.
|
||||
|
@ -94,6 +95,16 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
|||
INT RICHEDIT_GetSelText(HWND hwnd,LPSTR lpstrBuffer);
|
||||
|
||||
|
||||
const WCHAR RichEditInfoStr[] = { '_','R','T','F','_','I','n','f','o', 0 };
|
||||
|
||||
typedef struct _RTFControl_info
|
||||
{
|
||||
HWND hwndEdit;
|
||||
HWND hwndParent;
|
||||
char* rtfBuffer;
|
||||
RTF_Info *parser;
|
||||
} RTFControl_Info;
|
||||
|
||||
/*
|
||||
*
|
||||
* DESCRIPTION:
|
||||
|
@ -103,19 +114,15 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
|||
static LRESULT WINAPI RICHED32_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
|
||||
LPARAM lParam)
|
||||
{
|
||||
int RTFToBuffer(char* pBuffer, int nBufferSize);
|
||||
int RTFToBuffer(RTF_Info *parser, char* pBuffer, int nBufferSize);
|
||||
LONG newstyle = 0;
|
||||
LONG style = 0;
|
||||
|
||||
static HWND hwndEdit;
|
||||
static HWND hwndParent;
|
||||
static char* rtfBuffer;
|
||||
RTFControl_Info *info;
|
||||
int rtfBufferSize;
|
||||
|
||||
CHARRANGE *cr;
|
||||
TRACE("previous hwndEdit: %p hwndParent %p\n",hwndEdit,hwndParent);
|
||||
hwndEdit = GetWindow(hwnd,GW_CHILD);
|
||||
TRACE("uMsg: 0x%x hwnd: %p hwndEdit: %p\n",uMsg,hwnd,hwndEdit);
|
||||
|
||||
info = GetPropW( hwnd, RichEditInfoStr );
|
||||
TRACE("uMsg: 0x%x hwnd: %p\n",uMsg,hwnd);
|
||||
|
||||
switch (uMsg)
|
||||
{
|
||||
|
@ -128,8 +135,14 @@ static LRESULT WINAPI RICHED32_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
|
|||
case WM_NCCREATE :
|
||||
TRACE_EDIT_MSG32("WM_NCCREATE");
|
||||
|
||||
info = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
|
||||
sizeof (RTFControl_Info));
|
||||
info->parser = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
|
||||
sizeof (RTF_Info));
|
||||
SetPropW(hwnd, RichEditInfoStr, (HANDLE)info);
|
||||
|
||||
/* remove SCROLLBARS from the current window style */
|
||||
hwndParent = ((LPCREATESTRUCTA) lParam)->hwndParent;
|
||||
info->hwndParent = ((LPCREATESTRUCTA) lParam)->hwndParent;
|
||||
|
||||
newstyle = style = ((LPCREATESTRUCTA) lParam)->style;
|
||||
newstyle &= ~WS_HSCROLL;
|
||||
|
@ -138,26 +151,26 @@ static LRESULT WINAPI RICHED32_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
|
|||
newstyle &= ~ES_AUTOVSCROLL;
|
||||
SetWindowLongA(hwnd,GWL_STYLE, newstyle);
|
||||
|
||||
TRACE("previous hwndEdit: %p\n",hwndEdit);
|
||||
hwndEdit = CreateWindowA ("edit", ((LPCREATESTRUCTA) lParam)->lpszName,
|
||||
TRACE("previous hwndEdit: %p\n",info->hwndEdit);
|
||||
info->hwndEdit = CreateWindowA ("edit", ((LPCREATESTRUCTA) lParam)->lpszName,
|
||||
style, 0, 0, 0, 0,
|
||||
hwnd, (HMENU) ID_EDIT,
|
||||
((LPCREATESTRUCTA) lParam)->hInstance, NULL) ;
|
||||
TRACE("hwndEdit: %p hwnd: %p\n",hwndEdit,hwnd);
|
||||
TRACE("hwndEdit: %p hwnd: %p\n",info->hwndEdit,hwnd);
|
||||
|
||||
if (hwndEdit)
|
||||
if (info->hwndEdit)
|
||||
return TRUE ;
|
||||
else
|
||||
return FALSE ;
|
||||
|
||||
case WM_SETFOCUS :
|
||||
TRACE_EDIT_MSG32("WM_SETFOCUS");
|
||||
SetFocus (hwndEdit) ;
|
||||
SetFocus (info->hwndEdit) ;
|
||||
return 0 ;
|
||||
|
||||
case WM_SIZE :
|
||||
TRACE_EDIT_MSG32("WM_SIZE");
|
||||
MoveWindow (hwndEdit, 0, 0, LOWORD (lParam), HIWORD (lParam), TRUE) ;
|
||||
MoveWindow (info->hwndEdit, 0, 0, LOWORD (lParam), HIWORD (lParam), TRUE) ;
|
||||
return 0 ;
|
||||
|
||||
case WM_COMMAND :
|
||||
|
@ -169,7 +182,7 @@ static LRESULT WINAPI RICHED32_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
|
|||
case EN_SETFOCUS:
|
||||
case EN_UPDATE:
|
||||
case EN_VSCROLL:
|
||||
return SendMessageA(hwndParent, WM_COMMAND,
|
||||
return SendMessageA(info->hwndParent, WM_COMMAND,
|
||||
wParam, (LPARAM)(hwnd));
|
||||
|
||||
case EN_ERRSPACE:
|
||||
|
@ -183,22 +196,22 @@ static LRESULT WINAPI RICHED32_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
|
|||
TRACE_EDIT_MSG32("EM_STREAMIN");
|
||||
|
||||
/* setup the RTF parser */
|
||||
RTFSetEditStream(( EDITSTREAM*)lParam);
|
||||
rtfFormat = wParam&(SF_TEXT|SF_RTF);
|
||||
WriterInit();
|
||||
RTFInit ();
|
||||
BeginFile();
|
||||
RTFSetEditStream(info->parser,( EDITSTREAM*)lParam);
|
||||
info->parser->rtfFormat = wParam&(SF_TEXT|SF_RTF);
|
||||
WriterInit(info->parser);
|
||||
RTFInit (info->parser);
|
||||
BeginFile(info->parser);
|
||||
|
||||
/* do the parsing */
|
||||
RTFRead ();
|
||||
RTFRead (info->parser);
|
||||
|
||||
rtfBufferSize = RTFToBuffer(NULL, 0);
|
||||
rtfBuffer = HeapAlloc(RICHED32_hHeap, 0,rtfBufferSize*sizeof(char));
|
||||
if(rtfBuffer)
|
||||
rtfBufferSize = RTFToBuffer(info->parser,NULL, 0);
|
||||
info->rtfBuffer = HeapAlloc(RICHED32_hHeap, 0,rtfBufferSize*sizeof(char));
|
||||
if(info->rtfBuffer)
|
||||
{
|
||||
RTFToBuffer(rtfBuffer, rtfBufferSize);
|
||||
SetWindowTextA(hwndEdit,rtfBuffer);
|
||||
HeapFree(RICHED32_hHeap, 0,rtfBuffer);
|
||||
RTFToBuffer(info->parser,info->rtfBuffer, rtfBufferSize);
|
||||
SetWindowTextA(info->hwndEdit,info->rtfBuffer);
|
||||
HeapFree(RICHED32_hHeap, 0,info->rtfBuffer);
|
||||
}
|
||||
else
|
||||
WARN("Not enough memory for a allocating rtfBuffer\n");
|
||||
|
@ -226,7 +239,7 @@ static LRESULT WINAPI RICHED32_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
|
|||
case EM_EXGETSEL:
|
||||
TRACE_EDIT_MSG32("EM_EXGETSEL -> EM_GETSEL");
|
||||
cr = (VOID *) lParam;
|
||||
if (hwndEdit) SendMessageA( hwndEdit, EM_GETSEL, (INT)&cr->cpMin, (INT)&cr->cpMax);
|
||||
if (info->hwndEdit) SendMessageA( info->hwndEdit, EM_GETSEL, (INT)&cr->cpMin, (INT)&cr->cpMax);
|
||||
TRACE("cpMin: 0x%x cpMax: 0x%x\n",(INT)cr->cpMin,(INT)cr->cpMax);
|
||||
return 0;
|
||||
|
||||
|
@ -238,18 +251,18 @@ static LRESULT WINAPI RICHED32_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
|
|||
{
|
||||
limit = 0xFFFFFFFF;
|
||||
}
|
||||
return SendMessageA(hwndEdit,EM_SETLIMITTEXT,limit,0);
|
||||
return SendMessageA(info->hwndEdit,EM_SETLIMITTEXT,limit,0);
|
||||
}
|
||||
|
||||
case EM_EXLINEFROMCHAR:
|
||||
TRACE_EDIT_MSG32("EM_EXLINEFROMCHAR -> LINEFROMCHAR");
|
||||
if (hwndEdit) return SendMessageA( hwndEdit, EM_LINEFROMCHAR, lParam, wParam);
|
||||
if (info->hwndEdit) return SendMessageA( info->hwndEdit, EM_LINEFROMCHAR, lParam, wParam);
|
||||
return 0;
|
||||
|
||||
case EM_EXSETSEL:
|
||||
TRACE_EDIT_MSG32("EM_EXSETSEL -> EM_SETSEL");
|
||||
cr = (VOID *) lParam;
|
||||
if (hwndEdit) SendMessageA( hwndEdit, EM_SETSEL, cr->cpMin, cr->cpMax);
|
||||
if (info->hwndEdit) SendMessageA( info->hwndEdit, EM_SETSEL, cr->cpMin, cr->cpMax);
|
||||
return 0;
|
||||
|
||||
case EM_FINDTEXT:
|
||||
|
@ -338,7 +351,7 @@ static LRESULT WINAPI RICHED32_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
|
|||
|
||||
case EM_GETSELTEXT:
|
||||
TRACE_EDIT_MSG32("EM_GETSELTEXT");
|
||||
return RICHEDIT_GetSelText(hwndEdit,(void *)lParam);
|
||||
return RICHEDIT_GetSelText(info->hwndEdit,(void *)lParam);
|
||||
|
||||
case EM_GETTEXTEX:
|
||||
TRACE_EDIT_MSG32("EM_GETTEXTEX Ignored");
|
||||
|
@ -354,7 +367,7 @@ static LRESULT WINAPI RICHED32_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
|
|||
|
||||
case EM_GETTEXTRANGE:
|
||||
TRACE_EDIT_MSG32("EM_GETTEXTRANGE");
|
||||
return RICHEDIT_GetTextRange(hwndEdit,(TEXTRANGEA *)lParam);
|
||||
return RICHEDIT_GetTextRange(info->hwndEdit,(TEXTRANGEA *)lParam);
|
||||
|
||||
case EM_GETTYPOGRAPHYOPTIONS:
|
||||
TRACE_EDIT_MSG32("EM_GETTYPOGRAPHYOPTIONS Ignored");
|
||||
|
@ -507,139 +520,139 @@ static LRESULT WINAPI RICHED32_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
|
|||
/* Messages dispatched to the edit control */
|
||||
case EM_CANUNDO:
|
||||
TRACE_EDIT_MSG32("EM_CANUNDO Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case EM_CHARFROMPOS:
|
||||
TRACE_EDIT_MSG32("EM_CHARFROMPOS Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case EM_EMPTYUNDOBUFFER:
|
||||
TRACE_EDIT_MSG32("EM_EMPTYUNDOBUFFER Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case EM_FMTLINES:
|
||||
TRACE_EDIT_MSG32("EM_FMTLINES Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case EM_GETFIRSTVISIBLELINE:
|
||||
TRACE_EDIT_MSG32("EM_GETFIRSTVISIBLELINE Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case EM_GETHANDLE:
|
||||
TRACE_EDIT_MSG32("EM_GETHANDLE Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
/* case EM_GETIMESTATUS:*/
|
||||
case EM_GETLIMITTEXT:
|
||||
TRACE_EDIT_MSG32("EM_GETLIMITTEXT Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case EM_GETLINE:
|
||||
TRACE_EDIT_MSG32("EM_GETLINE Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case EM_GETLINECOUNT:
|
||||
TRACE_EDIT_MSG32("EM_GETLINECOUNT Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case EM_GETMARGINS:
|
||||
TRACE_EDIT_MSG32("EM_GETMARGINS Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case EM_GETMODIFY:
|
||||
TRACE_EDIT_MSG32("EM_GETMODIFY Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case EM_GETPASSWORDCHAR:
|
||||
TRACE_EDIT_MSG32("EM_GETPASSWORDCHAR Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case EM_GETRECT:
|
||||
TRACE_EDIT_MSG32("EM_GETRECT Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case EM_GETSEL:
|
||||
TRACE_EDIT_MSG32("EM_GETSEL Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case EM_GETTHUMB:
|
||||
TRACE_EDIT_MSG32("EM_GETTHUMB Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case EM_GETWORDBREAKPROC:
|
||||
TRACE_EDIT_MSG32("EM_GETWORDBREAKPROC Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case EM_LINEFROMCHAR:
|
||||
TRACE_EDIT_MSG32("EM_LINEFROMCHAR Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case EM_LINEINDEX:
|
||||
TRACE_EDIT_MSG32("EM_LINEINDEX Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case EM_LINELENGTH:
|
||||
TRACE_EDIT_MSG32("EM_LINELENGTH Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case EM_LINESCROLL:
|
||||
TRACE_EDIT_MSG32("EM_LINESCROLL Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case EM_POSFROMCHAR:
|
||||
TRACE_EDIT_MSG32("EM_POSFROMCHAR Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case EM_REPLACESEL:
|
||||
TRACE_EDIT_MSG32("case EM_REPLACESEL Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case EM_SCROLL:
|
||||
TRACE_EDIT_MSG32("case EM_SCROLL Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case EM_SCROLLCARET:
|
||||
TRACE_EDIT_MSG32("EM_SCROLLCARET Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case EM_SETHANDLE:
|
||||
TRACE_EDIT_MSG32("EM_SETHANDLE Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
/* case EM_SETIMESTATUS:*/
|
||||
case EM_SETLIMITTEXT:
|
||||
TRACE_EDIT_MSG32("EM_SETLIMITTEXT Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case EM_SETMARGINS:
|
||||
TRACE_EDIT_MSG32("case EM_SETMARGINS Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case EM_SETMODIFY:
|
||||
TRACE_EDIT_MSG32("EM_SETMODIFY Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case EM_SETPASSWORDCHAR:
|
||||
TRACE_EDIT_MSG32("EM_SETPASSWORDCHAR Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case EM_SETREADONLY:
|
||||
TRACE_EDIT_MSG32("EM_SETREADONLY Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case EM_SETRECT:
|
||||
TRACE_EDIT_MSG32("EM_SETRECT Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case EM_SETRECTNP:
|
||||
TRACE_EDIT_MSG32("EM_SETRECTNP Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case EM_SETSEL:
|
||||
TRACE_EDIT_MSG32("EM_SETSEL Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case EM_SETTABSTOPS:
|
||||
TRACE_EDIT_MSG32("EM_SETTABSTOPS Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case EM_SETWORDBREAKPROC:
|
||||
TRACE_EDIT_MSG32("EM_SETWORDBREAKPROC Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case EM_UNDO:
|
||||
TRACE_EDIT_MSG32("EM_UNDO Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
|
||||
case WM_STYLECHANGING:
|
||||
TRACE_EDIT_MSG32("WM_STYLECHANGING Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case WM_STYLECHANGED:
|
||||
TRACE_EDIT_MSG32("WM_STYLECHANGED Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case WM_GETTEXT:
|
||||
TRACE_EDIT_MSG32("WM_GETTEXT Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case WM_GETTEXTLENGTH:
|
||||
TRACE_EDIT_MSG32("WM_GETTEXTLENGTH Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case WM_SETTEXT:
|
||||
TRACE_EDIT_MSG32("WM_SETTEXT Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case WM_CUT:
|
||||
TRACE_EDIT_MSG32("WM_CUT Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case WM_COPY:
|
||||
TRACE_EDIT_MSG32("WM_COPY Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
case WM_PASTE:
|
||||
TRACE_EDIT_MSG32("WM_PASTE Passed to edit control");
|
||||
return SendMessageA( hwndEdit, uMsg, wParam, lParam);
|
||||
return SendMessageA( info->hwndEdit, uMsg, wParam, lParam);
|
||||
|
||||
/* Messages passed to default handler. */
|
||||
case WM_NCCALCSIZE:
|
||||
|
@ -678,6 +691,8 @@ static LRESULT WINAPI RICHED32_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
|
|||
return DefWindowProcA( hwnd,uMsg,wParam,lParam);
|
||||
case WM_DESTROY:
|
||||
TRACE_EDIT_MSG32("WM_DESTROY Passed to default");
|
||||
HeapFree( GetProcessHeap(), 0, info->parser );
|
||||
HeapFree( GetProcessHeap(), 0, info );
|
||||
return DefWindowProcA( hwnd,uMsg,wParam,lParam);
|
||||
case WM_CHILDACTIVATE:
|
||||
TRACE_EDIT_MSG32("WM_CHILDACTIVATE Passed to default");
|
||||
|
|
|
@ -10,8 +10,6 @@
|
|||
#include "winuser.h"
|
||||
#include "richedit.h"
|
||||
|
||||
void RTFSetEditStream(EDITSTREAM *es);
|
||||
|
||||
|
||||
/* The following defines are automatically generated. Do not edit. */
|
||||
|
||||
|
@ -420,21 +418,6 @@ void RTFSetEditStream(EDITSTREAM *es);
|
|||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Information pertaining to last token read by RTFToken. The
|
||||
* text is exactly as it occurs in the input file, e.g., "\{"
|
||||
* will be found in rtfTextBuf as "\{", even though it means "{".
|
||||
* These variables are also set when styles are reprocessed.
|
||||
*/
|
||||
|
||||
extern char *rtfTextBuf; /* text of token */
|
||||
extern int rtfTextLen; /* length of token in rtfTextBuf */
|
||||
extern int rtfClass; /* token class */
|
||||
extern int rtfMajor; /* token major number */
|
||||
extern int rtfMinor; /* token minor number */
|
||||
extern int rtfParam; /* control symbol parameter */
|
||||
extern int rtfFormat; /* either SF_RTF or SF_TEXT */
|
||||
|
||||
# ifdef THINK_C
|
||||
# define rtfNoParam (-32768) /* 16-bit max. neg. value */
|
||||
# endif
|
||||
|
@ -442,8 +425,8 @@ extern int rtfFormat; /* either SF_RTF or SF_TEXT */
|
|||
# define rtfNoParam (-1000000)
|
||||
# endif
|
||||
|
||||
extern long rtfLineNum; /* input line number */
|
||||
extern int rtfLinePos; /* input line position */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* For some reason, the no-style number is 222
|
||||
|
@ -1391,46 +1374,167 @@ struct RTFStyleElt
|
|||
};
|
||||
|
||||
|
||||
typedef void (*RTFFuncPtr) (); /* generic function pointer */
|
||||
#include "charlist.h"
|
||||
|
||||
/*
|
||||
* Return pointer to new element of type t, or NULL
|
||||
* if no memory available.
|
||||
*/
|
||||
|
||||
# define New(t) ((t *) RTFAlloc ((int) sizeof (t)))
|
||||
|
||||
/* maximum number of character values representable in a byte */
|
||||
|
||||
# define charSetSize 256
|
||||
|
||||
/* charset stack size */
|
||||
|
||||
# define maxCSStack 10
|
||||
|
||||
|
||||
struct _RTF_Info;
|
||||
typedef struct _RTF_Info RTF_Info;
|
||||
|
||||
typedef void (*RTFFuncPtr) (RTF_Info *); /* generic function pointer */
|
||||
|
||||
struct _RTF_Info {
|
||||
/*
|
||||
* Public variables (listed in rtf.h)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Information pertaining to last token read by RTFToken. The
|
||||
* text is exactly as it occurs in the input file, e.g., "\{"
|
||||
* will be found in rtfTextBuf as "\{", even though it means "{".
|
||||
* These variables are also set when styles are reprocessed.
|
||||
*/
|
||||
|
||||
int rtfClass;
|
||||
int rtfMajor;
|
||||
int rtfMinor;
|
||||
int rtfParam;
|
||||
int rtfFormat;
|
||||
char *rtfTextBuf;
|
||||
int rtfTextLen;
|
||||
|
||||
long rtfLineNum;
|
||||
int rtfLinePos;
|
||||
|
||||
|
||||
/*
|
||||
* Private stuff
|
||||
*/
|
||||
|
||||
int pushedChar; /* pushback char if read too far */
|
||||
|
||||
int pushedClass; /* pushed token info for RTFUngetToken() */
|
||||
int pushedMajor;
|
||||
int pushedMinor;
|
||||
int pushedParam;
|
||||
char *pushedTextBuf;
|
||||
|
||||
int prevChar;
|
||||
int bumpLine;
|
||||
|
||||
RTFFont *fontList; /* these lists MUST be */
|
||||
RTFColor *colorList; /* initialized to NULL */
|
||||
RTFStyle *styleList;
|
||||
|
||||
char *inputName;
|
||||
char *outputName;
|
||||
|
||||
EDITSTREAM editstream;
|
||||
CHARLIST inputCharList ;
|
||||
|
||||
/*
|
||||
* These arrays are used to map RTF input character values onto the standard
|
||||
* character names represented by the values. Input character values are
|
||||
* used as indices into the arrays to produce standard character codes.
|
||||
*/
|
||||
|
||||
|
||||
char *genCharSetFile ;
|
||||
int genCharCode[charSetSize]; /* general */
|
||||
int haveGenCharSet;
|
||||
|
||||
char *symCharSetFile;
|
||||
int symCharCode[charSetSize]; /* symbol */
|
||||
int haveSymCharSet;
|
||||
|
||||
int curCharSet;
|
||||
int *curCharCode;
|
||||
|
||||
/*
|
||||
* By default, the reader is configured to handle charset mapping invisibly,
|
||||
* including reading the charset files and switching charset maps as necessary
|
||||
* for Symbol font.
|
||||
*/
|
||||
|
||||
int autoCharSetFlags;
|
||||
|
||||
/*
|
||||
* Stack for keeping track of charset map on group begin/end. This is
|
||||
* necessary because group termination reverts the font to the previous
|
||||
* value, which may implicitly change it.
|
||||
*/
|
||||
|
||||
int csStack[maxCSStack];
|
||||
int csTop;
|
||||
|
||||
RTFFuncPtr ccb[rtfMaxClass]; /* class callbacks */
|
||||
|
||||
RTFFuncPtr dcb[rtfMaxDestination]; /* destination callbacks */
|
||||
|
||||
RTFFuncPtr readHook;
|
||||
|
||||
RTFFuncPtr panicProc;
|
||||
|
||||
FILE *(*libFileOpen) ();
|
||||
|
||||
char *outMap[rtfSC_MaxChar];
|
||||
|
||||
CHARLIST charlist;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Public RTF reader routines
|
||||
*/
|
||||
|
||||
void RTFInit ();
|
||||
void RTFSetInputName ();
|
||||
char *RTFGetInputName ();
|
||||
void RTFSetOutputName ();
|
||||
char *RTFGetOutputName ();
|
||||
void RTFSetClassCallback ();
|
||||
RTFFuncPtr RTFGetClassCallback ();
|
||||
void RTFSetDestinationCallback ();
|
||||
RTFFuncPtr RTFGetDestinationCallback ();
|
||||
void RTFRead ();
|
||||
int RTFGetToken (); /* writer should rarely need this */
|
||||
void RTFUngetToken ();
|
||||
int RTFPeekToken ();
|
||||
void RTFSetToken ();
|
||||
void RTFSetReadHook ();
|
||||
RTFFuncPtr RTFGetReadHook ();
|
||||
void RTFRouteToken ();
|
||||
void RTFSkipGroup ();
|
||||
void RTFExpandStyle ();
|
||||
int RTFCheckCM ();
|
||||
int RTFCheckCMM ();
|
||||
int RTFCheckMM ();
|
||||
RTFFont *RTFGetFont ();
|
||||
RTFColor *RTFGetColor ();
|
||||
RTFStyle *RTFGetStyle ();
|
||||
void RTFInit (RTF_Info *);
|
||||
void RTFSetInputName (RTF_Info *, char *);
|
||||
char *RTFGetInputName (RTF_Info *);
|
||||
void RTFSetOutputName (RTF_Info *, char *);
|
||||
char *RTFGetOutputName (RTF_Info *);
|
||||
void RTFSetClassCallback (RTF_Info *, int, RTFFuncPtr);
|
||||
RTFFuncPtr RTFGetClassCallback (RTF_Info *, int);
|
||||
void RTFSetDestinationCallback (RTF_Info *, int, RTFFuncPtr);
|
||||
RTFFuncPtr RTFGetDestinationCallback (RTF_Info *, int);
|
||||
void RTFRead (RTF_Info *);
|
||||
int RTFGetToken (RTF_Info *); /* writer should rarely need this */
|
||||
void RTFUngetToken (RTF_Info *);
|
||||
int RTFPeekToken (RTF_Info *);
|
||||
void RTFSetToken (RTF_Info *, int, int, int, int, char *);
|
||||
void RTFSetReadHook (RTF_Info *, RTFFuncPtr);
|
||||
RTFFuncPtr RTFGetReadHook (RTF_Info *);
|
||||
void RTFRouteToken (RTF_Info *);
|
||||
void RTFSkipGroup (RTF_Info *);
|
||||
void RTFExpandStyle (RTF_Info *, int);
|
||||
int RTFCheckCM (RTF_Info *, int, int);
|
||||
int RTFCheckCMM (RTF_Info *, int, int, int);
|
||||
int RTFCheckMM (RTF_Info *, int, int);
|
||||
RTFFont *RTFGetFont (RTF_Info *, int);
|
||||
RTFColor *RTFGetColor (RTF_Info *, int);
|
||||
RTFStyle *RTFGetStyle (RTF_Info *, int);
|
||||
# define RTFAlloc(size) _RTFAlloc ((int) size)
|
||||
char *_RTFAlloc ();
|
||||
char *RTFStrSave ();
|
||||
void RTFFree ();
|
||||
int RTFCharToHex (char);
|
||||
int RTFHexToChar ();
|
||||
void RTFSetMsgProc ();
|
||||
void RTFSetPanicProc ();
|
||||
char *_RTFAlloc (int);
|
||||
char *RTFStrSave (char *);
|
||||
void RTFFree (char *);
|
||||
int RTFCharToHex ( char);
|
||||
int RTFHexToChar ( int );
|
||||
void RTFSetMsgProc ( RTFFuncPtr );
|
||||
void RTFSetPanicProc ( RTF_Info *, RTFFuncPtr);
|
||||
|
||||
/*
|
||||
* The following messing around is used to allow RTFMsg() and RTFPanic()
|
||||
|
@ -1439,20 +1543,22 @@ void RTFSetPanicProc ();
|
|||
* stdarg.h.
|
||||
*/
|
||||
|
||||
void RTFMsg (char *fmt, ...);
|
||||
void RTFPanic (char *fmt, ...);
|
||||
void RTFMsg (RTF_Info *, char *fmt, ...);
|
||||
void RTFPanic (RTF_Info *, char *fmt, ...);
|
||||
|
||||
int RTFReadOutputMap ();
|
||||
int RTFReadCharSetMap ();
|
||||
void RTFSetCharSetMap ();
|
||||
int RTFStdCharCode ();
|
||||
char *RTFStdCharName ();
|
||||
int RTFMapChar ();
|
||||
int RTFGetCharSet();
|
||||
void RTFSetCharSet();
|
||||
int RTFReadOutputMap ( RTF_Info *, char *[], int);
|
||||
int RTFReadCharSetMap ( RTF_Info *, int);
|
||||
void RTFSetCharSetMap ( RTF_Info *, char *, int);
|
||||
int RTFStdCharCode ( RTF_Info *, char *);
|
||||
char *RTFStdCharName ( RTF_Info *, int);
|
||||
int RTFMapChar ( RTF_Info *, int);
|
||||
int RTFGetCharSet( RTF_Info * );
|
||||
void RTFSetCharSet( RTF_Info *, int);
|
||||
|
||||
/*char *RTFGetLibPrefix();*/
|
||||
void RTFSetOpenLibFileProc ();
|
||||
FILE *RTFOpenLibFile ();
|
||||
void RTFSetOpenLibFileProc ( RTF_Info *, FILE *(*)());
|
||||
FILE *RTFOpenLibFile ( RTF_Info *, char *, char *);
|
||||
|
||||
void RTFSetEditStream(RTF_Info *, EDITSTREAM *es);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -45,20 +45,22 @@
|
|||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(richedit);
|
||||
|
||||
static void TextClass ();
|
||||
static void ControlClass ();
|
||||
static void Destination ();
|
||||
static void SpecialChar ();
|
||||
static void PutStdChar ();
|
||||
static void PutLitChar ();
|
||||
static void PutLitStr ();
|
||||
static void TextClass (RTF_Info *info);
|
||||
static void ControlClass (RTF_Info *info);
|
||||
static void Destination (RTF_Info *info);
|
||||
static void SpecialChar (RTF_Info *info);
|
||||
static void PutStdChar (RTF_Info *info, int stdCode);
|
||||
static void PutLitChar (RTF_Info *info, int c);
|
||||
static void PutLitStr (RTF_Info *info, char *s);
|
||||
|
||||
#if 0
|
||||
static char *outMap[rtfSC_MaxChar];
|
||||
|
||||
static CHARLIST charlist = {0, NULL, NULL};
|
||||
#endif
|
||||
|
||||
int RTFToBuffer(char* pBuffer, int nBufferSize);
|
||||
int RTFToBuffer(char* pBuffer, int nBufferSize)
|
||||
/*int RTFToBuffer(char* pBuffer, int nBufferSize); */
|
||||
int RTFToBuffer(RTF_Info *info, char* pBuffer, int nBufferSize)
|
||||
{
|
||||
|
||||
/* check if the buffer is big enough to hold all characters */
|
||||
|
@ -66,13 +68,13 @@ int RTFToBuffer(char* pBuffer, int nBufferSize)
|
|||
|
||||
TRACE("\n");
|
||||
|
||||
if(nBufferSize < charlist.nCount + 1) {
|
||||
return charlist.nCount + CHARLIST_CountChar(&charlist, '\n') + 1;
|
||||
if(nBufferSize < info->charlist.nCount + 1) {
|
||||
return info->charlist.nCount + CHARLIST_CountChar(&info->charlist, '\n') + 1;
|
||||
}
|
||||
|
||||
while(charlist.nCount)
|
||||
while(info->charlist.nCount)
|
||||
{
|
||||
*pBuffer = CHARLIST_Dequeue(&charlist);
|
||||
*pBuffer = CHARLIST_Dequeue(&info->charlist);
|
||||
if(*pBuffer=='\n')
|
||||
{
|
||||
*pBuffer = '\r';
|
||||
|
@ -92,19 +94,19 @@ int RTFToBuffer(char* pBuffer, int nBufferSize)
|
|||
*/
|
||||
|
||||
void
|
||||
WriterInit ()
|
||||
WriterInit (RTF_Info *info )
|
||||
{
|
||||
RTFReadOutputMap (outMap,1);
|
||||
RTFReadOutputMap (info, info->outMap,1);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
BeginFile ()
|
||||
BeginFile (RTF_Info *info )
|
||||
{
|
||||
/* install class callbacks */
|
||||
|
||||
RTFSetClassCallback (rtfText, TextClass);
|
||||
RTFSetClassCallback (rtfControl, ControlClass);
|
||||
RTFSetClassCallback (info, rtfText, TextClass);
|
||||
RTFSetClassCallback (info, rtfControl, ControlClass);
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
@ -119,38 +121,38 @@ BeginFile ()
|
|||
*/
|
||||
|
||||
static void
|
||||
TextClass ()
|
||||
TextClass (RTF_Info *info)
|
||||
{
|
||||
char buf[rtfBufSiz];
|
||||
|
||||
TRACE("\n");
|
||||
|
||||
if (rtfFormat == SF_TEXT)
|
||||
PutLitChar (rtfMajor);
|
||||
else if (rtfMinor != rtfSC_nothing)
|
||||
PutStdChar (rtfMinor);
|
||||
if (info->rtfFormat == SF_TEXT)
|
||||
PutLitChar (info, info->rtfMajor);
|
||||
else if (info->rtfMinor != rtfSC_nothing)
|
||||
PutStdChar (info, info->rtfMinor);
|
||||
else
|
||||
{
|
||||
if (rtfMajor < 128) /* in ASCII range */
|
||||
sprintf (buf, "[[%c]]", rtfMajor);
|
||||
if (info->rtfMajor < 128) /* in ASCII range */
|
||||
sprintf (buf, "[[%c]]", info->rtfMajor);
|
||||
else
|
||||
sprintf (buf, "[[\\'%02x]]", rtfMajor);
|
||||
PutLitStr (buf);
|
||||
sprintf (buf, "[[\\'%02x]]", info->rtfMajor);
|
||||
PutLitStr (info, buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ControlClass ()
|
||||
ControlClass (RTF_Info *info)
|
||||
{
|
||||
TRACE("\n");
|
||||
switch (rtfMajor)
|
||||
switch (info->rtfMajor)
|
||||
{
|
||||
case rtfDestination:
|
||||
Destination ();
|
||||
Destination (info);
|
||||
break;
|
||||
case rtfSpecialChar:
|
||||
SpecialChar ();
|
||||
SpecialChar (info);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -163,12 +165,12 @@ ControlClass ()
|
|||
*/
|
||||
|
||||
static void
|
||||
Destination ()
|
||||
Destination (RTF_Info *info)
|
||||
{
|
||||
|
||||
TRACE("\n");
|
||||
|
||||
switch (rtfMinor)
|
||||
switch (info->rtfMinor)
|
||||
{
|
||||
case rtfPict:
|
||||
case rtfFNContSep:
|
||||
|
@ -183,7 +185,7 @@ Destination ()
|
|||
case rtfIComment:
|
||||
case rtfIVersion:
|
||||
case rtfIDoccomm:
|
||||
RTFSkipGroup ();
|
||||
RTFSkipGroup (info);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -195,52 +197,52 @@ Destination ()
|
|||
* can be controlled by the text-map file.
|
||||
*/
|
||||
|
||||
void SpecialChar ()
|
||||
void SpecialChar (RTF_Info *info)
|
||||
{
|
||||
|
||||
TRACE("\n");
|
||||
|
||||
switch (rtfMinor)
|
||||
switch (info->rtfMinor)
|
||||
{
|
||||
case rtfPage:
|
||||
case rtfSect:
|
||||
case rtfRow:
|
||||
case rtfLine:
|
||||
case rtfPar:
|
||||
PutLitChar ('\n');
|
||||
PutLitChar (info, '\n');
|
||||
break;
|
||||
case rtfCell:
|
||||
PutStdChar (rtfSC_space); /* make sure cells are separated */
|
||||
PutStdChar (info, rtfSC_space); /* make sure cells are separated */
|
||||
break;
|
||||
case rtfNoBrkSpace:
|
||||
PutStdChar (rtfSC_nobrkspace);
|
||||
PutStdChar (info, rtfSC_nobrkspace);
|
||||
break;
|
||||
case rtfTab:
|
||||
PutLitChar ('\t');
|
||||
PutLitChar (info, '\t');
|
||||
break;
|
||||
case rtfNoBrkHyphen:
|
||||
PutStdChar (rtfSC_nobrkhyphen);
|
||||
PutStdChar (info, rtfSC_nobrkhyphen);
|
||||
break;
|
||||
case rtfBullet:
|
||||
PutStdChar (rtfSC_bullet);
|
||||
PutStdChar (info, rtfSC_bullet);
|
||||
break;
|
||||
case rtfEmDash:
|
||||
PutStdChar (rtfSC_emdash);
|
||||
PutStdChar (info, rtfSC_emdash);
|
||||
break;
|
||||
case rtfEnDash:
|
||||
PutStdChar (rtfSC_endash);
|
||||
PutStdChar (info, rtfSC_endash);
|
||||
break;
|
||||
case rtfLQuote:
|
||||
PutStdChar (rtfSC_quoteleft);
|
||||
PutStdChar (info, rtfSC_quoteleft);
|
||||
break;
|
||||
case rtfRQuote:
|
||||
PutStdChar (rtfSC_quoteright);
|
||||
PutStdChar (info, rtfSC_quoteright);
|
||||
break;
|
||||
case rtfLDblQuote:
|
||||
PutStdChar (rtfSC_quotedblleft);
|
||||
PutStdChar (info, rtfSC_quotedblleft);
|
||||
break;
|
||||
case rtfRDblQuote:
|
||||
PutStdChar (rtfSC_quotedblright);
|
||||
PutStdChar (info, rtfSC_quotedblright);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -255,7 +257,7 @@ void SpecialChar ()
|
|||
* obvious and provides incentive to fix it. :-)
|
||||
*/
|
||||
|
||||
void PutStdChar (int stdCode)
|
||||
void PutStdChar (RTF_Info *info, int stdCode)
|
||||
{
|
||||
|
||||
char *oStr = (char *) NULL;
|
||||
|
@ -266,28 +268,28 @@ void PutStdChar (int stdCode)
|
|||
*/
|
||||
TRACE("\n");
|
||||
|
||||
oStr = outMap[stdCode];
|
||||
oStr = info->outMap[stdCode];
|
||||
if (oStr == (char *) NULL) /* no output sequence in map */
|
||||
{
|
||||
sprintf (buf, "[[%s]]", RTFStdCharName (stdCode));
|
||||
sprintf (buf, "[[%s]]", RTFStdCharName (info, stdCode));
|
||||
oStr = buf;
|
||||
}
|
||||
PutLitStr (oStr);
|
||||
PutLitStr (info, oStr);
|
||||
}
|
||||
|
||||
|
||||
void PutLitChar (int c)
|
||||
void PutLitChar (RTF_Info *info, int c)
|
||||
{
|
||||
CHARLIST_Enqueue(&charlist, (char) c);
|
||||
CHARLIST_Enqueue(&info->charlist, (char) c);
|
||||
/* fputc (c, ostream); */
|
||||
}
|
||||
|
||||
|
||||
static void PutLitStr (char *s)
|
||||
static void PutLitStr (RTF_Info *info, char *s)
|
||||
{
|
||||
for(;*s;s++)
|
||||
{
|
||||
CHARLIST_Enqueue(&charlist, *s);
|
||||
CHARLIST_Enqueue(&info->charlist, *s);
|
||||
}
|
||||
/* fputs (s, ostream); */
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue