kopetechatwindow.cpp 40.1 KB
Newer Older
1 2 3
/*
    kopetechatwindow.cpp - Chat Window

4
    Copyright (c) 2008      by Benson Tsai           <btsai@vrwarp.com>
Gustavo P. Boiko's avatar
Gustavo P. Boiko committed
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 17 18 19 20 21 22 23

    *************************************************************************
    *                                                                       *
    * This program is free software; you can redistribute it and/or modify  *
    * it under the terms of the GNU General Public License as published by  *
    * the Free Software Foundation; either version 2 of the License, or     *
    * (at your option) any later version.                                   *
    *                                                                       *
    *************************************************************************
*/

24 25
#include "kopetechatwindow.h"

26 27
#include <QMenu>
#include <QIcon>
R. Harish Navnit's avatar
R. Harish Navnit committed
28 29 30 31
#include <QTimer>
#include <QFrame>
#include <QLabel>
#include <QPixmap>
32 33 34
#include <QLayout>
#include <QDockWidget>
#include <QTextStream>
R. Harish Navnit's avatar
R. Harish Navnit committed
35 36
#include <QCloseEvent>
#include <QVBoxLayout>
37

38 39 40 41
#ifdef CHRONO
#include <QTime>
#endif

David Faure's avatar
David Faure committed
42
#include <kactioncollection.h>
43 44 45 46 47 48
#include <kcursor.h>
#include <klocale.h>
#include <kmenubar.h>
#include <kconfig.h>
#include <kiconloader.h>
#include <kdebug.h>
Luboš Luňák's avatar
Luboš Luňák committed
49
#include <kwindowsystem.h>
Jaison Lee's avatar
Jaison Lee committed
50
#include <ktemporaryfile.h>
51
#include <kedittoolbar.h>
52
#include <kstatusbar.h>
53
#include <kpushbutton.h>
Olivier Goffart's avatar
Olivier Goffart committed
54
#include <ktabwidget.h>
55
#include <kdialog.h>
56
#include <kstringhandler.h>
57
#include <ksqueezedtextlabel.h>
Aaron J. Seigo's avatar
build  
Aaron J. Seigo committed
58
#include <kstandardshortcut.h>
59
#include <kglobalsettings.h>
60
#include <kcolorscheme.h>
Urs Wolfer's avatar
Urs Wolfer committed
61 62
#include <khbox.h>
#include <kvbox.h>
63
#include <ktoolbar.h>
64
#include <KShortcut>
Aaron J. Seigo's avatar
Aaron J. Seigo committed
65
#include <kstandardaction.h>
66 67
#include <ktoggleaction.h>
#include <kactionmenu.h>
68
#include <ktoolbarspaceraction.h>
69

70
#include "chatmessagepart.h"
71
#include "chattexteditpart.h"
72
#include "chatview.h"
73
#include "kopeteapplication.h"
74
#include "kopetebehaviorsettings.h"
75 76
#include "kopeteemoticonaction.h"
#include "kopetegroup.h"
77
#include "kopetechatsession.h"
78 79 80 81
#include "kopetemetacontact.h"
#include "kopetepluginmanager.h"
#include "kopeteprotocol.h"
#include "kopetestdaction.h"
82
#include "kopeteviewmanager.h"
83 84
#include "chatmemberslistview.h"
#include "chatsessionmemberslistmodel.h"
85

Matt Rogers's avatar
Matt Rogers committed
86
#include <qtoolbutton.h>
Olivier Goffart's avatar
compile  
Olivier Goffart committed
87
#include <kxmlguifactory.h>
88
#include <KTabBar>
Jason Keirstead's avatar
Jason Keirstead committed
89

Richard Smith's avatar
Richard Smith committed
90 91 92
typedef QMap<Kopete::Account*,KopeteChatWindow*> AccountMap;
typedef QMap<Kopete::Group*,KopeteChatWindow*> GroupMap;
typedef QMap<Kopete::MetaContact*,KopeteChatWindow*> MetaContactMap;
Gustavo P. Boiko's avatar
Gustavo P. Boiko committed
93
typedef QList<KopeteChatWindow*> WindowList;
94

95 96
using Kopete::ChatSessionMembersListModel;

97 98
namespace
{
99
	AccountMap accountMap;
100
	GroupMap groupMap;
101
	MetaContactMap mcMap;
102 103 104
	WindowList windows;
}

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?
Richard Smith's avatar
Richard Smith committed
111
	Kopete::Group *group = 0L;
Richard Smith's avatar
Richard Smith committed
112
	Kopete::ContactPtrList members = manager->members();
Richard Smith's avatar
Richard Smith committed
113
	Kopete::MetaContact *metaContact = members.first()->metaContact();
114

115
	if ( metaContact )
116
	{
Richard Smith's avatar
Richard Smith committed
117
		Kopete::GroupList gList = metaContact->groups();
118
		group = gList.first();
119
	}
120

