예제 #1
0
//	Append the 'chat state' to the cursor
void
WChatLog::ChatLog_ChatStateTextAppend(INOUT OCursor & oTextCursor)
	{
	TContact ** ppContactStop;
	TContact ** ppContact = m_arraypContactsComposing.PrgpGetContactsStop(OUT &ppContactStop);
	if (ppContact == ppContactStop)
		{
		oTextCursor.removeSelectedText();
		}
	else
		{
		if (g_poImageComposing == NULL)
			g_poImageComposing = new QImage(":/ico/Pencil");
		while (TRUE)
			{
			oTextCursor.insertImage(*g_poImageComposing);
			TContact * pContact = *ppContact++;
			Assert(pContact != NULL);
			Assert(pContact->EGetRuntimeClass() == RTI(TContact));
			g_strScratchBufferStatusBar.Format(d_szu_nbsp " <b>^s</b> is typing...", pContact->ChatLog_PszGetNickname());
			oTextCursor.insertHtml(g_strScratchBufferStatusBar);
			if (ppContact == ppContactStop)
				break;
			} // while
		}
	if (m_pContactOrGroup->EGetRuntimeClass() == RTI(TContact))
		((TContact *)m_pContactOrGroup)->ChatLogContact_AppendExtraTextToChatState(INOUT oTextCursor);
	Widget_ScrollToEnd(INOUT this);
	} // ChatLog_ChatStateTextAppend()
예제 #2
0
void
WLayoutChatLog::ChatLog_ScrollToDisplayLastMessage()
	{
	#ifdef COMPILE_WITH_CHATLOG_HTML
	m_pwChatLog_NZ->_ScrollToDisplayLastEvent();
	#else
	Widget_ScrollToEnd(m_pwChatLog_NZ);
	#endif
	}
예제 #3
0
void
CMessageLog::AppendTextU(QRGBX coxTextColor, PSZUC pszuTextAppend, PSZAC pszTextExtra)
	{
	if (g_fMessageLogsPaused)
		return;
#ifdef CONFIG_MESSAGE_LOG_WIN32
	if (g_hwndMainWindow == NULL)
		{
		// The main window has not been created yet, so this message is very early (typically an assertion failure within a constructor or something of that sort)
		//Assert(g_pwMainWindow == NULL);	// This pointer should also be NULL
		//Assert(m_hwndMessageLog == NULL);
		::OutputDebugStringA((PSZAC)pszuTextAppend);
		::OutputDebugStringA((PSZAC)pszTextExtra);
		return;
		}
	if (m_hwndMessageLog == NULL)
		CreateLogWindow();
	if (!IsWindow(m_hwndRichEdit))
		{
		::OutputDebugStringA("MessageLog: Rich Edit is unavailable\n");
		if (this != &g_oErrorLog)
			ErrorLog_AddNewMessage("MessageLog: Rich Edit is unavailable\n", pszuTextAppend);
		/*
		if (g_pwMainWindow != NULL)
			g_pwMainWindow->setWindowTitle(QString::fromUtf8((const char *)pszuTextAppend));	// Try to display something to the user using the caption as the "Message Log"
		*/
		return;
		}
	RichEdit_SelectionMoveToEnd(m_hwndRichEdit);
	int ichSel = 0;	// Index of the last selected character.
	::SendMessage(m_hwndRichEdit, EM_GETSEL, OUT (WPARAM)&ichSel, OUT (LPARAM)&ichSel);	// The start and end of the selection should be  the same, since we just called RichEdit_SelectionMoveToEnd().
	if (ichSel >= d_cchLogMax)
		{
		// The log is full, so flush some of the data
		::SendMessage(m_hwndRichEdit, EM_SETSEL, 0, d_cchLogMax / 4);	// Remove one fourth of the log
		::SendMessage(m_hwndRichEdit, EM_REPLACESEL, FALSE /* fCanUndo */, (LPARAM)L"[...]");
		RichEdit_SelectionMoveToEnd(m_hwndRichEdit);
		}

	// Set the character format to the insertion point
	CHARFORMAT cf;
	InitToGarbage(OUT &cf, sizeof(cf));
	cf.cbSize = sizeof(cf);
	cf.dwMask = CFM_COLOR | CFM_BOLD;
	cf.crTextColor = COX_GetRGB(coxTextColor);
	cf.dwEffects = COX_IsBold(coxTextColor) ? CFE_BOLD : 0;
	Verify( ::SendMessage(m_hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, IN (LPARAM)&cf) );  // If the EM_SETCHARFORMAT fails, it may be because the method EditW_EnableColoring() was not called.

	SETTEXTEX st = { ST_SELECTION, CP_UTF8 };
	::SendMessage(m_hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)pszuTextAppend);
	if (pszTextExtra != NULL)
		::SendMessage(m_hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)pszTextExtra);
	::SendMessage(m_hwndRichEdit, WM_VSCROLL, SB_BOTTOM, d_zNA);	// Ensure the inserted text is visible by scrolling to the bottom
	::UpdateWindow(m_hwndRichEdit);	// Force the window to redraw immediately
