forked from voodoo-chile/Cambrian-src
/
WChatInput.cpp
200 lines (185 loc) · 7.27 KB
/
WChatInput.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
///////////////////////////////////////////////////////////////////////////////////////////////////
// WChatInput.cpp
//
// Display a widget for the user to type text for a Chat Log.
// Depending on what the user typed, the text may be interpreted as a text message to the user or group, or a command line.
///////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef PRECOMPILEDHEADERS_H
#include "PreCompiledHeaders.h"
#endif
#define d_ttiChatState 1000 // Create a 1-second timer tick interval (tti)
#define d_ttcChatStateEventPaused 10 // Consider the user paused after 10 timer ticks (10 seconds)
WChatInput::WChatInput(WLayoutChatLog * pwLayoutChatLog) : WEditTextArea(pwLayoutChatLog)
{
Assert(pwLayoutChatLog != NULL); // In the future, this may be NULL
m_pwLayoutChatLog = pwLayoutChatLog;
ChatInput_UpdateWatermarkText();
m_tidChatStateComposing = d_zNA;
m_pEventEdit = NULL;
/*
setMinimumSize(10, 10);
resize(100, 10);
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
*/
setAcceptDrops(false); // Prevent the input widget to accept drag & drops because its parent, the WLayoutChatLog, already handles drag & drops for both the input widget and the message history.
}
void
WChatInput::ChatInput_UpdateWatermarkText()
{
m_strWatermark.Format((m_pwLayoutChatLog->m_pContactParent_YZ != NULL) ? "Send a message to $s" : "Send a message to group $s", m_pwLayoutChatLog->m_pContactOrGroup_NZ->ChatLog_PszGetNickname());
}
// Edit an existing event
void
WChatInput::EditEventText(CEventMessageTextSent * pEventEdit)
{
m_pEventEdit = pEventEdit;
if (m_pEventEdit != NULL)
{
Assert(pEventEdit->EGetEventClass() == eEventClass_eMessageTextSent);
m_pEventEdit = pEventEdit->PFindEventMostRecent_NZ();
Assert(m_pEventEdit->EGetEventClass() == eEventClass_eMessageTextSent);
setPlainText(m_pEventEdit->m_strMessageText); // Use text from the most recent message
moveCursor(QTextCursor::End);
setFocus();
}
}
void
WChatInput::ChatStateComposingCancelTimer(BOOL fWriteXmlChatStatePaused)
{
if (m_tidChatStateComposing != d_zNA)
{
killTimer(m_tidChatStateComposing);
m_tidChatStateComposing = d_zNA;
}
m_ttcBeforeChatStatePaused = 0;
if (fWriteXmlChatStatePaused)
m_pwLayoutChatLog->Socket_WriteXmlChatState(eChatState_Paused); // Notify the remote contact the user stopped typing
}
// WChatInput::QWidget::minimumSizeHint()
QSize
WChatInput::minimumSizeHint() const
{
return QSize(0, 32); // fontMetrics().height() * 10);
}
// WChatInput::QWidget::sizeHint()
QSize
WChatInput::sizeHint() const
{
return minimumSizeHint();
}
#define d_kmKeyboardSpecialKeys 0xFF000000 // Mask of the special keys (escape, arrows, F1..F12) from the enum Qt::Key
// WChatInput::QObject::event()
bool
WChatInput::event(QEvent * pEvent)
{
QEvent::Type eEventType = pEvent->type();
//MessageLog_AppendTextFormatSev(eSeverityNoise, "WChatInput::event(type=$i)\n", eEventType);
if (eEventType == QEvent::KeyPress)
{
QKeyEvent * pEventKey = static_cast<QKeyEvent *>(pEvent);
const Qt::Key eKey = (Qt::Key)pEventKey->key();
//MessageLog_AppendTextFormatSev(eSeverityNoise, "WChatInput::event(QEvent::KeyPress, key=0x$p, modifiers=$x)\n", eKey, pEventKey->modifiers());
if ((eKey & d_kmKeyboardSpecialKeys) == 0)
{
// The user typed something other than a special key
m_ttcBeforeChatStatePaused = d_ttcChatStateEventPaused;
if (m_tidChatStateComposing == d_zNA)
{
m_tidChatStateComposing = startTimer(d_ttiChatState); // Create a timer to determine when the user 'stopped' typing
m_pwLayoutChatLog->Socket_WriteXmlChatState(eChatState_zComposing);
}
}
if ((pEventKey->modifiers() & ~Qt::KeypadModifier) == Qt::NoModifier)
{
ITreeItemChatLogEvents * pContactOrGroup = m_pwLayoutChatLog->PGetContactOrGroup_NZ();
pContactOrGroup->TreeItem_IconUpdateOnMessagesRead(); // Any key pressed in the message input assumes the user read the message history
//m_pwLayoutChatLog->TreeItem_UpdateIconMessageRead(); // Any key pressed in the message input assumes the user read the message history
if (eKey == Qt::Key_Enter || eKey == Qt::Key_Return)
{
EUserCommand eUserCommand = eUserCommand_ComposingStopped; // Pretend the text message was sent
CStr strText = *this;
if (!strText.FIsEmptyString())
{
m_strTextLastWritten = strText;
if (m_pEventEdit == NULL)
eUserCommand = pContactOrGroup->Xmpp_EParseUserCommandAndSendEvents(IN_MOD_INV strText); // This is the typical case of a new message
else
{
// The user was editing an existing message
m_pEventEdit->EventUpdateMessageText(strText, INOUT m_pwLayoutChatLog);
m_pEventEdit = NULL;
}
ChatStateComposingCancelTimer((BOOL)eUserCommand); // After sending a message, cancel (reset) the timer to, so a new 'composing' notification will be sent when the user starts typing again. BTW, there is no need to send a 'pause' command since receiving a text message automatically implies a pause.
} // if
if (eUserCommand != eUserCommand_Error)
{
clear(); // Clear the chat text
setCurrentCharFormat(QTextCharFormat());
}
return true;
} // if (enter)
if (eKey == Qt::Key_Up)
{
// Set the previous text if there is notning in the edit box
CStr strText = *this;
if (strText.FIsEmptyString())
{
//EditEventText(pContactOrGroup->Vault_PGetEventLastMessageSentEditable_YZ());
m_pEventEdit = pContactOrGroup->Vault_PFindEventLastMessageTextSentMatchingText(IN m_strTextLastWritten);
if (m_pEventEdit != NULL)
{
MessageLog_AppendTextFormatSev(eSeverityNoise, "Editing Event ID $t\n", m_pEventEdit->m_tsEventID);
}
setPlainText(m_strTextLastWritten);
moveCursor(QTextCursor::End);
return true;
}
}
if (eKey == Qt::Key_Escape)
{
m_pEventEdit = NULL;
clear(); // Clear the chat text
return TRUE;
}
} // if
}
else if (eEventType == QEvent::FocusIn)
{
//m_pwLayoutChatLog->OnEventFocusIn();
m_pwLayoutChatLog->PGetContactOrGroup_NZ()->TreeItem_IconUpdateOnMessagesRead();
}
return WEditTextArea::event(pEvent);
} // event()
// WChatInput::QObject::timerEvent()
void
WChatInput::timerEvent(QTimerEvent * pTimerEvent)
{
// MessageLog_AppendTextFormatSev(eSeverityNoise, "WChatInput::timerEvent(id=$i)\n", e->timerId());
if (pTimerEvent->timerId() == m_tidChatStateComposing)
{
Assert(m_tidChatStateComposing != d_zNA);
if (--m_ttcBeforeChatStatePaused <= 0)
ChatStateComposingCancelTimer(TRUE); // If the user is idle for too long, then notify the remote contact he/she stopped typing
}
WEditTextArea::timerEvent(pTimerEvent);
} // timerEvent()
bool
WChatInput::canInsertFromMimeData(const QMimeData * poMimeDataSource) const
{
//return poMimeDataSource->hasImage() || WEditTextArea::canInsertFromMimeData(poMimeDataSource);
return WEditTextArea::canInsertFromMimeData(poMimeDataSource);
}
void
WChatInput::insertFromMimeData(const QMimeData * poMimeDataSource)
{
if (poMimeDataSource->hasImage())
{
textCursor().insertImage(qvariant_cast<QImage>(poMimeDataSource->imageData()));
}
if (poMimeDataSource->hasText())
{
CStr strText = poMimeDataSource->text();
MessageLog_AppendTextFormatCo(d_coBlack, "Paste: '{Sf}'\n", &strText);
}
return WEditTextArea::insertFromMimeData(poMimeDataSource);
}