121
	switch( Kopete::BehaviorSettings::self()->chatWindowGroupPolicy() )
122
	{
123
		//Open chats from the same protocol in the same window
David Faure's avatar
David Faure committed
124
		case Kopete::BehaviorSettings::EnumChatWindowGroupPolicy::GroupByAccount:
125 126
			if( accountMap.contains( manager->account() ) )
				myWindow = accountMap[ manager->account() ];
127 128 129 130
			else
				windowCreated = true;
			break;

131
		//Open chats from the same group in the same window
David Faure's avatar
David Faure committed
132
		case Kopete::BehaviorSettings::EnumChatWindowGroupPolicy::GroupByGroup:
133 134
			if( group && groupMap.contains( group ) )
				myWindow = groupMap[ group ];
135 136 137
			else
				windowCreated = true;
			break;
138

139
		//Open chats from the same metacontact in the same window
David Faure's avatar
David Faure committed
140
		case Kopete::BehaviorSettings::EnumChatWindowGroupPolicy::GroupByMetaContact:
141 142
			if( mcMap.contains( metaContact ) )
				myWindow = mcMap[ metaContact ];
143 144 145
			else
				windowCreated = true;
			break;
146

147
		//Open all chats in the same window
David Faure's avatar
David Faure committed
148
		case Kopete::BehaviorSettings::EnumChatWindowGroupPolicy::GroupAll:
149 150 151 152
			if( windows.isEmpty() )
				windowCreated = true;
			else
			{
153 154 155
				//Here we are finding the window with the most tabs and
				//putting it there. Need this for the cases where config changes
				//midstream
156

157
				int viewCount = -1;
Gustavo P. Boiko's avatar
Gustavo P. Boiko committed
158 159
				WindowList::iterator it;
				for ( it = windows.begin(); it != windows.end(); ++it )
160
				{
Gustavo P. Boiko's avatar
Gustavo P. Boiko committed
161
					if( (*it)->chatViewCount() > viewCount )
162
					{
Gustavo P. Boiko's avatar
Gustavo P. Boiko committed
163 164
						myWindow = (*it);
						viewCount = (*it)->chatViewCount();
165 166 167 168
					}
				}
			}
			break;
169

170
		//Open every chat in a new window
David Faure's avatar
David Faure committed
171
		case Kopete::BehaviorSettings::EnumChatWindowGroupPolicy::OpenNewWindow:
172 173 174
		default:
			windowCreated = true;
			break;
175 176
	}

177
	if ( windowCreated )
178
	{
179
		myWindow = new KopeteChatWindow( manager->form() );
180

181
		if ( !accountMap.contains( manager->account() ) )
182
			accountMap.insert( manager->account(), myWindow );
183

184 185
		if ( !mcMap.contains( metaContact ) )
			mcMap.insert( metaContact, myWindow );
186

187 188
		if ( group && !groupMap.contains( group ) )
			groupMap.insert( group, myWindow );
189 190
	}

Thiago Macieira's avatar
Thiago Macieira committed
191
//	kDebug( 14010 ) << "Open Windows: " << windows.count();
192 193 194 195

	return myWindow;
}

196 197
KopeteChatWindow::KopeteChatWindow( Kopete::ChatSession::Form form, QWidget *parent  )
	: KXmlGuiWindow( parent ), initialForm( form )
198
{
199
#ifdef CHRONO
200
	QTime chrono;chrono.start();
201
#endif
202 203 204 205 206
	m_activeView = 0L;
	m_popupView = 0L;
	backgroundFile = 0L;
	updateBg = true;
	m_tabBar = 0L;
Jason Keirstead's avatar
Jason Keirstead committed
207

208
	m_participantsWidget = new QDockWidget(i18n("Participants"), this);
209
	m_participantsWidget->setAllowedAreas(Qt::RightDockWidgetArea | Qt::LeftDockWidgetArea);
210
	m_participantsWidget->setFeatures(QDockWidget::DockWidgetClosable);
211 212 213 214 215
	m_participantsWidget->setTitleBarWidget(0L);
	m_participantsWidget->setObjectName("Participants"); //object name is required for automatic position and settings save.

	ChatSessionMembersListModel *members_model = new ChatSessionMembersListModel(this);

Laurent Montel's avatar
Laurent Montel committed
216
	connect(this, SIGNAL(chatSessionChanged(Kopete::ChatSession*)), members_model, SLOT(setChatSession(Kopete::ChatSession*)));
217

218 219
	ChatMembersListView *chatmembers = new ChatMembersListView(m_participantsWidget);
	chatmembers->setModel(members_model);
220
	chatmembers->setWordWrap(true);
221
	m_participantsWidget->setWidget(chatmembers);
Matt Rogers's avatar
Matt Rogers committed
222 223
	initActions();

224
	addDockWidget(Qt::RightDockWidgetArea, m_participantsWidget);
David Faure's avatar
David Faure committed
225

Urs Wolfer's avatar
Urs Wolfer committed
226
	KVBox *vBox = new KVBox( this );
227 228
	vBox->setLineWidth( 0 );
	vBox->setSpacing( 0 );
Urs Wolfer's avatar
Urs Wolfer committed
229
	vBox->setFrameStyle( QFrame::NoFrame );
230
	// set default window size.  This could be removed by fixing the size hints of the contents
231 232 233 234 235 236
	if ( initialForm == Kopete::ChatSession::Chatroom ) {
		resize( 650, 400 );
	} else {
		m_participantsWidget->hide();
		resize( 400, 400 );
	}
237 238
	setCentralWidget( vBox );

Urs Wolfer's avatar
Urs Wolfer committed
239
	mainArea = new QFrame( vBox );
240 241 242
	mainArea->setLineWidth( 0 );
	mainArea->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) );
	mainLayout = new QVBoxLayout( mainArea );
