/* * tabdlg.cpp - dialog for handling tabbed chats * Copyright (C) 2005 Kevin Smith * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "tabdlg.h" #include "chatdlg.h" #include "iconwidget.h" #include "iconset.h" #include "common.h" #include "psicon.h" #include #include #include #include "psitabwidget.h" #ifdef Q_WS_WIN #include #endif //---------------------------------------------------------------------------- // TabDlg //---------------------------------------------------------------------------- TabDlg::TabDlg(PsiCon *psiCon) { psi=psiCon; //this->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred ); tabMenu = new QPopupMenu( this ); connect( tabMenu, SIGNAL( aboutToShow() ), SLOT( buildTabMenu() ) ); tabs = new KTabWidget (this); closeCross = new QPushButton(this); //closeCross->setText("x"); closeCross->setIconSet(IconsetFactory::icon("psi/closetab").iconSet()); closeCross->hide(); if (option.usePerTabCloseButton) tabs->setHoverCloseButton(true); else { tabs->setHoverCloseButton(false); tabs->setCornerWidget( closeCross ); closeCross->show(); } tabs->setHoverCloseButtonDelayed(false); //people may want this enabled, but it's currently horribly broken. tabs->setTabReorderingEnabled(true); tabs->setCloseIcon(IconsetFactory::icon("psi/closetab").iconSet()); connect (tabs, SIGNAL( mouseDoubleClick( QWidget* ) ), SLOT( detachChat( QWidget* ) ) ); connect (tabs, SIGNAL( testCanDecode(const QDragMoveEvent*, bool&) ), SLOT( tabTestCanDecode(const QDragMoveEvent*, bool&) ) ); connect (tabs, SIGNAL( receivedDropEvent( QDropEvent* ) ), SLOT( tabReceivedDropEvent( QDropEvent* ) ) ); connect (tabs, SIGNAL( receivedDropEvent( QWidget*, QDropEvent* ) ), SLOT( tabReceivedDropEvent( QWidget*, QDropEvent* ) ) ); connect (tabs, SIGNAL( initiateDrag( QWidget* ) ), SLOT( startDrag( QWidget* ) ) ); connect (tabs, SIGNAL( closeRequest( QWidget* ) ), SLOT( closeChat( QWidget* ) ) ); QVBoxLayout *vert1 = new QVBoxLayout( this, 1); vert1->addWidget(tabs); chats.setAutoDelete( FALSE ); X11WM_CLASS("chat"); connect( closeCross, SIGNAL( clicked() ), SLOT( closeChat() ) ); connect( tabs, SIGNAL( currentChanged( QWidget* ) ), SLOT( tabSelected( QWidget* ) ) ); setAcceptDrops(TRUE); setLooks(); resize(option.sizeTabDlg); } TabDlg::~TabDlg() { } void TabDlg::resizeEvent(QResizeEvent *e) { if(option.keepSizes) option.sizeTabDlg = e->size(); } void TabDlg::buildTabMenu() { tabMenu->clear(); tabMenu->insertItem( tr("Detach Current Tab"), this, SLOT( detachChat() ) ); tabMenu->insertItem( tr("Close Current Tab"), this, SLOT( closeChat() ) ); QPopupMenu* sendTo = new QPopupMenu(tabMenu); for (uint i = 0; i < psi->getTabSets()->count(); ++i) { TabDlg* tabSet= psi->getTabSets()->at(i); sendTo->insertItem( tabSet->getName(), this, SLOT( sendChatTo( tabSet ) ) ); } tabMenu->insertItem( tr("Sent Current Tab to"), sendTo); } void TabDlg::sendChatTo(QWidget* chatw, TabDlg* otherTabs) { if (otherTabs==this) return; ChatDlg* chat = (ChatDlg*)chatw; closeChat(chat, false); otherTabs->addChat(chat); } void TabDlg::setLooks() { //set the widget icon #ifndef Q_WS_MAC setIcon(IconsetFactory::icon("psi/start-chat")); #endif tabs->setTabPosition(QTabWidget::Top); if (option.putTabsAtBottom) tabs->setTabPosition(QTabWidget::Bottom); #if QT_VERSION >= 0x030300 setWindowOpacity(double(option.chatOpacity)/100); #endif } QString TabDlg::getName() { return ((ChatDlg*)(tabs->currentPage()))->getDisplayNick(); } void TabDlg::tabSelected(QWidget* chat) { ((ChatDlg*)chat)->activated(); //is this still necessary? updateCaption(); } bool TabDlg::managesChat(ChatDlg* chat) { if ( chats.contains(chat) ) return true; return false; } bool TabDlg::chatOnTop(ChatDlg* chat) { if ( tabs->currentPage() == chat ) return true; return false; } void TabDlg::addChat(ChatDlg* chat) { chats.append(chat); tabs->addTab(chat, chat->getDisplayNick()); tabs->setTabIconSet(chat, IconsetFactory::icon("psi/start-chat")); tabs->showPage(chat); connect ( chat, SIGNAL( captionChanged( ChatDlg*) ), SLOT( updateTab( ChatDlg* ) ) ); connect ( chat, SIGNAL( contactIsComposing(ChatDlg*, bool) ), SLOT( setTabComposing( ChatDlg*, bool) ) ); connect ( chat, SIGNAL( unreadMessageUpdate(ChatDlg*, int) ), SLOT( setTabHasMessages(ChatDlg*, int) ) ); this->show(); updateCaption(); } void TabDlg::detachChat() { detachChat(tabs->currentPage()); } void TabDlg::detachChat(QWidget* chat) { //don't detach singleton chats, fix for flyspray #477 if (tabs->count()==1) return; TabDlg *newTab = psi->newTabs(); sendChatTo(chat, newTab); } void TabDlg::closeChat() { ChatDlg* chat = (ChatDlg*)(tabs->currentPage()); closeChat(chat); } void TabDlg::closeChat(ChatDlg* chat, bool doclose=true) { chat->hide(); disconnect ( chat, SIGNAL( captionChanged( ChatDlg*) ), this, SLOT( updateTab( ChatDlg* ) ) ); disconnect ( chat, SIGNAL( contactIsComposing(ChatDlg*, bool) ), this, SLOT( setTabComposing( ChatDlg*, bool) ) ); disconnect ( chat, SIGNAL( unreadMessageUpdate(ChatDlg*, int) ), this, SLOT( setTabHasMessages(ChatDlg*, int) ) ); tabs->removePage(chat); tabIsComposing.erase(chat); tabHasMessages.erase(chat); chats.remove(chat); chat->reparent(0,QPoint()); if (doclose) chat->close(); if (tabs->count()>0) updateCaption(); checkHasChats(); } void TabDlg::closeChat(QWidget* chat) { closeChat((ChatDlg*)chat); } void TabDlg::selectTab(ChatDlg* chat) { tabs->showPage(chat); } void TabDlg::checkHasChats() { if (tabs->count()>0) return; closeMe(); } void TabDlg::windowActivationChange(bool oldstate) { QWidget::windowActivationChange(oldstate); // if we're bringing it to the front, get rid of the '*' if necessary if( isActiveWindow() ) { activated(); } } void TabDlg::activated() { updateCaption(); doFlash(false); } void TabDlg::updateCaption() { QString cap = ""; uint pending=0; for ( uint i=0; i 0) { cap += "* "; if(pending > 1) cap += QString("[%1] ").arg(pending); } cap += getName(); setCaption(cap); } void TabDlg::closeEvent(QCloseEvent* closeEvent) { Q_UNUSED(closeEvent); int count=tabs->count(); for (int i=0;icount() ; i++) { if (((ChatDlg*)tabs->page(i))->jid().full()==fullJid) { return (ChatDlg*)(tabs->page(i)); } } return false; } void TabDlg::updateTab( ChatDlg* chat) { QString label, prefix; int num=tabHasMessages[chat]; if (num == 0) { prefix=""; } else if (num == 1) { prefix="* "; } else { prefix=QString("[%1] ").arg(num); } label=prefix+chat->getDisplayNick(); tabs->setTabLabel( chat, label ); //now set text colour based upon whether there are new messages/composing etc if (tabIsComposing[chat]) tabs->setTabColor( chat, Qt::darkGreen ); else if (tabHasMessages[chat]) { tabs->setTabColor( chat, Qt::red ); doFlash(true); } else tabs->setTabColor( chat, Qt::black ); updateCaption(); } void TabDlg::setTabComposing(ChatDlg* chat, bool composing) { tabIsComposing[chat]=composing; updateTab(chat); } void TabDlg::setTabHasMessages(ChatDlg* chat, int messages) { tabHasMessages[chat]=messages; updateTab(chat); } void TabDlg::nextTab() { int page = tabs->currentPageIndex()+1; if ( page >= tabs->count() ) page = 0; tabs->setCurrentPage( page ); } void TabDlg::previousTab() { int page = tabs->currentPageIndex()-1; if ( page < 0 ) page = tabs->count() - 1; tabs->setCurrentPage( page ); } void TabDlg::tabTestCanDecode(const QDragMoveEvent* e, bool &b){ QString jid; QCString type; if ( QTextDrag::canDecode(e) && QTextDrag::decode(e, jid, type) && type=="psichatwindow" ) { b=true; } else { b=false; } } void TabDlg::tabReceivedDropEvent(QDropEvent* e){ ChatDlg* chat; QString jid; QCString type; if ( QTextDrag::decode(e, jid, type) && type=="psichatwindow" ) { chat=psi->getChatInTabs(jid); if (chat) { TabDlg *dlg=psi->getManagingTabs(chat); dlg->sendChatTo(chat, this); } } } void TabDlg::tabReceivedDropEvent(QWidget* w, QDropEvent* e){ Q_UNUSED(w); tabReceivedDropEvent(e); } void TabDlg::startDrag(QWidget* w) { QDragObject *d = new QTextDrag( ((ChatDlg*)w)->jid().full(), this ); ((QTextDrag*)d)->setSubtype("psichatwindow"); d->dragCopy(); // do NOT delete d. } void TabDlg::keyPressEvent(QKeyEvent *e) { if (e->key() == Key_Escape) { closeChat(); } else if ( e->key() == Key_W && (e->state() & ControlButton) ) { closeChat(); } else if ( e->key() == Key_PageUp && (e->state() & ControlButton) ) { previousTab(); } else if ( e->key() == Key_PageDown && (e->state() & ControlButton) ) { nextTab(); } else e->ignore(); }