98
102
this, SLOT ( slotNewLineButtonClicked() ) );
99
103
connect( messageEdit_, SIGNAL( textChanged() ),
100
104
this, SLOT ( slotMessageChanged() ) );
101
connect( inkEdit_, SIGNAL( inkChanged() ),
105
connect( inkCanvas_, SIGNAL( inkChanged() ),
102
106
this, SLOT ( slotMessageChanged() ) );
103
107
connect( textButton_, SIGNAL( clicked() ),
104
108
this, SLOT ( slotSwitchEditor() ) );
110
114
this, SLOT ( slotSwitchEditor() ) );
111
115
connect( customEmoticonButton_, SIGNAL( clicked() ),
112
116
this, SLOT ( slotSwitchEditor() ) );
117
connect( fontButton_, SIGNAL( clicked() ),
118
this, SLOT ( editFont() ) );
119
connect( fontColorButton_, SIGNAL( clicked() ),
120
this, SLOT ( editFontColor() ) );
114
122
// Create the contacts dock
115
123
contactsDock_ = new QDockWidget( i18n( "Contacts" ), this );
153
161
inkButton_ ->setIcon( KIcon( "draw-brush" ) );
154
162
winksButton_ ->setIcon( KIcon( "applications-toys" ) );
155
163
textButton_ ->setIcon( KIcon( "draw-text" ) );
164
fontButton_ ->setIcon( KIcon( "preferences-desktop-font" ) );
165
fontColorButton_ ->setIcon( KIcon( "format-stroke-color" ) );
167
// Set up the buttons for setting ink colour/stroke size/etc.
168
inkCanvas_->setPenSize( inkPenSize_->value() );
170
inkColorButton_->setIcon( KIcon( "format-stroke-color" ) );
171
inkEraseButton_->setIcon( KIcon( "draw-eraser" ) );
172
inkClearButton_->setIcon( KIcon( "edit-clear" ) );
174
connect( inkColorButton_, SIGNAL( clicked() ),
175
this, SLOT ( slotChangeInkColor() ) );
176
connect( inkEraseButton_, SIGNAL( clicked() ),
177
this, SLOT ( slotChangeInkBrush() ) );
178
connect( inkClearButton_, SIGNAL( clicked() ),
179
inkCanvas_, SLOT ( clear() ) );
180
connect( inkPenSize_, SIGNAL( valueChanged(int) ),
181
inkCanvas_, SLOT ( setPenSize(int) ) );
157
183
// Connect the message edit so that if its displayed color changes,
158
184
// it's checked to match the user's chosen color.
333
361
// The chat window is closing
334
362
bool ChatWindow::closeAllTabs()
336
// Do not ask if there only is one tab, or if the user has
337
// explicitly requested all the tabs to be closed
338
if( chatTabs_->count() > 1 && sender() != closeAllAction_ )
364
// Ask the user for confirmation
365
if( chatTabs_->count() > 1 // Do not ask if there only is one tab
366
&& sender() != closeAllAction_ // Do not ask if the user chose the "close all tabs" action
367
&& ! kapp->sessionSaving() ) // Do not ask if the KDE session is closing
340
369
int res = KMessageBox::questionYesNoCancel( this,
341
i18n( "<html>There are multiple tabs open in this chat window. Do you want to close the "
342
"current tab only, or all tabs?<br /><br />"
343
"<i>Note: You can close all tabs at once by pressing Alt+F4.</i></html>" ),
344
i18nc( "Dialog box caption: closing a chatwindow with a single tab", "Closing a Chat Tab" ),
370
i18n( "<html>There are multiple tabs open in this chat window. "
371
"Do you want to close the current tab only, or all tabs?<br /><br />"
372
"<i>Note: You can close all tabs at once by pressing Alt+F4.</i></html>" ),
373
i18nc( "Dialog box caption: closing a chatwindow with a single tab",
374
"Closing a Chat Tab" ),
345
375
KGuiItem( i18n( "Close All Tabs" ), "window-close" ), // Yes option
346
376
KGuiItem( i18n( "Close Current Tab" ), "tab-close" ), // No option
347
377
KStandardGuiItem::cancel(),
506
536
// Connect slots to signals for "Chat" menu
507
537
connect( inviteButton_, SIGNAL( triggered(bool) ),
508
this, SLOT ( slotInviteContact() ) );
538
this, SLOT ( slotInviteContact() ) );
509
539
connect( sendAction_, SIGNAL( triggered(bool) ),
510
540
this, SLOT ( startFileTransfer() ) );
511
541
connect( nudgeAction_, SIGNAL( triggered(bool) ),
693
727
messageEdit_->setFocus();
695
else if( inkEdit_->isVisible() )
729
else if( inkCanvas_->isVisible() )
697
inkEdit_->inkFrame_->setFocus();
731
inkCanvas_->setFocus();
737
if ( event->type() == QEvent::KeyPress )
739
QKeyEvent *keyEvent = static_cast<QKeyEvent*>( event );
740
if ( keyEvent->key() == Qt::Key_Escape )
703
747
// Only manage events for the editors from now on (the event filter code
704
748
// is complex enough as it is now...)
705
if( obj != messageEdit_ && obj != messageEdit_->viewport()
749
if( obj != messageEdit_
750
&& obj != messageEdit_->viewport()
707
752
&& obj != winksWidget_
708
753
&& obj != standardEmoticonsWidget_
709
754
&& obj != customEmoticonsWidget_ )
849
895
messageEdit_->setFocus();
851
else if( inkEdit_->isVisible() )
897
else if( inkCanvas_->isVisible() )
853
inkEdit_->inkFrame_->setFocus();
899
inkCanvas_->setFocus();
857
903
case QEvent::FocusOut:
858
904
case QEvent::Show:
906
QWidget *focusedWidget = QApplication::focusWidget();
908
// Allow this chat's search bar to take focus away from the message editor
909
if( focusedWidget && QString( focusedWidget->metaObject()->className() ) == "KHistoryComboBox" )
860
QWidget *focusedWidget = QApplication::focusWidget();
862
// Allow this chat's search bar to take focus away from the message editor
863
if( focusedWidget && QString( focusedWidget->metaObject()->className() ) == "KHistoryComboBox" )
868
messageEdit_->setFocus( Qt::OtherFocusReason );
914
messageEdit_->setFocus( Qt::OtherFocusReason );
872
918
case QEvent::DragEnter:
874
QDragEnterEvent *dragEvent = static_cast<QDragEnterEvent*>( event );
876
if( ! dragEvent || ! dragEvent->mimeData()->hasUrls() )
878
#ifdef KMESSDEBUG_CHATWINDOW
879
kDebug() << "Ignoring invalid drop";
919
case QEvent::DragMove:
921
QDragEnterEvent *dragEvent = static_cast<QDragEnterEvent*>( event );
925
#ifdef KMESSDEBUG_CHATWINDOW
926
kDebug() << "Ignoring invalid drag event!";
931
const QMimeData *mimeData = dragEvent->mimeData();
932
if( mimeData->hasUrls()
933
|| mimeData->hasImage() )
935
#ifdef KMESSDEBUG_CHATWINDOW
936
kDebug() << "Accepting drag event of mimetypes:" << dragEvent->mimeData()->formats();
884
938
dragEvent->acceptProposedAction();
942
#ifdef KMESSDEBUG_CHATWINDOW
943
kDebug() << "Ignoring invalid drop having mimetypes:" << dragEvent->mimeData()->formats();
888
949
case QEvent::Drop:
951
QDropEvent *dropEvent = static_cast<QDropEvent*>( event );
953
// Process the drop only if it comes from out of our application.
954
if( ! dropEvent || dropEvent->source() != 0 )
890
QDropEvent *dropEvent = static_cast<QDropEvent*>( event );
892
// Process the drop only if it contains file URLs and comes from out of our application.
893
if( ! dropEvent || ! dropEvent->mimeData()->hasUrls() || dropEvent->source() != 0 )
895
956
#ifdef KMESSDEBUG_CHATWINDOW
896
kDebug() << "Ignoring invalid drop";
957
kDebug() << "Ignoring invalid drop!";
962
const QMimeData *mimeData = dropEvent->mimeData();
963
if( mimeData->hasUrls() )
901
965
#ifdef KMESSDEBUG_CHATWINDOW
902
kDebug() << "Drag'n'dropped files:" << dropEvent->mimeData()->urls();
966
kDebug() << "Drag'n'dropped files:" << mimeData->urls();
905
969
// Send the files to the contact
906
getCurrentChat()->startFileTransfer( dropEvent->mimeData()->urls() );
908
dropEvent->acceptProposedAction();
970
getCurrentChat()->startFileTransfer( mimeData->urls() );
972
dropEvent->acceptProposedAction();
976
if( mimeData->hasImage() )
978
QImage image( qvariant_cast<QImage>( mimeData->imageData() ) );
982
#ifdef KMESSDEBUG_CHATVIEW
983
kDebug() << "Drag'n'dropped an invalid image!";
988
#ifdef KMESSDEBUG_CHATWINDOW
989
kDebug() << "Drag'n'dropped a" << image.size() << "image";
992
// Create a temporary file where the image will be stored.
993
// TODO: The file is not destroyed, as it needs to be kept
994
// available until the transfer is completed. Find a way
995
// to remove it when KMess quits or as soon as the transfer
998
file.setAutoRemove( false );
999
file.setFileTemplate( QDir::tempPath() + "/kmess.XXXXXX.jpg" );
1003
#ifdef KMESSDEBUG_CHATWINDOW
1004
kDebug() << "Cannot create temporary image file!";
1009
dropEvent->acceptProposedAction();
1011
// Save the image and get its local URL
1012
image.save( &file, "JPG" );
1014
QUrl imageUrl( "file://" + file.fileName() );
1016
// Send the image to the contact
1017
QList<QUrl> urlList;
1018
urlList.append( imageUrl );
1019
getCurrentChat()->startFileTransfer( urlList );
1325
1439
// Send a ink via server
1326
1440
void ChatWindow::sendInk()
1328
// Get the image bytes and send them
1329
const QByteArray& ink( inkEdit_->getImageBytes() );
1331
getCurrentChat()->sendInkMessage( ink );
1333
// Clear and reset the state of send button
1334
inkEdit_->clearImage();
1442
bool supportGifInk = true;
1443
bool supportIsfInk = true;
1445
// Find out which ink formats are supported by all participants
1446
const QStringList &participants( getCurrentChat()->getParticipants() );
1447
foreach( const QString &handle, participants )
1449
const ContactBase *contact = currentAccount_->getContactByHandle( handle );
1455
supportGifInk &= contact->hasCapability( ContactBase::MSN_CAP_INK_GIF );
1456
supportIsfInk &= contact->hasCapability( ContactBase::MSN_CAP_INK_ISF );
1459
// The contacts don't support either formats! Something is wrong, since the ink editor
1461
if( ! supportGifInk && ! supportIsfInk )
1463
kWarning() << "Neither Ink formats are supported by the participants!";
1465
getCurrentChat()->showMessage( ChatMessage( ChatMessage::TYPE_SYSTEM,
1466
ChatMessage::CONTENT_SYSTEM_ERROR,
1468
i18nc( "Error message shown in chat",
1469
"Failed to send the handwritten message: "
1470
"the contacts do not support it." ),
1481
#ifdef KMESSDEBUG_CHATWINDOW
1482
kDebug() << "Retrieving ISF ink data";
1485
format = FORMAT_ISF;
1486
ink = Isf::Stream::writer( *( inkCanvas_->drawing() ) );
1488
else if( supportGifInk )
1490
#ifdef KMESSDEBUG_CHATWINDOW
1491
kDebug() << "Retrieving GIF ink data";
1494
format = FORMAT_GIF;
1495
ink = Isf::Stream::writerGif( *( inkCanvas_->drawing() ) );
1497
// Any other possibility has been excluded above
1501
kWarning() << "An error occured while creating the" << ( supportIsfInk ? "ISF" : "GIF" ) << "Ink data!";
1503
getCurrentChat()->showMessage( ChatMessage( ChatMessage::TYPE_SYSTEM,
1504
ChatMessage::CONTENT_SYSTEM_ERROR,
1506
i18nc( "Error message shown in chat",
1507
"Failed to send the handwritten message: "
1508
"an error has occurred while creating it." ),
1514
getCurrentChat()->sendInkMessage( format, ink );
1516
// Get the pixels, to show the ink in chat
1517
QImage image( inkCanvas_->image() );
1519
// Save it as a PNG image, which KHTML will be able to show
1521
buffer.open( QIODevice::WriteOnly );
1522
image.save( &buffer, "PNG" );
1525
// Show the message in the browser window
1526
const QString& text( "<img src='data:image/png;base64," + buffer.data().toBase64() + "'>" );
1528
ChatMessage message( ChatMessage::TYPE_OUTGOING,
1529
ChatMessage::CONTENT_MESSAGE_INK,
1532
currentAccount_->getHandle(),
1533
currentAccount_->getFriendlyName( STRING_ORIGINAL ),
1534
currentAccount_->getPicturePath() );
1536
getCurrentChat()->showMessage( message );
1538
// Clear and reset the state of the send button
1539
inkCanvas_->clear();
1335
1540
sendButton_->setEnabled( false );
1337
// Show the message in the browser window
1338
const QString& text( "<img src='data:image/gif;base64," + ink.toBase64() + "'>" );
1340
ChatMessage message( ChatMessage::TYPE_OUTGOING,
1341
ChatMessage::CONTENT_MESSAGE_INK,
1344
currentAccount_->getHandle(),
1345
currentAccount_->getFriendlyName( STRING_ORIGINAL ),
1346
currentAccount_->getPicturePath());
1348
getCurrentChat()->showMessage(message);
1370
1562
// Messages like "//hello" should be sent as "/hello"
1371
1563
// Messages like "/hello" are commands.
1372
1564
// Check if this is a command, and if so, emit handleCommand signal
1373
if( text.left( 2 ) == "//" )
1375
text = text.mid( 1 );
1377
else if( text.left( 1 ) == "/" )
1379
const QString& command( text.mid( 1 ) );
1565
if( text.size() > 2 && text.mid( 2, 1 ) != "/" )
1567
if( text.left( 2 ) == "//" )
1569
text = text.mid( 1 );
1571
else if( text.left( 1 ) == "/" )
1573
const QString& command( text.mid( 1 ) );
1381
// Handle command. If 'false' is returned, send it anyway.
1382
if ( handleCommand( command ) )
1575
// Handle command. If 'false' is returned, send it anyway.
1576
if ( handleCommand( command ) )
1503
1698
customEmoticonsDock_ ->setEnabled( isEnabled );
1504
1699
standardEmoticonsDock_ ->setEnabled( isEnabled );
1506
inkEdit_ ->setEnabled( isEnabled );
1701
inkCanvas_ ->setEnabled( isEnabled );
1507
1702
messageEdit_ ->setEnabled( isEnabled );
1508
1703
newLineButton_ ->setEnabled( isEnabled );
1509
1704
sendButton_ ->setEnabled( isEnabled );
1510
1705
standardEmoticonButton_ ->setEnabled( isEnabled );
1511
1706
customEmoticonButton_ ->setEnabled( isEnabled );
1707
fontButton_ ->setEnabled( isEnabled );
1708
fontColorButton_ ->setEnabled( isEnabled );
1512
1709
inviteButton_ ->setEnabled( isEnabled );
1513
1710
textButton_ ->setEnabled( isEnabled );
1892
// Change color for current pen
1893
void ChatWindow::slotChangeInkColor()
1896
if ( KColorDialog::getColor( color ) == QDialog::Accepted )
1898
inkCanvas_->setPenColor( color );
1904
// Erase brush was selected
1905
void ChatWindow::slotChangeInkBrush()
1907
if( inkCanvas_->penType() == Isf::InkCanvas::DrawingPen )
1909
inkCanvas_->setPenType( Isf::InkCanvas::EraserPen );
1910
inkEraseButton_->setIcon( KIcon( "draw-freehand" ) );
1911
inkEraseButton_->setToolTip( i18n( "Drawing brush" ) );
1915
inkCanvas_->setPenType( Isf::InkCanvas::DrawingPen );
1916
inkEraseButton_->setIcon( KIcon( "draw-eraser" ) );
1917
inkEraseButton_->setToolTip( i18n( "Erase brush" ) );
1694
1923
// Make the caption blink if the window still doesn't have focus
1695
1924
void ChatWindow::slotBlinkCaption()
2217
2466
// Display the new chat contents in the UI. Block the signals to avoid the editors
2218
2467
// from firing the "message changed" signal, which sends a typing message.
2219
2468
messageEdit_ ->blockSignals( true );
2220
inkEdit_ ->blockSignals( true );
2469
inkCanvas_ ->blockSignals( true );
2221
2470
contactsDock_->setWidget( chat->getContactsWidget() );
2222
2471
messageEdit_ ->setDocument( chat->getMessageEditContents() );
2223
inkEdit_ ->setImage( chat->getInkEditContents() );
2472
inkCanvas_ ->setDrawing( chat->getInkDrawing() );
2224
2473
messageEdit_ ->blockSignals( false );
2225
inkEdit_ ->blockSignals( false );
2474
inkCanvas_ ->blockSignals( false );
2227
2476
// Reset quick re-type index
2228
2477
indexSentences_ = chat->getQuickRetypeList().size();
2455
2703
#if KMESS_ENABLE_INK == 1
2456
2704
if( enableInkButton )
2458
// Disable the Ink button if the contact doesn't support GIF Ink
2459
if( ! contact->hasCapability( ContactBase::MSN_CAP_INK_GIF ) )
2461
enableInkButton = false;
2464
// TODO Fix sending Ink to WLM 8.5 and 2009 (probably by implementing ISF support)
2465
// Disable the Ink button also if we're chatting with an ISF-enabled WLM8.5 / WLM2009
2466
if( ( contact->getClientName() == "Windows Live Messenger 8.5"
2467
|| contact->getClientName() == "Windows Live Messenger 2009" )
2468
&& contact->hasCapability( ContactBase::MSN_CAP_INK_ISF ) )
2706
// Disable the Ink button if the contact doesn't support Ink
2707
if( ! contact->hasCapability( ContactBase::MSN_CAP_INK_GIF )
2708
&& ! contact->hasCapability( ContactBase::MSN_CAP_INK_ISF ) )
2470
2710
enableInkButton = false;
2503
2743
if( getCurrentChat()->getParticipants().count() > 1 )
2505
2745
inkButton_->setStatusTip( i18nc( "Label text",
2506
"Handwriting is disabled: KMess cannot send drawings to "
2507
"some of the contacts." ) );
2746
"Handwriting is disabled: some of the contacts do not "
2747
"support receiving handwritten messages." ) );
2511
2751
inkButton_->setStatusTip( i18nc( "Label text",
2512
"Handwriting is disabled: KMess cannot send drawings to "
2513
"this contact." ) );
2752
"Handwriting is disabled: this contact does not "
2753
"support receiving handwritten messages." ) );
2526
2766
if( getCurrentChat()->getParticipants().count() > 1 )
2528
2768
winksButton_->setStatusTip( i18nc( "Label text",
2529
"Winks are disabled: KMess cannot send winks to "
2530
"some of the contacts." ) );
2769
"Winks are disabled: some of the contacts do not "
2770
"support receiving winks." ) );
2534
2774
winksButton_->setStatusTip( i18nc( "Label text",
2535
"Winks are disabled: KMess cannot send winks to "
2536
"this contact." ) );
2775
"Winks are disabled: this contact does not "
2776
"support receiving winks." ) );