243
	mainLayout->setContentsMargins(0, 4, 0, 0);
244

245
	if ( Kopete::BehaviorSettings::self()->chatWindowShowSendButton() )
246 247
	{
		//Send Button
248
		m_button_send = new KPushButton( i18nc("@action:button", "Send"), statusBar() );
249 250 251 252
		m_button_send->setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ) );
		m_button_send->setEnabled( false );
		m_button_send->setFont( statusBar()->font() );
		m_button_send->setFixedHeight( statusBar()->sizeHint().height() );
Laurent Montel's avatar
Laurent Montel committed
253
		connect( m_button_send, SIGNAL(clicked()), this, SLOT(slotSendMessage()) );
Thorben Kröger's avatar
Thorben Kröger committed
254
		statusBar()->addPermanentWidget( m_button_send, 0 );
255 256 257
	}
	else
		m_button_send = 0L;
258

259
	m_status_text = new KSqueezedTextLabel( i18nc("@info:status","Ready."), statusBar() );
Grzegorz Jaskiewicz's avatar
compile  
Grzegorz Jaskiewicz committed
260
	m_status_text->setAlignment( Qt::AlignLeft | Qt::AlignVCenter );
261 262 263
	m_status_text->setFont( statusBar()->font() );
	m_status_text->setFixedHeight( statusBar()->sizeHint().height() );
	statusBar()->addWidget( m_status_text, 1 );
264

265
	windows.append( this );
266
	windowListChanged();
267

268
	m_alwaysShowTabs = KSharedConfig::openConfig()->group( "ChatWindowSettings" ).
Stephan Kulow's avatar
ported  
Stephan Kulow committed
269
                           readEntry( QLatin1String("AlwaysShowTabs"), false );
Thiago Macieira's avatar
Thiago Macieira committed
270
//	kDebug( 14010 ) << "Open Windows: " << windows.count();
David Faure's avatar
David Faure committed
271

272 273
	setupGUI( static_cast<StandardWindowOptions>(ToolBar | Keys | StatusBar | Save | Create) , "kopetechatwindow.rc" );

274 275
	//has to be done after the setupGUI, in order to have the toolbar set up to restore window settings.
	readOptions();
276
#ifdef CHRONO
277
	kDebug()<<"TIME: "<<chrono.elapsed();
278
#endif
279 280 281 282
}

KopeteChatWindow::~KopeteChatWindow()
{
Thiago Macieira's avatar
Thiago Macieira committed
283
	kDebug( 14010 ) ;
284 285

	emit( closing( this ) );
286

287
	for( AccountMap::Iterator it = accountMap.begin(); it != accountMap.end(); )
288
	{
289 290 291 292
		if( it.value() == this )
			it=accountMap.erase( it );
		else
			++it;
293 294
	}

295
	for( GroupMap::Iterator it = groupMap.begin(); it != groupMap.end(); )
296
	{
297 298 299 300
		if( it.value() == this )
			it=groupMap.erase( it );
		else
			++it;
301
	}
302 303

	for( MetaContactMap::Iterator it = mcMap.begin(); it != mcMap.end(); )
304
	{
305 306 307 308
		if( it.value() == this )
			it=mcMap.erase( it );
		else
			++it;
309
	}
310

Gustavo P. Boiko's avatar
Gustavo P. Boiko committed
311
	windows.removeAt( windows.indexOf( this ) );
312
	windowListChanged();
313

314
//	kDebug( 14010 ) << "Open Windows: " << windows.count();
315

316 317
	saveOptions();

318
	delete backgroundFile;
319
	delete anim;
Roman Jarosz's avatar
Roman Jarosz committed
320
	delete animIcon;
321 322
}

323 324 325
void KopeteChatWindow::windowListChanged()
{
	// update all windows' Move Tab to Window action
Gustavo P. Boiko's avatar
Gustavo P. Boiko committed
326
	for ( WindowList::iterator it = windows.begin(); it != windows.end(); ++it )
327 328 329
		(*it)->checkDetachEnable();
}