#else
	Report(m_pwChatDebugger != NULL && "The widget should have been created!");
	if (m_pwChatDebugger == NULL)
		CreateLogWindow();
	Assert(m_pwChatDebugger != NULL);
	Assert(m_pwTextBrowser != NULL);
	if (m_pwTextBrowser != NULL)
		{
		QTextCursor oTextCursor = m_pwTextBrowser->textCursor();
		oTextCursor.movePosition(QTextCursor::End);
		m_pwTextBrowser->setTextCursor(oTextCursor);

		m_pwTextBrowser->setFontWeight(COX_IsBold(coxTextColor) ? QFont::Bold : QFont::Normal);
		m_pwTextBrowser->setTextColor(COX_GetQRGB(coxTextColor));
		m_pwTextBrowser->insertPlainText(QString::fromUtf8((char *)pszuTextAppend));
		if (pszTextExtra != NULL)
			m_pwTextBrowser->insertPlainText(QString::fromUtf8((char *)pszTextExtra));
		Widget_ScrollToEnd(m_pwTextBrowser);
		}
#endif
	} // AppendTextU()
예제 #4
0
void
WChatLog::ChatLog_EventsDisplay(const CArrayPtrEvents & arraypEvents, int iEventStart)
	{
	Assert(iEventStart >= 0);
	Assert(m_oTextBlockComposing.isValid());
//	CSocketXmpp * pSocket = m_pContactOrGroup->Xmpp_PGetSocketOnlyIfReady();

	OCursorSelectBlock oCursor(m_oTextBlockComposing);
	QTextBlock oTextBlockEvent;	// Text block for each event to insert
	IEvent ** ppEventStop;
	IEvent ** ppEventFirst = arraypEvents.PrgpGetEventsStop(OUT &ppEventStop) + iEventStart;
	IEvent ** ppEvent = ppEventFirst;
	if (!m_fDisplayAllMessages)
		{
		// For performance, limit the display to the last 100 events
		if (ppEventStop != NULL)
			{
			IEvent ** ppEventStart = ppEventStop - 100;
			if (ppEventStart > ppEvent)
				{
				ppEvent = ppEventStart;

				QTextBlockFormat oFormat;
				oFormat.setAlignment(Qt::AlignHCenter);
				oFormat.setBackground(c_brushSilver);	// Use a silver color
				oCursor.setBlockFormat(oFormat);
				g_strScratchBufferStatusBar.Format("<a href='" d_SzMakeCambrianAction(d_szCambrianAction_DisplayAllHistory) "'>Display complete history ($I messages)</a>", arraypEvents.GetSize());
				oCursor.insertHtml(g_strScratchBufferStatusBar);
				oCursor.AppendBlockBlank();
				}
			}
		}

	while (ppEvent < ppEventStop)
		{
		IEvent * pEvent = *ppEvent++;
		AssertValidEvent(pEvent);
		if (pEvent->m_tsEventID >= m_tsMidnightNext)
			{
			QDateTime dtl = QDateTime::fromMSecsSinceEpoch(pEvent->m_tsEventID).toLocalTime();
			QDate date = dtl.date();	// Strip the time of the day
			m_tsMidnightNext = QDateTime(date).toMSecsSinceEpoch() + d_ts_cDays;	// I am sure there is a more elegant way to strip the time from a date, however at the moment I don't have time to investigate a better solution (and this code works)

			QTextBlockFormat oFormatBlock;
			oFormatBlock.setAlignment(Qt::AlignHCenter);
			oFormatBlock.setBackground(c_brushSilver);
			oCursor.setBlockFormat(oFormatBlock);
			QTextCharFormat oFormatChar; // = oCursor.charFormat();
			oFormatChar.setFontWeight(QFont::Bold);
			//oFormatChar.setFontItalic(true);
			//oCursor.setCharFormat(oFormatChar);
			oCursor.insertText(date.toString("dddd MMMM d, yyyy"), oFormatChar);
			oCursor.AppendBlockBlank();
			}
		oTextBlockEvent = oCursor.block();	// Get the current block under the cursor
		Endorse(oTextBlockEvent.userData() == NULL);

		if (pEvent->m_uFlagsEvent & IEvent::FE_kfReplacing)
			{
			MessageLog_AppendTextFormatSev(eSeverityComment, "Attempting to replace Event ID $t\n", pEvent->m_tsEventID);
			QTextBlock oTextBlockUpdate;
			QTextBlock oTextBlockTemp = document()->lastBlock();
			IEvent * pEventOld = pEvent;
			const EEventClass eEventClassUpdater = pEvent->Event_FIsEventTypeSent() ? CEventUpdaterSent::c_eEventClass : CEventUpdaterReceived::c_eEventClass;	// Which updater to search for
			// The event is replacing an older event.  This code is a bit complex because the Chat Log may not display all events and therefore we need to find the most recent block displaying the most recent event.
			IEvent ** ppEventStop;
			IEvent ** ppEventFirst = pEvent->m_pVaultParent_NZ->m_arraypaEvents.PrgpGetEventsStop(OUT &ppEventStop);
			IEvent ** ppEventCompare = ppEventStop;	// Search the array from the end, as the event to search is likely to be a recent one
			while (ppEventFirst < ppEventCompare)
				{
				// Find the updater which should be right before the replacing event
				IEvent * pEventTemp = *--ppEventCompare;
				TryAgain:
				if (pEventTemp == pEventOld && ppEventFirst < ppEventCompare)
					{
					CEventUpdaterSent * pEventUpdater = (CEventUpdaterSent *)*--ppEventCompare;	// Get the updater which is just before the event
					if (pEventUpdater->EGetEventClass() != eEventClassUpdater)
						{
						MessageLog_AppendTextFormatSev(eSeverityErrorWarning, "\t Missing Updater for Event ID $t ({tL}); instead found class '$U' with Event ID $t.\n", pEventTemp->m_tsEventID, pEventTemp->m_tsEventID, pEventUpdater->EGetEventClass(), pEventUpdater->m_tsEventID);
						pEvent->m_uFlagsEvent &= ~IEvent::FE_kfReplacing;	// Remove the bit to avoid displaying the error again and again
						pEvent->m_pVaultParent_NZ->SetModified();			// Save the change
						continue;
						}
					const TIMESTAMP tsEventIdOld = pEventUpdater->m_tsEventIdOld;
					MessageLog_AppendTextFormatSev(eSeverityNoise, "\t [$i] Found updater: $t  ->  $t\n", ppEventCompare - ppEventFirst, pEventUpdater->m_tsEventIdNew, tsEventIdOld);
					// Now, search for the block containing the replacement event
					while (oTextBlockTemp.isValid())
						{
						OTextBlockUserDataEvent * pUserData = (OTextBlockUserDataEvent *)oTextBlockTemp.userData();
						if (pUserData != NULL)
							{
							TIMESTAMP_DELTA dtsEvent = (pUserData->m_pEvent->m_tsEventID - tsEventIdOld);
							MessageLog_AppendTextFormatCo(d_coPurple, "Comparing block Event ID $t with $t: dtsEvent = $T\n", pUserData->m_pEvent->m_tsEventID, tsEventIdOld, dtsEvent);
							if (dtsEvent <= 0)
								{
								if (dtsEvent == 0)
									{
									MessageLog_AppendTextFormatSev(eSeverityNoise, "\t Found matching textblock for replacement: Event ID $t  ->  $t\n", pEventOld->m_tsEventID, tsEventIdOld);
									oTextBlockUpdate = oTextBlockTemp;
									}
								break;
								}
							}
						oTextBlockTemp = oTextBlockTemp.previous();
						} // while
					// Keep searching in case there are chained updated events
					while (ppEventFirst < ppEventCompare)
						{
						pEventTemp = *--ppEventCompare;
						if (pEventTemp->m_tsEventID == tsEventIdOld)
							{
							MessageLog_AppendTextFormatSev(eSeverityNoise, "\t [$i] Found chained replacement: Event ID $t  -> $t\n", ppEventCompare - ppEventFirst, pEvent->m_tsEventID, tsEventIdOld);
							pEventTemp->m_uFlagsEvent |= IEvent::FE_kfReplaced;
							pEventOld = pEventTemp;
							goto TryAgain;
							}
						} // while
					} // if
				} // while
			if (oTextBlockUpdate.isValid())
				{
				MessageLog_AppendTextFormatSev(eSeverityNoise, "\t Event ID $t is updating its old Event ID $t\n", pEvent->m_tsEventID, pEventOld->m_tsEventID);
				OCursorSelectBlock oCursorEventOld(oTextBlockUpdate);
				pEvent->ChatLogUpdateTextBlock(INOUT &oCursorEventOld);
				continue;
				}
			MessageLog_AppendTextFormatSev(eSeverityErrorWarning, "Event ID $t is replacing another event which cannot be found\n", pEvent->m_tsEventID);
			} // if (replacing)
		oTextBlockEvent.setUserData(PA_CHILD new OTextBlockUserDataEvent(pEvent));		// Assign an event for each text block
		pEvent->ChatLogUpdateTextBlock(INOUT &oCursor);
		if ((pEvent->m_uFlagsEvent & IEvent::FE_kfEventHidden) == 0)
			oCursor.AppendBlockBlank();	// If the event is visible, then add a new text block (otherwise it will reuse the same old block)
		else
			oTextBlockEvent.setUserData(NULL);	// Since we are reusing the same block, delete its userdata so we may assing another OTextBlockUserDataEvent
		} // while
	m_oTextBlockComposing = oCursor.block();
	ChatLog_ChatStateTextAppend(INOUT oCursor);
	Widget_ScrollToEnd(INOUT this);
	} // ChatLog_EventsDisplay()