diff options
author | George Hazan <ghazan@miranda.im> | 2023-04-18 15:00:44 +0300 |
---|---|---|
committer | George Hazan <ghazan@miranda.im> | 2023-04-18 15:00:44 +0300 |
commit | b38f2534004135415ae8d576c7f3bb41785ca7e7 (patch) | |
tree | 895e89ce5da30f91995943686ef558a6ca8cd2ca | |
parent | cd5679ac850cd43c1b681de6485c8ec30a9e8e1d (diff) |
- further group chats unification;
- LOGSTREAMDATA / GCLogStreamDataBase removed from g_chatApi;
- CRtfLogWindow now in charge of all RTF processing- Srmm_LogStreamCallback is also removed and hidden inside the core
26 files changed, 355 insertions, 473 deletions
diff --git a/include/m_chat_int.h b/include/m_chat_int.h index 807845380b..92c166dfa4 100644 --- a/include/m_chat_int.h +++ b/include/m_chat_int.h @@ -74,7 +74,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. struct SESSION_INFO;
struct MODULEINFO;
-struct LOGSTREAMDATA;
class CMsgDialog;
@@ -94,7 +93,6 @@ struct MIR_APP_EXPORT GCModuleInfoBase : public MZeroedObject, public MNonCopyab char* pszModule;
wchar_t* ptszModDispName;
- char* pszHeader;
bool bBold, bItalics, bUnderline;
bool bColor, bBkgColor;
@@ -190,16 +188,6 @@ struct MIR_APP_EXPORT SESSION_INFO : public MZeroedObject, public MNonCopyable const char* getSoundName(int iEventType) const;
};
-struct GCLogStreamDataBase
-{
- char* buffer;
- int bufferOffset, bufferLen;
- int iStartEvent;
- bool bStripFormat, bRedraw;
- HWND hwnd;
- SESSION_INFO *si;
-};
-
struct GlobalLogSettingsBase
{
bool bShowTime;
@@ -245,7 +233,6 @@ struct GlobalLogSettingsBase /////////////////////////////////////////////////////////////////////////////////////////
#ifndef SRMM_OWN_STRUCTURES
-struct LOGSTREAMDATA : public GCLogStreamDataBase {};
struct MODULEINFO : public GCModuleInfoBase {};
#endif
@@ -280,7 +267,6 @@ struct CHAT_MANAGER void (*SM_InvalidateLogDirectories)(void);
MODULEINFO* (*MM_CreateModule)(void);
- void (*MM_FontsChanged)(void);
void (*MM_IconsChanged)(void);
BOOL (*MM_RemoveAll)(void);
@@ -296,13 +282,10 @@ struct CHAT_MANAGER USERINFO* (*UM_SetContactStatus)(SESSION_INFO *si, const wchar_t *pszUID, uint16_t status);
USERINFO* (*UM_TakeStatus)(SESSION_INFO *si, const wchar_t *pszUID, uint16_t status);
wchar_t* (*UM_FindUserAutoComplete)(SESSION_INFO *si, const wchar_t* pszOriginal, const wchar_t* pszCurrent);
- BOOL (*UM_RemoveUser)(SESSION_INFO *si, const wchar_t *pszUID);
BOOL (*SetOffline)(MCONTACT hContact, BOOL bHide);
BOOL (*SetAllOffline)(BOOL bHide, const char *pszModule);
- char* (*Log_CreateRTF)(LOGSTREAMDATA *streamData);
- char* (*Log_CreateRtfHeader)(void);
void (*LoadMsgDlgFont)(int i, LOGFONT *lf, COLORREF *color);
wchar_t* (*MakeTimeStamp)(wchar_t *pszStamp, time_t time);
diff --git a/include/m_srmm_int.h b/include/m_srmm_int.h index 9163536e5c..97e132e0a8 100644 --- a/include/m_srmm_int.h +++ b/include/m_srmm_int.h @@ -150,17 +150,27 @@ EXTERN_C MIR_APP_DLL(void) UnregisterSrmmLog(HANDLE); struct RtfLogStreamBase
{
- int stage;
+ int iStage;
MCONTACT hContact;
MEVENT hDbEvent, hDbEventLast;
int eventsToInsert;
- int isFirst, isEmpty;
+ bool isFirst, isEmpty;
CMStringA buf;
DB::EventInfo *dbei;
class CRtfLogWindow *pLog;
};
+struct RtfChatLogStreamData
+{
+ int iStage = 0, iStartEvent = 0;
+ bool bStripFormat, bAppend = false, bIsFirst = false;
+
+ CMStringA buf;
+ struct SESSION_INFO *si;
+ class CRtfLogWindow *pLog;
+};
+
#ifdef SRMM_OWN_STRUCTURES
struct RtfLogStreamData;
#else
@@ -180,13 +190,17 @@ public: virtual void AppendUnicodeString(CMStringA &str, const wchar_t *pwszBuf) = 0;
+ void StreamRtfEvents(RtfLogStreamData *dat, bool bAppend);
virtual void CreateRtfHeader(RtfLogStreamData *dat) = 0;
virtual bool CreateRtfEvent(RtfLogStreamData *dat, DB::EventInfo &dbei) = 0;
virtual void CreateRtfTail(RtfLogStreamData *dat);
- virtual INT_PTR WndProc(UINT msg, WPARAM wParam, LPARAM lParam);
+ void StreamChatRtfEvents(RtfChatLogStreamData *dat, bool bAppend);
+ virtual void CreateChatRtfHeader(RtfChatLogStreamData *dat);
+ virtual void CreateChatRtfEvent(RtfChatLogStreamData *dat, const struct LOGINFO &lin);
+ virtual void CreateChatRtfTail(RtfChatLogStreamData *dat);
- void StreamRtfEvents(RtfLogStreamData *dat, bool bAppend);
+ virtual INT_PTR WndProc(UINT msg, WPARAM wParam, LPARAM lParam);
////////////////////////////////////////////////////////////////////////////////////////
void Attach() override;
@@ -315,13 +329,7 @@ class CMsgDialog : public CSrmmBaseDialog {}; #endif
/////////////////////////////////////////////////////////////////////////////////////////
-// receives LOGSTREAMDATA* as the first parameter
-
-#ifdef _WINDOWS
-EXTERN_C MIR_APP_DLL(DWORD) CALLBACK Srmm_LogStreamCallback(DWORD_PTR dwCookie, uint8_t *pbBuff, LONG cb, LONG *pcb);
-#endif
-
-/////////////////////////////////////////////////////////////////////////////////////////
+// adds an event to SRMM message log
MIR_APP_DLL(void) Srmm_AddEvent(MCONTACT hContact, MEVENT hDbEvent);
diff --git a/libs/win32/mir_app.lib b/libs/win32/mir_app.lib Binary files differindex 820cc36f10..1d5ed165e0 100644 --- a/libs/win32/mir_app.lib +++ b/libs/win32/mir_app.lib diff --git a/libs/win64/mir_app.lib b/libs/win64/mir_app.lib Binary files differindex 8d0712009a..40d346ebba 100644 --- a/libs/win64/mir_app.lib +++ b/libs/win64/mir_app.lib diff --git a/plugins/Scriver/src/chat.h b/plugins/Scriver/src/chat.h index 194cd2723c..a325593905 100644 --- a/plugins/Scriver/src/chat.h +++ b/plugins/Scriver/src/chat.h @@ -50,11 +50,6 @@ struct MODULEINFO : public GCModuleInfoBase HICON hOfflineIcon, hOfflineTalkIcon, hOfflineIconBig;
};
-struct LOGSTREAMDATA : public GCLogStreamDataBase
-{
- BOOL isFirst;
-};
-
struct GlobalLogSettings : public GlobalLogSettingsBase
{
HFONT MessageBoxFont;
diff --git a/plugins/Scriver/src/chat_options.cpp b/plugins/Scriver/src/chat_options.cpp index 3cfa295203..df21a3b7bf 100644 --- a/plugins/Scriver/src/chat_options.cpp +++ b/plugins/Scriver/src/chat_options.cpp @@ -300,8 +300,6 @@ public: g_Settings.bStripFormat = db_get_b(0, CHAT_MODULE, "TrimFormatting", 0) != 0;
g_Settings.bLogIndentEnabled = Chat::bLogIndentEnabled;
-
- g_chatApi.MM_FontsChanged();
return true;
}
diff --git a/plugins/Scriver/src/msglog.cpp b/plugins/Scriver/src/msglog.cpp index 8a16ebd013..cf5d714c83 100644 --- a/plugins/Scriver/src/msglog.cpp +++ b/plugins/Scriver/src/msglog.cpp @@ -643,22 +643,21 @@ public: ////////////////////////////////////////////////////////////////////////////////////////
- void LogEvents(SESSION_INFO *si, int iStart, bool bRedraw) override
+ void LogEvents(SESSION_INFO *si, int iStart, bool bAppend) override
{
- if (m_rtf.GetHwnd() == nullptr || si == nullptr || si == nullptr)
+ if (m_rtf.GetHwnd() == nullptr || si == nullptr)
return;
auto &lin = si->arEvents[iStart];
- if (!bRedraw && (si->iType == GCW_CHATROOM || si->iType == GCW_PRIVMESS) && !(m_pDlg.m_iLogFilterFlags & lin.iType))
+ if (!bAppend && (si->iType == GCW_CHATROOM || si->iType == GCW_PRIVMESS) && !(m_pDlg.m_iLogFilterFlags & lin.iType))
return;
- LOGSTREAMDATA streamData;
- memset(&streamData, 0, sizeof(streamData));
- streamData.hwnd = m_rtf.GetHwnd();
+ RtfChatLogStreamData streamData;
+ streamData.pLog = this;
streamData.si = si;
streamData.iStartEvent = iStart;
streamData.bStripFormat = FALSE;
- streamData.isFirst = bRedraw ? 1 : m_rtf.GetRichTextLength() == 0;
+ streamData.bIsFirst = bAppend ? 1 : m_rtf.GetRichTextLength() == 0;
SCROLLINFO scroll;
scroll.cbSize = sizeof(SCROLLINFO);
@@ -681,28 +680,20 @@ public: // fix for the indent... must be a M$ bug
if (sel.cpMax == 0)
- bRedraw = TRUE;
-
- // should the event(s) be appended to the current log
- WPARAM wp = bRedraw ? SF_RTF : SFF_SELECTION | SF_RTF;
+ bAppend = TRUE;
// get the number of pixels per logical inch
bool bFlag = false;
- if (bRedraw) {
+ if (bAppend) {
m_rtf.SetDraw(false);
bFlag = true;
}
// stream in the event(s)
- streamData.bRedraw = bRedraw;
-
- EDITSTREAM stream = {};
- stream.pfnCallback = Srmm_LogStreamCallback;
- stream.dwCookie = (DWORD_PTR)&streamData;
- m_rtf.SendMsg(EM_STREAMIN, wp, (LPARAM)&stream);
+ StreamChatRtfEvents(&streamData, bAppend);
// do smileys
- if (g_dat.smileyAddInstalled && (bRedraw || (lin.ptszText && lin.iType != GC_EVENT_JOIN && lin.iType != GC_EVENT_NICK && lin.iType != GC_EVENT_ADDSTATUS && lin.iType != GC_EVENT_REMOVESTATUS))) {
+ if (g_dat.smileyAddInstalled && (bAppend || (lin.ptszText && lin.iType != GC_EVENT_JOIN && lin.iType != GC_EVENT_NICK && lin.iType != GC_EVENT_ADDSTATUS && lin.iType != GC_EVENT_REMOVESTATUS))) {
newsel.cpMax = -1;
newsel.cpMin = sel.cpMin;
if (newsel.cpMin < 0)
@@ -711,7 +702,7 @@ public: SMADD_RICHEDIT3 sm = { sizeof(sm) };
sm.hwndRichEditControl = m_rtf.GetHwnd();
sm.Protocolname = si->pszModule;
- sm.rangeToReplace = bRedraw ? nullptr : &newsel;
+ sm.rangeToReplace = bAppend ? nullptr : &newsel;
sm.flags = 0;
sm.disableRedraw = TRUE;
sm.hContact = m_pDlg.m_hContact;
@@ -719,7 +710,7 @@ public: }
// scroll log to bottom if the log was previously scrolled to bottom, else restore old position
- if (bRedraw || (UINT)scroll.nPos >= (UINT)scroll.nMax - scroll.nPage - 5 || scroll.nMax - scroll.nMin - scroll.nPage < 50)
+ if (bAppend || (UINT)scroll.nPos >= (UINT)scroll.nMax - scroll.nPage - 5 || scroll.nMax - scroll.nMin - scroll.nPage < 50)
ScrollToBottom();
else
m_rtf.SendMsg(EM_SETSCROLLPOS, 0, (LPARAM)&point);
diff --git a/plugins/TabSRMM/src/chat.h b/plugins/TabSRMM/src/chat.h index 0c4a88a64b..29fd9e4596 100644 --- a/plugins/TabSRMM/src/chat.h +++ b/plugins/TabSRMM/src/chat.h @@ -50,12 +50,6 @@ struct MODULEINFO : public GCModuleInfoBase wchar_t tszIdleMsg[60];
};
-struct LOGSTREAMDATA : public GCLogStreamDataBase
-{
- int crCount;
- CMsgDialog *dat;
-};
-
struct TMUCSettings : public GlobalLogSettingsBase
{
HICON hIconOverlay;
@@ -81,10 +75,6 @@ extern TMUCSettings g_Settings; //////////////////////////////////////////////////////////////////////////////////
-// log.c
-char* Log_CreateRtfHeader(void);
-char* Log_CreateRTF(LOGSTREAMDATA *streamData);
-
// options.c
enum { FONTSECTION_AUTO, FONTSECTION_IM, FONTSECTION_IP };
void LoadMsgDlgFont(int section, int i, LOGFONTW *lf, COLORREF *colour = nullptr);
diff --git a/plugins/TabSRMM/src/chat_log.cpp b/plugins/TabSRMM/src/chat_log.cpp index 624384a362..49e573aed3 100644 --- a/plugins/TabSRMM/src/chat_log.cpp +++ b/plugins/TabSRMM/src/chat_log.cpp @@ -133,7 +133,7 @@ static int EventToIcon(const LOGINFO &lin) return 0;
}
-static void Log_AppendRTF(LOGSTREAMDATA *streamData, const LOGINFO &lin, bool simpleMode, CMStringA &str, const wchar_t *line)
+static void Log_AppendRTF(RtfChatLogStreamData *streamData, const LOGINFO &lin, bool simpleMode, CMStringA &str, const wchar_t *line)
{
int textCharsCount = 0;
@@ -220,23 +220,10 @@ static void Log_AppendRTF(LOGSTREAMDATA *streamData, const LOGINFO &lin, bool si str += res;
}
-static void AddEventToBuffer(CMStringA &str, LOGSTREAMDATA *streamData, const LOGINFO &lin)
-{
- if (streamData == nullptr)
- return;
-
- CMStringW wszCaption;
- bool bTextUsed = Chat_GetDefaultEventDescr(streamData->si, &lin, wszCaption);
- if (!wszCaption.IsEmpty())
- Log_AppendRTF(streamData, lin, !bTextUsed, str, wszCaption);
- if (!bTextUsed && lin.ptszText) {
- if (!wszCaption.IsEmpty())
- Log_AppendRTF(streamData, lin, false, str, L" ");
- Log_AppendRTF(streamData, lin, false, str, lin.ptszText);
- }
-}
+/////////////////////////////////////////////////////////////////////////////////////////
+// RTF header
-char* Log_CreateRtfHeader(void)
+void CLogWindow::CreateChatRtfHeader(RtfChatLogStreamData *streamData)
{
// get the number of pixels per logical inch
if (g_chatApi.logPixelSY == 0) {
@@ -247,9 +234,10 @@ char* Log_CreateRtfHeader(void) }
// ### RTF HEADER
+ CMStringA &str = streamData->buf;
// font table
- CMStringA str("{\\rtf1\\ansi\\deff0{\\fonttbl");
+ str.Append("{\\rtf1\\ansi\\deff0{\\fonttbl");
for (int i = 0; i < OPTIONS_FONTCOUNT; i++)
str.AppendFormat("{\\f%u\\fnil\\fcharset%u%S;}", i, g_chatApi.aFonts[i].lf.lfCharSet, g_chatApi.aFonts[i].lf.lfFaceName);
@@ -298,140 +286,122 @@ char* Log_CreateRtfHeader(void) iIndent += iSize;
}
str.AppendFormat("\\fi-%u\\li%u", iIndent, iIndent);
-
- return str.Detach();
}
-char* Log_CreateRTF(LOGSTREAMDATA *streamData)
+/////////////////////////////////////////////////////////////////////////////////////////
+// RTF event
+
+void CLogWindow::CreateChatRtfEvent(RtfChatLogStreamData *streamData, const LOGINFO &lin)
{
SESSION_INFO *si = streamData->si;
- MODULEINFO *mi = si->pMI;
+ CMStringA &str = streamData->buf;
- // ### RTF HEADER
+ if (streamData->iStartEvent != 0)
+ str.Append("\\par ");
- if (mi->pszHeader == nullptr)
- mi->pszHeader = Log_CreateRtfHeader();
+ if (m_pDlg.m_bDividerWanted) {
+ static char szStyle_div[128] = "\0";
+ if (szStyle_div[0] == 0)
+ mir_snprintf(szStyle_div, "\\f%u\\cf%u\\ul0\\b%d\\i%d\\fs%u", 17, 18, 0, 0, 5);
- char *header = mi->pszHeader;
- streamData->crCount = 0;
+ if (streamData->iStartEvent != si->arEvents.getCount() - 1 || !streamData->bAppend)
+ str.AppendFormat("\\qc\\sl-1\\highlight%d %s ---------------------------------------------------------------------------------------\\par ", 18, szStyle_div);
+ m_pDlg.m_bDividerWanted = false;
+ }
+ // create new line, and set font and color
+ str.AppendFormat("\\ql\\sl0%s ", g_chatApi.Log_SetStyle(0));
+ str.AppendFormat("\\v~-+%p+-~\\v0 ", &lin);
- CMStringA str;
- if (header)
- str.Append(header);
+ // Insert icon
+ if (g_Settings.bLogSymbols) // use symbols
+ str.AppendFormat("%s %c", g_chatApi.Log_SetStyle(17), EventToSymbol(lin));
+ else if (g_Settings.dwIconFlags) {
+ int iIndex = lin.bIsHighlighted ? ICON_HIGHLIGHT : EventToIcon(lin);
+ str.Append("\\f0\\fs14");
+ str.Append(g_chatApi.pLogIconBmpBits[iIndex]);
+ }
- // ### RTF BODY (one iteration per event that should be streamed in)
- int iEventCount = si->arEvents.getCount();
- for (int i = streamData->iStartEvent; i < iEventCount; i++) {
- auto &lin = si->arEvents[i];
+ if (g_Settings.bTimeStampEventColour) {
+ // colored timestamps
+ static char szStyle[256];
+ LOGFONT &F = g_chatApi.aFonts[0].lf;
+ int iii;
+ if (lin.ptszNick && lin.iType == GC_EVENT_MESSAGE) {
+ iii = lin.bIsHighlighted ? 16 : (lin.bIsMe ? 2 : 1);
+ mir_snprintf(szStyle, "\\f0\\cf%u\\ul0\\highlight0\\b%d\\i%d\\ul%d\\fs%u",
+ iii + 1, F.lfWeight >= FW_BOLD ? 1 : 0, F.lfItalic, F.lfUnderline, 2 * abs(F.lfHeight) * 74 / g_chatApi.logPixelSY);
+ str.Append(szStyle);
+ }
+ else {
+ iii = lin.bIsHighlighted ? 16 : EventToIndex(lin);
+ mir_snprintf(szStyle, "\\f0\\cf%u\\ul0\\highlight0\\b%d\\i%d\\ul%d\\fs%u",
+ iii + 1, F.lfWeight >= FW_BOLD ? 1 : 0, F.lfItalic, F.lfUnderline, 2 * abs(F.lfHeight) * 74 / g_chatApi.logPixelSY);
+ str.Append(szStyle);
+ }
+ }
+ else str.Append(g_chatApi.Log_SetStyle(0));
+ str.AppendChar(' ');
- // filter
- if ((si->iType != GCW_CHATROOM && si->iType != GCW_PRIVMESS) || (si->pDlg->m_iLogFilterFlags & lin.iType) != 0) {
- if (i != 0)
- str.Append("\\par ");
+ // insert a TAB if necessary to put the timestamp in the right position
+ if (g_Settings.dwIconFlags)
+ str.Append("\\tab ");
- if (streamData->dat->m_bDividerWanted) {
- static char szStyle_div[128] = "\0";
- if (szStyle_div[0] == 0)
- mir_snprintf(szStyle_div, "\\f%u\\cf%u\\ul0\\b%d\\i%d\\fs%u", 17, 18, 0, 0, 5);
+ // insert timestamp
+ if (g_Settings.bShowTime) {
+ wchar_t szTimeStamp[30], szOldTimeStamp[30];
- if (i != iEventCount - 1 || !streamData->bRedraw)
- str.AppendFormat("\\qc\\sl-1\\highlight%d %s ---------------------------------------------------------------------------------------\\par ", 18, szStyle_div);
- streamData->dat->m_bDividerWanted = false;
- }
- // create new line, and set font and color
- str.AppendFormat("\\ql\\sl0%s ", g_chatApi.Log_SetStyle(0));
- str.AppendFormat("\\v~-+%p+-~\\v0 ", &lin);
-
- // Insert icon
- if (g_Settings.bLogSymbols) // use symbols
- str.AppendFormat("%s %c", g_chatApi.Log_SetStyle(17), EventToSymbol(lin));
- else if (g_Settings.dwIconFlags) {
- int iIndex = lin.bIsHighlighted ? ICON_HIGHLIGHT : EventToIcon(lin);
- str.Append("\\f0\\fs14");
- str.Append(g_chatApi.pLogIconBmpBits[iIndex]);
- }
+ wcsncpy_s(szTimeStamp, g_chatApi.MakeTimeStamp(g_Settings.pszTimeStamp, lin.time), _TRUNCATE);
+ wcsncpy_s(szOldTimeStamp, g_chatApi.MakeTimeStamp(g_Settings.pszTimeStamp, si->LastTime), _TRUNCATE);
+ if (!g_Settings.bShowTimeIfChanged || si->LastTime == 0 || mir_wstrcmp(szTimeStamp, szOldTimeStamp)) {
+ si->LastTime = lin.time;
+ Log_AppendRTF(streamData, lin, TRUE, str, szTimeStamp);
+ }
+ str.Append("\\tab ");
+ }
- if (g_Settings.bTimeStampEventColour) {
- // colored timestamps
- static char szStyle[256];
- LOGFONT &F = g_chatApi.aFonts[0].lf;
- int iii;
- if (lin.ptszNick && lin.iType == GC_EVENT_MESSAGE) {
- iii = lin.bIsHighlighted ? 16 : (lin.bIsMe ? 2 : 1);
- mir_snprintf(szStyle, "\\f0\\cf%u\\ul0\\highlight0\\b%d\\i%d\\ul%d\\fs%u",
- iii + 1, F.lfWeight >= FW_BOLD ? 1 : 0, F.lfItalic, F.lfUnderline, 2 * abs(F.lfHeight) * 74 / g_chatApi.logPixelSY);
- str.Append(szStyle);
- }
- else {
- iii = lin.bIsHighlighted ? 16 : EventToIndex(lin);
- mir_snprintf(szStyle, "\\f0\\cf%u\\ul0\\highlight0\\b%d\\i%d\\ul%d\\fs%u",
- iii + 1, F.lfWeight >= FW_BOLD ? 1 : 0, F.lfItalic, F.lfUnderline, 2 * abs(F.lfHeight) * 74 / g_chatApi.logPixelSY);
- str.Append(szStyle);
- }
- }
- else str.Append(g_chatApi.Log_SetStyle(0));
- str.AppendChar(' ');
-
- // insert a TAB if necessary to put the timestamp in the right position
- if (g_Settings.dwIconFlags)
- str.Append("\\tab ");
-
- // insert timestamp
- if (g_Settings.bShowTime) {
- wchar_t szTimeStamp[30], szOldTimeStamp[30];
-
- wcsncpy_s(szTimeStamp, g_chatApi.MakeTimeStamp(g_Settings.pszTimeStamp, lin.time), _TRUNCATE);
- wcsncpy_s(szOldTimeStamp, g_chatApi.MakeTimeStamp(g_Settings.pszTimeStamp, si->LastTime), _TRUNCATE);
- if (!g_Settings.bShowTimeIfChanged || si->LastTime == 0 || mir_wstrcmp(szTimeStamp, szOldTimeStamp)) {
- si->LastTime = lin.time;
- Log_AppendRTF(streamData, lin, TRUE, str, szTimeStamp);
- }
- str.Append("\\tab ");
- }
+ // Insert the nick
+ if (lin.ptszNick && lin.iType == GC_EVENT_MESSAGE) {
+ char pszIndicator[3] = "\0\0";
+ int crNickIndex = 0;
- // Insert the nick
- if (lin.ptszNick && lin.iType == GC_EVENT_MESSAGE) {
- char pszIndicator[3] = "\0\0";
- int crNickIndex = 0;
+ if (g_Settings.bLogClassicIndicators || g_Settings.bColorizeNicksInLog)
+ pszIndicator[0] = GetIndicator(si, lin.ptszNick, &crNickIndex);
- if (g_Settings.bLogClassicIndicators || g_Settings.bColorizeNicksInLog)
- pszIndicator[0] = GetIndicator(si, lin.ptszNick, &crNickIndex);
+ str.Append(g_chatApi.Log_SetStyle(lin.bIsMe ? 2 : 1));
+ str.AppendChar(' ');
- str.Append(g_chatApi.Log_SetStyle(lin.bIsMe ? 2 : 1));
- str.AppendChar(' ');
+ if (g_Settings.bLogClassicIndicators)
+ str.Append(pszIndicator);
- if (g_Settings.bLogClassicIndicators)
- str.Append(pszIndicator);
+ CMStringW pszTemp(lin.bIsMe ? g_Settings.pszOutgoingNick : g_Settings.pszIncomingNick);
+ if (!lin.bIsMe) {
+ if (g_Settings.bClickableNicks)
+ pszTemp.Replace(L"%n", CLICKNICK_BEGIN L"%n" CLICKNICK_END);
- CMStringW pszTemp(lin.bIsMe ? g_Settings.pszOutgoingNick : g_Settings.pszIncomingNick);
- if (!lin.bIsMe) {
- if (g_Settings.bClickableNicks)
- pszTemp.Replace(L"%n", CLICKNICK_BEGIN L"%n" CLICKNICK_END);
+ if (g_Settings.bColorizeNicksInLog && pszIndicator[0])
+ str.AppendFormat("\\cf%u ", OPTIONS_FONTCOUNT + Utils::rtf_clrs.getCount() + crNickIndex);
+ }
+ pszTemp.Replace(L"%n", lin.ptszNick);
- if (g_Settings.bColorizeNicksInLog && pszIndicator[0])
- str.AppendFormat("\\cf%u ", OPTIONS_FONTCOUNT + Utils::rtf_clrs.getCount() + streamData->crCount + crNickIndex);
- }
- pszTemp.Replace(L"%n", lin.ptszNick);
+ if (g_Settings.bNewLineAfterNames)
+ pszTemp.AppendChar('\n');
- if (g_Settings.bNewLineAfterNames)
- pszTemp.AppendChar('\n');
+ Log_AppendRTF(streamData, lin, TRUE, str, pszTemp);
+ str.AppendChar(' ');
+ }
- Log_AppendRTF(streamData, lin, TRUE, str, pszTemp);
- str.AppendChar(' ');
- }
+ // Insert the message
+ str.Append(g_chatApi.Log_SetStyle(lin.bIsHighlighted ? 16 : EventToIndex(lin)));
+ str.AppendChar(' ');
- // Insert the message
- str.Append(g_chatApi.Log_SetStyle(lin.bIsHighlighted ? 16 : EventToIndex(lin)));
- str.AppendChar(' ');
- AddEventToBuffer(str, streamData, lin);
- }
+ CMStringW wszCaption;
+ bool bTextUsed = Chat_GetDefaultEventDescr(streamData->si, &lin, wszCaption);
+ if (!wszCaption.IsEmpty())
+ Log_AppendRTF(streamData, lin, !bTextUsed, str, wszCaption);
+ if (!bTextUsed && lin.ptszText) {
+ if (!wszCaption.IsEmpty())
+ Log_AppendRTF(streamData, lin, false, str, L" ");
+ Log_AppendRTF(streamData, lin, false, str, lin.ptszText);
}
-
- // ### RTF END
- if (streamData->bRedraw)
- str.Append("\\par}");
- else
- str.Append("}");
- return str.Detach();
}
diff --git a/plugins/TabSRMM/src/chat_main.cpp b/plugins/TabSRMM/src/chat_main.cpp index c095cc94e0..1a4a20082a 100644 --- a/plugins/TabSRMM/src/chat_main.cpp +++ b/plugins/TabSRMM/src/chat_main.cpp @@ -376,8 +376,6 @@ int Chat_Load() g_chatApi.IsHighlighted = IsHighlighted;
oldDoPopup = g_chatApi.DoPopup; g_chatApi.DoPopup = DoPopup;
oldDoTrayIcon = g_chatApi.DoTrayIcon; g_chatApi.ShowPopup = ShowPopup;
- g_chatApi.Log_CreateRTF = Log_CreateRTF;
- g_chatApi.Log_CreateRtfHeader = Log_CreateRtfHeader;
g_chatApi.UM_CompareItem = UM_CompareItem;
g_chatApi.ReloadSettings();
diff --git a/plugins/TabSRMM/src/chat_options.cpp b/plugins/TabSRMM/src/chat_options.cpp index 93c78a9817..40c2c9ca4e 100644 --- a/plugins/TabSRMM/src/chat_options.cpp +++ b/plugins/TabSRMM/src/chat_options.cpp @@ -126,7 +126,7 @@ static FontOptionsList IP_fontOptionsList[] = { LPGENW("Window caption (skinned mode)"), RGB(255, 255, 255), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12 },
};
-void LoadMsgDlgFont(int section, int i, LOGFONT *lf, COLORREF* colour)
+void LoadMsgDlgFont(int section, int i, LOGFONTW *lf, COLORREF* colour)
{
char str[32];
int db_idx = (section == FONTSECTION_IM) ? i : i + 100;
@@ -394,8 +394,7 @@ int FontServiceFontsChanged(WPARAM, LPARAM) {
g_chatApi.ReloadSettings();
g_chatApi.MM_IconsChanged();
- g_chatApi.MM_FontsChanged();
-
+
PluginConfig.reloadSettings();
CSkin::initAeroEffect();
CacheMsgLogIcons();
@@ -469,7 +468,7 @@ protected: {
g_chatApi.ReloadSettings();
g_chatApi.MM_IconsChanged();
- g_chatApi.MM_FontsChanged();
+
Chat_UpdateOptions();
Chat_ReconfigureFilters();
diff --git a/plugins/TabSRMM/src/msgdlgother.cpp b/plugins/TabSRMM/src/msgdlgother.cpp index 1b3003ee04..5043f45e8d 100644 --- a/plugins/TabSRMM/src/msgdlgother.cpp +++ b/plugins/TabSRMM/src/msgdlgother.cpp @@ -56,7 +56,7 @@ void CMsgDialog::AddLog() }
}
- CSrmmBaseDialog::AddLog();
+ CSuper::AddLog();
}
/////////////////////////////////////////////////////////////////////////////////////////
diff --git a/plugins/TabSRMM/src/msglog.cpp b/plugins/TabSRMM/src/msglog.cpp index 709b44a3d0..89cd3e7d34 100644 --- a/plugins/TabSRMM/src/msglog.cpp +++ b/plugins/TabSRMM/src/msglog.cpp @@ -1226,24 +1226,22 @@ void CLogWindow::LogEvents(MEVENT hDbEventFirst, int count, bool fAppend, DB::Ev /////////////////////////////////////////////////////////////////////////////////////////
-void CLogWindow::LogEvents(SESSION_INFO *si, int iStart, bool bRedraw)
+void CLogWindow::LogEvents(SESSION_INFO *si, int iStart, bool bAppend)
{
if (m_rtf.GetHwnd() == nullptr || si == nullptr)
return;
auto &lin = si->arEvents[iStart];
- if (!bRedraw && m_pDlg.AllowTyping() && !(m_pDlg.m_iLogFilterFlags & lin.iType))
+ if (!bAppend && m_pDlg.AllowTyping() && !(m_pDlg.m_iLogFilterFlags & lin.iType))
return;
bool bFlag = false, bDoReplace, bAtBottom = AtBottom();
- LOGSTREAMDATA streamData;
- memset(&streamData, 0, sizeof(streamData));
- streamData.hwnd = m_rtf.GetHwnd();
+ RtfChatLogStreamData streamData;
+ streamData.pLog = this;
streamData.si = si;
streamData.iStartEvent = iStart;
streamData.bStripFormat = FALSE;
- streamData.dat = &m_pDlg;
POINT point = { 0 };
m_rtf.SendMsg(EM_GETSCROLLPOS, 0, (LPARAM)&point);
@@ -1260,13 +1258,13 @@ void CLogWindow::LogEvents(SESSION_INFO *si, int iStart, bool bRedraw) // fix for the indent... must be a M$ bug
if (sel.cpMax == 0)
- bRedraw = TRUE;
+ bAppend = TRUE;
// should the event(s) be appended to the current log
- WPARAM wp = bRedraw ? SF_RTF : SFF_SELECTION | SF_RTF;
+ WPARAM wp = bAppend ? SF_RTF : SFF_SELECTION | SF_RTF;
// get the number of pixels per logical inch
- if (bRedraw) {
+ if (bAppend) {
HDC hdc = GetDC(nullptr);
g_chatApi.logPixelSY = GetDeviceCaps(hdc, LOGPIXELSY);
g_chatApi.logPixelSX = GetDeviceCaps(hdc, LOGPIXELSX);
@@ -1275,22 +1273,16 @@ void CLogWindow::LogEvents(SESSION_INFO *si, int iStart, bool bRedraw) bFlag = true;
}
- // stream in the event(s)
- streamData.bRedraw = bRedraw;
-
- EDITSTREAM stream = {};
- stream.pfnCallback = Srmm_LogStreamCallback;
- stream.dwCookie = (DWORD_PTR)&streamData;
- m_rtf.SendMsg(EM_STREAMIN, wp, (LPARAM)&stream);
+ StreamChatRtfEvents(&streamData, bAppend);
// for new added events, only replace in message or action events.
// no need to replace smileys or math formulas elsewhere
- bDoReplace = (bRedraw || (lin.ptszText && (lin.iType == GC_EVENT_MESSAGE || lin.iType == GC_EVENT_ACTION)));
+ bDoReplace = (bAppend || (lin.ptszText && (lin.iType == GC_EVENT_MESSAGE || lin.iType == GC_EVENT_ACTION)));
// replace marked nicknames with hyperlinks to make the nicks clickable
if (g_Settings.bClickableNicks) {
FINDTEXTEX fi, fi2;
- fi.chrg.cpMin = bRedraw ? 0 : sel.cpMin;
+ fi.chrg.cpMin = bAppend ? 0 : sel.cpMin;
fi.chrg.cpMax = -1;
fi.lpstrText = CLICKNICK_BEGIN;
@@ -1334,7 +1326,7 @@ void CLogWindow::LogEvents(SESSION_INFO *si, int iStart, bool bRedraw) SMADD_RICHEDIT3 sm = { sizeof(sm) };
sm.hwndRichEditControl = m_rtf.GetHwnd();
sm.Protocolname = si->pszModule;
- sm.rangeToReplace = bRedraw ? nullptr : &newsel;
+ sm.rangeToReplace = bAppend ? nullptr : &newsel;
sm.disableRedraw = TRUE;
sm.hContact = si->hContact;
CallService(MS_SMILEYADD_REPLACESMILEYS, 0, (LPARAM)&sm);
@@ -1358,7 +1350,7 @@ void CLogWindow::LogEvents(SESSION_INFO *si, int iStart, bool bRedraw) }
// scroll log to bottom if the log was previously scrolled to bottom, else restore old position
- if (bRedraw || bAtBottom)
+ if (bAppend || bAtBottom)
ScrollToBottom(false, false);
else
m_rtf.SendMsg(EM_SETSCROLLPOS, 0, (LPARAM)&point);
diff --git a/plugins/TabSRMM/src/msgoptions.cpp b/plugins/TabSRMM/src/msgoptions.cpp index d94ecf0eb8..60cecb9087 100644 --- a/plugins/TabSRMM/src/msgoptions.cpp +++ b/plugins/TabSRMM/src/msgoptions.cpp @@ -578,7 +578,7 @@ public: TextOutW(dis->hDC, dis->rcItem.left, dis->rcItem.top, pwszName, (int)mir_wstrlen(pwszName));
}
- return CSrmmBaseDialog::DlgProc(uMsg, wParam, lParam);
+ return CSuper::DlgProc(uMsg, wParam, lParam);
}
void onChange_Text(CCtrlEdit *)
diff --git a/plugins/TabSRMM/src/msgs.h b/plugins/TabSRMM/src/msgs.h index 79032e37b0..439f506308 100644 --- a/plugins/TabSRMM/src/msgs.h +++ b/plugins/TabSRMM/src/msgs.h @@ -690,6 +690,9 @@ public: void CreateRtfHeader(RtfLogStreamData *streamData) override;
bool CreateRtfEvent(RtfLogStreamData *streamData, DB::EventInfo &dbei) override;
+ void CreateChatRtfHeader(RtfChatLogStreamData *dat) override;
+ void CreateChatRtfEvent(RtfChatLogStreamData *dat, const LOGINFO &lin) override;
+
void AppendUnicodeString(CMStringA &str, const wchar_t *pwszBuf) override;
void Attach() override;
void LogEvents(MEVENT hDbEventFirst, int count, bool bAppend) override;
diff --git a/src/core/stdmsg/src/msglog.cpp b/src/core/stdmsg/src/msglog.cpp index ba0d25e44a..22486d106c 100644 --- a/src/core/stdmsg/src/msglog.cpp +++ b/src/core/stdmsg/src/msglog.cpp @@ -478,21 +478,20 @@ public: /////////////////////////////////////////////////////////////////////////////////////////
- void LogEvents(SESSION_INFO *si, int iStart, bool bRedraw) override
+ void LogEvents(SESSION_INFO *si, int iStart, bool bAppend) override
{
if (si == nullptr)
return;
auto &lin = si->arEvents[iStart];
- if (!bRedraw && si->iType == GCW_CHATROOM && (m_pDlg.m_iLogFilterFlags & lin.iType) == 0)
+ if (!bAppend && si->iType == GCW_CHATROOM && (m_pDlg.m_iLogFilterFlags & lin.iType) == 0)
return;
- LOGSTREAMDATA streamData;
- memset(&streamData, 0, sizeof(streamData));
- streamData.hwnd = m_rtf.GetHwnd();
+ RtfChatLogStreamData streamData;
+ streamData.pLog = this;
streamData.si = si;
streamData.iStartEvent = iStart;
- streamData.bStripFormat = FALSE;
+ streamData.bStripFormat = false;
bool bFlag = false;
@@ -510,19 +509,16 @@ public: if (oldsel.cpMax != oldsel.cpMin)
m_rtf.SetDraw(false);
- //set the insertion point at the bottom
+ // set the insertion point at the bottom
sel.cpMin = sel.cpMax = m_rtf.GetRichTextLength();
m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel);
// fix for the indent... must be a M$ bug
if (sel.cpMax == 0)
- bRedraw = TRUE;
-
- // should the event(s) be appended to the current log
- WPARAM wp = bRedraw ? SF_RTF : SFF_SELECTION | SF_RTF;
+ bAppend = true;
- //get the number of pixels per logical inch
- if (bRedraw) {
+ // get the number of pixels per logical inch
+ if (bAppend) {
HDC hdc = GetDC(nullptr);
g_chatApi.logPixelSY = GetDeviceCaps(hdc, LOGPIXELSY);
g_chatApi.logPixelSX = GetDeviceCaps(hdc, LOGPIXELSX);
@@ -532,15 +528,10 @@ public: }
// stream in the event(s)
- streamData.bRedraw = bRedraw;
-
- EDITSTREAM stream = {};
- stream.pfnCallback = Srmm_LogStreamCallback;
- stream.dwCookie = (DWORD_PTR)&streamData;
- m_rtf.SendMsg(EM_STREAMIN, wp, (LPARAM)&stream);
+ StreamChatRtfEvents(&streamData, bAppend);
// do smileys
- if (g_plugin.bSmileyInstalled && (bRedraw || (lin.ptszText && lin.iType != GC_EVENT_JOIN && lin.iType != GC_EVENT_NICK && lin.iType != GC_EVENT_ADDSTATUS && lin.iType != GC_EVENT_REMOVESTATUS))) {
+ if (g_plugin.bSmileyInstalled && (bAppend || (lin.ptszText && lin.iType != GC_EVENT_JOIN && lin.iType != GC_EVENT_NICK && lin.iType != GC_EVENT_ADDSTATUS && lin.iType != GC_EVENT_REMOVESTATUS))) {
CHARRANGE newsel;
newsel.cpMax = -1;
newsel.cpMin = sel.cpMin;
@@ -551,14 +542,14 @@ public: sm.cbSize = sizeof(sm);
sm.hwndRichEditControl = m_rtf.GetHwnd();
sm.Protocolname = si->pszModule;
- sm.rangeToReplace = bRedraw ? nullptr : &newsel;
+ sm.rangeToReplace = bAppend ? nullptr : &newsel;
sm.disableRedraw = TRUE;
sm.hContact = si->hContact;
CallService(MS_SMILEYADD_REPLACESMILEYS, 0, (LPARAM)&sm);
}
// scroll log to bottom if the log was previously scrolled to bottom, else restore old position
- if (bRedraw || (UINT)scroll.nPos >= (UINT)scroll.nMax - scroll.nPage - 5 || scroll.nMax - scroll.nMin - scroll.nPage < 50)
+ if (bAppend || (UINT)scroll.nPos >= (UINT)scroll.nMax - scroll.nPage - 5 || scroll.nMax - scroll.nMin - scroll.nPage < 50)
ScrollToBottom();
else
m_rtf.SendMsg(EM_SETSCROLLPOS, 0, (LPARAM)&point);
diff --git a/src/core/stdmsg/src/stdafx.h b/src/core/stdmsg/src/stdafx.h index 8e2b93764c..dc6fdc6c5d 100644 --- a/src/core/stdmsg/src/stdafx.h +++ b/src/core/stdmsg/src/stdafx.h @@ -127,7 +127,6 @@ CTabbedWindow *GetContainer(); /////////////////////////////////////////////////////////////////////////////////////////
struct MODULEINFO : public GCModuleInfoBase {};
-struct LOGSTREAMDATA : public GCLogStreamDataBase {};
#include "cmdlist.h"
#include "msgs.h"
diff --git a/src/mir_app/src/chat.h b/src/mir_app/src/chat.h index df5141f2e1..5f6a1f0bde 100644 --- a/src/mir_app/src/chat.h +++ b/src/mir_app/src/chat.h @@ -25,6 +25,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include <m_popup.h>
#include <m_fontservice.h>
+#define STREAMSTAGE_HEADER 0
+#define STREAMSTAGE_EVENTS 1
+#define STREAMSTAGE_TAIL 2
+#define STREAMSTAGE_STOP 3
+
void Srmm_CreateToolbarIcons(HWND hwndDlg, int flags);
void Srmm_ProcessToolbarHotkey(MCONTACT hContact, INT_PTR iButtonFrom, HWND hwndDlg);
@@ -53,12 +58,11 @@ extern const char *g_pszHotkeySection; // log.c
void LoadMsgLogBitmaps(void);
void FreeMsgLogBitmaps(void);
-void RedrawLog2(SESSION_INFO *si);
void ValidateFilename (wchar_t *filename);
wchar_t* MakeTimeStamp(wchar_t *pszStamp, time_t time);
wchar_t* GetChatLogsFilename(SESSION_INFO *si, time_t tTime);
char* Log_CreateRtfHeader();
-char* Log_CreateRTF(LOGSTREAMDATA *streamData);
+char* Log_CreateRTF(RtfChatLogStreamData *streamData);
char* Log_SetStyle(int style);
// chat_manager.cpp
diff --git a/src/mir_app/src/chat_log.cpp b/src/mir_app/src/chat_log.cpp index 5f82bace10..5bbf07065d 100644 --- a/src/mir_app/src/chat_log.cpp +++ b/src/mir_app/src/chat_log.cpp @@ -86,7 +86,7 @@ char* Log_SetStyle(int style) return "";
}
-static int Log_AppendRTF(LOGSTREAMDATA *streamData, bool simpleMode, CMStringA &buf, const wchar_t *line)
+static int Log_AppendRTF(RtfChatLogStreamData *streamData, bool simpleMode, CMStringA &buf, const wchar_t *line)
{
int textCharsCount = 0;
auto &lin = streamData->si->arEvents[streamData->iStartEvent];
@@ -253,19 +253,6 @@ MIR_APP_DLL(bool) Chat_GetDefaultEventDescr(const SESSION_INFO *si, const LOGINF return false;
}
-static void AddEventToBuffer(CMStringA &buf, LOGSTREAMDATA *streamData, const LOGINFO &lin)
-{
- CMStringW wszCaption;
- bool bTextUsed = Chat_GetDefaultEventDescr(streamData->si, &lin, wszCaption);
- if (!wszCaption.IsEmpty())
- Log_AppendRTF(streamData, !bTextUsed, buf, wszCaption);
- if (!bTextUsed && lin.ptszText) {
- if (!wszCaption.IsEmpty())
- Log_AppendRTF(streamData, false, buf, L" ");
- Log_AppendRTF(streamData, false, buf, lin.ptszText);
- }
-}
-
wchar_t* MakeTimeStamp(wchar_t *pszStamp, time_t time)
{
static wchar_t szTime[100];
@@ -274,98 +261,73 @@ wchar_t* MakeTimeStamp(wchar_t *pszStamp, time_t time) return szTime;
}
-char* Log_CreateRTF(LOGSTREAMDATA *streamData)
-{
- SESSION_INFO *si = streamData->si;
- MODULEINFO *mi = si->pMI;
-
- // guesstimate amount of memory for the RTF
- CMStringA buf;
-
- // ### RTF HEADER
- char *header = mi->pszHeader;
- if (header)
- buf.Append(header);
-
- // ### RTF BODY (one iteration per event that should be streamed in)
- for (int i = 0; i < si->arEvents.getCount(); i++) {
- auto &lin = si->arEvents[i];
-
- // filter
- if (si->iType == GCW_CHATROOM || si->iType == GCW_PRIVMESS)
- if (!(si->pDlg->m_iLogFilterFlags & lin.iType))
- continue;
-
- // create new line, and set font and color
- if (i != 0)
- buf.Append("\\par ");
- buf.AppendFormat("%s ", Log_SetStyle(0));
-
- // Insert icon
- if ((lin.iType & g_Settings->dwIconFlags) || lin.bIsHighlighted && (g_Settings->dwIconFlags & GC_EVENT_HIGHLIGHT)) {
- int iIndex = (lin.bIsHighlighted && (g_Settings->dwIconFlags & GC_EVENT_HIGHLIGHT)) ? ICON_HIGHLIGHT : EventToIcon(lin);
- buf.Append("\\f0\\fs14");
- buf.Append(pLogIconBmpBits[iIndex]);
- }
-
- if (g_Settings->bTimeStampEventColour) {
- LOGFONT &lf = g_chatApi.aFonts[0].lf;
+/////////////////////////////////////////////////////////////////////////////////////////
+// Chat event streamer
- // colored timestamps
- if (lin.ptszNick && lin.iType == GC_EVENT_MESSAGE) {
- int iii = lin.bIsHighlighted ? 16 : (lin.bIsMe ? 2 : 1);
- buf.AppendFormat("\\f0\\cf%u\\ul0\\highlight0\\b%d\\i%d\\fs%u", iii + 1, lf.lfWeight >= FW_BOLD ? 1 : 0, lf.lfItalic, 2 * abs(lf.lfHeight) * 74 / g_chatApi.logPixelSY);
- }
- else {
- int iii = lin.bIsHighlighted ? 16 : EventToIndex(lin);
- buf.AppendFormat("\\f0\\cf%u\\ul0\\highlight0\\b%d\\i%d\\fs%u", iii + 1, lf.lfWeight >= FW_BOLD ? 1 : 0, lf.lfItalic, 2 * abs(lf.lfHeight) * 74 / g_chatApi.logPixelSY);
+static DWORD CALLBACK ChatLogStreamCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
+{
+ RtfChatLogStreamData *dat = (RtfChatLogStreamData *)dwCookie;
+
+ if (dat->buf.IsEmpty()) {
+ switch (dat->iStage) {
+ case STREAMSTAGE_HEADER:
+ dat->pLog->CreateChatRtfHeader(dat);
+ dat->iStage = STREAMSTAGE_EVENTS;
+ break;
+
+ case STREAMSTAGE_EVENTS:
+ {
+ auto &events = dat->si->arEvents;
+ if (dat->iStartEvent < events.getCount()) {
+ auto *si = dat->si;
+ auto &lin = events[dat->iStartEvent];
+ if (si->iType == GCW_SERVER || (si->pDlg->m_iLogFilterFlags & lin.iType) != 0)
+ dat->pLog->CreateChatRtfEvent(dat, lin);
+ dat->iStartEvent++;
+ break;
+ }
}
- }
- else buf.AppendFormat("%s ", Log_SetStyle(0));
- if (g_Settings->dwIconFlags)
- buf.Append("\\tab ");
+ dat->iStage = STREAMSTAGE_TAIL;
+ __fallthrough;
- // insert timestamp
- if (g_Settings->bShowTime) {
- wchar_t szTimeStamp[100], szOldTimeStamp[100];
+ case STREAMSTAGE_TAIL:
+ dat->pLog->CreateChatRtfTail(dat);
+ dat->iStage = STREAMSTAGE_STOP;
+ break;
- wcsncpy_s(szTimeStamp, MakeTimeStamp(g_Settings->pszTimeStamp, lin.time), _TRUNCATE);
- wcsncpy_s(szOldTimeStamp, MakeTimeStamp(g_Settings->pszTimeStamp, si->LastTime), _TRUNCATE);
- if (!g_Settings->bShowTimeIfChanged || si->LastTime == 0 || mir_wstrcmp(szTimeStamp, szOldTimeStamp)) {
- si->LastTime = lin.time;
- Log_AppendRTF(streamData, true, buf, szTimeStamp);
- }
- buf.Append("\\tab ");
+ case STREAMSTAGE_STOP:
+ *pcb = 0;
+ return 0;
}
+ }
- // Insert the nick
- if (lin.ptszNick && lin.iType == GC_EVENT_MESSAGE) {
- buf.AppendFormat("%s ", Log_SetStyle(lin.bIsMe ? 2 : 1));
+ *pcb = min(cb, dat->buf.GetLength());
+ memcpy(pbBuff, dat->buf.GetBuffer(), *pcb);
+ if (dat->buf.GetLength() == *pcb)
+ dat->buf.Empty();
+ else
+ dat->buf.Delete(0, *pcb);
- CMStringW tmp((lin.bIsMe) ? g_Settings->pszOutgoingNick : g_Settings->pszIncomingNick);
- tmp.Replace(L"%n", lin.ptszNick);
- Log_AppendRTF(streamData, TRUE, buf, tmp);
- buf.AppendChar(' ');
- }
+ return 0;
+}
- // Insert the message
- buf.AppendFormat("%s ", Log_SetStyle(lin.bIsHighlighted ? 16 : EventToIndex(lin)));
- AddEventToBuffer(buf, streamData, lin);
- }
+void CRtfLogWindow::StreamChatRtfEvents(RtfChatLogStreamData *streamData, bool bAppend)
+{
+ streamData->bAppend = bAppend;
- // ### RTF END
- if (streamData->bRedraw)
- buf.Append("\\par}");
- else
- buf.Append("}");
- return buf.Detach();
+ EDITSTREAM stream = {};
+ stream.pfnCallback = ChatLogStreamCallback;
+ stream.dwCookie = (DWORD_PTR)streamData;
+ m_rtf.SendMsg(EM_STREAMIN, bAppend ? SF_RTF : SFF_SELECTION | SF_RTF, (LPARAM)&stream);
}
-char* Log_CreateRtfHeader()
+/////////////////////////////////////////////////////////////////////////////////////////
+// Chat event header
+
+void CRtfLogWindow::CreateChatRtfHeader(RtfChatLogStreamData *streamData)
{
- // guesstimate amount of memory for the RTF header
- CMStringA buf;
+ CMStringA &buf = streamData->buf;
// get the number of pixels per logical inch
HDC hdc = GetDC(nullptr);
@@ -373,8 +335,6 @@ char* Log_CreateRtfHeader() g_chatApi.logPixelSX = GetDeviceCaps(hdc, LOGPIXELSX);
ReleaseDC(nullptr, hdc);
- // ### RTF HEADER
-
// font table
buf.Append("{\\rtf1\\ansi\\deff0{\\fonttbl");
for (int i = 0; i < OPTIONS_FONTCOUNT; i++)
@@ -406,7 +366,94 @@ char* Log_CreateRtfHeader() }
buf.AppendFormat("\\fi-%u\\li%u", iIndent, iIndent);
- return buf.Detach();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Chat event body
+
+void CRtfLogWindow::CreateChatRtfEvent(RtfChatLogStreamData *streamData, const LOGINFO &lin)
+{
+ SESSION_INFO *si = streamData->si;
+ CMStringA &buf = streamData->buf;
+
+ // create new line, and set font and color
+ if (streamData->iStartEvent != 0)
+ buf.Append("\\par ");
+ buf.AppendFormat("%s ", Log_SetStyle(0));
+
+ // Insert icon
+ if ((lin.iType & g_Settings->dwIconFlags) || lin.bIsHighlighted && (g_Settings->dwIconFlags & GC_EVENT_HIGHLIGHT)) {
+ int iIndex = (lin.bIsHighlighted && (g_Settings->dwIconFlags & GC_EVENT_HIGHLIGHT)) ? ICON_HIGHLIGHT : EventToIcon(lin);
+ buf.Append("\\f0\\fs14");
+ buf.Append(pLogIconBmpBits[iIndex]);
+ }
+
+ if (g_Settings->bTimeStampEventColour) {
+ LOGFONT &lf = g_chatApi.aFonts[0].lf;
+
+ // colored timestamps
+ if (lin.ptszNick && lin.iType == GC_EVENT_MESSAGE) {
+ int iii = lin.bIsHighlighted ? 16 : (lin.bIsMe ? 2 : 1);
+ buf.AppendFormat("\\f0\\cf%u\\ul0\\highlight0\\b%d\\i%d\\fs%u", iii + 1, lf.lfWeight >= FW_BOLD ? 1 : 0, lf.lfItalic, 2 * abs(lf.lfHeight) * 74 / g_chatApi.logPixelSY);
+ }
+ else {
+ int iii = lin.bIsHighlighted ? 16 : EventToIndex(lin);
+ buf.AppendFormat("\\f0\\cf%u\\ul0\\highlight0\\b%d\\i%d\\fs%u", iii + 1, lf.lfWeight >= FW_BOLD ? 1 : 0, lf.lfItalic, 2 * abs(lf.lfHeight) * 74 / g_chatApi.logPixelSY);
+ }
+ }
+ else buf.AppendFormat("%s ", Log_SetStyle(0));
+
+ if (g_Settings->dwIconFlags)
+ buf.Append("\\tab ");
+
+ // insert timestamp
+ if (g_Settings->bShowTime) {
+ wchar_t szTimeStamp[100], szOldTimeStamp[100];
+
+ wcsncpy_s(szTimeStamp, MakeTimeStamp(g_Settings->pszTimeStamp, lin.time), _TRUNCATE);
+ wcsncpy_s(szOldTimeStamp, MakeTimeStamp(g_Settings->pszTimeStamp, si->LastTime), _TRUNCATE);
+ if (!g_Settings->bShowTimeIfChanged || si->LastTime == 0 || mir_wstrcmp(szTimeStamp, szOldTimeStamp)) {
+ si->LastTime = lin.time;
+ Log_AppendRTF(streamData, true, buf, szTimeStamp);
+ }
+ buf.Append("\\tab ");
+ }
+
+ // Insert the nick
+ if (lin.ptszNick && lin.iType == GC_EVENT_MESSAGE) {
+ buf.AppendFormat("%s ", Log_SetStyle(lin.bIsMe ? 2 : 1));
+
+ CMStringW tmp((lin.bIsMe) ? g_Settings->pszOutgoingNick : g_Settings->pszIncomingNick);
+ tmp.Replace(L"%n", lin.ptszNick);
+ Log_AppendRTF(streamData, TRUE, buf, tmp);
+ buf.AppendChar(' ');
+ }
+
+ // Insert the message
+ buf.AppendFormat("%s ", Log_SetStyle(lin.bIsHighlighted ? 16 : EventToIndex(lin)));
+
+ CMStringW wszCaption;
+ bool bTextUsed = Chat_GetDefaultEventDescr(streamData->si, &lin, wszCaption);
+ if (!wszCaption.IsEmpty())
+ Log_AppendRTF(streamData, !bTextUsed, buf, wszCaption);
+ if (!bTextUsed && lin.ptszText) {
+ if (!wszCaption.IsEmpty())
+ Log_AppendRTF(streamData, false, buf, L" ");
+ Log_AppendRTF(streamData, false, buf, lin.ptszText);
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Chat event tail
+
+void CRtfLogWindow::CreateChatRtfTail(RtfChatLogStreamData *streamData)
+{
+ CMStringA &str = streamData->buf;
+
+ if (streamData->bAppend)
+ str.Append("\\par}");
+ else
+ str.Append("}");;
}
#define RTFPICTHEADERMAXSIZE 78
diff --git a/src/mir_app/src/chat_manager.cpp b/src/mir_app/src/chat_manager.cpp index 3917e19801..e12f308528 100644 --- a/src/mir_app/src/chat_manager.cpp +++ b/src/mir_app/src/chat_manager.cpp @@ -230,33 +230,39 @@ BOOL SM_AddEvent(SESSION_INFO *si, GCEVENT *gce, bool bIsHighlighted) return TRUE;
}
-BOOL SM_RemoveUser(SESSION_INFO *pSI, const wchar_t *pszUID)
+BOOL SM_RemoveUser(SESSION_INFO *si, const wchar_t *pszUID)
{
- if (!pSI || !pszUID)
+ if (!si || !pszUID)
return FALSE;
- for (auto &si : g_arSessions) {
- if (si != pSI || mir_strcmpi(si->pszModule, pSI->pszModule))
- continue;
-
- USERINFO *ui = UM_FindUser(si, pszUID);
- if (ui) {
- if (g_chatApi.OnRemoveUser)
- g_chatApi.OnRemoveUser(si, ui);
+ USERINFO *ui = UM_FindUser(si, pszUID);
+ if (!ui)
+ return FALSE;
- if (si->pMe == ui)
- si->pMe = nullptr;
- g_chatApi.UM_RemoveUser(si, pszUID);
+ if (g_chatApi.OnRemoveUser)
+ g_chatApi.OnRemoveUser(si, ui);
- if (si->pDlg)
- si->pDlg->UpdateNickList();
+ if (si->pMe == ui)
+ si->pMe = nullptr;
+
+ auto &arKeys = si->getKeyList();
+ if (arKeys.remove(ui) == -1)
+ DebugBreak();
- // !!!!!!!!!! if (pszID)
- return TRUE;
+ auto &arUsers = si->getUserList();
+ for (auto &it : arUsers) {
+ if (!mir_wstrcmpi(it->pszUID, pszUID)) {
+ mir_free(it->pszNick);
+ mir_free(it->pszUID);
+ arUsers.removeItem(&it);
+ break;
}
}
+
+ if (si->pDlg)
+ si->pDlg->UpdateNickList();
- return FALSE;
+ return TRUE;
}
static USERINFO* SM_GetUserFromIndex(const wchar_t *pszID, const char *pszModule, int index)
@@ -440,7 +446,6 @@ GCModuleInfoBase::~GCModuleInfoBase() mir_free(pszModule);
mir_free(ptszModDispName);
- mir_free(pszHeader);
}
MODULEINFO* MM_AddModule(const char *pszModule)
@@ -474,12 +479,6 @@ static void MM_IconsChanged() g_chatApi.OnCreateModule(mi);
}
-static void MM_FontsChanged()
-{
- for (auto &mi : g_arModules)
- mi->pszHeader = g_chatApi.Log_CreateRtfHeader();
-}
-
MODULEINFO* MM_FindModule(const char *pszModule)
{
if (!pszModule)
@@ -754,28 +753,6 @@ static wchar_t* UM_FindUserAutoComplete(SESSION_INFO *si, const wchar_t* pszOrig return pszName;
}
-static BOOL UM_RemoveUser(SESSION_INFO *si, const wchar_t *pszUID)
-{
- auto *pUser = UM_FindUser(si, pszUID);
- if (pUser == nullptr)
- return FALSE;
-
- auto &arKeys = si->getKeyList();
- if (arKeys.remove(pUser) == -1)
- DebugBreak();
-
- auto &arUsers = si->getUserList();
- for (auto &ui : arUsers) {
- if (!mir_wstrcmpi(ui->pszUID, pszUID)) {
- mir_free(ui->pszNick);
- mir_free(ui->pszUID);
- arUsers.removeItem(&ui);
- break;
- }
- }
- return TRUE;
-}
-
BOOL UM_RemoveAll(SESSION_INFO *si)
{
if (!si)
@@ -820,7 +797,6 @@ static void ResetApi() g_chatApi.SM_InvalidateLogDirectories = ::SM_InvalidateLogDirectories;
g_chatApi.MM_CreateModule = ::MM_CreateModule;
- g_chatApi.MM_FontsChanged = ::MM_FontsChanged;
g_chatApi.MM_IconsChanged = ::MM_IconsChanged;
g_chatApi.MM_RemoveAll = ::MM_RemoveAll;
@@ -836,14 +812,11 @@ static void ResetApi() g_chatApi.UM_SetContactStatus = ::UM_SetContactStatus;
g_chatApi.UM_TakeStatus = ::UM_TakeStatus;
g_chatApi.UM_FindUserAutoComplete = ::UM_FindUserAutoComplete;
- g_chatApi.UM_RemoveUser = ::UM_RemoveUser;
g_chatApi.SetOffline = ::SetOffline;
g_chatApi.SetAllOffline = ::SetAllOffline;
g_chatApi.DoRtfToTags = ::DoRtfToTags;
- g_chatApi.Log_CreateRTF = ::Log_CreateRTF;
- g_chatApi.Log_CreateRtfHeader = ::Log_CreateRtfHeader;
g_chatApi.LoadMsgDlgFont = ::LoadMsgDlgFont;
g_chatApi.MakeTimeStamp = ::MakeTimeStamp;
diff --git a/src/mir_app/src/chat_svc.cpp b/src/mir_app/src/chat_svc.cpp index cc573729c6..a6f665ba5e 100644 --- a/src/mir_app/src/chat_svc.cpp +++ b/src/mir_app/src/chat_svc.cpp @@ -103,7 +103,6 @@ static int FontsChanged(WPARAM, LPARAM) SetIndentSize();
g_Settings->bLogIndentEnabled = Chat::bLogIndentEnabled;
- g_chatApi.MM_FontsChanged();
Chat_UpdateOptions();
return 0;
}
@@ -189,7 +188,6 @@ MIR_APP_DLL(int) Chat_Register(const GCREGISTER *gcr) mi->bDatabase = (gcr->dwFlags & GC_DATABASE) != 0;
mi->bPersistent = (gcr->dwFlags & GC_PERSISTENT) != 0;
mi->iMaxText = gcr->iMaxText;
- mi->pszHeader = g_chatApi.Log_CreateRtfHeader();
g_chatApi.SetAllOffline(TRUE, gcr->pszModule);
return 0;
@@ -550,7 +548,7 @@ static BOOL HandleChatEvent(GCEVENT &gce, int bManyFix) if (isOk)
si->pDlg->AddLog();
else
- RedrawLog2(si);
+ si->pDlg->RedrawLog();
}
if (!(gce.dwFlags & GCEF_NOTNOTIFY))
diff --git a/src/mir_app/src/mir_app.def b/src/mir_app/src/mir_app.def index f2f4b08172..52cba2c880 100644 --- a/src/mir_app/src/mir_app.def +++ b/src/mir_app/src/mir_app.def @@ -314,7 +314,6 @@ Srmm_FindDialog @406 NONAME ??2CSrmmBaseDialog@@SAPAXI@Z @409 NONAME
??3CSrmmBaseDialog@@SAXPAX@Z @410 NONAME
?isChat@CSrmmBaseDialog@@QBE_NXZ @411 NONAME
-Srmm_LogStreamCallback @412
?RunUserMenu@CSrmmBaseDialog@@IAEXPAUHWND__@@PAUUSERINFO@@ABUtagPOINT@@@Z @414 NONAME
?ClearLog@CSrmmBaseDialog@@QAEXXZ @415 NONAME
?CloseTab@CSrmmBaseDialog@@UAEXXZ @416 NONAME
@@ -855,3 +854,7 @@ Chat_IsMuted @941 NONAME ?isSrmm@EventInfo@DB@@QBE_NXZ @971 NONAME
?CreateRtfTail@CRtfLogWindow@@UAEXPAURtfLogStreamData@@@Z @972 NONAME
?StreamRtfEvents@CRtfLogWindow@@QAEXPAURtfLogStreamData@@_N@Z @973 NONAME
+?CreateChatRtfEvent@CRtfLogWindow@@UAEXPAURtfChatLogStreamData@@ABULOGINFO@@@Z @974 NONAME
+?CreateChatRtfHeader@CRtfLogWindow@@UAEXPAURtfChatLogStreamData@@@Z @975 NONAME
+?CreateChatRtfTail@CRtfLogWindow@@UAEXPAURtfChatLogStreamData@@@Z @976 NONAME
+?StreamChatRtfEvents@CRtfLogWindow@@QAEXPAURtfChatLogStreamData@@_N@Z @977 NONAME
diff --git a/src/mir_app/src/mir_app64.def b/src/mir_app/src/mir_app64.def index 5151b526c4..803d785347 100644 --- a/src/mir_app/src/mir_app64.def +++ b/src/mir_app/src/mir_app64.def @@ -314,7 +314,6 @@ Srmm_FindDialog @406 NONAME ??2CSrmmBaseDialog@@SAPEAX_K@Z @409 NONAME
??3CSrmmBaseDialog@@SAXPEAX@Z @410 NONAME
?isChat@CSrmmBaseDialog@@QEBA_NXZ @411 NONAME
-Srmm_LogStreamCallback @412
?RunUserMenu@CSrmmBaseDialog@@IEAAXPEAUHWND__@@PEAUUSERINFO@@AEBUtagPOINT@@@Z @414 NONAME
?ClearLog@CSrmmBaseDialog@@QEAAXXZ @415 NONAME
?CloseTab@CSrmmBaseDialog@@UEAAXXZ @416 NONAME
@@ -855,3 +854,7 @@ Chat_IsMuted @941 NONAME ?isSrmm@EventInfo@DB@@QEBA_NXZ @971 NONAME
?CreateRtfTail@CRtfLogWindow@@UEAAXPEAURtfLogStreamData@@@Z @972 NONAME
?StreamRtfEvents@CRtfLogWindow@@QEAAXPEAURtfLogStreamData@@_N@Z @973 NONAME
+?CreateChatRtfEvent@CRtfLogWindow@@UEAAXPEAURtfChatLogStreamData@@AEBULOGINFO@@@Z @974 NONAME
+?CreateChatRtfHeader@CRtfLogWindow@@UEAAXPEAURtfChatLogStreamData@@@Z @975 NONAME
+?CreateChatRtfTail@CRtfLogWindow@@UEAAXPEAURtfChatLogStreamData@@@Z @976 NONAME
+?StreamChatRtfEvents@CRtfLogWindow@@QEAAXPEAURtfChatLogStreamData@@_N@Z @977 NONAME
diff --git a/src/mir_app/src/srmm_base.cpp b/src/mir_app/src/srmm_base.cpp index 99ded72210..94a7a6d21e 100644 --- a/src/mir_app/src/srmm_base.cpp +++ b/src/mir_app/src/srmm_base.cpp @@ -610,49 +610,19 @@ void CSrmmBaseDialog::UpdateOptions() EnableWindow(m_btnChannelMgr.GetHwnd(), mi->bChanMgr);
Resize();
- RedrawLog2(m_si);
+ RedrawLog();
}
/////////////////////////////////////////////////////////////////////////////////////////
-void RedrawLog2(SESSION_INFO *si)
-{
- si->LastTime = 0;
-
- int iEventCount = si->arEvents.getCount();
- if (iEventCount)
- si->pDlg->log()->LogEvents(si, 0, TRUE);
-}
-
-static void __cdecl phase2(SESSION_INFO *si)
-{
- Sleep(30);
- if (si && si->pDlg)
- RedrawLog2(si);
-}
-
void CSrmmBaseDialog::RedrawLog()
{
m_si->LastTime = 0;
- int iEventCount = m_si->arEvents.getCount();
- if (iEventCount) {
- if (iEventCount > 60) {
- int index = 0;
- while (index < 59) {
- if (iEventCount == 0)
- break;
-
- iEventCount--;
- if (m_si->iType != GCW_CHATROOM || (m_iLogFilterFlags & m_si->arEvents[iEventCount].iType) != 0)
- index++;
- }
- m_pLog->LogEvents(m_si, iEventCount, true);
- mir_forkThread<SESSION_INFO>(phase2, m_si);
- }
- else m_pLog->LogEvents(m_si, 0, true);
- }
- else ClearLog();
+ if (m_si->arEvents.getCount())
+ m_pLog->LogEvents(m_si, 0, true);
+ else
+ ClearLog();
}
void CSrmmBaseDialog::UpdateChatLog()
diff --git a/src/mir_app/src/srmm_log_rtf.cpp b/src/mir_app/src/srmm_log_rtf.cpp index 80cbe4662d..75290337af 100644 --- a/src/mir_app/src/srmm_log_rtf.cpp +++ b/src/mir_app/src/srmm_log_rtf.cpp @@ -27,11 +27,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "stdafx.h"
#include "chat.h"
-#define STREAMSTAGE_HEADER 0
-#define STREAMSTAGE_EVENTS 1
-#define STREAMSTAGE_TAIL 2
-#define STREAMSTAGE_STOP 3
-
#define EVENTTYPE_STATUSCHANGE 25368
#define EVENTTYPE_ERRMSG 25366
@@ -303,10 +298,10 @@ static DWORD CALLBACK LogStreamInEvents(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG auto *dat = (RtfLogStreamData *)dwCookie;
if (dat->buf.IsEmpty()) {
- switch (dat->stage) {
+ switch (dat->iStage) {
case STREAMSTAGE_HEADER:
dat->pLog->CreateRtfHeader(dat);
- dat->stage = STREAMSTAGE_EVENTS;
+ dat->iStage = STREAMSTAGE_EVENTS;
break;
case STREAMSTAGE_EVENTS:
@@ -333,12 +328,12 @@ static DWORD CALLBACK LogStreamInEvents(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG break;
}
}
- dat->stage = STREAMSTAGE_TAIL;
+ dat->iStage = STREAMSTAGE_TAIL;
__fallthrough;
case STREAMSTAGE_TAIL:
dat->pLog->CreateRtfTail(dat);
- dat->stage = STREAMSTAGE_STOP;
+ dat->iStage = STREAMSTAGE_STOP;
break;
case STREAMSTAGE_STOP:
diff --git a/src/mir_app/src/srmm_util.cpp b/src/mir_app/src/srmm_util.cpp index 51d4647e62..b4480fafc0 100644 --- a/src/mir_app/src/srmm_util.cpp +++ b/src/mir_app/src/srmm_util.cpp @@ -28,34 +28,6 @@ const char *g_pszHotkeySection; /////////////////////////////////////////////////////////////////////////////////////////
-MIR_APP_DLL(DWORD) CALLBACK Srmm_LogStreamCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
-{
- LOGSTREAMDATA *lstrdat = (LOGSTREAMDATA*)dwCookie;
- if (lstrdat) {
- // create the RTF
- if (lstrdat->buffer == nullptr) {
- lstrdat->bufferOffset = 0;
- lstrdat->buffer = g_chatApi.Log_CreateRTF(lstrdat);
- lstrdat->bufferLen = (int)mir_strlen(lstrdat->buffer);
- }
-
- // give the RTF to the RE control
- *pcb = min(cb, LONG(lstrdat->bufferLen - lstrdat->bufferOffset));
- memcpy(pbBuff, lstrdat->buffer + lstrdat->bufferOffset, *pcb);
- lstrdat->bufferOffset += *pcb;
-
- // free stuff if the streaming operation is complete
- if (lstrdat->bufferOffset == lstrdat->bufferLen) {
- mir_free(lstrdat->buffer);
- lstrdat->buffer = nullptr;
- }
- }
-
- return 0;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
MIR_APP_DLL(int) Srmm_GetWindowData(MCONTACT hContact, MessageWindowData &mwd)
{
if (hContact == 0)
|