330 331 332 333
void KopeteChatWindow::slotTabContextMenu( QWidget *tab, const QPoint &pos )
{
	m_popupView = static_cast<ChatView*>( tab );

R. Harish Navnit's avatar
R. Harish Navnit committed
334 335
	QMenu popup;
	popup.addSection( KStringHandler::rsqueeze( m_popupView->caption() ) );
336 337 338 339 340 341 342 343 344
	popup.addAction( actionContactMenu );
	popup.addSeparator();
	popup.addAction( actionTabPlacementMenu );
	popup.addAction( tabDetach );
	popup.addAction( actionDetachMenu );
	popup.addAction( tabCloseAllOthers );
	popup.addAction( tabClose );
	popup.exec( pos );

345 346 347 348 349 350 351 352
	m_popupView = 0;
}

ChatView *KopeteChatWindow::activeView()
{
	return m_activeView;
}

353 354
void KopeteChatWindow::updateSendKeySequence()
{
355 356 357
	if ( !sendMessage || !m_activeView )
		return;

358
	m_activeView->editPart()->textEdit()->setSendKeySequenceList( sendMessage->shortcuts() );
359 360
}

361 362 363 364
void KopeteChatWindow::initActions(void)
{
	KActionCollection *coll = actionCollection();

365 366
	createStandardStatusBarAction();

R. Harish Navnit's avatar
R. Harish Navnit committed
367
	chatSend = new QAction( QIcon::fromTheme("mail-send"), i18n( "&Send Message" ), coll );
368 369
	//Recuperate the qAction for later
	sendMessage = coll->addAction( "chat_send", chatSend );
370 371
	//Set up change signal in case the user changer the shortcut later
	connect( sendMessage, SIGNAL(changed()), SLOT(updateSendKeySequence()) );
372

Laurent Montel's avatar
Laurent Montel committed
373
	connect( chatSend, SIGNAL(triggered(bool)), SLOT(slotSendMessage()) );
374 375 376
	//Default to 'Return' and 'Enter' for sending messages
	//'Return' is the key in the main part of the keyboard
	//'Enter' is on the Numpad
R. Harish Navnit's avatar
R. Harish Navnit committed
377
	QKeySequence chatSendShortcut( QKeySequence((int)Qt::Key_Return), QKeySequence((int)Qt::Key_Enter) );
378
	chatSend->setShortcut( chatSendShortcut );
379 380
	chatSend->setEnabled( false );

R. Harish Navnit's avatar
R. Harish Navnit committed
381
	chatSendFile = new QAction( QIcon::fromTheme("mail-attachment"), i18n( "Send File..." ), coll );
382
	coll->addAction( "chat_send_file", chatSendFile );
Laurent Montel's avatar
Laurent Montel committed
383
	connect( chatSendFile, SIGNAL(triggered(bool)), SLOT(slotSendFile()) );
384 385
	chatSendFile->setEnabled( false );

386 387
	KStandardAction::save ( this, SLOT(slotChatSave()), coll );
	KStandardAction::print ( this, SLOT(slotChatPrint()), coll );
R. Harish Navnit's avatar
R. Harish Navnit committed
388
	QAction * quitAction = KStandardAction::quit ( this, SLOT(close()), coll );
389
	quitAction->setText( i18n("Close All Chats") );
390

David Faure's avatar
David Faure committed
391
	tabClose = KStandardAction::close ( this, SLOT(slotChatClosed()), coll );
392
	coll->addAction( "tabs_close", tabClose );
393

R. Harish Navnit's avatar
R. Harish Navnit committed
394
	tabActive=new QAction( i18n( "&Activate Next Active Tab" ), coll );
395 396 397 398
	coll->addAction( "tabs_active", tabActive );
// 	tabActive->setShortcut( KStandardShortcut::tabNext() );
	tabActive->setEnabled( false );
	connect( tabActive, SIGNAL(triggered(bool)), this, SLOT(slotNextActiveTab()) );
399

R. Harish Navnit's avatar
R. Harish Navnit committed
400
	tabRight=new QAction( i18n( "&Activate Next Tab" ), coll );
401
	coll->addAction( "tabs_right", tabRight );
402
	tabRight->setShortcuts( KStandardShortcut::tabNext() );
403
	tabRight->setEnabled( false );
404 405
	connect( tabRight, SIGNAL(triggered(bool)), this, SLOT(slotNextTab()) );

R. Harish Navnit's avatar
R. Harish Navnit committed
406
	tabLeft=new QAction( i18n( "&Activate Previous Tab" ), coll );
407
	coll->addAction( "tabs_left", tabLeft );
408
	tabLeft->setShortcuts( KStandardShortcut::tabPrev() );
409 410
	tabLeft->setEnabled( false );
	connect( tabLeft, SIGNAL(triggered(bool)), this, SLOT(slotPreviousTab()) );
411

412 413
	// This action exists mostly so that the shortcut is configurable.
	// The actual "slot" is the eventFilter.
R. Harish Navnit's avatar
R. Harish Navnit committed
414
	nickComplete = new QAction( i18n( "Nic&k Completion" ), coll );
415
	coll->addAction( "nick_complete", nickComplete );
Grzegorz Jaskiewicz's avatar
compile  
Grzegorz Jaskiewicz committed
416
	nickComplete->setShortcut( QKeySequence( Qt::Key_Tab ) );
417

R. Harish Navnit's avatar
R. Harish Navnit committed
418
	tabDetach = new QAction( QIcon::fromTheme("tab-detach"), i18n( "&Detach Chat" ), coll );
419
	coll->addAction( "tabs_detach", tabDetach );
420
	tabDetach->setEnabled( false );
Laurent Montel's avatar
Laurent Montel committed
421
	connect( tabDetach, SIGNAL(triggered(bool)), this, SLOT(slotDetachChat()));
422

R. Harish Navnit's avatar
R. Harish Navnit committed
423
	tabCloseAllOthers = new QAction( QIcon::fromTheme("tab-close"), i18n( "Close &All But This Tab" ), coll );
424 425
	coll->addAction( "tabs_close_others", tabCloseAllOthers );
	tabCloseAllOthers->setEnabled( true );
Laurent Montel's avatar
Laurent Montel committed
426
	connect( tabCloseAllOthers, SIGNAL(triggered(bool)), this, SLOT(slotCloseAllOtherTabs()));
427

R. Harish Navnit's avatar
R. Harish Navnit committed
428
	actionDetachMenu = new KActionMenu( QIcon::fromTheme("tab-detach"), i18n( "&Move Tab to Window" ), coll );
429
	coll->addAction( "tabs_detachmove", actionDetachMenu );
430 431
	actionDetachMenu->setDelayed( false );

432
	connect ( actionDetachMenu->menu(), SIGNAL(aboutToShow()), this, SLOT(slotPrepareDetachMenu()) );
433
	connect ( actionDetachMenu->menu(), SIGNAL(triggered(QAction*)), this, SLOT(slotDetachChat(QAction*)) );
434

David Faure's avatar
David Faure committed
435
	actionTabPlacementMenu = new KActionMenu( i18n( "&Tab Placement" ), coll );
436
	coll->addAction( "tabs_placement", actionTabPlacementMenu );
437
	connect ( actionTabPlacementMenu->menu(), SIGNAL(aboutToShow()), this, SLOT(slotPreparePlacementMenu()) );
438
	connect ( actionTabPlacementMenu->menu(), SIGNAL(triggered(QAction*)), this, SLOT(slotPlaceTabs(QAction*)) );
439

Grzegorz Jaskiewicz's avatar
compile  
Grzegorz Jaskiewicz committed
440
	tabDetach->setShortcut( QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_B) );
