1 /*
2 kopetechatwindow.cpp - Chat Window
3
4 Copyright (c) 2008 by Benson Tsai <btsai@vrwarp.com>
5 Copyright (c) 2007 by Gustavo Pichorim Boiko <gustavo.boiko@kdemail.net>
6 Copyright (c) 2002-2006 by Olivier Goffart <ogoffart@kde.org>
7 Copyright (c) 2003-2004 by Richard Smith <kde@metafoo.co.uk>
8 Copyright (C) 2002 by James Grant
9 Copyright (c) 2002 by Stefan Gehn <metz@gehn.net>
10 Copyright (c) 2002-2004 by Martijn Klingens <klingens@kde.org>
11
12 Kopete (c) 2002-2005 by the Kopete developers <kopete-devel@kde.org>
13
14 *************************************************************************
15 * *
16 * This program is free software; you can redistribute it and/or modify *
17 * it under the terms of the GNU General Public License as published by *
18 * the Free Software Foundation; either version 2 of the License, or *
19 * (at your option) any later version. *
20 * *
21 *************************************************************************
22 */
23
24 #include "kopetechatwindow.h"
25
26 #include <QMenu>
27 #include <QIcon>
28 #include <QTimer>
29 #include <QFrame>
30 #include <QLabel>
31 #include <QPixmap>
32 #include <QLayout>
33 #include <QDockWidget>
34 #include <QTextStream>
35 #include <QCloseEvent>
36 #include <QVBoxLayout>
37
38 #ifdef CHRONO
39 #include <QTime>
40 #endif
41
42 #include <kactioncollection.h>
43 #include <kcursor.h>
44 #include <KLocalizedString>
45 #include <QMenuBar>
46 #include <kconfig.h>
47 #include <kiconloader.h>
48 #include "kopetechatwindow_debug.h"
49 #include <kwindowsystem.h>
50 #include <ktemporaryfile.h>
51 #include <kedittoolbar.h>
52 #include <QPushButton>
53 #include <ktabwidget.h>
54 #include <kdialog.h>
55 #include <kstringhandler.h>
56 #include <ksqueezedtextlabel.h>
57 #include <kstandardshortcut.h>
58 #include <kglobalsettings.h>
59 #include <kcolorscheme.h>
60 #include <khbox.h>
61 #include <kvbox.h>
62 #include <ktoolbar.h>
63 #include <KShortcut>
64 #include <kstandardaction.h>
65 #include <ktoggleaction.h>
66 #include <kactionmenu.h>
67 #include <ktoolbarspaceraction.h>
68 #include <QStatusBar>
69
70 #include "chatmessagepart.h"
71 #include "chattexteditpart.h"
72 #include "chatview.h"
73 #include "kopeteapplication.h"
74 #include "kopetebehaviorsettings.h"
75 #include "kopeteemoticonaction.h"
76 #include "kopetegroup.h"
77 #include "kopetechatsession.h"
78 #include "kopetemetacontact.h"
79 #include "kopetepluginmanager.h"
80 #include "kopeteprotocol.h"
81 #include "kopetestdaction.h"
82 #include "kopeteviewmanager.h"
83 #include "chatmemberslistview.h"
84 #include "chatsessionmemberslistmodel.h"
85
86 #include <qtoolbutton.h>
87 #include <kxmlguifactory.h>
88 #include <KTabBar>
89 #include <KSharedConfig>
90
91 typedef QMap<Kopete::Account *, KopeteChatWindow *> AccountMap;
92 typedef QMap<Kopete::Group *, KopeteChatWindow *> GroupMap;
93 typedef QMap<Kopete::MetaContact *, KopeteChatWindow *> MetaContactMap;
94 typedef QList<KopeteChatWindow *> WindowList;
95
96 using Kopete::ChatSessionMembersListModel;
97
98 namespace {
99 AccountMap accountMap;
100 GroupMap groupMap;
101 MetaContactMap mcMap;
102 WindowList windows;
103 }
104
window(Kopete::ChatSession * manager)105 KopeteChatWindow *KopeteChatWindow::window(Kopete::ChatSession *manager)
106 {
107 bool windowCreated = false;
108 KopeteChatWindow *myWindow = 0;
109
110 //Take the first and the first? What else?
111 Kopete::Group *group = nullptr;
112 Kopete::ContactPtrList members = manager->members();
113 Kopete::MetaContact *metaContact = members.first()->metaContact();
114
115 if (metaContact) {
116 Kopete::GroupList gList = metaContact->groups();
117 group = gList.first();
118 }
119
120 switch (Kopete::BehaviorSettings::self()->chatWindowGroupPolicy()) {
121 //Open chats from the same protocol in the same window
122 case Kopete::BehaviorSettings::EnumChatWindowGroupPolicy::GroupByAccount:
123 if (accountMap.contains(manager->account())) {
124 myWindow = accountMap[ manager->account() ];
125 } else {
126 windowCreated = true;
127 }
128 break;
129
130 //Open chats from the same group in the same window
131 case Kopete::BehaviorSettings::EnumChatWindowGroupPolicy::GroupByGroup:
132 if (group && groupMap.contains(group)) {
133 myWindow = groupMap[ group ];
134 } else {
135 windowCreated = true;
136 }
137 break;
138
139 //Open chats from the same metacontact in the same window
140 case Kopete::BehaviorSettings::EnumChatWindowGroupPolicy::GroupByMetaContact:
141 if (mcMap.contains(metaContact)) {
142 myWindow = mcMap[ metaContact ];
143 } else {
144 windowCreated = true;
145 }
146 break;
147
148 //Open all chats in the same window
149 case Kopete::BehaviorSettings::EnumChatWindowGroupPolicy::GroupAll:
150 if (windows.isEmpty()) {
151 windowCreated = true;
152 } else {
153 //Here we are finding the window with the most tabs and
154 //putting it there. Need this for the cases where config changes
155 //midstream
156
157 int viewCount = -1;
158 WindowList::iterator it;
159 for (it = windows.begin(); it != windows.end(); ++it) {
160 if ((*it)->chatViewCount() > viewCount) {
161 myWindow = (*it);
162 viewCount = (*it)->chatViewCount();
163 }
164 }
165 }
166 break;
167
168 //Open every chat in a new window
169 case Kopete::BehaviorSettings::EnumChatWindowGroupPolicy::OpenNewWindow:
170 default:
171 windowCreated = true;
172 break;
173 }
174
175 if (windowCreated) {
176 myWindow = new KopeteChatWindow(manager->form());
177
178 if (!accountMap.contains(manager->account())) {
179 accountMap.insert(manager->account(), myWindow);
180 }
181
182 if (!mcMap.contains(metaContact)) {
183 mcMap.insert(metaContact, myWindow);
184 }
185
186 if (group && !groupMap.contains(group)) {
187 groupMap.insert(group, myWindow);
188 }
189 }
190
191 // kDebug( 14010 ) << "Open Windows: " << windows.count();
192
193 return myWindow;
194 }
195
KopeteChatWindow(Kopete::ChatSession::Form form,QWidget * parent)196 KopeteChatWindow::KopeteChatWindow(Kopete::ChatSession::Form form, QWidget *parent)
197 : KXmlGuiWindow(parent)
198 , initialForm(form)
199 {
200 #ifdef CHRONO
201 QTime chrono;
202 chrono.start();
203 #endif
204 m_activeView = nullptr;
205 m_popupView = nullptr;
206 backgroundFile = nullptr;
207 updateBg = true;
208 m_tabBar = nullptr;
209
210 m_participantsWidget = new QDockWidget(i18n("Participants"), this);
211 m_participantsWidget->setAllowedAreas(Qt::RightDockWidgetArea | Qt::LeftDockWidgetArea);
212 m_participantsWidget->setFeatures(QDockWidget::DockWidgetClosable);
213 m_participantsWidget->setTitleBarWidget(nullptr);
214 m_participantsWidget->setObjectName(QStringLiteral("Participants")); //object name is required for automatic position and settings save.
215
216 ChatSessionMembersListModel *members_model = new ChatSessionMembersListModel(this);
217
218 connect(this, SIGNAL(chatSessionChanged(Kopete::ChatSession*)), members_model, SLOT(setChatSession(Kopete::ChatSession*)));
219
220 ChatMembersListView *chatmembers = new ChatMembersListView(m_participantsWidget);
221 chatmembers->setModel(members_model);
222 chatmembers->setWordWrap(true);
223 m_participantsWidget->setWidget(chatmembers);
224 initActions();
225
226 addDockWidget(Qt::RightDockWidgetArea, m_participantsWidget);
227
228 KVBox *vBox = new KVBox(this);
229 vBox->setLineWidth(0);
230 vBox->setSpacing(0);
231 vBox->setFrameStyle(QFrame::NoFrame);
232 // set default window size. This could be removed by fixing the size hints of the contents
233 if (initialForm == Kopete::ChatSession::Chatroom) {
234 resize(650, 400);
235 } else {
236 m_participantsWidget->hide();
237 resize(400, 400);
238 }
239 setCentralWidget(vBox);
240
241 mainArea = new QFrame(vBox);
242 mainArea->setLineWidth(0);
243 mainArea->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
244 mainLayout = new QVBoxLayout(mainArea);
245 mainLayout->setContentsMargins(0, 4, 0, 0);
246
247 if (Kopete::BehaviorSettings::self()->chatWindowShowSendButton()) {
248 //Send Button
249 m_button_send = new QPushButton(i18nc("@action:button", "Send"), statusBar());
250 m_button_send->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum));
251 m_button_send->setEnabled(false);
252 m_button_send->setFont(statusBar()->font());
253 m_button_send->setFixedHeight(statusBar()->sizeHint().height());
254 connect(m_button_send, SIGNAL(clicked()), this, SLOT(slotSendMessage()));
255 statusBar()->addPermanentWidget(m_button_send, 0);
256 } else {
257 m_button_send = nullptr;
258 }
259
260 m_status_text = new KSqueezedTextLabel(i18nc("@info:status", "Ready."), statusBar());
261 m_status_text->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
262 m_status_text->setFont(statusBar()->font());
263 m_status_text->setFixedHeight(statusBar()->sizeHint().height());
264 statusBar()->addWidget(m_status_text, 1);
265
266 windows.append(this);
267 windowListChanged();
268
269 m_alwaysShowTabs = KSharedConfig::openConfig()->group("ChatWindowSettings").
270 readEntry(QStringLiteral("AlwaysShowTabs"), false);
271 // kDebug( 14010 ) << "Open Windows: " << windows.count();
272
273 setupGUI(static_cast<StandardWindowOptions>(ToolBar | Keys | StatusBar | Save | Create), QStringLiteral("kopetechatwindow.rc"));
274
275 //has to be done after the setupGUI, in order to have the toolbar set up to restore window settings.
276 readOptions();
277 #ifdef CHRONO
278 qDebug()<<"TIME: "<<chrono.elapsed();
279 #endif
280 }
281
~KopeteChatWindow()282 KopeteChatWindow::~KopeteChatWindow()
283 {
284 kDebug(14010);
285
286 emit(closing(this));
287
288 for (AccountMap::Iterator it = accountMap.begin(); it != accountMap.end();) {
289 if (it.value() == this) {
290 it = accountMap.erase(it);
291 } else {
292 ++it;
293 }
294 }
295
296 for (GroupMap::Iterator it = groupMap.begin(); it != groupMap.end();) {
297 if (it.value() == this) {
298 it = groupMap.erase(it);
299 } else {
300 ++it;
301 }
302 }
303
304 for (MetaContactMap::Iterator it = mcMap.begin(); it != mcMap.end();) {
305 if (it.value() == this) {
306 it = mcMap.erase(it);
307 } else {
308 ++it;
309 }
310 }
311
312 windows.removeAt(windows.indexOf(this));
313 windowListChanged();
314
315 // kDebug( 14010 ) << "Open Windows: " << windows.count();
316
317 saveOptions();
318
319 delete backgroundFile;
320 delete anim;
321 delete animIcon;
322 }
323
windowListChanged()324 void KopeteChatWindow::windowListChanged()
325 {
326 // update all windows' Move Tab to Window action
327 for (WindowList::iterator it = windows.begin(); it != windows.end(); ++it) {
328 (*it)->checkDetachEnable();
329 }
330 }
331
slotTabContextMenu(QWidget * tab,const QPoint & pos)332 void KopeteChatWindow::slotTabContextMenu(QWidget *tab, const QPoint &pos)
333 {
334 m_popupView = static_cast<ChatView *>(tab);
335
336 QMenu popup;
337 popup.addSection(KStringHandler::rsqueeze(m_popupView->caption()));
338 popup.addAction(actionContactMenu);
339 popup.addSeparator();
340 popup.addAction(actionTabPlacementMenu);
341 popup.addAction(tabDetach);
342 popup.addAction(actionDetachMenu);
343 popup.addAction(tabCloseAllOthers);
344 popup.addAction(tabClose);
345 popup.exec(pos);
346
347 m_popupView = 0;
348 }
349
activeView()350 ChatView *KopeteChatWindow::activeView()
351 {
352 return m_activeView;
353 }
354
updateSendKeySequence()355 void KopeteChatWindow::updateSendKeySequence()
356 {
357 if (!sendMessage || !m_activeView) {
358 return;
359 }
360
361 m_activeView->editPart()->textEdit()->setSendKeySequenceList(sendMessage->shortcuts());
362 }
363
initActions(void)364 void KopeteChatWindow::initActions(void)
365 {
366 KActionCollection *coll = actionCollection();
367
368 createStandardStatusBarAction();
369
370 chatSend = new QAction(QIcon::fromTheme(QStringLiteral("mail-send")), i18n("&Send Message"), coll);
371 //Recuperate the qAction for later
372 sendMessage = coll->addAction(QStringLiteral("chat_send"), chatSend);
373 //Set up change signal in case the user changer the shortcut later
374 connect(sendMessage, SIGNAL(changed()), SLOT(updateSendKeySequence()));
375
376 connect(chatSend, SIGNAL(triggered(bool)), SLOT(slotSendMessage()));
377 //Default to 'Return' and 'Enter' for sending messages
378 //'Return' is the key in the main part of the keyboard
379 //'Enter' is on the Numpad
380 QList<QKeySequence> chatSendShortcuts;
381 chatSendShortcuts << QKeySequence(Qt::Key_Return) << QKeySequence(Qt::Key_Enter);
382 coll->setDefaultShortcuts(chatSend, chatSendShortcuts);
383 chatSend->setEnabled(false);
384
385 chatSendFile = new QAction(QIcon::fromTheme(QStringLiteral("mail-attachment")), i18n("Send File..."), coll);
386 coll->addAction(QStringLiteral("chat_send_file"), chatSendFile);
387 connect(chatSendFile, SIGNAL(triggered(bool)), SLOT(slotSendFile()));
388 chatSendFile->setEnabled(false);
389
390 KStandardAction::save(this, SLOT(slotChatSave()), coll);
391 KStandardAction::print(this, SLOT(slotChatPrint()), coll);
392 QAction *quitAction = KStandardAction::quit(this, SLOT(close()), coll);
393 quitAction->setText(i18n("Close All Chats"));
394
395 tabClose = KStandardAction::close(this, SLOT(slotChatClosed()), coll);
396 coll->addAction(QStringLiteral("tabs_close"), tabClose);
397
398 tabActive = new QAction(i18n("&Activate Next Active Tab"), coll);
399 coll->addAction(QStringLiteral("tabs_active"), tabActive);
400 // tabActive->setShortcut( KStandardShortcut::tabNext() );
401 tabActive->setEnabled(false);
402 connect(tabActive, SIGNAL(triggered(bool)), this, SLOT(slotNextActiveTab()));
403
404 tabRight = new QAction(i18n("&Activate Next Tab"), coll);
405 coll->addAction(QStringLiteral("tabs_right"), tabRight);
406 coll->setDefaultShortcuts(tabRight, KStandardShortcut::tabNext());
407 tabRight->setEnabled(false);
408 connect(tabRight, SIGNAL(triggered(bool)), this, SLOT(slotNextTab()));
409
410 tabLeft = new QAction(i18n("&Activate Previous Tab"), coll);
411 coll->addAction(QStringLiteral("tabs_left"), tabLeft);
412 coll->setDefaultShortcuts(tabLeft, KStandardShortcut::tabPrev());
413 tabLeft->setEnabled(false);
414 connect(tabLeft, SIGNAL(triggered(bool)), this, SLOT(slotPreviousTab()));
415
416 // This action exists mostly so that the shortcut is configurable.
417 // The actual "slot" is the eventFilter.
418 nickComplete = new QAction(i18n("Nic&k Completion"), coll);
419 coll->addAction(QStringLiteral("nick_complete"), nickComplete);
420 coll->setDefaultShortcut(nickComplete, QKeySequence(Qt::Key_Tab));
421
422 tabDetach = new QAction(QIcon::fromTheme(QStringLiteral("tab-detach")), i18n("&Detach Chat"), coll);
423 coll->addAction(QStringLiteral("tabs_detach"), tabDetach);
424 tabDetach->setEnabled(false);
425 connect(tabDetach, SIGNAL(triggered(bool)), this, SLOT(slotDetachChat()));
426
427 tabCloseAllOthers = new QAction(QIcon::fromTheme(QStringLiteral("tab-close")), i18n("Close &All But This Tab"), coll);
428 coll->addAction(QStringLiteral("tabs_close_others"), tabCloseAllOthers);
429 tabCloseAllOthers->setEnabled(true);
430 connect(tabCloseAllOthers, SIGNAL(triggered(bool)), this, SLOT(slotCloseAllOtherTabs()));
431
432 actionDetachMenu = new KActionMenu(QIcon::fromTheme(QStringLiteral("tab-detach")), i18n("&Move Tab to Window"), coll);
433 coll->addAction(QStringLiteral("tabs_detachmove"), actionDetachMenu);
434 actionDetachMenu->setDelayed(false);
435
436 connect(actionDetachMenu->menu(), SIGNAL(aboutToShow()), this, SLOT(slotPrepareDetachMenu()));
437 connect(actionDetachMenu->menu(), SIGNAL(triggered(QAction*)), this, SLOT(slotDetachChat(QAction*)));
438
439 actionTabPlacementMenu = new KActionMenu(i18n("&Tab Placement"), coll);
440 coll->addAction(QStringLiteral("tabs_placement"), actionTabPlacementMenu);
441 connect(actionTabPlacementMenu->menu(), SIGNAL(aboutToShow()), this, SLOT(slotPreparePlacementMenu()));
442 connect(actionTabPlacementMenu->menu(), SIGNAL(triggered(QAction*)), this, SLOT(slotPlaceTabs(QAction*)));
443
444 coll->setDefaultShortcut(tabDetach, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_B));
445
446 KStandardAction::cut(this, SLOT(slotCut()), coll);
447 KStandardAction::copy(this, SLOT(slotCopy()), coll);
448 KStandardAction::paste(this, SLOT(slotPaste()), coll);
449
450 QAction *action;
451
452 historyUp = new QAction(i18n("Previous History"), coll);
453 coll->addAction(QStringLiteral("history_up"), historyUp);
454 coll->setDefaultShortcut(historyUp, QKeySequence(Qt::CTRL + Qt::Key_Up));
455 connect(historyUp, SIGNAL(triggered(bool)), this, SLOT(slotHistoryUp()));
456
457 historyDown = new QAction(i18n("Next History"), coll);
458 coll->addAction(QStringLiteral("history_down"), historyDown);
459 coll->setDefaultShortcut(historyDown, QKeySequence(Qt::CTRL + Qt::Key_Down));
460 connect(historyDown, SIGNAL(triggered(bool)), this, SLOT(slotHistoryDown()));
461
462 action = KStandardAction::prior(this, SLOT(slotPageUp()), coll);
463 coll->addAction(QStringLiteral("scroll_up"), action);
464 action = KStandardAction::next(this, SLOT(slotPageDown()), coll);
465 coll->addAction(QStringLiteral("scroll_down"), action);
466
467 KStandardAction::showMenubar(menuBar(), SLOT(setVisible(bool)), coll);
468
469 toggleAutoSpellCheck = new KToggleAction(i18n("Automatic Spell Checking"), coll);
470 coll->addAction(QStringLiteral("enable_auto_spell_check"), toggleAutoSpellCheck);
471 toggleAutoSpellCheck->setChecked(true);
472 connect(toggleAutoSpellCheck, SIGNAL(triggered(bool)), this, SLOT(toggleAutoSpellChecking()));
473
474 QAction *toggleParticipantsAction = m_participantsWidget->toggleViewAction();
475 toggleParticipantsAction->setText(i18n("Show Participants"));
476 toggleParticipantsAction->setIconText(i18n("Participants"));
477 toggleParticipantsAction->setIcon(QIcon::fromTheme(QStringLiteral("system-users")));
478 coll->addAction(QStringLiteral("show_participants_widget"), toggleParticipantsAction);
479
480 actionSmileyMenu = new KopeteEmoticonAction(coll);
481 coll->addAction(QStringLiteral("format_smiley"), actionSmileyMenu);
482 actionSmileyMenu->setDelayed(false);
483 connect(actionSmileyMenu, SIGNAL(activated(QString)), this, SLOT(slotSmileyActivated(QString)));
484
485 actionContactMenu = new KActionMenu(i18n("Co&ntacts"), coll);
486 coll->addAction(QStringLiteral("contacts_menu"), actionContactMenu);
487 actionContactMenu->setDelayed(false);
488 connect(actionContactMenu->menu(), SIGNAL(aboutToShow()), this, SLOT(slotPrepareContactMenu()));
489
490 KopeteStdAction::preferences(coll, "settings_prefs");
491
492 KToolBarSpacerAction *spacer = new KToolBarSpacerAction(coll);
493 coll->addAction(QStringLiteral("spacer"), spacer);
494
495 //The Sending movie
496 normalIcon = QPixmap(BarIcon(QStringLiteral("kopete")));
497
498 // we can't set the tool bar as parent, if we do, it will be deleted when we configure toolbars
499 anim = new QLabel(QString(), 0L);
500 anim->setObjectName(QStringLiteral("kde toolbar widget"));
501 anim->setMargin(5);
502 anim->setPixmap(normalIcon);
503
504 animIcon = KIconLoader::global()->loadMovie(QStringLiteral("newmessage"), KIconLoader::Toolbar);
505 if (animIcon) {
506 animIcon->setPaused(true);
507 }
508
509 QWidgetAction *animAction = new QWidgetAction(coll);
510 animAction->setText(i18n("Toolbar Animation"));
511 animAction->setDefaultWidget(anim);
512 coll->addAction(QStringLiteral("toolbar_animation"), animAction);
513
514 //toolBar()->insertWidget( 99, anim->width(), anim );
515 //toolBar()->alignItemRight( 99 );
516 }
517
518 /*
519 const QString KopeteChatWindow::fileContents( const QString &path ) const
520 {
521 QString contents;
522 QFile file( path );
523 if ( file.open( QIODevice::ReadOnly ) )
524 {
525 QTextStream stream( &file );
526 contents = stream.readAll();
527 file.close();
528 }
529
530 return contents;
531 }
532 */
slotStopAnimation(ChatView * view)533 void KopeteChatWindow::slotStopAnimation(ChatView *view)
534 {
535 if (view == m_activeView) {
536 anim->setPixmap(normalIcon);
537 if (animIcon && animIcon->state() == QMovie::Running) {
538 animIcon->setPaused(true);
539 }
540 }
541 }
542
slotUpdateSendEnabled()543 void KopeteChatWindow::slotUpdateSendEnabled()
544 {
545 if (!m_activeView) {
546 return;
547 }
548
549 bool enabled = m_activeView->canSend();
550 chatSend->setEnabled(enabled);
551 if (m_button_send) {
552 m_button_send->setEnabled(enabled);
553 }
554 }
555
updateChatSendFileAction()556 void KopeteChatWindow::updateChatSendFileAction()
557 {
558 if (!m_activeView) {
559 return;
560 }
561
562 chatSendFile->setEnabled(m_activeView->canSendFile());
563 }
564
toggleAutoSpellChecking()565 void KopeteChatWindow::toggleAutoSpellChecking()
566 {
567 if (!m_activeView) {
568 return;
569 }
570
571 bool currentSetting = m_activeView->editPart()->checkSpellingEnabled();
572 m_activeView->editPart()->setCheckSpellingEnabled(!currentSetting);
573 updateSpellCheckAction();
574 }
575
updateSpellCheckAction()576 void KopeteChatWindow::updateSpellCheckAction()
577 {
578 if (!m_activeView) {
579 return;
580 }
581
582 bool currentSetting = m_activeView->editPart()->checkSpellingEnabled();
583 toggleAutoSpellCheck->setChecked(currentSetting);
584 }
585
enableSpellCheckAction(bool enable)586 void KopeteChatWindow::enableSpellCheckAction(bool enable)
587 {
588 toggleAutoSpellCheck->setChecked(enable);
589 }
590
updateActions()591 void KopeteChatWindow::updateActions()
592 {
593 updateSpellCheckAction();
594 updateChatSendFileAction();
595 }
596
slotHistoryUp()597 void KopeteChatWindow::slotHistoryUp()
598 {
599 if (m_activeView) {
600 m_activeView->editPart()->historyUp();
601 }
602 }
603
slotHistoryDown()604 void KopeteChatWindow::slotHistoryDown()
605 {
606 if (m_activeView) {
607 m_activeView->editPart()->historyDown();
608 }
609 }
610
slotPageUp()611 void KopeteChatWindow::slotPageUp()
612 {
613 if (m_activeView) {
614 m_activeView->messagePart()->pageUp();
615 }
616 }
617
slotPageDown()618 void KopeteChatWindow::slotPageDown()
619 {
620 if (m_activeView) {
621 m_activeView->messagePart()->pageDown();
622 }
623 }
624
slotCut()625 void KopeteChatWindow::slotCut()
626 {
627 m_activeView->cut();
628 }
629
slotCopy()630 void KopeteChatWindow::slotCopy()
631 {
632 m_activeView->copy();
633 }
634
slotPaste()635 void KopeteChatWindow::slotPaste()
636 {
637 m_activeView->paste();
638 }
639
slotResetFontAndColor()640 void KopeteChatWindow::slotResetFontAndColor()
641 {
642 m_activeView->resetFontAndColor();
643 }
644
setStatus(const QString & text)645 void KopeteChatWindow::setStatus(const QString &text)
646 {
647 m_status_text->setText(text);
648 }
649
testCanDecode(const QDragMoveEvent * event,bool & accept)650 void KopeteChatWindow::testCanDecode(const QDragMoveEvent *event, bool &accept)
651 {
652 if (m_tabBar && qobject_cast<KTabBar *>(m_tabBar->childAt(event->pos()))
653 && chatViewList[static_cast<KTabBar *>(m_tabBar->childAt(event->pos()))->selectTab(event->pos())]->isDragEventAccepted(event)) {
654 accept = true;
655 } else {
656 accept = false;
657 }
658 }
659
receivedDropEvent(QWidget * w,QDropEvent * e)660 void KopeteChatWindow::receivedDropEvent(QWidget *w, QDropEvent *e)
661 {
662 m_tabBar->setCurrentWidget(w);
663 activeView()->dropEvent(e);
664 }
665
createTabBar()666 void KopeteChatWindow::createTabBar()
667 {
668 if (!m_tabBar) {
669 KConfigGroup cg(KSharedConfig::openConfig(), QStringLiteral("ChatWindowSettings"));
670
671 m_tabBar = new KTabWidget(mainArea);
672 m_tabBar->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
673 m_tabBar->setTabsClosable(cg.readEntry(QStringLiteral("HoverClose"), true));
674 m_tabBar->setMovable(true);
675 m_tabBar->setAutomaticResizeTabs(true);
676 connect(m_tabBar, SIGNAL(closeRequest(QWidget*)), this, SLOT(slotCloseChat(QWidget*)));
677
678 m_UpdateChatLabel = cg.readEntry(QStringLiteral("ShowContactName"), true);
679
680 QToolButton *m_rightWidget = new QToolButton(m_tabBar);
681 connect(m_rightWidget, SIGNAL(clicked()), this, SLOT(slotChatClosed()));
682 m_rightWidget->setIcon(SmallIcon("tab-close"));
683 m_rightWidget->adjustSize();
684 m_rightWidget->setToolTip(i18nc("@info:tooltip", "Close the current tab"));
685 m_tabBar->setCornerWidget(m_rightWidget, Qt::TopRightCorner);
686
687 mainLayout->addWidget(m_tabBar);
688 m_tabBar->show();
689
690 for (ChatViewList::iterator it = chatViewList.begin(); it != chatViewList.end(); ++it) {
691 addTab(*it);
692 }
693
694 connect(m_tabBar, SIGNAL(testCanDecode(const QDragMoveEvent*,bool&)), this, SLOT(testCanDecode(const QDragMoveEvent*,bool&)));
695 connect(m_tabBar, SIGNAL(receivedDropEvent(QWidget*,QDropEvent*)), this, SLOT(receivedDropEvent(QWidget*,QDropEvent*)));
696 connect(m_tabBar, SIGNAL(currentChanged(QWidget*)), this, SLOT(setActiveView(QWidget*)));
697 connect(m_tabBar, SIGNAL(contextMenu(QWidget*,QPoint)), this, SLOT(slotTabContextMenu(QWidget*,QPoint)));
698
699 if (m_activeView) {
700 m_tabBar->setCurrentWidget(m_activeView);
701 } else {
702 setActiveView(chatViewList.first());
703 }
704
705 int tabPosition = cg.readEntry(QStringLiteral("Tab Placement"), 0);
706
707 QAction action(this);
708 action.setData(tabPosition);
709 slotPlaceTabs(&action);
710 }
711 }
712
slotCloseChat(QWidget * chatView)713 void KopeteChatWindow::slotCloseChat(QWidget *chatView)
714 {
715 static_cast<ChatView *>(chatView)->closeView();
716 //FIXME: check if we need to remove from the chatViewList
717 }
718
addTab(ChatView * view)719 void KopeteChatWindow::addTab(ChatView *view)
720 {
721 QList<Kopete::Contact *> chatMembers = view->msgManager()->members();
722 Kopete::Contact *c = nullptr;
723 foreach (Kopete::Contact *contact, chatMembers) {
724 if (!c || c->onlineStatus() < contact->onlineStatus()) {
725 c = contact;
726 }
727 }
728 QIcon pluginIcon = c ? view->msgManager()->contactOnlineStatus(c).iconFor(c)
729 : QIcon::fromTheme(view->msgManager()->protocol()->pluginIcon());
730
731 view->setParent(m_tabBar);
732 view->setWindowFlags(0);
733 view->move(QPoint());
734 view->show();
735
736 m_tabBar->addTab(view, pluginIcon, QLatin1String(""));
737 view->setVisible(view == m_activeView);
738 connect(view, SIGNAL(updateStatusIcon(ChatView*)), this, SLOT(slotUpdateCaptionIcons(ChatView*)));
739
740 if (m_UpdateChatLabel) {
741 connect(view, SIGNAL(captionChanged(bool)), this, SLOT(updateChatLabel()));
742 view->setCaption(view->caption(), false);
743 }
744 }
745
setPrimaryChatView(ChatView * view)746 void KopeteChatWindow::setPrimaryChatView(ChatView *view)
747 {
748 //TODO figure out what else we have to save here besides the font
749 //reparent clears a lot of stuff out
750 view->setParent(mainArea);
751 view->setWindowFlags(0);
752 view->move(QPoint());
753 view->show();
754
755 mainLayout->addWidget(view);
756 setActiveView(view);
757 }
758
deleteTabBar()759 void KopeteChatWindow::deleteTabBar()
760 {
761 if (m_tabBar) {
762 disconnect(m_tabBar, SIGNAL(currentChanged(QWidget*)), this, SLOT(setActiveView(QWidget*)));
763 disconnect(m_tabBar, SIGNAL(contextMenu(QWidget*,QPoint)), this, SLOT(slotTabContextMenu(QWidget*,QPoint)));
764
765 if (!chatViewList.isEmpty()) {
766 setPrimaryChatView(chatViewList.first());
767 }
768
769 m_tabBar->deleteLater();
770 m_tabBar = nullptr;
771 }
772 }
773
attachChatView(ChatView * newView)774 void KopeteChatWindow::attachChatView(ChatView *newView)
775 {
776 chatViewList.append(newView);
777
778 if (!m_alwaysShowTabs && chatViewList.count() == 1) {
779 setPrimaryChatView(newView);
780 } else {
781 if (!m_tabBar) {
782 createTabBar();
783 } else {
784 addTab(newView);
785 }
786 newView->setActive(false);
787 }
788
789 newView->setMainWindow(this);
790 newView->editWidget()->installEventFilter(this);
791
792 KCursor::setAutoHideCursor(newView->editWidget(), true, true);
793 connect(newView, SIGNAL(captionChanged(bool)), this, SLOT(slotSetCaption(bool)));
794 connect(newView, SIGNAL(messageSuccess(ChatView*)), this, SLOT(slotStopAnimation(ChatView*)));
795 connect(newView, SIGNAL(updateStatusIcon(ChatView*)), this, SLOT(slotUpdateCaptionIcons(ChatView*)));
796
797 if (m_UpdateChatLabel) {
798 connect(newView, SIGNAL(updateChatState(ChatView*,int)), this, SLOT(updateChatState(ChatView*,int)));
799 }
800
801 updateActions();
802 checkDetachEnable();
803 connect(newView, SIGNAL(autoSpellCheckEnabled(ChatView*,bool)),
804 this, SLOT(slotAutoSpellCheckEnabled(ChatView*,bool)));
805 }
806
checkDetachEnable()807 void KopeteChatWindow::checkDetachEnable()
808 {
809 bool haveTabs = (chatViewList.count() > 1);
810 tabCloseAllOthers->setEnabled(haveTabs);
811 tabDetach->setEnabled(haveTabs);
812 tabLeft->setEnabled(haveTabs);
813 tabRight->setEnabled(haveTabs);
814 tabActive->setEnabled(haveTabs);
815 actionTabPlacementMenu->setEnabled(m_tabBar != 0);
816
817 bool otherWindows = (windows.count() > 1);
818 actionDetachMenu->setEnabled(otherWindows);
819 }
820
detachChatView(ChatView * view)821 void KopeteChatWindow::detachChatView(ChatView *view)
822 {
823 chatViewList.removeAt(chatViewList.indexOf(view));
824
825 disconnect(view, SIGNAL(captionChanged(bool)), this, SLOT(slotSetCaption(bool)));
826 disconnect(view, SIGNAL(updateStatusIcon(ChatView*)), this, SLOT(slotUpdateCaptionIcons(ChatView*)));
827 disconnect(view, SIGNAL(updateChatState(ChatView*,int)), this, SLOT(updateChatState(ChatView*,int)));
828 view->editWidget()->removeEventFilter(this);
829
830 if (m_tabBar) {
831 int curPage = m_tabBar->currentIndex();
832 QWidget *page = m_tabBar->currentWidget();
833
834 // if the current view is to be detached, switch to a different one
835 if (page == view) {
836 if (curPage > 0) {
837 m_tabBar->setCurrentIndex(curPage - 1);
838 } else {
839 m_tabBar->setCurrentIndex(curPage + 1);
840 }
841 }
842
843 m_tabBar->removePage(view);
844
845 if (m_tabBar->currentWidget()) {
846 setActiveView(static_cast<ChatView *>(m_tabBar->currentWidget()));
847 }
848 }
849
850 if (m_activeView == view) {
851 m_activeView = 0;
852 }
853
854 if (chatViewList.isEmpty()) {
855 close();
856 } else if (!m_alwaysShowTabs && chatViewList.count() == 1) {
857 deleteTabBar();
858 }
859
860 checkDetachEnable();
861 }
862
slotDetachChat(QAction * action)863 void KopeteChatWindow::slotDetachChat(QAction *action)
864 {
865 KopeteChatWindow *newWindow = nullptr;
866 ChatView *detachedView;
867
868 if (m_popupView) {
869 detachedView = m_popupView;
870 } else {
871 detachedView = m_activeView;
872 }
873
874 if (!detachedView) {
875 return;
876 }
877
878 //if we don't do this, we might crash
879 createGUI(nullptr);
880 guiFactory()->removeClient(detachedView->msgManager());
881
882 if (!action) {
883 newWindow = new KopeteChatWindow(detachedView->msgManager()->form());
884 newWindow->setObjectName(QStringLiteral("KopeteChatWindow"));
885 } else {
886 newWindow = windows.at(action->data().toInt());
887 }
888
889 newWindow->show();
890 newWindow->raise();
891
892 detachChatView(detachedView);
893 newWindow->attachChatView(detachedView);
894 }
895
slotCloseAllOtherTabs()896 void KopeteChatWindow::slotCloseAllOtherTabs()
897 {
898 ChatView *detachedView;
899
900 if (m_popupView) {
901 detachedView = m_popupView;
902 } else {
903 detachedView = m_activeView;
904 }
905
906 foreach (ChatView *view, chatViewList) {
907 if (view != detachedView) {
908 view->closeView();
909 }
910 }
911 }
912
slotPreviousTab()913 void KopeteChatWindow::slotPreviousTab()
914 {
915 int curPage = m_tabBar->currentIndex();
916 if (curPage > 0) {
917 m_tabBar->setCurrentIndex(curPage - 1);
918 } else {
919 m_tabBar->setCurrentIndex(m_tabBar->count() - 1);
920 }
921 }
922
slotNextTab()923 void KopeteChatWindow::slotNextTab()
924 {
925 int curPage = m_tabBar->currentIndex();
926 if (curPage == (m_tabBar->count() - 1)) {
927 m_tabBar->setCurrentIndex(0);
928 } else {
929 m_tabBar->setCurrentIndex(curPage + 1);
930 }
931 }
932
slotNextActiveTab()933 void KopeteChatWindow::slotNextActiveTab()
934 {
935 int curPage = m_tabBar->currentIndex();
936 for (int i = (curPage+1) % m_tabBar->count(); i != curPage; i = (i+1) % m_tabBar->count()) {
937 ChatView *v = static_cast<ChatView *>(m_tabBar->widget(i)); //We assume we only have ChatView's
938 if (v->tabState() == ChatView::Highlighted || v->tabState() == ChatView::Message) {
939 m_tabBar->setCurrentIndex(i);
940 break;
941 }
942 }
943 }
944
slotSetCaption(bool active)945 void KopeteChatWindow::slotSetCaption(bool active)
946 {
947 if (active && m_activeView) {
948 setCaption(m_activeView->caption(), false);
949 }
950 }
951
updateBackground(const QPixmap & pm)952 void KopeteChatWindow::updateBackground(const QPixmap &pm)
953 {
954 if (updateBg) {
955 updateBg = false;
956 delete backgroundFile;
957
958 backgroundFile = new KTemporaryFile();
959 backgroundFile->setSuffix(QStringLiteral(".bmp"));
960 backgroundFile->open();
961 pm.save(backgroundFile, "BMP");
962 QTimer::singleShot(100, this, SLOT(slotEnableUpdateBg()));
963 }
964 }
965
setActiveView(QWidget * widget)966 void KopeteChatWindow::setActiveView(QWidget *widget)
967 {
968 ChatView *view = static_cast<ChatView *>(widget);
969
970 if (m_activeView == view) {
971 return;
972 }
973
974 if (m_activeView) {
975 disconnect(m_activeView->editWidget(), SIGNAL(checkSpellingChanged(bool)), this, SLOT(enableSpellCheckAction(bool)));
976 disconnect(m_activeView, SIGNAL(canSendChanged(bool)), this, SLOT(slotUpdateSendEnabled()));
977 disconnect(m_activeView, SIGNAL(canAcceptFilesChanged()), this, SLOT(updateChatSendFileAction()));
978 guiFactory()->removeClient(m_activeView->msgManager());
979 m_activeView->saveChatSettings();
980 }
981
982 if (view != 0) {
983 guiFactory()->addClient(view->msgManager());
984 }
985 // createGUI( view->editPart() );
986
987 if (m_activeView) {
988 m_activeView->setActive(false);
989 }
990
991 m_activeView = view;
992
993 if (view == 0) {
994 return;
995 }
996
997 if (chatViewList.indexOf(view) == -1) {
998 attachChatView(view);
999 }
1000
1001 connect(m_activeView->editWidget(), SIGNAL(checkSpellingChanged(bool)), this, SLOT(enableSpellCheckAction(bool)));
1002 connect(m_activeView, SIGNAL(canSendChanged(bool)), this, SLOT(slotUpdateSendEnabled()));
1003 connect(m_activeView, SIGNAL(canAcceptFilesChanged()), this, SLOT(updateChatSendFileAction()));
1004
1005 //Tell it it is active
1006 m_activeView->setActive(true);
1007
1008 //Update icons to match
1009 slotUpdateCaptionIcons(m_activeView);
1010
1011 if (m_activeView->sendInProgress() && animIcon) {
1012 anim->setMovie(animIcon);
1013 animIcon->setPaused(false);
1014 } else {
1015 anim->setPixmap(normalIcon);
1016 if (animIcon) {
1017 animIcon->setPaused(true);
1018 }
1019 }
1020
1021 if (m_alwaysShowTabs || chatViewList.count() > 1) {
1022 if (!m_tabBar) {
1023 createTabBar();
1024 }
1025
1026 m_tabBar->setCurrentWidget(m_activeView);
1027 }
1028
1029 setCaption(m_activeView->caption());
1030 setStatus(m_activeView->statusText());
1031 m_activeView->setFocus();
1032 updateActions();
1033 slotUpdateSendEnabled();
1034 m_activeView->loadChatSettings();
1035 updateSendKeySequence();
1036
1037 emit chatSessionChanged(m_activeView->msgManager());
1038 }
1039
slotUpdateCaptionIcons(ChatView * view)1040 void KopeteChatWindow::slotUpdateCaptionIcons(ChatView *view)
1041 {
1042 if (!view) {
1043 return; //(pas de charité)
1044 }
1045 QList<Kopete::Contact *> chatMembers = view->msgManager()->members();
1046 Kopete::Contact *c = nullptr;
1047 foreach (Kopete::Contact *contact, chatMembers) {
1048 if (!c || c->onlineStatus() < contact->onlineStatus()) {
1049 c = contact;
1050 }
1051 }
1052
1053 if (view == m_activeView) {
1054 setWindowIcon(c ? view->msgManager()->contactOnlineStatus(c).iconFor(c)
1055 : QIcon::fromTheme(view->msgManager()->protocol()->pluginIcon()));
1056 }
1057
1058 if (m_tabBar) {
1059 m_tabBar->setTabIcon(m_tabBar->indexOf(view), c ? view->msgManager()->contactOnlineStatus(c).iconFor(c)
1060 : QIcon::fromTheme(view->msgManager()->protocol()->pluginIcon()));
1061 }
1062 }
1063
slotChatClosed()1064 void KopeteChatWindow::slotChatClosed()
1065 {
1066 if (m_popupView) {
1067 m_popupView->closeView();
1068 } else {
1069 m_activeView->closeView();
1070 }
1071 }
1072
slotPrepareDetachMenu(void)1073 void KopeteChatWindow::slotPrepareDetachMenu(void)
1074 {
1075 QMenu *detachMenu = actionDetachMenu->menu();
1076 detachMenu->clear();
1077
1078 QAction *action;
1079 for (int id = 0; id < windows.count(); id++) {
1080 KopeteChatWindow *win = windows.at(id);
1081 if (win != this) {
1082 action = detachMenu->addAction(win->windowIcon(), win->windowTitle());
1083 action->setData(id);
1084 }
1085 }
1086 }
1087
slotSendMessage()1088 void KopeteChatWindow::slotSendMessage()
1089 {
1090 if (m_activeView && m_activeView->canSend()) {
1091 if (animIcon) {
1092 anim->setMovie(animIcon);
1093 animIcon->setPaused(false);
1094 }
1095 m_activeView->sendMessage();
1096 }
1097 }
1098
slotSendFile()1099 void KopeteChatWindow::slotSendFile()
1100 {
1101 if (m_activeView) {
1102 m_activeView->sendFile();
1103 }
1104 }
1105
slotPrepareContactMenu(void)1106 void KopeteChatWindow::slotPrepareContactMenu(void)
1107 {
1108 QMenu *contactsMenu = actionContactMenu->menu();
1109 contactsMenu->clear();
1110
1111 Kopete::ContactPtrList m_them;
1112
1113 if (m_popupView) {
1114 m_them = m_popupView->msgManager()->members();
1115 } else {
1116 m_them = m_activeView->msgManager()->members();
1117 }
1118
1119 //TODO: don't display a menu with one contact in it, display that
1120 // contact's menu instead. Will require changing text and icon of
1121 // 'Contacts' action, or something cleverer.
1122 uint contactCount = 0;
1123
1124 foreach (Kopete::Contact *contact, m_them) {
1125 QMenu *p = contact->popupMenu();
1126 connect(actionContactMenu->menu(), SIGNAL(aboutToHide()),
1127 p, SLOT(deleteLater()));
1128
1129 p->setIcon(contact->onlineStatus().iconFor(contact));
1130 if (contact->metaContact()) {
1131 p->setTitle(contact->metaContact()->displayName());
1132 } else {
1133 p->setTitle(contact->contactId());
1134 }
1135
1136 contactsMenu->addMenu(p);
1137
1138 //FIXME: This number should be a config option
1139 if (++contactCount == 15 && contact != m_them.last()) {
1140 KActionMenu *moreMenu = new KActionMenu(QIcon::fromTheme(QStringLiteral("folder-open")), i18n("More..."), this);
1141 connect(actionContactMenu->menu(), SIGNAL(aboutToHide()),
1142 moreMenu, SLOT(deleteLater()));
1143 contactsMenu->addAction(moreMenu);
1144 contactsMenu = moreMenu->menu();
1145 contactCount = 0;
1146 }
1147 }
1148 }
1149
slotPreparePlacementMenu()1150 void KopeteChatWindow::slotPreparePlacementMenu()
1151 {
1152 QMenu *placementMenu = actionTabPlacementMenu->menu();
1153 placementMenu->clear();
1154
1155 QAction *action;
1156 action = placementMenu->addAction(i18n("Top"));
1157 action->setData(0);
1158
1159 action = placementMenu->addAction(i18n("Bottom"));
1160 action->setData(1);
1161
1162 action = placementMenu->addAction(i18n("Left"));
1163 action->setData(2);
1164
1165 action = placementMenu->addAction(i18n("Right"));
1166 action->setData(3);
1167 }
1168
slotPlaceTabs(QAction * action)1169 void KopeteChatWindow::slotPlaceTabs(QAction *action)
1170 {
1171 int placement = action->data().toInt();
1172
1173 if (m_tabBar) {
1174 switch (placement) {
1175 case 1:
1176 m_tabBar->setTabPosition(QTabWidget::South);
1177 break;
1178 case 2:
1179 m_tabBar->setTabPosition(QTabWidget::West);
1180 break;
1181 case 3:
1182 m_tabBar->setTabPosition(QTabWidget::East);
1183 break;
1184 default:
1185 m_tabBar->setTabPosition(QTabWidget::North);
1186 }
1187 saveOptions();
1188 }
1189 }
1190
readOptions()1191 void KopeteChatWindow::readOptions()
1192 {
1193 // load and apply config file settings affecting the appearance of the UI
1194 // kDebug(14010) ;
1195 applyMainWindowSettings(KSharedConfig::openConfig()->group((initialForm
1196 == Kopete::ChatSession::Chatroom ? QStringLiteral("KopeteChatWindowGroupMode") : QStringLiteral("KopeteChatWindowIndividualMode"))));
1197 //config->setGroup( QLatin1String("ChatWindowSettings") );
1198 }
1199
saveOptions()1200 void KopeteChatWindow::saveOptions()
1201 {
1202 // kDebug(14010) ;
1203
1204 KConfigGroup kopeteChatWindowMainWinSettings(KSharedConfig::openConfig(), (initialForm == Kopete::ChatSession::Chatroom ? QStringLiteral("KopeteChatWindowGroupMode") : QStringLiteral(
1205 "KopeteChatWindowIndividualMode")));
1206
1207 // saves menubar,toolbar and statusbar setting
1208 saveMainWindowSettings(kopeteChatWindowMainWinSettings);
1209 if (m_tabBar) {
1210 KConfigGroup chatWindowSettings(KSharedConfig::openConfig(), QStringLiteral("ChatWindowSettings"));
1211 chatWindowSettings.writeEntry(QStringLiteral("Tab Placement"), (int)m_tabBar->tabPosition());
1212 chatWindowSettings.sync();
1213 }
1214 kopeteChatWindowMainWinSettings.sync();
1215 }
1216
slotChatSave()1217 void KopeteChatWindow::slotChatSave()
1218 {
1219 // kDebug(14010) << "KopeteChatWindow::slotChatSave()";
1220 if (isActiveWindow() && m_activeView) {
1221 m_activeView->messagePart()->save();
1222 }
1223 }
1224
changeEvent(QEvent * e)1225 void KopeteChatWindow::changeEvent(QEvent *e)
1226 {
1227 if (e->type() == QEvent::ActivationChange && isActiveWindow() && m_activeView) {
1228 m_activeView->setActive(true);
1229 }
1230 }
1231
slotChatPrint()1232 void KopeteChatWindow::slotChatPrint()
1233 {
1234 m_activeView->messagePart()->print();
1235 }
1236
slotSmileyActivated(const QString & sm)1237 void KopeteChatWindow::slotSmileyActivated(const QString &sm)
1238 {
1239 if (!sm.isNull()) {
1240 m_activeView->addText(' ' + sm + ' ');
1241 }
1242 //we are adding space around the emoticon becasue our parser only display emoticons not in a word.
1243 }
1244
slotAutoSpellCheckEnabled(ChatView * view,bool isEnabled)1245 void KopeteChatWindow::slotAutoSpellCheckEnabled(ChatView *view, bool isEnabled)
1246 {
1247 if (view != m_activeView) {
1248 return;
1249 }
1250
1251 toggleAutoSpellCheck->setChecked(isEnabled);
1252 m_activeView->editPart()->setCheckSpellingEnabled(isEnabled);
1253 }
1254
queryClose()1255 bool KopeteChatWindow::queryClose()
1256 {
1257 #ifdef CHRONO
1258 QTime chrono;
1259 chrono.start();
1260 #endif
1261 bool canClose = true;
1262
1263 // kDebug( 14010 ) << " Windows left open:";
1264 // for( QPtrListIterator<ChatView> it( chatViewList ); it; ++it)
1265 // kDebug( 14010 ) << " " << *it << " (" << (*it)->caption() << ")";
1266 setUpdatesEnabled(false);//hide the crazyness from users
1267 while (!chatViewList.isEmpty())
1268 {
1269 ChatView *view = chatViewList.takeFirst();
1270
1271 // FIXME: This should only check if it *can* close
1272 // and not start closing if the close can be aborted halfway, it would
1273 // leave us with half the chats open and half of them closed. - Martijn
1274
1275 // if the view is closed, it is removed from chatViewList for us
1276 if (!view->closeView()) {
1277 qDebug() << "Closing view failed!";
1278 canClose = false;
1279 }
1280 }
1281 setUpdatesEnabled(true);
1282 #ifdef CHRONO
1283 qDebug()<<"TIME: "<<chrono.elapsed();
1284 #endif
1285 return canClose;
1286 }
1287
queryExit()1288 bool KopeteChatWindow::queryExit()
1289 {
1290 KopeteApplication *app = static_cast<KopeteApplication *>(qApp);
1291 if (app->isSavingSession()
1292 || app->isShuttingDown() /* only set if KopeteApplication::quitKopete() or
1293 KopeteApplication::commitData() called */
1294 || !Kopete::BehaviorSettings::self()->showSystemTray() /* also close if our tray icon is hidden! */
1295 || isHidden()) {
1296 Kopete::PluginManager::self()->shutdown();
1297 return true;
1298 } else {
1299 return false;
1300 }
1301 }
1302
closeEvent(QCloseEvent * e)1303 void KopeteChatWindow::closeEvent(QCloseEvent *e)
1304 {
1305 // if there's a system tray applet and we are not shutting down then just do what needs to be done if a
1306 // window is closed.
1307 KopeteApplication *app = static_cast<KopeteApplication *>(qApp);
1308 if (Kopete::BehaviorSettings::self()->showSystemTray() && !app->isShuttingDown() && !app->isSavingSession()) {
1309 // hide();
1310 // BEGIN of code borrowed from KMainWindow::closeEvent
1311 // Save settings if auto-save is enabled, and settings have changed
1312 if (settingsDirty() && autoSaveSettings()) {
1313 saveAutoSaveSettings();
1314 }
1315
1316 if (queryClose()) {
1317 e->accept();
1318 } else {
1319 e->ignore();
1320 }
1321 // END of code borrowed from KMainWindow::closeEvent
1322 } else {
1323 KXmlGuiWindow::closeEvent(e);
1324 }
1325 }
1326
updateChatState(ChatView * cv,int newState)1327 void KopeteChatWindow::updateChatState(ChatView *cv, int newState)
1328 {
1329 Q_UNUSED(cv);
1330
1331 if (m_tabBar) {
1332 KColorScheme scheme(QPalette::Active, KColorScheme::Window);
1333 switch (newState) {
1334 case ChatView::Highlighted:
1335 m_tabBar->setTabTextColor(m_tabBar->indexOf(cv), scheme.foreground(KColorScheme::LinkText).color());
1336 break;
1337 case ChatView::Message:
1338 m_tabBar->setTabTextColor(m_tabBar->indexOf(cv), scheme.foreground(KColorScheme::ActiveText).color());
1339 break;
1340 case ChatView::Changed:
1341 m_tabBar->setTabTextColor(m_tabBar->indexOf(cv), scheme.foreground(KColorScheme::NeutralText).color());
1342 break;
1343 case ChatView::Typing:
1344 m_tabBar->setTabTextColor(m_tabBar->indexOf(cv), scheme.foreground(KColorScheme::PositiveText).color());
1345 break;
1346 case ChatView::Normal:
1347 default:
1348 m_tabBar->setTabTextColor(m_tabBar->indexOf(cv), scheme.foreground(KColorScheme::NormalText).color());
1349 break;
1350 }
1351 }
1352 }
1353
updateChatTooltip(ChatView * cv)1354 void KopeteChatWindow::updateChatTooltip(ChatView *cv)
1355 {
1356 if (m_tabBar) {
1357 m_tabBar->setTabToolTip(m_tabBar->indexOf(cv), QStringLiteral("<qt>%1</qt>").arg(cv->caption()));
1358 }
1359 }
1360
updateChatLabel()1361 void KopeteChatWindow::updateChatLabel()
1362 {
1363 ChatView *chat = dynamic_cast<ChatView *>(sender());
1364 if (!chat || !m_tabBar) {
1365 return;
1366 }
1367
1368 if (m_tabBar) {
1369 m_tabBar->setTabText(m_tabBar->indexOf(chat), chat->caption());
1370 if (m_tabBar->count() < 2 || m_tabBar->currentWidget() == chat) {
1371 setCaption(chat->caption());
1372 }
1373 }
1374 }
1375
resizeEvent(QResizeEvent * e)1376 void KopeteChatWindow::resizeEvent(QResizeEvent *e)
1377 {
1378 KXmlGuiWindow::resizeEvent(e);
1379 if (m_activeView && m_activeView->messagePart()) {
1380 m_activeView->messagePart()->keepScrolledDown();
1381 }
1382 }
1383
eventFilter(QObject * obj,QEvent * event)1384 bool KopeteChatWindow::eventFilter(QObject *obj, QEvent *event)
1385 {
1386 if (m_activeView && obj == m_activeView->editWidget() && event->type() == QEvent::KeyPress) {
1387 KShortcut *eventFilterShortcut = new KShortcut(nickComplete->shortcut());
1388 QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
1389 if (eventFilterShortcut->primary() == QKeySequence(keyEvent->key())) {
1390 m_activeView->nickComplete();
1391 return true;
1392 }
1393 }
1394 return KXmlGuiWindow::eventFilter(obj, event);
1395 }
1396
1397 // vim: set noet ts=4 sts=4 sw=4:
1398