21 #include "kopetecontact.h"
22 #include "kopetechatsession.h"
23 #include "kopeteonlinestatus.h"
24 #include "kopeteprotocol.h"
25 #include "kopeteglobal.h"
26 #include "kopeteappearancesettings.h"
30 #include <kactioncollection.h>
31 #include <kcolordialog.h>
33 #include <kcompletion.h>
35 #include <kfontaction.h>
36 #include <kfontdialog.h>
37 #include <kfontsizeaction.h>
38 #include <kglobalsettings.h>
39 #include <kcolorscheme.h>
41 #include <kparts/genericfactory.h>
42 #include <kstandardaction.h>
43 #include <ktoggleaction.h>
44 #include <kxmlguifactory.h>
48 #include <QtCore/QTimer>
49 #include <QtCore/QRegExp>
50 #include <QtCore/QEvent>
52 #include <QtGui/QTextCursor>
53 #include <QtGui/QTextCharFormat>
60 : KParts::ReadOnlyPart( parent ), m_session(session)
62 init(session, parent);
66 : KParts::ReadOnlyPart( parent ), m_session()
68 init(m_session, parent);
71 void ChatTextEditPart::init( Kopete::ChatSession *session,
QWidget *parent)
74 setComponentData( ChatTextEditPartFactory::componentData() );
76 editor =
new KopeteRichTextWidget(parent, m_session->protocol()->capabilities(), actionCollection());
80 setXMLFile(
"kopeterichtexteditpart/kopeterichtexteditpartfull.rc" );
84 mComplete =
new KCompletion();
85 mComplete->setIgnoreCase(
true );
86 mComplete->setOrder( KCompletion::Weighted );
89 textEdit()->setMinimumSize( QSize( 75, 20 ) );
92 connect(
textEdit(), SIGNAL(textChanged()),
this, SLOT(slotTextChanged()) );
95 m_typingRepeatTimer =
new QTimer(
this);
96 m_typingRepeatTimer->setObjectName(
"m_typingRepeatTimer");
97 m_typingStopTimer =
new QTimer(
this);
98 m_typingStopTimer->setObjectName(
"m_typingStopTimer");
100 connect( m_typingRepeatTimer, SIGNAL(timeout()),
this, SLOT(slotRepeatTypingTimer()) );
101 connect( m_typingStopTimer, SIGNAL(timeout()),
this, SLOT(slotStoppedTypingTimer()) );
103 connect( session, SIGNAL(contactAdded(
const Kopete::Contact*,
bool)),
104 this, SLOT(slotContactAdded(
const Kopete::Contact*)) );
105 connect( session, SIGNAL(contactRemoved(
const Kopete::Contact*,QString,Qt::TextFormat,
bool)),
106 this, SLOT(slotContactRemoved(
const Kopete::Contact*)) );
107 connect( session, SIGNAL(onlineStatusChanged(Kopete::Contact*,Kopete::OnlineStatus,Kopete::OnlineStatus)),
108 this, SLOT(slotContactStatusChanged(Kopete::Contact*,Kopete::OnlineStatus,Kopete::OnlineStatus)) );
110 connect( Kopete::AppearanceSettings::self(), SIGNAL(appearanceChanged()),
111 this, SLOT(slotAppearanceChanged()) );
113 connect( KGlobalSettings::self(), SIGNAL(kdisplayFontChanged()),
114 this, SLOT(slotAppearanceChanged()) );
116 connect( editor, SIGNAL(richTextSupportChanged()),
this, SLOT (slotRichTextSupportChanged()) );
118 slotAppearanceChanged();
120 slotContactAdded( session->myself() );
122 foreach( Kopete::Contact *contact, session->members() )
123 slotContactAdded( contact );
133 QTextCursor textCursor =
textEdit()->textCursor();
134 QTextBlock block = textCursor.block();
136 QString txt = block.text();
137 const int blockLength = block.length() - 1;
138 const int blockPosition = block.position();
139 int cursorPos = textCursor.position() - blockPosition;
142 const int startPos = txt.lastIndexOf( QRegExp( QLatin1String(
"\\s\\S+") ), cursorPos - 1 ) + 1;
143 int endPos = txt.indexOf( QRegExp( QLatin1String(
"[\\s\\:]") ), startPos );
146 endPos = blockLength;
148 const QString word = txt.mid( startPos, endPos - startPos );
150 if ( endPos < txt.length() && txt[endPos] ==
':') {
154 if ( endPos < txt.length() && txt[endPos] ==
' ') {
164 if ( word != m_lastMatch )
166 match = mComplete->makeCompletion( word );
171 match = mComplete->nextMatch();
174 if ( !match.isEmpty() )
178 if ( textCursor.blockNumber() == 0 && startPos == 0 )
180 match += QLatin1String(
": ");
185 textCursor.setPosition( startPos + blockPosition );
186 textCursor.setPosition( endPos + blockPosition, QTextCursor::KeepAnchor );
189 textCursor.insertText( match );
190 textEdit()->setTextCursor( textCursor );
198 void ChatTextEditPart::slotPropertyChanged( Kopete::PropertyContainer*,
const QString &key,
199 const QVariant& oldValue,
const QVariant &newValue )
201 if ( key == Kopete::Global::Properties::self()->nickName().key() )
203 mComplete->removeItem( oldValue.toString() );
204 mComplete->addItem( newValue.toString() );
208 void ChatTextEditPart::slotContactAdded(
const Kopete::Contact *contact )
210 connect( contact, SIGNAL(propertyChanged(Kopete::PropertyContainer*,QString,QVariant,QVariant)),
211 this, SLOT(slotPropertyChanged(Kopete::PropertyContainer*,QString,QVariant,QVariant)) ) ;
213 QString contactName = contact->property(Kopete::Global::Properties::self()->nickName()).value().toString();
214 mComplete->addItem( contactName );
217 void ChatTextEditPart::slotContactRemoved(
const Kopete::Contact *contact )
219 disconnect( contact, SIGNAL(propertyChanged(Kopete::PropertyContainer*,QString,QVariant,QVariant)),
220 this, SLOT(slotPropertyChanged(Kopete::PropertyContainer*,QString,QVariant,QVariant)) ) ;
222 QString contactName = contact->property(Kopete::Global::Properties::self()->nickName()).value().toString();
223 mComplete->removeItem( contactName );
228 if ( !m_session )
return false;
231 if (
text(Qt::PlainText).isEmpty() )
237 if ( !( m_session->protocol()->capabilities() & Kopete::Protocol::CanSendOffline ) )
239 bool reachableContactFound =
false;
242 for(
int i = 0; i != members.size(); ++i )
244 if ( members[i]->isReachable() )
246 reachableContactFound =
true;
252 if ( !reachableContactFound )
259 void ChatTextEditPart::slotContactStatusChanged( Kopete::Contact *,
const Kopete::OnlineStatus &newStatus,
const Kopete::OnlineStatus &oldStatus )
262 if ( ( oldStatus.status() == Kopete::OnlineStatus::Offline )
263 != ( newStatus.status() == Kopete::OnlineStatus::Offline ) )
271 QString txt = this->
text( Qt::PlainText );
273 if ( txt.isEmpty() || txt ==
"\n" )
276 if ( m_lastMatch.isNull() && ( txt.indexOf( QRegExp( QLatin1String(
"^\\w+:\\s") ) ) > -1 ) )
278 QString search = txt.left( txt.indexOf(
':') );
279 if( !search.isEmpty() )
281 QString match = mComplete->makeCompletion( search );
282 if( !match.isNull() )
283 textEdit()->setText( txt.replace(0,search.length(),match) );
287 if ( !m_lastMatch.isNull() )
290 mComplete->addItem( m_lastMatch );
294 slotStoppedTypingTimer();
295 Kopete::Message sentMessage =
contents();
297 historyList.prepend( this->
text( Qt::AutoText) );
299 textEdit()->moveCursor(QTextCursor::End);
306 QString txt =
text( Qt::PlainText );
311 return !txt.trimmed().isEmpty();
314 void ChatTextEditPart::slotTextChanged()
319 if( !m_typingRepeatTimer->isActive() )
321 m_typingRepeatTimer->setSingleShot(
false );
322 m_typingRepeatTimer->start( 4000 );
323 slotRepeatTypingTimer();
327 m_typingStopTimer->setSingleShot(
true );
328 m_typingStopTimer->start( 4500 );
336 if ( historyList.empty() || historyPos == historyList.count() - 1 )
339 QString
text = this->
text(Qt::PlainText);
340 bool empty = text.trimmed().isEmpty();
345 text = this->
text(Qt::AutoText);
346 if ( historyPos == -1 )
348 historyList.prepend( text );
353 historyList[historyPos] =
text;
359 QString newText = historyList[historyPos];
361 textEdit()->moveCursor( QTextCursor::End );
366 if ( historyList.empty() || historyPos == -1 )
369 QString
text = this->
text(Qt::PlainText);
370 bool empty = text.trimmed().isEmpty();
375 text = this->
text(Qt::AutoText);
376 historyList[historyPos] =
text;
381 QString newText = ( historyPos >= 0 ? historyList[historyPos] : QString() );
385 textEdit()->moveCursor( QTextCursor::End );
390 if( Qt::mightBeRichText(text) )
400 textEdit()->insertPlainText( doc.toPlainText() );
405 textEdit()->insertPlainText( text );
412 textEdit()->setHtml ( message.escapedBody() );
414 textEdit()->setPlainText ( message.plainBody() );
415 textEdit()->moveCursor ( QTextCursor::End );
420 Kopete::Message currentMsg( m_session->myself(), m_session->members() );
421 currentMsg.setDirection( Kopete::Message::Outbound );
425 currentMsg.setHtmlBody(
text());
427 Kopete::Protocol::Capabilities protocolCaps = m_session->protocol()->capabilities();
430 if (protocolCaps & Kopete::Protocol::BaseFormatting)
432 currentMsg.setFont(
textEdit()->currentRichFormat().font());
435 if (protocolCaps & Kopete::Protocol::BaseFgColor)
437 currentMsg.setForegroundColor(
textEdit()->currentRichFormat().foreground().color());
440 if (protocolCaps & Kopete::Protocol::BaseBgColor)
442 currentMsg.setBackgroundColor(
textEdit()->currentRichFormat().background().color());
447 currentMsg.setPlainBody(
text());
453 void ChatTextEditPart::slotRepeatTypingTimer()
458 void ChatTextEditPart::slotStoppedTypingTimer()
460 m_typingRepeatTimer->stop();
461 m_typingStopTimer->stop();
465 void ChatTextEditPart::slotAppearanceChanged()
467 Kopete::AppearanceSettings *settings = Kopete::AppearanceSettings::self();
469 QFont font = ( settings->chatFontSelection() == 1 ) ? settings->chatFont() : KGlobalSettings::generalFont();
470 QTextCharFormat format;
471 format.setFont(font);
472 format.setBackground(settings->chatBackgroundColor());
473 format.setForeground(settings->chatTextColor());
479 void ChatTextEditPart::slotRichTextSupportChanged()
481 KXMLGUIFactory * f = factory();
484 f->removeClient(
this);
496 editor->setCheckSpellingEnabled( enabled );
501 return editor->checkSpellingEnabled();
511 KAboutData *aboutData =
new KAboutData(
"krichtexteditpart", 0, ki18n(
"Chat Text Edit Part"),
"0.1",
512 ki18n(
"A simple rich text editor part"),
513 KAboutData::License_LGPL );
514 aboutData->addAuthor(ki18n(
"Richard J. Moore"), KLocalizedString(),
"rich@kde.org",
"http://xmelegance.org/" );
515 aboutData->addAuthor(ki18n(
"Jason Keirstead"), KLocalizedString(),
"jason@keirstead.org",
"http://www.keirstead.org/" );
516 aboutData->addAuthor(ki18n(
"Michaƫl Larouche"), KLocalizedString(),
"larouche@kde.org" "http://www.tehbisnatch.org/" );
517 aboutData->addAuthor(ki18n(
"Benson Tsai"), KLocalizedString(),
"btsai@vrwarp.com" "http://www.vrwarp.com/" );
524 kDebug() <<
"Loading config";
528 QFont font = config.readEntry(
"TextFont", format.font() );
529 QColor fg = config.readEntry(
"TextFgColor", format.foreground().color() );
530 QColor bg = config.readEntry(
"TextBgColor", format.background().color() );
533 desiredFormat.setFont(font);
534 desiredFormat.setForeground(fg);
535 desiredFormat.setBackground(bg);
538 textEdit()->setAlignment(static_cast<Qt::AlignmentFlag>(config.readEntry(
"EditAlignment",
int(Qt::AlignLeft) )));
543 kDebug() <<
"Saving config";
546 config.writeEntry(
"TextFgColor", editor->
currentRichFormat().foreground().color() );
547 config.writeEntry(
"TextBgColor", editor->
currentRichFormat().background().color() );
548 config.writeEntry(
"EditAlignment",
int(editor->alignment()) );
553 kDebug() <<
"Setting default font style";
559 config.deleteEntry(
"TextFont" );
560 config.deleteEntry(
"TextFg" );
561 config.deleteEntry(
"TextBg" );
562 config.deleteEntry(
"EditAlignment" );
568 return editor->toHtml();
570 return editor->toPlainText();
578 #include "chattexteditpart.moc"
void complete()
Try to complete the word under the cursor.
void setDefaultRichCharFormat(const QTextCharFormat &format)
void historyUp()
Go up an entry in the message history.
bool isRichTextEnabled() const
Is rich text is currently enabled.
ChatTextEditPart(Kopete::ChatSession *session, QWidget *parent)
bool canSend()
Can we send messages now?
void resetConfig(KConfigGroup &config)
void messageSent(Kopete::Message &message)
Emitted when a message is sent.
void checkToolbarEnabled()
void readConfig(KConfigGroup &config)
void typing(bool typing)
Emitted every 4 seconds while the user is typing.
void addText(const QString &text)
Adds text into the edit area.
void historyDown()
Go down an entry in the message history.
A KopeteRichTextWidget with overridden behaviors.
bool isTyping()
Is the user typing right now?
QTextCharFormat currentRichFormat() const
An instant message composition part.
void setCurrentRichCharFormat(const QTextCharFormat &format)
void canSendChanged(bool canSend)
Our send-button-enabled flag might have changed.
void toolbarToggled(bool enabled)
void setCheckSpellingEnabled(bool enabled)
Enable or Disable the automatic spell checking.
void sendMessage()
Sends the text currently entered into the edit area.
static KAboutData * createAboutData()
KParts::GenericFactory< ChatTextEditPart > ChatTextEditPartFactory
void setTextOrHtml(const QString &text)
Kopete::Message contents()
Returns the message currently in the edit area.
void writeConfig(KConfigGroup &config)
bool isRichTextEnabled() const
void slotResetFontAndColor()
bool checkSpellingEnabled() const
Get the state of auto spell checking.
void setContents(const Kopete::Message &message)
Sets the message in the edit field.
void setDefaultPlainCharFormat(const QTextCharFormat &format)
QString text(Qt::TextFormat format=Qt::AutoText) const
Get the text in the editor in the given format.
QTextCharFormat defaultRichFormat() const
KopeteRichTextWidget * textEdit()
Get the inside KTextEdit.
QList< Contact * > ContactPtrList