441

Aaron J. Seigo's avatar
Aaron J. Seigo committed
442 443 444
	KStandardAction::cut( this, SLOT(slotCut()), coll);
	KStandardAction::copy( this, SLOT(slotCopy()), coll);
	KStandardAction::paste( this, SLOT(slotPaste()), coll);
445

R. Harish Navnit's avatar
R. Harish Navnit committed
446
	QAction * action;
447

R. Harish Navnit's avatar
R. Harish Navnit committed
448
	historyUp = new QAction( i18n( "Previous History" ), coll );
449
	coll->addAction( "history_up", historyUp );
Grzegorz Jaskiewicz's avatar
compile  
Grzegorz Jaskiewicz committed
450
	historyUp->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_Up) );
451
	connect( historyUp, SIGNAL(triggered(bool)), this, SLOT(slotHistoryUp()) );
452

R. Harish Navnit's avatar
R. Harish Navnit committed
453
	historyDown = new QAction( i18n( "Next History" ), coll );
454
	coll->addAction( "history_down", historyDown );
Grzegorz Jaskiewicz's avatar
compile  
Grzegorz Jaskiewicz committed
455
	historyDown->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_Down) );
456
	connect( historyDown, SIGNAL(triggered(bool)), this, SLOT(slotHistoryDown()) );
457

Laurent Montel's avatar
Laurent Montel committed
458
	action = KStandardAction::prior( this, SLOT(slotPageUp()), coll );
459
	coll->addAction( "scroll_up", action );
Laurent Montel's avatar
Laurent Montel committed
460
	action = KStandardAction::next( this, SLOT(slotPageDown()), coll );
461
	coll->addAction( "scroll_down", action );
Jason Keirstead's avatar
Jason Keirstead committed
462

463
	KStandardAction::showMenubar( menuBar(), SLOT(setVisible(bool)), coll );
464

David Faure's avatar
David Faure committed
465
	toggleAutoSpellCheck = new KToggleAction( i18n( "Automatic Spell Checking" ), coll );
466
	coll->addAction( "enable_auto_spell_check", toggleAutoSpellCheck );
