~ubuntu-branches/ubuntu/vivid/psi/vivid

« back to all changes in this revision

Viewing changes to src/tabdlg.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jan Niehusmann
  • Date: 2008-08-28 18:46:52 UTC
  • mfrom: (1.2.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20080828184652-iiik12dl91nq7cdi
Tags: 0.12-2
Uploading to unstable (Closes: Bug#494352)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * tabdlg.cpp - dialog for handling tabbed chats
3
 
 * Copyright (C) 2005  Kevin Smith
4
 
 *
5
 
 * This program is free software; you can redistribute it and/or
6
 
 * modify it under the terms of the GNU General Public License
7
 
 * as published by the Free Software Foundation; either version 2
8
 
 * of the License, or (at your option) any later version.
9
 
 *
10
 
 * This program is distributed in the hope that it will be useful,
11
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
 * GNU General Public License for more details.
14
 
 *
15
 
 * You should have received a copy of the GNU General Public License
16
 
 * along with this library; if not, write to the Free Software
17
 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 
 *
19
 
 */
20
 
 
21
 
#include "tabdlg.h"
22
 
 
23
 
#include "iconwidget.h"
24
 
#include "iconset.h"
25
 
#include "common.h"
26
 
#include "psicon.h"
27
 
#include <qmenubar.h>
28
 
#include <qcursor.h>
29
 
#include <q3dragobject.h>
30
 
#include <QVBoxLayout>
31
 
#include <QDragMoveEvent>
32
 
#include <QResizeEvent>
33
 
#include <QKeyEvent>
34
 
#include <Q3PopupMenu>
35
 
#include <QDropEvent>
36
 
#include <QCloseEvent>
37
 
#include "psitabwidget.h"
38
 
#include "psioptions.h"
39
 
#include "shortcutmanager.h"
40
 
#include "chatdlg.h"
41
 
 
42
 
#ifdef Q_WS_WIN
43
 
#include <windows.h>
44
 
#endif
45
 
 
46
 
//----------------------------------------------------------------------------
47
 
// TabDlg
48
 
//----------------------------------------------------------------------------
49
 
TabDlg::TabDlg(PsiCon *psiCon)
50
 
{
51
 
        if ( option.brushedMetal )
52
 
                setAttribute(Qt::WA_MacMetalStyle);
53
 
        psi=psiCon;
54
 
 
55
 
        tabMenu = new QMenu( this );
56
 
        
57
 
        tabs = new PsiTabWidget (this);
58
 
        tabs->setCloseIcon(IconsetFactory::icon("psi/closetab").icon());
59
 
        //tabs->setCloseIcon(IconsetFactory::icon("psi/closetab").iconSet());
60
 
        connect (tabs, SIGNAL( mouseDoubleClickTab( QWidget* ) ), SLOT( detachChat( QWidget* ) ) );
61
 
        connect (tabs, SIGNAL(aboutToShowMenu(QMenu *)), SLOT(tab_aboutToShowMenu(QMenu *)));
62
 
        connect (tabs, SIGNAL(tabContextMenu(int,QPoint,QContextMenuEvent*)), SLOT(showTabMenu(int,QPoint,QContextMenuEvent*)));
63
 
 
64
 
        //connect (tabs, SIGNAL( testCanDecode(const QDragMoveEvent*, bool&) ), SLOT( tabTestCanDecode(const QDragMoveEvent*, bool&) ) );
65
 
        //connect (tabs, SIGNAL( receivedDropEvent( QDropEvent* ) ), SLOT( tabReceivedDropEvent( QDropEvent* ) ) );
66
 
        //connect (tabs, SIGNAL( receivedDropEvent( QWidget*, QDropEvent* ) ), SLOT( tabReceivedDropEvent( QWidget*, QDropEvent* ) ) );
67
 
        //connect (tabs, SIGNAL( initiateDrag( QWidget* ) ), SLOT( startDrag( QWidget* ) ) );
68
 
        //connect (tabs, SIGNAL( closeRequest( QWidget* ) ), SLOT( closeChat( QWidget* ) ) );
69
 
        
70
 
                
71
 
        QVBoxLayout *vert1 = new QVBoxLayout( this, 1);
72
 
        vert1->addWidget(tabs);
73
 
        chats.setAutoDelete( FALSE );
74
 
        X11WM_CLASS("chat");
75
 
        
76
 
        connect( tabs, SIGNAL( closeButtonClicked() ), SLOT( closeChat() ) );
77
 
        connect( tabs, SIGNAL( currentChanged( QWidget* ) ), SLOT( tabSelected( QWidget* ) ) ); 
78
 
 
79
 
        setAcceptDrops(TRUE);
80
 
 
81
 
        setLooks();
82
 
 
83
 
        resize(option.sizeTabDlg);
84
 
 
85
 
        act_close = new QAction(this);
86
 
        addAction(act_close);
87
 
        connect(act_close,SIGNAL(activated()), SLOT(closeChat()));
88
 
        act_prev = new QAction(this);
89
 
        addAction(act_prev);
90
 
        connect(act_prev,SIGNAL(activated()), SLOT(previousTab()));
91
 
        act_next = new QAction(this);
92
 
        addAction(act_next);
93
 
        connect(act_next,SIGNAL(activated()), SLOT(nextTab()));
94
 
 
95
 
        setShortcuts();
96
 
}
97
 
 
98
 
TabDlg::~TabDlg()
99
 
{
100
 
 
101
 
}
102
 
 
103
 
 
104
 
Q_DECLARE_METATYPE ( TabDlg* );
105
 
 
106
 
 
107
 
void TabDlg::setShortcuts()
108
 
{
109
 
        //act_close->setShortcuts(ShortcutManager::instance()->shortcuts("common.close"));
110
 
        act_prev->setShortcuts(ShortcutManager::instance()->shortcuts("chat.previous-tab"));
111
 
        act_next->setShortcuts(ShortcutManager::instance()->shortcuts("chat.next-tab"));
112
 
}
113
 
 
114
 
void TabDlg::resizeEvent(QResizeEvent *e)
115
 
{
116
 
  if(option.keepSizes)
117
 
        option.sizeTabDlg = e->size();
118
 
}
119
 
 
120
 
void TabDlg::showTabMenu(int tab, QPoint pos, QContextMenuEvent * event)
121
 
{
122
 
        tabMenu->clear();
123
 
 
124
 
        if (tab!=-1) {
125
 
                QAction *d = tabMenu->addAction(tr("Detach Tab"));
126
 
                QAction *c = tabMenu->addAction(tr("Close Tab"));
127
 
 
128
 
                QMenu* sendTo = new QMenu(tabMenu);
129
 
                sendTo->setTitle(tr("Send Tab to"));
130
 
                QMap<QAction*, TabDlg*> sentTos;
131
 
                for (uint i = 0; i < psi->getTabSets()->count(); ++i)
132
 
                {
133
 
                        TabDlg* tabSet= psi->getTabSets()->at(i);
134
 
                        QAction *act = sendTo->addAction( tabSet->getName());
135
 
                        if (tabSet == this) act->setEnabled(false);
136
 
                        sentTos[act] = tabSet;
137
 
                }
138
 
                tabMenu->addMenu(sendTo);
139
 
 
140
 
                QAction *act = tabMenu->exec(pos);
141
 
                if (!act) return;
142
 
                if (act == c) {
143
 
                        closeChat(getTab(tab));
144
 
                } else if (act == d) {
145
 
                        detachChat(getTab(tab));
146
 
                } else {
147
 
                        TabDlg* target = sentTos[act];
148
 
                        if (target) queuedSendChatTo(getTab(tab), target);
149
 
                }
150
 
        }
151
 
}
152
 
 
153
 
void TabDlg::tab_aboutToShowMenu(QMenu *menu)
154
 
{
155
 
        menu->addSeparator ();
156
 
        menu->addAction( tr("Detach Current Tab"), this, SLOT( detachChat() ) );
157
 
        menu->addAction( tr("Close Current Tab"), this, SLOT( closeChat() ) );
158
 
 
159
 
        QMenu* sendTo = new QMenu(menu);
160
 
        sendTo->setTitle(tr("Send Current Tab to"));
161
 
        int tabdlgmetatype = qRegisterMetaType<TabDlg*>("TabDlg*");
162
 
        for (uint i = 0; i < psi->getTabSets()->count(); ++i)
163
 
        {
164
 
                TabDlg* tabSet= psi->getTabSets()->at(i);
165
 
                QAction *act = sendTo->addAction( tabSet->getName());
166
 
                act->setData(QVariant(tabdlgmetatype, &tabSet));
167
 
                if (tabSet == this) act->setEnabled(false);
168
 
        }
169
 
        connect(sendTo, SIGNAL(triggered(QAction*)), SLOT(menu_sendChatTo(QAction*)));
170
 
        menu->addMenu(sendTo);
171
 
}
172
 
 
173
 
void TabDlg::menu_sendChatTo(QAction *act)
174
 
{
175
 
        queuedSendChatTo(tabs->currentPage(), act->data().value<TabDlg*>());
176
 
}
177
 
 
178
 
void TabDlg::sendChatTo(QWidget* chatw, TabDlg* otherTabs)
179
 
{
180
 
        if (otherTabs==this)
181
 
                return;
182
 
        ChatDlg* chat = (ChatDlg*)chatw;
183
 
        closeChat(chat, false);
184
 
        otherTabs->addChat(chat);
185
 
}
186
 
 
187
 
void TabDlg::queuedSendChatTo(QWidget* chat, TabDlg *dest)
188
 
{
189
 
        qRegisterMetaType<TabDlg*>("TabDlg*");
190
 
        QMetaObject::invokeMethod(this, "sendChatTo",  Qt::QueuedConnection, Q_ARG(QWidget*, chat), Q_ARG(TabDlg*, dest));
191
 
}
192
 
 
193
 
void TabDlg::optionsUpdate()
194
 
{
195
 
        setShortcuts();
196
 
}
197
 
 
198
 
void TabDlg::setLooks()
199
 
{
200
 
        //set the widget icon
201
 
#ifndef Q_WS_MAC
202
 
        setWindowIcon(IconsetFactory::icon("psi/start-chat").icon());
203
 
#endif
204
 
        tabs->setTabPosition(QTabWidget::Top);
205
 
        if (option.putTabsAtBottom)
206
 
                tabs->setTabPosition(QTabWidget::Bottom);
207
 
 
208
 
        setWindowOpacity(double(qMax(MINIMUM_OPACITY,PsiOptions::instance()->getOption("options.ui.chat.opacity").toInt()))/100);
209
 
}
210
 
 
211
 
QString TabDlg::getName()
212
 
{
213
 
        return ((ChatDlg*)(tabs->currentPage()))->getDisplayNick();
214
 
}
215
 
 
216
 
void TabDlg::tabSelected(QWidget* chat)
217
 
{
218
 
        if (!chat) return; // FIXME
219
 
        ((ChatDlg*)chat)->activated(); //is this still necessary?
220
 
        updateCaption();
221
 
}
222
 
 
223
 
bool TabDlg::managesChat(ChatDlg* chat)
224
 
{
225
 
        if ( chats.contains(chat) )
226
 
                        return true;
227
 
        return false;
228
 
}
229
 
 
230
 
bool TabDlg::chatOnTop(ChatDlg* chat)
231
 
{
232
 
        if ( tabs->currentPage() == chat )
233
 
                return true;
234
 
        return false;
235
 
}
236
 
 
237
 
void TabDlg::addChat(ChatDlg* chat)
238
 
{
239
 
        chats.append(chat);
240
 
        QString tablabel = chat->getDisplayNick();
241
 
        tablabel.replace("&", "&&");
242
 
        tabs->addTab(chat, tablabel);
243
 
        //tabs->setTabIconSet(chat, IconsetFactory::icon("psi/start-chat").icon());
244
 
 
245
 
        //tabs->showPage(chat);
246
 
        connect ( chat, SIGNAL( captionChanged( ChatDlg*) ), SLOT( updateTab( ChatDlg* ) ) );
247
 
        connect ( chat, SIGNAL( contactStateChanged( XMPP::ChatState ) ), SLOT( setTabState( XMPP::ChatState ) ) );
248
 
        connect ( chat, SIGNAL( unreadMessageUpdate(ChatDlg*, int) ), SLOT( setTabHasMessages(ChatDlg*, int) ) );
249
 
        
250
 
        this->show();
251
 
        updateCaption();
252
 
}
253
 
 
254
 
void TabDlg::detachChat()
255
 
{
256
 
        detachChat(tabs->currentPage());
257
 
}
258
 
 
259
 
void TabDlg::detachChat(QWidget* chat)
260
 
{
261
 
        //don't detach singleton chats, fix for flyspray #477
262
 
        if (tabs->count()==1)
263
 
                return;
264
 
        
265
 
        if (!chat) { // fail gracefully this is delayed/signaled user input.
266
 
                return;
267
 
        }
268
 
 
269
 
        TabDlg *newTab = psi->newTabs();
270
 
        sendChatTo(chat, newTab);
271
 
}
272
 
 
273
 
void TabDlg::closeChat()
274
 
{
275
 
        ChatDlg* chat = (ChatDlg*)(tabs->currentPage());
276
 
        closeChat(chat);
277
 
}
278
 
 
279
 
/**
280
 
 * Removes the chat from the tabset, 'closing' it if specified.
281
 
 * The method is used without closing tabs when transferring from one
282
 
 * tabset to another.
283
 
 * \param chat Chat to remove.
284
 
 * \param doclose Whether the chat is 'closed' while removing it.
285
 
 */ 
286
 
void TabDlg::closeChat(ChatDlg* chat, bool doclose=true)
287
 
{
288
 
        if (doclose && !chat->readyToHide()) {
289
 
                return;
290
 
        }
291
 
        chat->hide();
292
 
        disconnect ( chat, SIGNAL( captionChanged( ChatDlg*) ), this, SLOT( updateTab( ChatDlg* ) ) );
293
 
        disconnect ( chat, SIGNAL( contactStateChanged( XMPP::ChatState ) ), this, SLOT( setTabState( XMPP::ChatState ) ) );
294
 
        disconnect ( chat, SIGNAL( unreadMessageUpdate(ChatDlg*, int) ), this, SLOT( setTabHasMessages(ChatDlg*, int) ) );
295
 
        tabs->removePage(chat);
296
 
        tabIsComposing.erase(chat);
297
 
        tabHasMessages.erase(chat);
298
 
        chats.remove(chat);
299
 
        chat->reparent(0,QPoint());
300
 
        if (doclose && chat->testAttribute(Qt::WA_DeleteOnClose))
301
 
                chat->close();
302
 
        if (tabs->count()>0)
303
 
                updateCaption();
304
 
        checkHasChats();
305
 
}
306
 
 
307
 
void TabDlg::closeChat(QWidget* chat)
308
 
{
309
 
        closeChat((ChatDlg*)chat);
310
 
}
311
 
 
312
 
void TabDlg::selectTab(ChatDlg* chat)
313
 
{
314
 
        tabs->showPage(chat);
315
 
}
316
 
 
317
 
void TabDlg::checkHasChats()
318
 
{
319
 
        if (tabs->count()>0)
320
 
                return;
321
 
        closeMe();
322
 
}
323
 
 
324
 
void TabDlg::windowActivationChange(bool oldstate)
325
 
{
326
 
        QWidget::windowActivationChange(oldstate);
327
 
 
328
 
        // if we're bringing it to the front, get rid of the '*' if necessary
329
 
        if( isActiveWindow() ) { 
330
 
                activated();
331
 
        }
332
 
}
333
 
 
334
 
void TabDlg::activated()
335
 
{
336
 
        updateCaption();
337
 
        doFlash(false);
338
 
}
339
 
 
340
 
void TabDlg::updateCaption()
341
 
{
342
 
        QString cap = "";
343
 
        uint pending=0;
344
 
        for ( int i=0; i<tabHasMessages.count(); ++i)
345
 
        {
346
 
                pending+=tabHasMessages.values()[i];
347
 
        }
348
 
        if(pending > 0) {
349
 
                cap += "* ";
350
 
                if(pending > 1)
351
 
                        cap += QString("[%1] ").arg(pending);
352
 
        }
353
 
        cap += getName();
354
 
        if (tabIsComposing[(ChatDlg*)(tabs->currentPage())])
355
 
                cap += tr(" is composing");
356
 
        setWindowTitle(cap);
357
 
}
358
 
 
359
 
void TabDlg::closeEvent(QCloseEvent* closeEvent)
360
 
{
361
 
        Q_UNUSED(closeEvent);
362
 
        int count=tabs->count();
363
 
        for (int i=0;i<count;++i) {
364
 
                closeChat();
365
 
        }
366
 
}
367
 
 
368
 
void TabDlg::closeMe()
369
 
{
370
 
        emit isDying(this);
371
 
        //we do not delete it here, let the PsiCon do that, they create, they destroy.
372
 
}
373
 
 
374
 
 
375
 
ChatDlg *TabDlg::getTab(int i)
376
 
{
377
 
        return ((ChatDlg*)tabs->page(i));
378
 
}
379
 
 
380
 
 
381
 
ChatDlg* TabDlg::getChatPointer(QString fullJid)
382
 
{
383
 
        for (int i=0; i < tabs->count() ; i++)
384
 
        {
385
 
                if (getTab(i)->jid().full()==fullJid)
386
 
                {
387
 
                        return getTab(i);
388
 
                }
389
 
        }
390
 
        return false;
391
 
}
392
 
 
393
 
void TabDlg::updateTab( ChatDlg* chat)
394
 
{
395
 
        QString label, prefix;
396
 
        int num=tabHasMessages[chat];
397
 
        if (num == 0)
398
 
        {
399
 
                prefix="";
400
 
        } 
401
 
        else if (num == 1) 
402
 
        {
403
 
                prefix="* ";
404
 
        }
405
 
        else
406
 
        {
407
 
                prefix=QString("[%1] ").arg(num);
408
 
        }
409
 
 
410
 
        label=prefix+chat->getDisplayNick();
411
 
        label.replace("&", "&&");
412
 
        tabs->setTabLabel( chat, label );
413
 
        //now set text colour based upon whether there are new messages/composing etc
414
 
 
415
 
        if (tabIsComposing[chat])
416
 
                tabs->setTabTextColor( chat, Qt::darkGreen );
417
 
        else if (tabHasMessages[chat])
418
 
        {
419
 
                tabs->setTabTextColor( chat, Qt::red );
420
 
                if (PsiOptions::instance()->getOption("options.ui.flash-windows").toBool())
421
 
                        doFlash(true);
422
 
        }
423
 
        else
424
 
                tabs->setTabTextColor( chat, Qt::black );
425
 
        updateCaption();
426
 
}
427
 
 
428
 
void TabDlg::setTabState( XMPP::ChatState state )
429
 
{
430
 
        ChatDlg* chat = (ChatDlg*) sender();
431
 
        if ( state == XMPP::StateComposing )
432
 
                tabIsComposing[chat] = true;
433
 
        else
434
 
                tabIsComposing[chat] = false;
435
 
        updateTab(chat);
436
 
}
437
 
 
438
 
void TabDlg::setTabHasMessages(ChatDlg* chat, int messages)
439
 
{
440
 
        tabHasMessages[chat]=messages;
441
 
        updateTab(chat);
442
 
}
443
 
 
444
 
void TabDlg::nextTab()
445
 
{
446
 
        int page = tabs->currentPageIndex()+1;
447
 
        if ( page >= tabs->count() )
448
 
                page = 0;
449
 
        tabs->setCurrentPage( page );
450
 
}
451
 
 
452
 
void TabDlg::previousTab()
453
 
{
454
 
        int page = tabs->currentPageIndex()-1;
455
 
        if ( page < 0 )
456
 
                page = tabs->count() - 1;
457
 
        tabs->setCurrentPage( page );
458
 
}
459
 
 
460
 
void TabDlg::keyPressEvent(QKeyEvent *e)
461
 
{
462
 
        if (e->key() == Qt::Key_Escape)
463
 
        {
464
 
                closeChat();
465
 
        }
466
 
        else if ( e->key() == Qt::Key_W && (e->modifiers() & Qt::ControlModifier) )
467
 
        {
468
 
                closeChat();
469
 
        }
470
 
        else if ( e->key() == Qt::Key_PageUp && (e->modifiers() & Qt::ControlModifier) )
471
 
        {
472
 
                previousTab();
473
 
        }
474
 
        else if ( e->key() == Qt::Key_PageDown && (e->modifiers() & Qt::ControlModifier) )
475
 
        {
476
 
                nextTab();
477
 
        }
478
 
        else
479
 
                e->ignore();
480
 
        
481
 
}
482
 
 
483
 
void TabDlg::dragEnterEvent(QDragEnterEvent *event)
484
 
{
485
 
        if ( event->mimeData()->hasFormat("psiTabDrag") ) {
486
 
                event->setDropAction(Qt::MoveAction);
487
 
                event->accept();
488
 
        }
489
 
}
490
 
 
491
 
void TabDlg::dropEvent(QDropEvent *event)
492
 
{
493
 
        QByteArray data;
494
 
        if (event->mimeData()->hasFormat("psiTabDrag")) {
495
 
                data = event->mimeData()->data("psiTabDrag");
496
 
        } else {
497
 
                return;
498
 
        }
499
 
        int remoteTab = data.toInt();
500
 
        event->acceptProposedAction();
501
 
        //the event's been and gone, now do something about it
502
 
        PsiTabBar* source = dynamic_cast<PsiTabBar*> (event->source());
503
 
        if (source)
504
 
        {
505
 
                PsiTabWidget* barParent = source->psiTabWidget();
506
 
                QWidget* widget = barParent->widget(remoteTab);
507
 
                ChatDlg* chat=dynamic_cast<ChatDlg*>(widget);
508
 
                TabDlg *dlg=psi->getManagingTabs(chat);
509
 
                if (!chat || !dlg)
510
 
                        return;
511
 
                dlg->queuedSendChatTo(chat, this);
512
 
        } 
513
 
        
514
 
}