diff options
Diffstat (limited to 'ksirc/toplevel.cpp')
-rw-r--r-- | ksirc/toplevel.cpp | 1848 |
1 files changed, 1848 insertions, 0 deletions
diff --git a/ksirc/toplevel.cpp b/ksirc/toplevel.cpp new file mode 100644 index 00000000..f064a291 --- /dev/null +++ b/ksirc/toplevel.cpp @@ -0,0 +1,1848 @@ +/********************************************************************** + + TopLevel IRC Channel/query Window + + $$Id$$ + + This is the main window with which the user interacts. It handles + both normal channel conversations and private conversations. + + 2 classes are defined, the UserControlMenu and KSircToplevel. The + user control menu is used as a list of user defineable menus used by + KSircToplevel. + + KSircTopLevel: + + Signals: + + outputLine(QString &): + output_toplevel(QString): + + closing(KSircTopLevel *, QString channel): + + changeChannel(QString old, QString new): + + currentWindow(KSircTopLevel *): + + Slots: + + + + *********************************************************************/ + +#include "toplevel.h" +#include "alistbox.h" +#include "chanparser.h" +#include "ksopts.h" +#include "control_message.h" +#include "displayMgr.h" +#include "NewWindowDialog.h" +#include "usercontrolmenu.h" +#include "topic.h" +#include "charSelector.h" +#include "ksview.h" +#include "logfile.h" +#include "servercontroller.h" +#include "ioDCC.h" + +#include "KSTicker/ksticker.h" + +#include <stdlib.h> + +#include <qaccel.h> +#include <qclipboard.h> +#include <qregexp.h> +#include <qcursor.h> +#include <qtimer.h> +#include <qlayout.h> +#include <qtextcodec.h> +#include <qvbox.h> +#include <qlabel.h> + +#include <kmenubar.h> +#include <kapplication.h> +#include <kdebug.h> +#include <kwin.h> +#include <knotifyclient.h> +#include <kpopupmenu.h> +#include <kmessagebox.h> +#include <klocale.h> +#include <kfiledialog.h> +#include <ktempfile.h> +#include <kio/netaccess.h> +#include <kstatusbar.h> +#include <kstdaction.h> +#include <kaction.h> +#include <kcharsets.h> +#include <kglobalsettings.h> +#include <kstdguiitem.h> + +extern DisplayMgr *displayMgr; +//QPopupMenu *KSircTopLevel::user_controls = 0L; +QPtrList<UserControlMenu> *KSircTopLevel::user_menu = 0L; +QStringList KSircTopLevel::cmd_menu; + +void +KSircTopLevel::initColors() +{ + QColorGroup cg_mainw = kapp->palette().active(); + cg_mainw.setColor(QColorGroup::Base, ksopts->backgroundColor); + cg_mainw.setColor(QColorGroup::Text, ksopts->textColor); + cg_mainw.setColor(QColorGroup::Link, ksopts->linkColor); + cg_mainw.setColor(QColorGroup::Highlight, ksopts->selBackgroundColor); + cg_mainw.setColor(QColorGroup::HighlightedText, ksopts->selForegroundColor); + mainw->setPalette(QPalette(cg_mainw,cg_mainw, cg_mainw)); + nicks->setPalette(QPalette(cg_mainw,cg_mainw, cg_mainw)); + linee->setPalette(QPalette(cg_mainw,cg_mainw, cg_mainw)); + lag->setPalette(QPalette(cg_mainw,cg_mainw, cg_mainw)); + cg_mainw.setColor(QColorGroup::Background, ksopts->backgroundColor); + cg_mainw.setColor(QColorGroup::Foreground, ksopts->textColor); + ksTopic->setPalette(QPalette(cg_mainw,cg_mainw, cg_mainw)); + selector->setFont( ksopts->defaultFont.family() ); + mainw->setFont( ksopts->defaultFont ); + nicks->setFont( ksopts->defaultFont ); + linee->setFont( ksopts->defaultFont ); + ksTopic->setFont( ksopts->defaultFont ); + +} + +KSircTopLevel::KSircTopLevel(KSircProcess *_proc, const KSircChannel &channelInfo, const char * name) + : KMainWindow(0, name, 0/*no WDestructiveClose !*/), + UnicodeMessageReceiver(_proc), + lastBeep( QTime::currentTime() ), + m_channelInfo(channelInfo) + +{ + // prevent us from being quitted when closing a channel-window. Only + // closing the servercontroller shall quit. + // KMainWindow will deref() us in closeEvent + kapp->ref(); + + + m_topic = QString::null; + + QCString kstl_name = QCString(QObject::name()) + "_" + "toplevel"; + setName(kstl_name); + + if(!m_channelInfo.channel().isEmpty()) { + setCaption(m_channelInfo.channel()); + caption = m_channelInfo.channel(); + } + else + { + caption = QString::null; + } + + Buffer = FALSE; + + have_focus = 0; + tab_pressed = -1; // Tab (nick completion not pressed yet) + tab_start = -1; + tab_end = -1; + + m_gotMsgWithoutFocus = false; + + KickWinOpen = false; + current_size = size(); + + ksopts->channelSetup(ksircProcess()->serverName(), m_channelInfo.channel()); + m_channelInfo.setEncoding(ksopts->chan(m_channelInfo).encoding); + + selector = new charSelector(); + connect(selector, SIGNAL(clicked()), this, SLOT(insertText())); + selector->setFont(ksopts->defaultFont.family()); + + file = new QPopupMenu(this, QCString(QObject::name()) + "_popup_file"); + file->setCheckable(true); + + KAction *act = KStdAction::openNew( this, SLOT( newWindow() ), actionCollection() ); + act->plug( file ); + file->insertItem(i18n("New Ser&ver..."), servercontroller::self(), SLOT(new_connection()), Key_F2); + file->insertSeparator(); + file->insertItem(i18n("&DCC Manager..."), this, SLOT(showDCCMgr())); + file->insertItem(i18n("&Save to Logfile..."), this, SLOT(saveCurrLog()), CTRL + Key_S); + + tsitem = file->insertItem(i18n("Time St&"), this, SLOT(toggleTimestamp()), CTRL + Key_T); + file->setItemChecked(tsitem, ksopts->chan(m_channelInfo).timeStamp); + + fjpitem = file->insertItem(i18n("Hide Join/Part Messages"), this, SLOT(toggleFilterJoinPart())); + file->setItemChecked(fjpitem, ksopts->chan(m_channelInfo).filterJoinPart); + + file->insertItem(i18n("Character &Table"), selector, SLOT(show()), CTRL + Key_H); + beepitem = file->insertItem(i18n("N&otify on Change"), this, SLOT(toggleBeep()), CTRL + Key_P); + file->setItemChecked(beepitem, ksopts->chan(m_channelInfo).beepOnMsg); + + encodingAction = new KSelectAction( i18n( "&Encoding" ), 0, this ); + connect( encodingAction, SIGNAL( activated() ), this, SLOT( setEncoding() ) ); + QStringList encodings = KGlobal::charsets()->descriptiveEncodingNames(); + + topicitem = file->insertItem(i18n("S&how Topic"), this, SLOT(toggleTopic()), CTRL + Key_O); + if (isPrivateChat() || m_channelInfo.channel().startsWith("!no_channel")) { + file->setItemEnabled(topicitem, false); + } + else { + file->setItemChecked(topicitem, ksopts->chan(m_channelInfo).topicShow); + } + + tickeritem = file->insertItem(i18n("Ticker &Mode"), this, SLOT(toggleTicker())); + + // remove utf16/ucs2 as it just doesn't work for IRC + QStringList::Iterator encodingIt = encodings.begin(); + while ( encodingIt != encodings.end() ) { + if ( ( *encodingIt ).find( "utf16" ) != -1 || + ( *encodingIt ).find( "iso-10646" ) != -1 ) + encodingIt = encodings.remove( encodingIt ); + else + ++encodingIt; + } + encodings.prepend( i18n( "Default" ) ); + + encodingAction->setItems( encodings ); + encodingAction->plug( file ); + + int eindex = encodings.findIndex(ksopts->chan(m_channelInfo).encoding); + if(eindex == -1) + encodingAction->setCurrentItem( 0 ); + else + encodingAction->setCurrentItem(eindex); + setEncoding(); + + file->insertSeparator(); + act = KStdAction::close( this, SLOT( terminate() ), actionCollection() ); + act->plug( file ); + + kmenu = menuBar(); + kmenu->insertItem(i18n("&Channel"), file, KST_CHANNEL_ID, -1); + kmenu->setAccel(Key_F, KST_CHANNEL_ID); + + /* + * Ok, let's look at the basic widget "layout" + * Everything belongs to q QFrame F, this is use so we + * can give the KApplication a single main client widget, which is needs. + * + * A QVbox and a QHbox is used to ctronl the 3 sub widget + * The Modified QListBox is then added side by side with the User list box. + * The SLE is then fit bello. + */ + + // kstInside does not setup fonts, etc, it simply handles sizing + + top = new QVBox( this ); + + ksTopic = new KSircTopic( top ); + ksTopic->setFont(ksopts->defaultFont); + connect( ksTopic, SIGNAL( topicChange( const QString & ) ), + this, SLOT( setTopicIntern( const QString & ) ) ); + + QCString kstn = QCString(QObject::name()) + "_"; + + pan = new QSplitter(QSplitter::Horizontal, top, kstn + "splitter"); +#if KDE_IS_VERSION(3,1,92) + pan->setOpaqueResize( KGlobalSettings::opaqueResize() ); +#else + pan->setOpaqueResize( true ); +#endif + + mainw = new KSircView(ksircProcess(), pan, kstn + "KSircView" ); + mainw->setFocusPolicy(QWidget::NoFocus); + + nicks_box = new QVBox(pan); + + channelButtons = new chanButtons(ksircProcess(), nicks_box); + connect(channelButtons, SIGNAL(mode(QString, int, QString)), + this, SLOT(setMode(QString, int, QString))); + + nicks = new aListBox(nicks_box, kstn + "aListBox"); + nicks->setFocusPolicy(QWidget::NoFocus); + //nicks->hide(); // default = only the main widget + + lag = new QLabel(nicks_box); + lag->setFrameStyle(QFrame::Panel|QFrame::Sunken); + lag->setAlignment(Qt::AlignCenter | Qt::SingleLine); + lag->setText(i18n("Lag: Wait")); + + + QValueList<int> sizes; + sizes << int(width()*0.85) << int(width()*0.15); + pan->setSizes(sizes); + pan->setResizeMode( mainw, QSplitter::Stretch ); + pan->setResizeMode( nicks_box, QSplitter::Stretch ); + +// f = new kstInside(top, QString(QObject::name()) + "_" + "kstIFrame"); + top->setStretchFactor(pan, 1); + + setCentralWidget(top); // Tell the KApplication what the main widget is. + + logFile = 0; + if ( ksopts->chan(m_channelInfo).logging && (m_channelInfo.channel() != "!no_channel" )) + { + logFile = new LogFile( m_channelInfo.channel(), m_channelInfo.server() ); + logFile->open(); + } + + // get basic variable + +// mainw = f->mainw; +// nicks = f->nicks; + // pan = f->pan; + + clearWindow(); + + if(isPrivateChat()){ + KConfig conf("ksirc/winlog/" + channelInfo.server() + "-" + channelInfo.channel(), + false, false, "data"); + QString group = "Message-History"; + + if(conf.hasGroup( group )){ + conf.setGroup( group ); + + QStringList strlist = conf.readListEntry("History"); + if(strlist.count() > 0){ + mainw->enableTimeStamps(true); + for ( QStringList::Iterator it = strlist.begin(); + it != strlist.end(); + ++it ) { + mainw->addRichText(*it); + } + } + strlist.clear(); + } + } + + mainw->enableTimeStamps(ksopts->chan(m_channelInfo).timeStamp); + + edit = new QPopupMenu(this); + act = KStdAction::copy( mainw, SLOT( copy() ), actionCollection() ); + act->plug( edit ); + act = KStdAction::paste( this, SLOT( pasteToWindow() ), actionCollection() ); + act->plug( edit ); + edit->insertItem(i18n("C&lear Window"), this, SLOT(clearWindow()), CTRL + Key_L); + kmenu->insertItem(i18n("&Edit"), edit, -1, -1); + + linee = new aHistLineEdit(top, ""); + + initColors(); + + // ksb_main->addWidget(linee, mainw->width()); +// ksb_main->insertItem(, KSB_MAIN_LAG, true); + + // don't show the nick lists in a private chat or the default window + if (isPrivateChat() || m_channelInfo.channel().startsWith("!no_channel")) + { + nicks_box->hide(); + ksTopic->hide(); + // nicks->hide(); + // lag->hide(); + // channelButtons->hide(); + } + else + { + nicks_box->show(); + + if(file->isItemChecked(topicitem)){ + ksTopic->show(); +// channelButtons->show(); + } + else{ + ksTopic->hide(); + // channelButtons->hide(); + } + // channelButtons->show(); + // lag->show(); + // nicks->show(); + } + + + connect(mainw, SIGNAL(pasteReq( const QString& )), + this, SLOT( slotTextDropped( const QString& ))); + + nicks->setFont(ksopts->defaultFont); + + // setup line editor + + linee->setFocusPolicy(QWidget::StrongFocus); + linee->setFont(ksopts->defaultFont); + + if(ksopts->oneLineEntry == true) { + linee->setWordWrap(QTextEdit::NoWrap); + } + else { + linee->setWordWrap(QTextEdit::WidgetWidth); + } + + connect(linee, SIGNAL(gotFocus()), + this, SLOT(gotFocus())); + connect(linee, SIGNAL(lostFocus()), + this, SLOT(lostFocus())); + connect(linee, SIGNAL(pasteText(const QString&)), + this, SLOT(slotTextDropped(const QString&))); + connect(linee, SIGNAL(notTab()), + this, SLOT(lineeNotTab())); + + connect( linee, SIGNAL( gotReturnPressed() ), + this, SLOT( returnPressed() ) ); + + linee->setFocus(); // Give SLE focus + linee->slotMaybeResize(); + + lines = 0; // Set internal line counter to 0 + + ticker = 0x0; + + /* + * Set generic run time variables + * + */ + + opami = FALSE; + continued_line = FALSE; +// on_root = FALSE; + + /* + * Load basic pics and images + * This should use on of the KDE finder commands + */ + + KWin::setIcons(winId(), kapp->icon(), kapp->miniIcon()); + + /* + * Create our basic parser object + */ + + ChanParser = new ChannelParser(this); + + + /* + * Create the user Controls popup menu, and connect it with the + * nicks list on the lefthand side (highlighted()). + * + */ + + if(user_menu == 0) + user_menu = UserControlMenu::parseKConfig(); + + user_controls = new QPopupMenu(this); + kmenu->insertItem(i18n("&Users"), user_controls); + + command = new QPopupMenu(this); + + setupCommandMenu(); + + int i = 0; + QDict<QPopupMenu> cml; + for(QStringList::Iterator it = cmd_menu.begin(); + it != cmd_menu.end(); + ++it){ + QString top, item; + top = (*it).section('/', 0, 0); + item = (*it).section('/', 1, 1); + if(!cml[top]) { + cml.insert(top, new QPopupMenu(this)); + command->insertItem(top, cml[top]); + } + cml[top]->insertItem(item, this, SLOT(cmd_process(int)), 0, i); + + i++; + } + + kmenu->insertItem(i18n("C&ommand"), command); + + kmenu->insertItem( KStdGuiItem::help().text(), helpMenu( QString::null, false )); + + connect(user_controls, SIGNAL(activated(int)), + this, SLOT(UserParseMenu(int))); + + connect(nicks, SIGNAL(contextMenuRequested(int)), this, + SLOT(UserSelected(int))); + connect(nicks, SIGNAL(selectedNick(const QString &)), + this, SLOT(openQueryFromNick(const QString &))); + connect(nicks, SIGNAL(mouseButtonClicked ( int, QListBoxItem *, const QPoint &)), + this, SLOT(pasteToNickList(int, QListBoxItem *, const QPoint &))); + connect(nicks, SIGNAL(textDropped( const QListBoxItem *, const QString& )), + this, SLOT(dndTextToNickList(const QListBoxItem *, const QString&))); + + UserUpdateMenu(); // Must call to update Popup. + + accel = new QAccel(this, "accel"); + + accel->connectItem(accel->insertItem(SHIFT + Key_PageUp), + this, + SLOT(AccelScrollUpPage())); + accel->connectItem(accel->insertItem(SHIFT + Key_PageDown), + this, + SLOT(AccelScrollDownPage())); + + /* + * Pageup/dn + * Added for stupid wheel mice + */ + + accel->connectItem(accel->insertItem(Key_PageUp), + this, + SLOT(AccelScrollUpPage())); + accel->connectItem(accel->insertItem(Key_PageDown), + this, + SLOT(AccelScrollDownPage())); + + /* + * These are not presently implemented, so let's not fill the logs. + accel->connectItem(accel->insertItem(CTRL + Key_Return), + this, + SLOT(AccelPriorMsgNick())); + + accel->connectItem(accel->insertItem(CTRL + SHIFT + Key_Return), + this, + SLOT(AccelNextMsgNick())); + */ + + accel->connectItem(accel->insertItem(Key_Tab), // adds TAB accelerator + this, // connected to the main + SLOT(TabNickCompletionNormal())); // TabNickCompletion() slot + accel->connectItem(accel->insertItem(SHIFT+Key_Tab), // adds TAB accelerator + this, // connected to the main + SLOT(TabNickCompletionShift())); // TabNickCompletion() slot + accel->connectItem(accel->insertItem(CTRL + Key_N), + this, SLOT(newWindow())); +// accel->connectItem(accel->insertItem(CTRL + Key_S), +// this, SLOT(toggleTimestamp())); + + // Drag & Drop + connect( mainw, SIGNAL( textDropped(const QString&) ), + SLOT( slotTextDropped(const QString&) )); + connect( mainw, SIGNAL( urlsDropped(const QStringList&) ), + SLOT( slotDropURLs(const QStringList&) )); + connect( nicks, SIGNAL( urlsDropped( const QStringList&, const QString& )), + SLOT( slotDccURLs( const QStringList&, const QString& ))); + connect( this, SIGNAL( changed(bool, QString) ), this, SLOT( doChange(bool, QString) )); + + mainw->setAcceptFiles( isPrivateChat() ); + resize(600, 360); + +} + +KSircTopLevel::~KSircTopLevel() +{ + // Cleanup and shutdown + // if(this == ksircProcess()->getWindowList()["default"]) + // write(sirc_stdin, "/quit\n", 7); // tell dsirc to close + // + // if(ksircProcess()->getWindowList()[m_channelInfo.channel()]) + // ksircProcess()->getWindowList().remove(m_channelInfo.channel()); + + // if((m_channelInfo.channel()[0] == '#') || (m_channelInfo.channel()[0] == '&')){ + // QString str = QString("/part ") + m_channelInfo.channel() + "\n"; + // emit outputLine(str); + // } + + kdDebug(5008) << "~KSircTopLevel in" << endl; + if ( ksopts->autoSaveHistory ) + { + if ( isPublicChat() ) { + kdDebug(5008) << "*** parting channel: " << m_channelInfo.channel() << endl; + QString str = QString("/part ") + m_channelInfo.channel() + "\n"; + emit outputUnicodeLine(str); + } + else { + QStringList strlist; + + mainw->addLine("user|X", ksopts->channelColor, " Saved log of previous messages"); + + mainw->enableTimeStamps(true); + + for(KSirc::TextParagIterator ksit = mainw->firstParag(); + ksit.atEnd() == 0; + ++ksit) { + QString rt = ksit.richText(); + if(rt.contains("<img src=\"user|servinfo\">")) + continue; + + kdDebug(5008) << rt << endl; + + strlist += rt; + + } + + KConfig conf("ksirc/winlog/" + channelInfo().server() + + "-" + channelInfo().channel(), + false, false, "data"); + QString group = "Message-History"; + + conf.setGroup( group ); + + conf.writeEntry("History", strlist); + conf.sync(); + + } + } + delete ticker; + delete user_controls; + delete ChanParser; + delete selector; + delete channelButtons; + delete logFile; + kdDebug(5008) << "~KSircToplevel out" << endl; +} + +void KSircTopLevel::setMode(QString mode, int mode_type, QString currentNick) +{ + QString command; + if (mode_type == 0) + command = QString::fromLatin1("/mode %1 %2\n").arg(m_channelInfo.channel()).arg(mode); + else + command = QString::fromLatin1("/mode %1 %2\n").arg(currentNick).arg(mode); + sirc_write(command); + linee->setFocus(); +} + +void KSircTopLevel::setEncoding() +{ + int index = encodingAction->currentItem(); + if ( index == 0 ) {// default (locale) encoding + ksopts->chan(m_channelInfo).encoding = QString::null; + UnicodeMessageReceiver::setEncoding( QString::null ); + } + else { + ksopts->chan(m_channelInfo).encoding = encodingAction->currentText(); + UnicodeMessageReceiver::setEncoding( KGlobal::charsets()->encodingForName( encodingAction->currentText() ) ); + } + ksopts->save(KSOptions::Channels); +} + +void KSircTopLevel::setupCommandMenu() +{ + if(cmd_menu.empty() == true){ + cmd_menu.append(i18n("Help") + "/" + "help"); + cmd_menu.append(i18n("Client") + "/" + "alias"); + cmd_menu.append(i18n("User") + "/" + "away"); + cmd_menu.append(i18n("Client") + "/" + "bye"); + cmd_menu.append(i18n("Client") + "/" + "cd"); + cmd_menu.append(i18n("Basic") + "/" + "ctcp"); + cmd_menu.append(i18n("Basic") + "/" + "dcc"); + cmd_menu.append(i18n("Operator") + "/" + "deop"); + cmd_menu.append(i18n("User") + "/" + "describe"); + cmd_menu.append(i18n("Client") + "/" + "eval"); + cmd_menu.append(i18n("Client") + "/" + "exit"); + cmd_menu.append(i18n("Client") + "/" + "hop"); + cmd_menu.append(i18n("Basic") + "/" + "ignore"); + cmd_menu.append(i18n("Server") + "/" + "info"); + cmd_menu.append(i18n("Channel") + "/" + "invite" + "/" + "*chan*"); + cmd_menu.append(i18n("Basic") + "/" + "join"); + cmd_menu.append(i18n("Operator") + "/" + "kick"); + cmd_menu.append(i18n("Oper") + "/" + "kill"); + cmd_menu.append(i18n("Basic") + "/" + "leave"); + cmd_menu.append(i18n("Server") + "/" + "links"); + cmd_menu.append(i18n("Basic") + "/" + "list"); + cmd_menu.append(i18n("Basic") + "/" + "ll"); + cmd_menu.append(i18n("Client") + "/" + "load"); + cmd_menu.append(i18n("Server") + "/" + "lusers"); + cmd_menu.append(i18n("Server") + "/" + "map"); + cmd_menu.append(i18n("Basic") + "/" + "me"); + cmd_menu.append(i18n("Channel") + "/" + "mode" + "/" + "*chan*"); + cmd_menu.append(i18n("Server") + "/" + "motd"); + cmd_menu.append(i18n("Basic") + "/" + "msg"); + cmd_menu.append(i18n("Basic") + "/" + "nick"); + cmd_menu.append(i18n("Basic") + "/" + "notice"); + cmd_menu.append(i18n("Basic") + "/" + "notify"); + cmd_menu.append(i18n("Operator") + "/" + "op"); + cmd_menu.append(i18n("Oper") + "/" + "oper"); + cmd_menu.append(i18n("Basic") + "/" + "query"); + cmd_menu.append(i18n("Channel") + "/" + "part"+ "/" + "*chan*"); + cmd_menu.append(i18n("Basic") + "/" + "ping"); + cmd_menu.append(i18n("Client") + "/" + "quit"); + cmd_menu.append(i18n("Server") + "/" + "quote"); + cmd_menu.append(i18n("Oper") + "/" + "rping"); + cmd_menu.append(i18n("Oper") + "/" + "rehash"); + cmd_menu.append(i18n("Basic") + "/" + "say"); + cmd_menu.append(i18n("Server") + "/" + "stats"); + cmd_menu.append(i18n("Client") + "/" + "system"); + cmd_menu.append(i18n("Server") + "/" + "time"); + cmd_menu.append(i18n("Channel") + "/" + "topic" + "/" + "*chan*"); + cmd_menu.append(i18n("Client") + "/" + "version"); + cmd_menu.append(i18n("Oper") + "/" + "wallops"); + cmd_menu.append(i18n("Channel") + "/" + "who" + "/" + "*chan*"); + cmd_menu.append(i18n("Basic") + "/" + "whois"); + cmd_menu.append(i18n("Basic") + "/" + "whowas"); + cmd_menu.append(i18n("Basic") + "/" + "wi"); + cmd_menu.append(i18n("Help") + "/" + "newuser"); + cmd_menu.append(i18n("Channel") + "/" + "ban"); + cmd_menu.append(i18n("Channel") + "/" + "unban"); + cmd_menu.append(i18n("Channel") + "/" + "clrban" + "/" + "*chan*"); + cmd_menu.append(i18n("Channel") + "/" + "banlist" + "/" + "*chan*"); + cmd_menu.append(i18n("Basic") + "/" + "pig"); + cmd_menu.append(i18n("Channel") + "/" + "wallop"); + cmd_menu.append(i18n("Client") + "/" + "exec"); + cmd_menu.append(i18n("Basic") + "/" + "url"); + cmd_menu.sort(); + } +} + +void KSircTopLevel::insertText() +{ + linee->insert(selector->currentText()); +} + +void KSircTopLevel::show() +{ + KMainWindow::show(); + linee->setFocus(); + mainw->scrollToBottom(true); +} + +enum { + KSTUp = 1, + KSTDown = 2 +}; + +void KSircTopLevel::TabNickCompletionShift() +{ + TabNickCompletion(KSTDown); +} + +void KSircTopLevel::TabNickCompletionNormal() +{ + TabNickCompletion(KSTUp); +} + +void KSircTopLevel::TabNickCompletion(int dir) +{ + /* + * Gets current text from lined find the last item and try and perform + * a nick completion, then return and reset the line. + */ + + int start, end; + int extra = 0; + bool first = false; + QString s; + + if(tab_pressed == -1){ + s = linee->text(); + tab_saved = s; + end = linee->cursorPosition() - 1; + start = s.findRev(" ", end, FALSE); + tab_start = start; + tab_end = end; + first = true; + } + else{ + s = tab_saved; + start = tab_start; + end = tab_end; + } + + if(dir == KSTDown){ + if(tab_pressed > 0) + tab_pressed -= 1; + } + else { + tab_pressed += 1; + } + + + if(s.length() == 0){ + if(tab_nick.isEmpty()) { + KNotifyClient::beep(); + lineeNotTab(); + return; + } + QString line = tab_nick + ": "; // tab_nick holds the last night since we haven't overritten it yet. + linee->setText(line); + linee->setCursorPosition(line.length()); + connect(linee, SIGNAL(notTab()), + this, SLOT(lineeNotTab())); + return; + } + + if (start == -1) { + tab_nick = findNick(s.mid(0, end+1), tab_pressed); + + if(first && (tab_nick.isNull() == TRUE)){ + KNotifyClient::beep(); + lineeNotTab(); + return; + } + else if(tab_nick.isNull() == TRUE){ + tab_pressed -= 1; + tab_nick = findNick(s.mid(0, end+1), tab_pressed); + } + s.replace(0, end + 1, ""); + if(s[0] == ':') + s.replace(0, 2, ""); + s.prepend(tab_nick + ": "); + extra = 2; + } + else { + tab_nick = findNick(s.mid(start + 1, end - start), tab_pressed); + if(first && (tab_nick.isNull() == TRUE)){ + KNotifyClient::beep(); + lineeNotTab(); + return; + } + else if(tab_nick.isNull() == TRUE){ + tab_pressed -= 1; + tab_nick = findNick(s.mid(start + 1, end - start), tab_pressed); + } + + if((uint) end == s.length() - 1){ /* if we're at the end add a space */ + s.replace(start + 1, end - start, tab_nick + " "); + extra = 1; + } + else { + s.replace(start + 1, end - start, tab_nick); + extra = 0; + } + } + + int tab = tab_pressed; + + linee->setText(s); + linee->setCursorPosition(start + tab_nick.length() + 1 + extra); + + tab_pressed = tab; // setText causes lineeTextChanged to get called and erase tab_pressed + + connect(linee, SIGNAL(notTab()), + this, SLOT(lineeNotTab())); + +} + +void KSircTopLevel::sirc_receive(QString str, bool broadcast) +{ + + /* + * read and parse output from dsirc. + * call reader, split the read input into lines, parse the lines + * then print line by line into the main text area. + * + * PROBLEMS: if a line terminates in mid line, it will get borken oddly + * + */ + + if(!Buffer){ + if( !str.isEmpty() ){ + LineBuffer.append( BufferedLine( str, broadcast ) ); + } + + bool addressed = false; + BufferedLine line; + + // be careful not to use a QValueList iterator here, as it is possible + // that we enter a local event loop (think of the ssfeprompt dialog!) + // which might trigger a socketnotifier activation which in turn + // might result in the execution of code that modifies the LineBuffer, + // which would invalidate iterators (Simon) + while ( LineBuffer.begin() != LineBuffer.end() ) + { + QString plainText(""); + line = *LineBuffer.begin(); + LineBuffer.remove( LineBuffer.begin() ); + + // Get the need list box item, with colour, etc all set + if (parse_input(line.message, plainText)) + { + // If we should add anything, add it. + // Don't announce server messages as they are + // spread through all channels anyway + + bool addressedLine = false; + + if(line.message.contains( ">~o")){ /* highlighted with our nick */ + addressedLine = true; + } + + // detect /msg's -- needed when auto-create-window is off + if ( line.message.find( QRegExp( "^\\[~b.+~b\\].+$" ) ) == 0 ) + addressedLine = true; + + if ( addressedLine == true && line.message.startsWith("* " + ksircProcess()->getNick())) + addressedLine = false; + + if ( addressedLine ) + addressed = true; + + if ( !line.wasBroadcast ) { + // This line is addressed to me if it contains my nick, or is in a private chat + emit changed( addressedLine || isPrivateChat(), plainText ); + } + } + } + LineBuffer.clear(); // Clear it since it's been added + } + else{ + LineBuffer.append( BufferedLine( str, broadcast ) ); + } + + QValueList<int> list; + QValueList<int>::iterator it; + QString values; + list = pan->sizes(); + it = list.begin(); + while( it != list.end()){ + values += QString("%1 ").arg(*it); + ++it; + } +} +void KSircTopLevel::sirc_line_return(const QString &text) +{ + + /* Take line from SLE, and output if to dsirc */ + + QString s = text; + + if(s.length() == 0) + return; + + tab_pressed = -1; // new line, zero the counter. + s += '\n'; // Append a need carriage return :) + + sirc_write(s); + + linee->setText(""); + linee->slotMaybeResize(); + +} + +void KSircTopLevel::sirc_write(const QString &str) +{ + /* + * Parse line forcommand we handle + */ + QString command = str, plain = str.lower().simplifyWhiteSpace(); + if(plain.startsWith("/join ") || + plain.startsWith("/j ") || + plain.startsWith("/query ")) { + + QString s = plain.mid(plain.find(' ')+1); + + QStringList channels = QStringList::split(",", s); + QStringList::ConstIterator it = channels.begin(); + + for( ; it != channels.end(); ++it){ + QString name = *it; + //kdDebug(5008) << "Doing " << name << endl; + QRegExp rx("(\\S+)\\s*(\\S*)"); + rx.search(name); + KSircChannel ci(m_channelInfo.server(), + rx.cap(1), // channel + rx.cap(2)); // optional key + linee->setText(QString::null); + emit open_toplevel(ci); +/* if(name[0] != '#'){ + emit open_toplevel(name); + linee->setText(QString::null); + } + else { + emit outputUnicodeLine(plain + "\n"); + emit open_toplevel(encoder()->fromUnicode(name)); + } +*/ + } + // Finish sending /join + return; + } + else if(plain.startsWith("/server ")) { + plain.simplifyWhiteSpace(); + QRegExp rx("/server (\\S+) *(\\S*) *(\\S*)"); + if(rx.search(str) >= 0){ + QString server = rx.cap(1); + QString port = rx.cap(2); + QString pass = rx.cap(3); + + bool ssl = false; + if(server.startsWith("+")){ + server.replace(0, 1, ""); + ssl = true; + } + + KSircServer serv(server, port, QString::null, pass, ssl); + servercontroller::self()->new_ksircprocess(serv); + + return; + } + } + else if(plain.startsWith("/part") || + plain.startsWith("/leave") || + plain.startsWith("/hop")) { + QApplication::postEvent(this, new QCloseEvent()); // WE'RE DEAD + linee->setText(QString::null); + return; + } + else if( plain.startsWith( "/bye" ) || + plain.startsWith( "/exit" ) || + plain.startsWith( "/quit" )) { + linee->setText( QString::null ); + emit requestQuit( command.ascii() ); + return; + } + else if ( plain.startsWith( "/away" ) ) { + QString awayEvalCommand = QString::fromLatin1( "/eval $publicAway = %1\n" ).arg( ksopts->publicAway ? '1' : '0' ); + emit outputUnicodeLine( awayEvalCommand ); + } + + // + // Look at the command, if we're assigned a channel name, default + // messages, etc to the right place. This include /me, etc + // + + if(!isSpecialWindow()) { // channel or private chat + if(plain[0].latin1() != '/'){ + command.prepend(QString::fromLatin1("/msg %1 ").arg(m_channelInfo.channel())); + } + else if(plain.startsWith("/me ")) { + command.remove(0, 3); + command.prepend(QString("/de ") + m_channelInfo.channel()); + } + } + + // Write out line + + emit outputUnicodeLine(command); + /* + * as opposed to what some might think + * it doesn't matter when you call stb + */ + mainw->scrollToBottom(true); +} + +bool KSircTopLevel::parse_input(const QString &string, QString &plainText) +{ + /* + * Parsing routines are broken into 3 majour sections + * + * 1. Search and replace evil characters. The string is searched for + * each character in turn (evil[i]), and the character string in + * evil_rep[i] is replaced. + * + * 2. Parse control messages, add pixmaps, and colourize required + * lines. Caption is also set as required. + * + * 3. Create and return the ircListItem. + * + */ + + /* + * No-output get's set to 1 if we should ignore the line + */ + + /* + * This is the second generation parsing code. + * Each line type is determined by the first 3 characters on it. + * Each line type is then sent to a parsing function. + */ + parseResult *pResult = ChanParser->parse(string); + + parseSucc *item = dynamic_cast<parseSucc *>(pResult); + parseError *err = dynamic_cast<parseError *>(pResult); + + QString logString; + + if(item) + { + parseJoinPart *jp = dynamic_cast<parseJoinPart *>(pResult); + if(jp && + ksopts->chan(m_channelInfo).filterJoinPart){ + delete pResult; + return true; + } + else if (!item->string.isEmpty()) { + logString = mainw-> + addLine( item->pm, item->colour, item->string ); + if(ticker != NULL){ + ticker->mergeString(item->string, item->colour); + } + } else { + delete pResult; + return false; + } + } + else if (err) + { + if(err->err.isEmpty() == FALSE) + { + kdWarning() << err->err << ": " << string << endl; + delete pResult; + return false; + } + if (!err->str.isEmpty()) { + logString = mainw->addLine( "user|error", ksopts->errorColor, err->str ); + } + + } + else + { + logString = mainw->addLine( QString::null, ksopts->textColor, string ); + if(ticker != NULL){ + ticker->mergeString(string); + } + // If it contains our nick, move the speaker to the top + // of the nick completion list + if(string.contains("~o")){ + QRegExp rx("<(\\S+)>"); + if ( (rx.search(logString) >= 0) && + (rx.cap(1) != ksircProcess()->getNick()) ) { + //kdDebug(5008) << "addCompleteNick: " << rx.cap(1) << endl; + addCompleteNick( rx.cap(1) ); + } + } + + } + delete pResult; + + if ( !logString.isEmpty() && logFile ) + logFile->log( logString ); + + if(!plainText.isNull()) + plainText = logString; + + return true; +} + +void KSircTopLevel::returnPressed() +{ + + QString s = linee->text(); + + uint i; + QChar c; + for(i = 0; (c = s[i]); i++){ + switch(c.unicode()){ + case 0336: + s[i] = 002; + break; + case 0327: + s[i] = 037; + break; + case 0237: + s[i] = 026; + break; + case 0252: + s[i] = 003; + break; + } + } + + while(s.length() > IRC_SAFE_MAX_LINE){ + int wrap = s.findRev(' ', IRC_SAFE_MAX_LINE); + if(wrap == -1) + wrap = IRC_SAFE_MAX_LINE; + sirc_line_return(s.left(wrap)); + s = s.mid(wrap + 1); + } + if(!s.stripWhiteSpace().isEmpty()) + sirc_line_return(s); + else { + linee->setText(""); + linee->slotMaybeResize(); + } +} + +void KSircTopLevel::UserSelected(int index) +{ + if(index >= 0) + user_controls->popup(this->cursor().pos()); +} + +void KSircTopLevel::UserParseMenu(int id) +{ + if(nicks->currentItem() < 0) + return; + + QString s; + s = QString("/eval $dest_nick='%1';\n").arg(nicks->text(nicks->currentItem())); + sirc_write(s); + // set $$dest_chan variable + s = QString("/eval $dest_chan='%1';\n").arg(m_channelInfo.channel()); + sirc_write(s); + QString action = user_menu->at(id)->action; + if (action.length() && action[0] == '/') + action.remove(0, 1); + s = QString("/eval &docommand(eval{\"%1\"});\n").arg(action); + s.replace(QRegExp("\\$\\$"), "$"); + sirc_write(s); +} + +void KSircTopLevel::UserUpdateMenu() +{ + int i = 0; + UserControlMenu *ucm; + + user_controls->clear(); + for(ucm = user_menu->first(); ucm != 0; ucm = user_menu->next(), i++){ + if(ucm->type == UserControlMenu::Seperator){ + user_controls->insertSeparator(); + } + else{ + user_controls->insertItem(ucm->title, i); + if(ucm->accel) + user_controls->setAccel(i, ucm->accel); + if((ucm->op_only == TRUE) && (opami == FALSE)) + user_controls->setItemEnabled(i, FALSE); + } + } +} + +void KSircTopLevel::AccelScrollDownPage() +{ + mainw->verticalScrollBar()->addPage(); +} + +void KSircTopLevel::AccelScrollUpPage() +{ + mainw->verticalScrollBar()->subtractPage(); +} + +void KSircTopLevel::newWindow() +{ + NewWindowDialog w(KSircChannel(m_channelInfo.server(), QString::null)); + connect(&w, SIGNAL(openTopLevel(const KSircChannel &)), SIGNAL(open_toplevel(const KSircChannel &))); + w.exec(); +} + +void KSircTopLevel::closeEvent(QCloseEvent *e) +{ + KMainWindow::closeEvent( e ); + e->accept(); + + //Let's not part the channel till we are acutally delete. + // We should always get a close event, *BUT* we will always be deleted. + // if( isPublicChat() ) { + // QString str = QString("/part ") + m_channelInfo.channel() + "\n"; + // emit outputLine(str); + // } + + // Hide ourselves until we finally die + hide(); + qApp->flushX(); + // Let's say we're closing + kdDebug(5008) << "Toplevel closing: " << m_channelInfo.channel() << endl; + emit closing(this, m_channelInfo.channel()); +} + +void KSircTopLevel::focusChange(QWidget *w) +{ + QWidget *me = this; + if(w == me){ + gotFocus(); + } + else { + lostFocus(); + } +} + +void KSircTopLevel::gotFocus() +{ + if(isVisible() == TRUE){ + if(have_focus == 0){ + if(m_channelInfo.channel()[0] != '!' ){ + QString str = QString("/join %1").arg(m_channelInfo.channel()); + if(m_channelInfo.key().length() > 0){ + str.append(" " + m_channelInfo.key()); + } + kdDebug(5008) << "Doing join: " << str << " / " << m_channelInfo.channel() << endl; + str.append("\n"); + emit outputUnicodeLine(str); + } + have_focus = 1; + emit currentWindow(this); + } + } + if(m_gotMsgWithoutFocus == true){ + m_gotMsgWithoutFocus = false; + servercontroller::self()->decreaseNotificationCount(QString("%1 -> %2 got message").arg(ksircProcess()->serverID()).arg(m_channelInfo.channel())); + } + +} + +void KSircTopLevel::lostFocus() +{ + if(have_focus == 1){ + have_focus = 0; + } +} + +void KSircTopLevel::control_message(int command, QString str) +{ + switch(command){ + case CHANGE_CHANNEL: // 001 is defined as changeChannel + { + KSircChannel ci(m_channelInfo.server(), QString::null); + QRegExp rx("([^!]+)!+([^!]+)!*([^!]*)"); + if(rx.search(str) < 0){ + ci.setChannel(str); + } + else{ + ci.setChannel(rx.cap(2)); + ci.setKey(rx.cap(3)); + } + //kdDebug(5008) << "CHANGE NAME: " << ci.channel() << " key: " << ci.key() << endl; + emit changeChannel(m_channelInfo.channel(), ci.channel()); + ksopts->channelSetup(m_channelInfo.server(), m_channelInfo.channel()); + m_channelInfo.setChannel(ci.channel()); + m_channelInfo.setKey(ci.key()); + m_channelInfo.setEncoding(ksopts->chan(m_channelInfo).encoding); + if ( !logFile && ksopts->chan(m_channelInfo).logging ) + { + logFile = new LogFile( m_channelInfo.channel(), ksircProcess()->serverName() ); + logFile->open(); + } + setName(m_channelInfo.server().utf8() + "_" + m_channelInfo.channel().utf8() + "_" + "toplevel"); + pan->setName(QCString(QObject::name()) + "_" + "QSplitter"); + kmenu->setName(QCString(QObject::name()) + "_ktoolframe"); + linee->setName(QCString(QObject::name()) + "_" + "LineEnter"); + kmenu->show(); + setCaption(m_channelInfo.channel()); + emit currentWindow(this); + + if(m_channelInfo.channel()[0] == '#' || m_channelInfo.channel()[0] == '&'){ + QString str = QString("/join %1 %2\n").arg(m_channelInfo.channel()).arg(m_channelInfo.key()); + kdDebug(5008) << "Doing /join " << m_channelInfo.channel() << " :" << str << endl; + emit outputUnicodeLine(str); + emit outputLine("/eval $query=''\n"); + } + else if (m_channelInfo.channel()[0] != '!') + { + emit outputUnicodeLine(QString("/eval $query='%1'\n").arg(m_channelInfo.channel())); + } + + bool isPrivate = isPrivateChat(); + + mainw->setAcceptFiles( isPrivate ); + + if ( isPrivate ) + { + nicks_box->hide(); + ksTopic->hide(); + file->setItemEnabled(topicitem, false); + } + else + { + file->setItemEnabled(topicitem, true); + file->setItemChecked(topicitem, ksopts->channel[m_channelInfo.server()][m_channelInfo.channel()].topicShow); + if(file->isItemChecked(topicitem)){ + ksTopic->show(); + // channelButtons->show(); + } + nicks_box->show(); + pan->show(); +// channelButtons->show(); +// nicks->show(); +// lag->show(); + } + if(layout()) { + //kdDebug(5008) << "Redoeing layout" << endl; + layout()->invalidate(); + layout()->activate(); + } + else { + //kdDebug(5008) << "No layout" << endl; + } + pan->refresh(); + + ksopts->channelSetup(m_channelInfo.server(), m_channelInfo.channel()); + file->setItemChecked(topicitem, ksopts->chan(m_channelInfo).topicShow); + file->setItemChecked(beepitem, ksopts->chan(m_channelInfo).beepOnMsg); + file->setItemChecked(tsitem, ksopts->chan(m_channelInfo).timeStamp); + file->setItemChecked(fjpitem, ksopts->chan(m_channelInfo).filterJoinPart); + int eindex = encodingAction->items().findIndex(ksopts->chan(m_channelInfo).encoding); + //kdDebug(5008) << "in change channel we want: " << ksopts->chan(m_channelInfo).encoding << " eindex: " << eindex << endl; + encodingAction->setCurrentItem(eindex < 0 ? 0 : eindex); + setEncoding(); + mainw->enableTimeStamps(ksopts->chan(m_channelInfo).timeStamp); + + break; + } + case STOP_UPDATES: + Buffer = TRUE; + break; + case RESUME_UPDATES: + Buffer = FALSE; + if(LineBuffer.isEmpty() == FALSE) + sirc_receive(QString::null); + break; + case REREAD_CONFIG: + emit freezeUpdates(TRUE); // Stop the list boxes update + selector->setFont( ksopts->defaultFont.family() ); + mainw->setFont( ksopts->defaultFont ); + nicks->setFont( ksopts->defaultFont ); + linee->setFont( ksopts->defaultFont ); + ksTopic->setFont( ksopts->defaultFont ); + UserUpdateMenu(); // Must call to update Popup. + emit freezeUpdates(FALSE); // Stop the list boxes update + initColors(); + ksopts->channelSetup(m_channelInfo.server(), m_channelInfo.channel()); + file->setItemChecked(topicitem, ksopts->channel[m_channelInfo.server()][m_channelInfo.channel()].topicShow); + file->setItemChecked(beepitem, ksopts->channel[m_channelInfo.server()][m_channelInfo.channel()].beepOnMsg); + file->setItemChecked(tsitem, ksopts->channel[m_channelInfo.server()][m_channelInfo.channel()].timeStamp); + { + int eindex = encodingAction->items().findIndex(ksopts->channel[m_channelInfo.server()][m_channelInfo.channel()].encoding); + //kdDebug(5008) << "in re-readconfig we want: " << ksopts->channel[m_channelInfo.server()][m_channelInfo.channel()].encoding << " eindex: " << eindex << endl; + encodingAction->setCurrentItem(eindex < 0 ? 0 : eindex); + setEncoding(); + } + mainw->enableTimeStamps(ksopts->channel[m_channelInfo.server()][m_channelInfo.channel()].timeStamp); + if(ksopts->oneLineEntry == true) { + linee->setWordWrap(QTextEdit::NoWrap); + } + else { + linee->setWordWrap(QTextEdit::WidgetWidth); + } + mainw->scrollToBottom(true); + update(); + break; + case SET_LAG: + if(str.isNull() == FALSE){ + bool ok = TRUE; + + str.truncate(6); + double lag = str.toDouble(&ok); + if(ok == TRUE){ + lag -= (lag*100.0 - int(lag*100.0))/100.0; + QString s_lag; + s_lag.sprintf("Lag: %.2f", lag); + this->lag->setText(s_lag); + } + else{ + this->lag->setText(str); + } + } + break; + case RESET_NOTIF: + m_gotMsgWithoutFocus = 0; + break; + default: + kdDebug(5008) << "Unkown control message: " << str << endl; + } +} + +void KSircTopLevel::setTopic( const QString &topic ) +{ + m_topic = topic; + ksTopic->setText( topic ); +} + +void KSircTopLevel::toggleTimestamp() +{ + ksopts->channel[m_channelInfo.server()][m_channelInfo.channel()].timeStamp = !ksopts->channel[m_channelInfo.server()][m_channelInfo.channel()].timeStamp; + ksopts->save(KSOptions::Channels); + mainw->enableTimeStamps( ksopts->channel[m_channelInfo.server()][m_channelInfo.channel()].timeStamp ); + file->setItemChecked( tsitem, ksopts->channel[m_channelInfo.server()][m_channelInfo.channel()].timeStamp ); +} + +void KSircTopLevel::toggleFilterJoinPart() +{ + ksopts->chan(m_channelInfo).filterJoinPart = !ksopts->chan(m_channelInfo).filterJoinPart; + ksopts->save(KSOptions::Channels); + file->setItemChecked( fjpitem, ksopts->chan(m_channelInfo).filterJoinPart ); +} + +QString KSircTopLevel::findNick(QString part, uint which) +{ + QStringList matches; + + for (QStringList::ConstIterator it = completeNicks.begin(); + it != completeNicks.end(); + ++it) + { + if ((*it).left(part.length()).lower() == part.lower() && nicks->findNick(*it) >= 0) { + matches.append(*it); + } + } + + for(uint i=0; i < nicks->count(); i++){ + if (matches.contains(nicks->text(i))) + continue; + if(nicks->text(i).length() >= part.length()){ + if(nicks->text(i).lower().startsWith( part.lower())){ + if(nicks->text(i) != ksircProcess()->getNick() ){ // Don't match your own nick + matches.append(nicks->text(i)); + } + } + } + } + if(matches.count() > 0){ + if(which < matches.count()) + return *(matches.at(which)); + else + return QString::null; + } + return QString::null; + +} + +void KSircTopLevel::removeCompleteNick(const QString &nick) +{ + QStringList::Iterator it = completeNicks.find(nick); + if (it != completeNicks.end()) + completeNicks.remove(it); +} + +void KSircTopLevel::addCompleteNick(const QString &nick) +{ + removeCompleteNick(nick); + completeNicks.prepend(nick); +} + +void KSircTopLevel::changeCompleteNick(const QString &oldNick, const QString &newNick) +{ + QStringList::Iterator it = completeNicks.find(oldNick); + if (it != completeNicks.end()) + *it = newNick; +} + +void KSircTopLevel::openQueryFromNick(const QString &nick) +{ + KSircChannel ci(m_channelInfo.server(), nick.lower()); + emit open_toplevel(ci); +} + +void KSircTopLevel::pasteToWindow() +{ + // Ctrl-V + //kdDebug(5008) << "Going to paste: " << KApplication::clipboard()->text( QClipboard::Clipboard ) << endl; + slotTextDropped(KApplication::clipboard()->text( QClipboard::Clipboard ) ); +} + +void KSircTopLevel::pasteToNickList(int button, + QListBoxItem *item, + const QPoint &) +{ + if(button == Qt::MidButton && item){ + KSircChannel ci(m_channelInfo.server(), item->text().lower()); + emit open_toplevel(ci); + + QStringList lines = QStringList::split( '\n', + KApplication::clipboard()->text( QClipboard::Selection ), + true ); + QStringList::ConstIterator it = lines.begin(); + QStringList::ConstIterator end = lines.end(); + for (; it != end; ++it ) + { + if ((*it).isEmpty()) + continue; + + QString str = + QString("/msg ") + item->text().lower() + " " + + *it + "\n"; + emit outputUnicodeLine(str); + + } + } + +} + +void KSircTopLevel::dndTextToNickList(const QListBoxItem *item, + const QString& text) +{ + if(item){ + KSircChannel ci(m_channelInfo.server(), item->text().lower()); + emit open_toplevel(ci); + + QStringList lines = QStringList::split( '\n', + text, + true ); + QStringList::ConstIterator it = lines.begin(); + QStringList::ConstIterator end = lines.end(); + for (; it != end; ++it ) + { + if ((*it).isEmpty()) + continue; + + QString str = + QString("/msg ") + item->text().lower() + " " + + *it + "\n"; + emit outputUnicodeLine(str); + + } + } + +} + +enum KSircTopLevelCommands{ Ask, Parse, Escape }; +void KSircTopLevel::slotTextDropped( const QString& _text ) +{ + if (_text.isEmpty()) + return; + QString text = linee->text(); + int curPos = linee->cursorPosition(); + + text = text.mid( 0, curPos ) + _text + text.mid( curPos ); + + if (text[text.length()-1] != '\n') + text += "\n"; + int lines = text.contains("\n"); + int approx_lines = text.length() / 75; + if ( lines > approx_lines ) + approx_lines = lines; + if (lines > 4) { + int result = KMessageBox::warningContinueCancel(this, + i18n("You are about to send %1 lines of text.\nDo you really want to send that much?").arg(approx_lines), + QString::null, i18n("Send")); + if (result != KMessageBox::Continue) + { +// linee->setText(""); + return; + } + } + + tab_pressed = -1; + if(lines > 1){ + linee->setUpdatesEnabled(FALSE); + + QStringList lines = QStringList::split( '\n', text, true ); + QStringList::ConstIterator it = lines.begin(); + QStringList::ConstIterator end = lines.end(); + KSircTopLevelCommands commands = Ask; + for (; it != end; ++it ) + { + if ((*it).isEmpty()) + continue; + QString line = *it; + if ( line[0].latin1() == '/' ) + { + if ( commands == Ask ) + switch ( KMessageBox::questionYesNo( this, i18n( + "The text you pasted contains lines that start with /.\n" + "Should they be interpreted as IRC commands?" ), QString::null, i18n("Interpret"), i18n("Do Not Interpret") ) ) + { + case KMessageBox::Yes: + commands = Parse; + break; + case KMessageBox::No: + commands = Escape; + break; + } + if ( commands == Escape ) + line.prepend( "/say " ); + } + linee->setText( line ); + sirc_line_return(line); + } + + linee->setText(""); + linee->setUpdatesEnabled(TRUE); + linee->update(); + } + else{ + text.replace(QRegExp("\n"), ""); + linee->setText(text); + linee->setCursorPosition( curPos + _text.length() ); + } +} + +void KSircTopLevel::clearWindow() +{ + kdDebug(5008) << "Doing clear on main window" << endl; + mainw->clear(); +} + +void KSircTopLevel::lineeNotTab() +{ + tab_pressed = -1; + disconnect(linee, SIGNAL(notTab()), + this, SLOT(lineeNotTab())); + addCompleteNick(tab_nick); +} + +void KSircTopLevel::toggleRootWindow() +{ +} + +bool KSircTopLevel::event( QEvent *e) +{ + if(e->type() == QEvent::ApplicationPaletteChange || + e->type() == QEvent::ApplicationFontChange) + { + QTimer::singleShot(750, this, SLOT(initColors())); + initColors(); + } + return KMainWindow::event(e); +} + +void KSircTopLevel::saveCurrLog() +{ + KURL url = KURL( KFileDialog::getSaveFileName(QString::null, + "*.log", 0L, + i18n("Save Chat/Query Logfile"))); + if( url.isEmpty()) + return; + + KTempFile temp; + QTextStream *str = temp.textStream(); + + *str << mainw->plainText(); + + temp.close(); +#if KDE_IS_VERSION(3,1,92) + KIO::NetAccess::upload(temp.name(), url, this); +#else + KIO::NetAccess::upload(temp.name(), url); +#endif +} + + +void KSircTopLevel::slotDropURLs( const QStringList& urls ) +{ + if ( !isPrivateChat() ) + return; + + slotDccURLs( urls, m_channelInfo.channel() ); +} + +// sends the list of urls to $dest_nick +void KSircTopLevel::slotDccURLs( const QStringList& urls, const QString& nick ) +{ + if ( urls.isEmpty() || nick.isEmpty() ) + return; + + QStringList::ConstIterator it = urls.begin(); + // QString s("/eval &docommand(eval{\"dcc send " + nick + " %1\"});\n"); + QString s("/dcc send " + nick + " %1\n"); + for ( ; it != urls.end(); ++it ) { + QString file( *it ); + kdDebug(5008) << "........ " << file << endl; + if ( !file.isEmpty() ) + sirc_write(s.arg( file )); + } +} + +bool KSircTopLevel::isPrivateChat() const +{ + return ((m_channelInfo.channel()[0] != '!') && (m_channelInfo.channel()[0] != '&') && + (m_channelInfo.channel()[0] != '#')); +} + +bool KSircTopLevel::isPublicChat() const +{ + return ((m_channelInfo.channel()[0] == '#') || (m_channelInfo.channel()[0] == '&')); +} + +bool KSircTopLevel::isSpecialWindow() const +{ + return (m_channelInfo.channel()[0] == '!'); +} + +void KSircTopLevel::outputUnicodeLine( const QString &message ) +{ + emit outputLine( encoder()->fromUnicode( message ) ); +} + +void KSircTopLevel::setTopicIntern( const QString &topic ) +{ + QString command = QString::fromLatin1( "/topic %1 %2\n" ).arg( m_channelInfo.channel() ).arg( topic ); + sirc_write( command ); + linee->setFocus(); +} + +void KSircTopLevel::doChange(bool pers, QString text) +{ + QTime ctime = QTime::currentTime(); + if (ksopts->channel[m_channelInfo.server()][m_channelInfo.channel()].beepOnMsg) { + // beep only every 2 seconds otherwise it'll get very noisy in the room ;) + if ( QABS( lastBeep.secsTo( ctime ) ) > 1 ) { + if ( pers ) { + int winId = !ticker ? topLevelWidget()->winId() : ticker->winId(); + KNotifyClient::event(winId, + QString::fromLatin1("ChannelPersonal"), + i18n("Your nick appeared on channel %1").arg(m_channelInfo.channel())); + } else { + int winId = !ticker ? topLevelWidget()->winId() : ticker->winId(); + KNotifyClient::event(winId, + QString::fromLatin1("ChannelChanged"), + i18n("Channel %1 changed").arg(m_channelInfo.channel())); + } + lastBeep = ctime; + } + } + + if(have_focus == 0 && pers == true && m_gotMsgWithoutFocus == false){ + m_gotMsgWithoutFocus = true; + servercontroller::self()->increaseNotificationCount(QString("%1 -> %2").arg(ksircProcess()->serverID()).arg(m_channelInfo.channel()), text); + } +} + +void KSircTopLevel::toggleBeep() +{ + ksopts->channel[m_channelInfo.server()][m_channelInfo.channel()].beepOnMsg = !ksopts->channel[m_channelInfo.server()][m_channelInfo.channel()].beepOnMsg; + ksopts->save(KSOptions::Channels); + file->setItemChecked(beepitem, ksopts->channel[m_channelInfo.server()][m_channelInfo.channel()].beepOnMsg); +} + +void KSircTopLevel::toggleTopic() +{ + if(file->isItemChecked(topicitem)){ + ksTopic->hide(); +// channelButtons->hide(); + ksopts->channel[m_channelInfo.server()][m_channelInfo.channel()].topicShow = false; + } + else { + ksTopic->show(); +// channelButtons->show(); + ksopts->channel[m_channelInfo.server()][m_channelInfo.channel()].topicShow = true; + } + file->setItemChecked(topicitem, !file->isItemChecked(topicitem)); + ksopts->save(KSOptions::Channels); +} + +void KSircTopLevel::toggleTicker() +{ + //kdDebug(5008) << "Got toggle ticker" << endl; + if(ticker){ + show(); + displayMgr->show(this); + linee->setFocus(); // Give focus back to the linee, someone takes it away on new create + tickerpoint = ticker->pos(); + tickersize = ticker->size(); + delete ticker; + ticker = 0x0; + } + else { + ticker = new KSTicker(0x0, m_channelInfo.channel().utf8() + "_ticker"); + ticker->setCaption(m_channelInfo.channel()); + if(tickerpoint.isNull() == false) + ticker->move(tickerpoint); + if(tickersize.isEmpty() == false) + ticker->resize(tickersize); + ticker->show(); + displayMgr->hide(this); + + connect(ticker, SIGNAL(doubleClick()), this, SLOT(toggleTicker())); + } +} + +bool KSircTopLevel::atBottom() +{ + return mainw->verticalScrollBar()->maxValue() - mainw->verticalScrollBar()->value() < 20; +} + +void KSircTopLevel::cmd_process(int id) +{ + if(cmd_menu.at(id) != cmd_menu.end()) { + QString item, arg, out; + item = cmd_menu[id].section('/', 1, 1); + arg = cmd_menu[id].section('/', 2, 2); + + out = "/" + item; + + if(arg == "*chan*") + out.append(" " + m_channelInfo.channel()); + + out.append(" "); + + linee->insertAt(out, 0, 0); + linee->setCursorPosition(linee->cursorPosition() + out.length()); + } +} + +void KSircTopLevel::showDCCMgr() +{ + KSircMessageReceiver *kmr = ksircProcess()->mrList().find("!dcc"); + if(kmr){ + KSircIODCC *dcc = static_cast<KSircIODCC *>(kmr); + if(dcc){ + dcc->showMgr(); + } + } +} + +#include "toplevel.moc" + +// vim: ts=2 sw=2 et |