467
	toggleAutoSpellCheck->setChecked( true );
468
	connect( toggleAutoSpellCheck, SIGNAL(triggered(bool)), this, SLOT(toggleAutoSpellChecking()) );
Matt Rogers's avatar
Matt Rogers committed
469

470
	QAction *toggleParticipantsAction = m_participantsWidget->toggleViewAction( );
471 472
	toggleParticipantsAction->setText( i18n( "Show Participants" ) );
	toggleParticipantsAction->setIconText(i18n( "Participants" ));
R. Harish Navnit's avatar
R. Harish Navnit committed
473
	toggleParticipantsAction->setIcon(QIcon::fromTheme( "system-users" ) );
474
	coll->addAction ( "show_participants_widget", toggleParticipantsAction );
Matt Rogers's avatar
Matt Rogers committed
475

David Faure's avatar
David Faure committed
476
	actionSmileyMenu = new KopeteEmoticonAction( coll );
477
	coll->addAction( "format_smiley", actionSmileyMenu );
478
	actionSmileyMenu->setDelayed( false );
Laurent Montel's avatar
Laurent Montel committed
479
	connect(actionSmileyMenu, SIGNAL(activated(QString)), this, SLOT(slotSmileyActivated(QString)));
480

David Faure's avatar
David Faure committed
481
	actionContactMenu = new KActionMenu(i18n("Co&ntacts"), coll );
482
	coll->addAction( "contacts_menu", actionContactMenu );
483
	actionContactMenu->setDelayed( false );
484
	connect ( actionContactMenu->menu(), SIGNAL(aboutToShow()), this, SLOT(slotPrepareContactMenu()) );
485

486
	KopeteStdAction::preferences( coll , "settings_prefs" );
Olivier Goffart's avatar
 
Olivier Goffart committed
487

488 489 490
	KToolBarSpacerAction * spacer = new KToolBarSpacerAction( coll );
	coll->addAction( "spacer", spacer );

Olivier Goffart's avatar
 
Olivier Goffart committed
491
	//The Sending movie
492
	normalIcon = QPixmap( BarIcon( QLatin1String( "kopete" ) ) );
493

Olivier Goffart's avatar
 
Olivier Goffart committed
494
	// we can't set the tool bar as parent, if we do, it will be deleted when we configure toolbars
495
	anim = new QLabel( QString(), 0L );
496
	anim->setObjectName( QLatin1String("kde toolbar widget") );
Olivier Goffart's avatar
 
Olivier Goffart committed
497 498
	anim->setMargin(5);
	anim->setPixmap( normalIcon );
499

500
	animIcon = KIconLoader::global()->loadMovie( QLatin1String( "newmessage" ), KIconLoader::Toolbar);
Roman Jarosz's avatar
Roman Jarosz committed
501 502
	if ( animIcon )
		animIcon->setPaused(true);
Jason Keirstead's avatar
Jason Keirstead committed
503

504 505 506 507
	QWidgetAction *animAction = new QWidgetAction( coll );
	animAction->setText( i18n("Toolbar Animation") );
	animAction->setDefaultWidget( anim );
	coll->addAction( "toolbar_animation", animAction );
Olivier Goffart's avatar
 
Olivier Goffart committed
508 509 510

	//toolBar()->insertWidget( 99, anim->width(), anim );
	//toolBar()->alignItemRight( 99 );
511 512
}

513
/*
514 515 516 517
const QString KopeteChatWindow::fileContents( const QString &path ) const
{
 	QString contents;
	QFile file( path );
Matt Rogers's avatar
Matt Rogers committed
518
	if ( file.open( QIODevice::ReadOnly ) )
519 520
	{
		QTextStream stream( &file );
521
		contents = stream.readAll();
522 523 524 525 526
		file.close();
	}

	return contents;
}
527
*/
528 529 530
void KopeteChatWindow::slotStopAnimation( ChatView* view )
{
	if( view == m_activeView )
531
	{
532
		anim->setPixmap( normalIcon );
Roman Jarosz's avatar
Roman Jarosz committed
533
		if( animIcon && animIcon->state() == QMovie::Running )
534
			animIcon->setPaused( true );
535
	}
536 537
}

538
void KopeteChatWindow::slotUpdateSendEnabled()
539
{
540 541 542
	if ( !m_activeView ) return;

	bool enabled = m_activeView->canSend();
543
	chatSend->setEnabled( enabled );
544 545
	if(m_button_send)
		m_button_send->setEnabled( enabled );
546 547
}

548 549 550 551
void KopeteChatWindow::updateChatSendFileAction()
{
	if ( !m_activeView )
		return;
552

553 554 555
	chatSendFile->setEnabled( m_activeView->canSendFile() );
}

556 557 558 559 560
void KopeteChatWindow::toggleAutoSpellChecking()
{
	if ( !m_activeView )
		return;

561 562
	bool currentSetting = m_activeView->editPart()->checkSpellingEnabled();
	m_activeView->editPart()->setCheckSpellingEnabled( !currentSetting );
563 564 565 566 567 568 569 570
	updateSpellCheckAction();
}

