source: psi/trunk/src/tabdlg.cpp@ 77

Last change on this file since 77 was 49, checked in by dmik, 19 years ago

Psi: Improved: Pressing ESC in a chat or a group chat window minimizes it.

File size: 9.8 KB
Line 
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#include "chatdlg.h"
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 <qdragobject.h>
30#include "psitabwidget.h"
31
32#ifdef Q_WS_WIN
33#include<windows.h>
34#endif
35
36//----------------------------------------------------------------------------
37// TabDlg
38//----------------------------------------------------------------------------
39TabDlg::TabDlg(PsiCon *psiCon)
40{
41 psi=psiCon;
42
43 //this->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
44
45 tabMenu = new QPopupMenu( this );
46 connect( tabMenu, SIGNAL( aboutToShow() ), SLOT( buildTabMenu() ) );
47
48 tabs = new KTabWidget (this);
49
50 closeCross = new QPushButton(this);
51 //closeCross->setText("x");
52 closeCross->setIconSet(IconsetFactory::icon("psi/closetab").iconSet());
53 closeCross->hide();
54 if (option.usePerTabCloseButton)
55 tabs->setHoverCloseButton(true);
56 else
57 {
58 tabs->setHoverCloseButton(false);
59 tabs->setCornerWidget( closeCross );
60 closeCross->show();
61 }
62
63 tabs->setHoverCloseButtonDelayed(false); //people may want this enabled, but it's currently horribly broken.
64 tabs->setTabReorderingEnabled(true);
65 tabs->setCloseIcon(IconsetFactory::icon("psi/closetab").iconSet());
66 connect (tabs, SIGNAL( mouseDoubleClick( QWidget* ) ), SLOT( detachChat( QWidget* ) ) );
67 connect (tabs, SIGNAL( testCanDecode(const QDragMoveEvent*, bool&) ), SLOT( tabTestCanDecode(const QDragMoveEvent*, bool&) ) );
68 connect (tabs, SIGNAL( receivedDropEvent( QDropEvent* ) ), SLOT( tabReceivedDropEvent( QDropEvent* ) ) );
69 connect (tabs, SIGNAL( receivedDropEvent( QWidget*, QDropEvent* ) ), SLOT( tabReceivedDropEvent( QWidget*, QDropEvent* ) ) );
70 connect (tabs, SIGNAL( initiateDrag( QWidget* ) ), SLOT( startDrag( QWidget* ) ) );
71 connect (tabs, SIGNAL( closeRequest( QWidget* ) ), SLOT( closeChat( QWidget* ) ) );
72
73
74 QVBoxLayout *vert1 = new QVBoxLayout( this, 1);
75 vert1->addWidget(tabs);
76 chats.setAutoDelete( FALSE );
77 X11WM_CLASS("chat");
78
79 connect( closeCross, SIGNAL( clicked() ), SLOT( closeChat() ) );
80 connect( tabs, SIGNAL( currentChanged( QWidget* ) ), SLOT( tabSelected( QWidget* ) ) );
81
82 setAcceptDrops(TRUE);
83
84
85
86
87 setLooks();
88
89 resize(option.sizeTabDlg);
90}
91
92TabDlg::~TabDlg()
93{
94
95}
96
97void TabDlg::resizeEvent(QResizeEvent *e)
98{
99 if(option.keepSizes)
100 option.sizeTabDlg = e->size();
101}
102
103void TabDlg::buildTabMenu()
104{
105 tabMenu->clear();
106 tabMenu->insertItem( tr("Detach Current Tab"), this, SLOT( detachChat() ) );
107 tabMenu->insertItem( tr("Close Current Tab"), this, SLOT( closeChat() ) );
108
109 QPopupMenu* sendTo = new QPopupMenu(tabMenu);
110 for (uint i = 0; i < psi->getTabSets()->count(); ++i)
111 {
112 TabDlg* tabSet= psi->getTabSets()->at(i);
113 sendTo->insertItem( tabSet->getName(), this, SLOT( sendChatTo( tabSet ) ) );
114 }
115 tabMenu->insertItem( tr("Sent Current Tab to"), sendTo);
116}
117
118void TabDlg::sendChatTo(QWidget* chatw, TabDlg* otherTabs)
119{
120 if (otherTabs==this)
121 return;
122 ChatDlg* chat = (ChatDlg*)chatw;
123 closeChat(chat, false);
124 otherTabs->addChat(chat);
125}
126
127void TabDlg::setLooks()
128{
129 //set the widget icon
130#ifndef Q_WS_MAC
131 setIcon(IconsetFactory::icon("psi/start-chat"));
132#endif
133 tabs->setTabPosition(QTabWidget::Top);
134 if (option.putTabsAtBottom)
135 tabs->setTabPosition(QTabWidget::Bottom);
136
137#if QT_VERSION >= 0x030300
138 setWindowOpacity(double(option.chatOpacity)/100);
139#endif
140}
141
142QString TabDlg::getName()
143{
144 return ((ChatDlg*)(tabs->currentPage()))->getDisplayNick();
145}
146
147void TabDlg::tabSelected(QWidget* chat)
148{
149 ((ChatDlg*)chat)->activated(); //is this still necessary?
150 updateCaption();
151}
152
153bool TabDlg::managesChat(ChatDlg* chat)
154{
155 if ( chats.contains(chat) )
156 return true;
157 return false;
158}
159
160bool TabDlg::chatOnTop(ChatDlg* chat)
161{
162 if ( tabs->currentPage() == chat )
163 return true;
164 return false;
165}
166
167void TabDlg::addChat(ChatDlg* chat)
168{
169 chats.append(chat);
170 tabs->addTab(chat, chat->getDisplayNick());
171 tabs->setTabIconSet(chat, IconsetFactory::icon("psi/start-chat"));
172
173 tabs->showPage(chat);
174 connect ( chat, SIGNAL( captionChanged( ChatDlg*) ), SLOT( updateTab( ChatDlg* ) ) );
175 connect ( chat, SIGNAL( contactIsComposing(ChatDlg*, bool) ), SLOT( setTabComposing( ChatDlg*, bool) ) );
176 connect ( chat, SIGNAL( unreadMessageUpdate(ChatDlg*, int) ), SLOT( setTabHasMessages(ChatDlg*, int) ) );
177
178 this->show();
179 updateCaption();
180}
181
182void TabDlg::detachChat()
183{
184 detachChat(tabs->currentPage());
185}
186
187void TabDlg::detachChat(QWidget* chat)
188{
189 //don't detach singleton chats, fix for flyspray #477
190 if (tabs->count()==1)
191 return;
192
193 TabDlg *newTab = psi->newTabs();
194 sendChatTo(chat, newTab);
195}
196
197void TabDlg::closeChat()
198{
199 ChatDlg* chat = (ChatDlg*)(tabs->currentPage());
200 closeChat(chat);
201}
202
203bool TabDlg::closeChat(ChatDlg* chat, bool doclose=true)
204{
205 if (doclose) {
206 if (!chat->close())
207 return false;
208 } else {
209 chat->hide();
210 }
211 disconnect ( chat, SIGNAL( captionChanged( ChatDlg*) ), this, SLOT( updateTab( ChatDlg* ) ) );
212 disconnect ( chat, SIGNAL( contactIsComposing(ChatDlg*, bool) ), this, SLOT( setTabComposing( ChatDlg*, bool) ) );
213 disconnect ( chat, SIGNAL( unreadMessageUpdate(ChatDlg*, int) ), this, SLOT( setTabHasMessages(ChatDlg*, int) ) );
214 tabs->removePage(chat);
215 tabIsComposing.erase(chat);
216 tabHasMessages.erase(chat);
217 chats.remove(chat);
218 chat->reparent(0,QPoint());
219 if (tabs->count()>0)
220 updateCaption();
221 checkHasChats();
222 return true;
223}
224
225void TabDlg::closeChat(QWidget* chat)
226{
227 closeChat((ChatDlg*)chat);
228}
229
230void TabDlg::selectTab(ChatDlg* chat)
231{
232 tabs->showPage(chat);
233}
234
235void TabDlg::checkHasChats()
236{
237 if (tabs->count()>0)
238 return;
239 closeMe();
240}
241
242void TabDlg::windowActivationChange(bool oldstate)
243{
244 QWidget::windowActivationChange(oldstate);
245
246 // if we're bringing it to the front, get rid of the '*' if necessary
247 if( isActiveWindow() ) {
248 activated();
249 }
250}
251
252void TabDlg::activated()
253{
254 updateCaption();
255 doFlash(false);
256}
257
258void TabDlg::updateCaption()
259{
260 QString cap = "";
261 uint pending=0;
262 for ( uint i=0; i<tabHasMessages.count(); ++i)
263 {
264 pending+=tabHasMessages.values()[i];
265 }
266 if(pending > 0) {
267 cap += "* ";
268 if(pending > 1)
269 cap += QString("[%1] ").arg(pending);
270 }
271 cap += getName();
272
273 setCaption(cap);
274}
275
276void TabDlg::closeEvent(QCloseEvent* closeEvent)
277{
278 Q_UNUSED(closeEvent);
279 int count=tabs->count();
280 for (int i=0;i<count;++i) {
281 if (!closeChat((ChatDlg*)(tabs->currentPage())))
282 return;
283 }
284}
285
286void TabDlg::closeMe()
287{
288 emit isDying(this);
289 //we do not delete it here, let the PsiCon do that, they create, they destroy.
290}
291
292ChatDlg* TabDlg::getChatPointer(QString fullJid)
293{
294 for (int i=0; i < tabs->count() ; i++)
295 {
296 if (((ChatDlg*)tabs->page(i))->jid().full()==fullJid)
297 {
298 return (ChatDlg*)(tabs->page(i));
299 }
300 }
301 return false;
302}
303
304void TabDlg::updateTab( ChatDlg* chat)
305{
306 QString label, prefix;
307 int num=tabHasMessages[chat];
308 if (num == 0)
309 {
310 prefix="";
311 }
312 else if (num == 1)
313 {
314 prefix="* ";
315 }
316 else
317 {
318 prefix=QString("[%1] ").arg(num);
319 }
320
321 label=prefix+chat->getDisplayNick();
322 tabs->setTabLabel( chat, label );
323 //now set text colour based upon whether there are new messages/composing etc
324 if (tabIsComposing[chat])
325 tabs->setTabColor( chat, Qt::darkGreen );
326 else if (tabHasMessages[chat])
327 {
328 tabs->setTabColor( chat, Qt::red );
329 doFlash(true);
330 }
331 else
332 tabs->setTabColor( chat, Qt::black );
333 updateCaption();
334}
335
336void TabDlg::setTabComposing(ChatDlg* chat, bool composing)
337{
338 tabIsComposing[chat]=composing;
339 updateTab(chat);
340}
341
342void TabDlg::setTabHasMessages(ChatDlg* chat, int messages)
343{
344 tabHasMessages[chat]=messages;
345 updateTab(chat);
346}
347
348void TabDlg::nextTab()
349{
350 int page = tabs->currentPageIndex()+1;
351 if ( page >= tabs->count() )
352 page = 0;
353 tabs->setCurrentPage( page );
354}
355
356void TabDlg::previousTab()
357{
358 int page = tabs->currentPageIndex()-1;
359 if ( page < 0 )
360 page = tabs->count() - 1;
361 tabs->setCurrentPage( page );
362}
363
364void TabDlg::tabTestCanDecode(const QDragMoveEvent* e, bool &b){
365 QString jid;
366 QCString type;
367 if ( QTextDrag::canDecode(e) && QTextDrag::decode(e, jid, type) && type=="psichatwindow" )
368 {
369 b=true;
370 }
371 else
372 {
373 b=false;
374 }
375}
376
377void TabDlg::tabReceivedDropEvent(QDropEvent* e){
378 ChatDlg* chat;
379 QString jid;
380 QCString type;
381 if ( QTextDrag::decode(e, jid, type) && type=="psichatwindow" ) {
382 chat=psi->getChatInTabs(jid);
383 if (chat)
384 {
385 TabDlg *dlg=psi->getManagingTabs(chat);
386 dlg->sendChatTo(chat, this);
387 }
388 }
389}
390
391void TabDlg::tabReceivedDropEvent(QWidget* w, QDropEvent* e){
392 Q_UNUSED(w);
393 tabReceivedDropEvent(e);
394}
395
396
397void TabDlg::startDrag(QWidget* w)
398{
399 QDragObject *d = new QTextDrag( ((ChatDlg*)w)->jid().full(), this );
400 ((QTextDrag*)d)->setSubtype("psichatwindow");
401 d->dragCopy();
402 // do NOT delete d.
403}
404
405void TabDlg::keyPressEvent(QKeyEvent *e)
406{
407 if (e->key() == Key_Escape && e->state() == 0)
408 {
409 showMinimized();
410 }
411 else if ( e->key() == Key_W && (e->state() & ControlButton) )
412 {
413 closeChat();
414 }
415 else if ( e->key() == Key_PageUp && (e->state() & ControlButton) ||
416 e->key() == Key_Backtab && (e->state() & ControlButton) )
417 {
418 previousTab();
419 }
420 else if ( e->key() == Key_PageDown && (e->state() & ControlButton) ||
421 e->key() == Key_Tab && (e->state() & ControlButton) )
422 {
423 nextTab();
424 }
425 else
426 e->ignore();
427
428}
429
Note: See TracBrowser for help on using the repository browser.