void KopeteChatWindow::updateSpellCheckAction()
{
	if ( !m_activeView )
		return;

571 572 573 574 575 576 577
	bool currentSetting = m_activeView->editPart()->checkSpellingEnabled();
	toggleAutoSpellCheck->setChecked( currentSetting );
}

void KopeteChatWindow::enableSpellCheckAction(bool enable)
{
	toggleAutoSpellCheck->setChecked( enable );
578 579
}

580 581 582 583 584 585
void KopeteChatWindow::updateActions()
{
	updateSpellCheckAction();
	updateChatSendFileAction();
}

586 587 588
void KopeteChatWindow::slotHistoryUp()
{
	if( m_activeView )
589
		m_activeView->editPart()->historyUp();
590 591 592 593 594
}

void KopeteChatWindow::slotHistoryDown()
{
	if( m_activeView )
595
		m_activeView->editPart()->historyDown();
596 597
}

598 599 600 601 602 603 604 605 606 607 608 609
void KopeteChatWindow::slotPageUp()
{
	if( m_activeView )
		m_activeView->messagePart()->pageUp();
}

void KopeteChatWindow::slotPageDown()
{
	if( m_activeView )
		m_activeView->messagePart()->pageDown();
}

610 611 612 613 614 615 616 617 618 619 620 621 622 623 624
void KopeteChatWindow::slotCut()
{
	m_activeView->cut();
}

void KopeteChatWindow::slotCopy()
{
	m_activeView->copy();
}

void KopeteChatWindow::slotPaste()
{
	m_activeView->paste();
}

625 626 627 628 629
void KopeteChatWindow::slotResetFontAndColor()
{
	m_activeView->resetFontAndColor();
}

630 631
void KopeteChatWindow::setStatus(const QString &text)
{
632
	m_status_text->setText(text);
633 634
}

635 636
void KopeteChatWindow::testCanDecode(const QDragMoveEvent *event, bool &accept)
{
637
	if ( m_tabBar && qobject_cast<KTabBar*>(m_tabBar->childAt( event->pos() )) && chatViewList[static_cast<KTabBar*>(m_tabBar->childAt( event->pos()))->selectTab( event->pos() )]->isDragEventAccepted( event )) {
638 639 640 641 642 643 644 645 646 647 648 649
		accept = true;
	} else {
		accept = false;
	}
}

void KopeteChatWindow::receivedDropEvent( QWidget *w, QDropEvent *e )
{
	m_tabBar->setCurrentWidget( w );
	activeView()->dropEvent( e );
}

650 651 652 653
void KopeteChatWindow::createTabBar()
{
	if( !m_tabBar )
	{
654
		KConfigGroup cg( KSharedConfig::openConfig(), QLatin1String("ChatWindowSettings") );
655

656
		m_tabBar = new KTabWidget( mainArea );
657
		m_tabBar->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) );
658
		m_tabBar->setTabsClosable(cg.readEntry( QLatin1String("HoverClose"), true ));
659
		m_tabBar->setMovable(true);
660
		m_tabBar->setAutomaticResizeTabs(true);
Laurent Montel's avatar
Laurent Montel committed
661
		connect( m_tabBar, SIGNAL(closeRequest(QWidget*)), this, SLOT(slotCloseChat(QWidget*)) );
Olivier Goffart's avatar
Olivier Goffart committed
662

663 664
		m_UpdateChatLabel = cg.readEntry( QLatin1String("ShowContactName"), true );

665
		QToolButton* m_rightWidget = new QToolButton( m_tabBar );
Laurent Montel's avatar
Laurent Montel committed
666
		connect( m_rightWidget, SIGNAL(clicked()), this, SLOT(slotChatClosed()) );
Pino Toscano's avatar
Pino Toscano committed
667
		m_rightWidget->setIcon( SmallIcon( "tab-close" ) );
668
		m_rightWidget->adjustSize();
669
		m_rightWidget->setToolTip( i18nc("@info:tooltip","Close the current tab") );
Laurent Montel's avatar
Laurent Montel committed
670
		m_tabBar->setCornerWidget( m_rightWidget, Qt::TopRightCorner );
Olivier Goffart's avatar
Olivier Goffart committed
671

672 673 674
		mainLayout->addWidget( m_tabBar );
		m_tabBar->show();

Gustavo P. Boiko's avatar
Gustavo P. Boiko committed
675 676
		for( ChatViewList::iterator it = chatViewList.begin(); it != chatViewList.end(); ++it )
			addTab( *it );
677

Laurent Montel's avatar
Laurent Montel committed
678 679 680 681
		connect ( m_tabBar, SIGNAL(testCanDecode(const QDragMoveEvent*,bool&)), this, SLOT(testCanDecode(const QDragMoveEvent*,bool&)) );
		connect ( m_tabBar, SIGNAL(receivedDropEvent(QWidget*,QDropEvent*)), this, SLOT(receivedDropEvent(QWidget*,QDropEvent*)) );
		connect ( m_tabBar, SIGNAL(currentChanged(QWidget*)), this, SLOT(setActiveView(QWidget*)) );
		connect ( m_tabBar, SIGNAL(contextMenu(QWidget*,QPoint)), this, SLOT(slotTabContextMenu(QWidget*,QPoint)) );
682

683
		if( m_activeView )
684
			m_tabBar->setCurrentWidget( m_activeView );
685 686
		else
			setActiveView( chatViewList.first() );
687

Stephan Kulow's avatar
ported  
Stephan Kulow committed
688
		int tabPosition = cg.readEntry( QLatin1String("Tab Placement") , 0 );
689 690 691 692

		QAction action(this);
		action.setData(tabPosition);
		slotPlaceTabs( &action );
693 694 695
	}
}

696 697 698
void KopeteChatWindow::slotCloseChat( QWidget *chatView )
{
	static_cast<ChatView*>( chatView )->closeView();
Gustavo P. Boiko's avatar
Gustavo P. Boiko committed
699
	//FIXME: check if we need to remove from the chatViewList
700 701
}

702 703
void KopeteChatWindow::addTab( ChatView *view )
{
Olivier Goffart's avatar
compile  
Olivier Goffart committed
704
	QList<Kopete::Contact*> chatMembers=view->msgManager()->members();
Richard Smith's avatar
Richard Smith committed
705
	Kopete::Contact *c=0L;
Olivier Goffart's avatar
compile  
Olivier Goffart committed
706
	foreach( Kopete::Contact *contact , chatMembers )
707 708 709 710
	{
		if(!c || c->onlineStatus() < contact->onlineStatus())
			c=contact;
	}
711
	QIcon pluginIcon = c ? view->msgManager()->contactOnlineStatus( c ).iconFor( c) :
R. Harish Navnit's avatar
R. Harish Navnit committed
712
			QIcon::fromTheme( view->msgManager()->protocol()->pluginIcon() );
713

Dave Rowe's avatar
Dave Rowe committed
714
	view->setParent( m_tabBar );
715 716 717
	view->setWindowFlags( 0 );
	view->move( QPoint() );
	//view->show();
David Faure's avatar
David Faure committed
718

719
	m_tabBar->addTab( view, pluginIcon, "");
720
        view->setVisible(view == m_activeView);
Laurent Montel's avatar
Laurent Montel committed
721
	connect( view, SIGNAL(updateStatusIcon(ChatView*)), this, SLOT(slotUpdateCaptionIcons(ChatView*)) );
722 723

	if (m_UpdateChatLabel) {
Laurent Montel's avatar
Laurent Montel committed
724
		connect( view, SIGNAL(captionChanged(bool)), this, SLOT(updateChatLabel()) );
725 726 727
		view->setCaption( view->caption(), false );
	}

728 729 730 731
}

void KopeteChatWindow::setPrimaryChatView( ChatView *view )
{
732 733
	//TODO figure out what else we have to save here besides the font
	//reparent clears a lot of stuff out
Dave Rowe's avatar
Dave Rowe committed
734
	view->setParent( mainArea );
735 736
	view->setWindowFlags( 0 );
	view->move( QPoint() );
737
	view->show();
738

739 740 741 742 743 744 745 746
	mainLayout->addWidget( view );
	setActiveView( view );
}

void KopeteChatWindow::deleteTabBar()
{
	if( m_tabBar )
	{
Laurent Montel's avatar
Laurent Montel committed
747 748
		disconnect ( m_tabBar, SIGNAL(currentChanged(QWidget*)), this, SLOT(setActiveView(QWidget*)) );
		disconnect ( m_tabBar, SIGNAL(contextMenu(QWidget*,QPoint)), this, SLOT(slotTabContextMenu(QWidget*,QPoint)) );
749 750 751 752 753 754 755 756 757 758 759 760 761

		if( !chatViewList.isEmpty() )
			setPrimaryChatView( chatViewList.first() );

		m_tabBar->deleteLater();
		m_tabBar = 0L;
	}
}

void KopeteChatWindow::attachChatView( ChatView* newView )
{
	chatViewList.append( newView );

762
	if ( !m_alwaysShowTabs && chatViewList.count() == 1 )
763
		setPrimaryChatView( newView );
Jason Keirstead's avatar
Jason Keirstead committed
764
	else
765 766 767 768 769 770 771
	{
		if ( !m_tabBar )
			createTabBar();
		else
			addTab( newView );
		newView->setActive( false );
	}
772

Jason Keirstead's avatar
Jason Keirstead committed
773
	newView->setMainWindow( this );
774
	newView->editWidget()->installEventFilter( this );
Jason Keirstead's avatar
Jason Keirstead committed
775