/* 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. */ /* Shows the list of channels begin: Die Apr 29 2003 copyright: (C) 2003 by Dario Abatianni email: eisfuchs@tigress.com */ #include "channellistpanel.h" #include "channel.h" #include "channellistviewitem.h" #include "server.h" #include "common.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include ChannelListPanel::ChannelListPanel(TQWidget* parent) : ChatWindow(parent) { setType(ChatWindow::ChannelList); setName(i18n("Channel List")); m_oldSortColumn = 0; setNumChannels(0); setNumUsers(0); setVisibleChannels(0); setVisibleUsers(0); setMinUsers(0); setMaxUsers(0); setChannelTarget(true); setTopicTarget(false); setRegExp(false); filterTextChanged(TQString()); TQHGroupBox* filterGroup=new TQHGroupBox(i18n("Filter Settings"),this); TQGrid* mainGrid=new TQGrid(2,Qt::Vertical,filterGroup); mainGrid->setSpacing(spacing()); TQLabel* minLabel=new TQLabel(i18n("Minimum users:"),mainGrid); TQLabel* maxLabel=new TQLabel(i18n("Maximum users:"),mainGrid); TQSpinBox* minUsersSpin=new TQSpinBox(0, 9999, 1, mainGrid,"min_users_spin"); TQWhatsThis::add(minUsersSpin, i18n("You can limit the channel list to those channels with a minimum number of users here. Choosing 0 disables this criterion.")); TQSpinBox* maxUsersSpin=new TQSpinBox(0, 9999, 1, mainGrid,"max_users_spin"); TQWhatsThis::add(maxUsersSpin, i18n("You can limit the channel list to those channels with a maximum number of users here. Choosing 0 disables this criterion.")); minUsersSpin->setValue(getMinUsers()); maxUsersSpin->setValue(getMaxUsers()); minLabel->setBuddy(minUsersSpin); maxLabel->setBuddy(maxUsersSpin); TQLabel* patternLabel=new TQLabel(i18n("Filter pattern:"),mainGrid); new TQLabel(i18n("Filter target:"),mainGrid); filterInput=new KLineEdit(mainGrid,"channel_list_filter_input"); TQWhatsThis::add(filterInput, i18n("Enter a filter string here.")); filterInput->setText(getFilterText()); patternLabel->setBuddy(filterInput); TQHBox* targetBox=new TQHBox(mainGrid); targetBox->setSpacing(spacing()); channelFilter=new TQCheckBox(i18n("Channel"),targetBox,"filter_target_channel_check"); topicFilter=new TQCheckBox(i18n("Topic"),targetBox,"filter_target_topic_check"); regexpCheck=new TQCheckBox(i18n("Regular expression"),targetBox,"regexp_check"); applyFilter=new TQPushButton(i18n("Apply Filter"),targetBox,"apply_filter_button"); TQWhatsThis::add(applyFilter, i18n("Click here to retrieve the list of channels from the server and apply the filter.")); channelFilter->setChecked(getChannelTarget()); topicFilter->setChecked(getTopicTarget()); regexpCheck->setChecked(getRegExp()); targetBox->setStretchFactor(topicFilter,10); channelListView=new TDEListView(this,"channel_list_view"); TQWhatsThis::add(channelListView, i18n("The filtered list of channels is displayed here. Notice that if you do not use regular expressions, Konversation lists any channel whose name contains the filter string you entered. The channel name does not have to start with the string you entered.\n\nSelect a channel you want to join by clicking on it. Right click on the channel to get a list of all web addresses mentioned in the channel's topic.")); channelListView->addColumn(i18n("Channel Name")); channelListView->addColumn(i18n("Users")); channelListView->addColumn(i18n("Channel Topic")); channelListView->setAllColumnsShowFocus(true); channelListView->setResizeMode( TDEListView::LastColumn ); channelListView->setSortColumn(-1); //Disable sorting TQHBox* statsBox=new TQHBox(this); statsBox->setSpacing(spacing()); TQLabel* channelsLabel=new TQLabel(TQString(),statsBox); TQLabel* usersLabel=new TQLabel(TQString(),statsBox); statsBox->setStretchFactor(usersLabel,10); TQHBox* actionBox=new TQHBox(this); actionBox->setSpacing(spacing()); refreshListButton=new TQPushButton(i18n("Refresh List"),actionBox,"refresh_list_button"); TQPushButton* saveListButton=new TQPushButton(i18n("Save List..."),actionBox,"save_list_button"); joinChannelButton=new TQPushButton(i18n("Join Channel"),actionBox,"join_channel_button"); TQWhatsThis::add(joinChannelButton, i18n("Click here to join the channel. A new tab is created for the channel.")); connect(&updateTimer,TQT_SIGNAL (timeout()),this,TQT_SLOT (updateDisplay())); // double click on channel entry joins the channel connect(channelListView,TQT_SIGNAL (doubleClicked(TQListViewItem*)), this,TQT_SLOT (joinChannelClicked()) ); connect(channelListView,TQT_SIGNAL (contextMenu (TDEListView*, TQListViewItem*, const TQPoint&) ), this, TQT_SLOT (contextMenu (TDEListView*, TQListViewItem*, const TQPoint&)) ); connect(minUsersSpin,TQT_SIGNAL (valueChanged(int)),this,TQT_SLOT(setMinUsers(int)) ); connect(maxUsersSpin,TQT_SIGNAL (valueChanged(int)),this,TQT_SLOT(setMaxUsers(int)) ); connect(this,TQT_SIGNAL (adjustMinValue(int)),minUsersSpin,TQT_SLOT (setValue(int)) ); connect(this,TQT_SIGNAL (adjustMaxValue(int)),maxUsersSpin,TQT_SLOT (setValue(int)) ); connect(filterInput,TQT_SIGNAL (textChanged(const TQString&)),this,TQT_SLOT (filterTextChanged(const TQString&)) ); connect(filterInput,TQT_SIGNAL (returnPressed()),this,TQT_SLOT (applyFilterClicked()) ); connect(channelFilter,TQT_SIGNAL (clicked()),this,TQT_SLOT (channelTargetClicked()) ); connect(topicFilter,TQT_SIGNAL (clicked()),this,TQT_SLOT (topicTargetClicked()) ); connect(regexpCheck,TQT_SIGNAL (clicked()),this,TQT_SLOT (regExpClicked()) ); connect(applyFilter,TQT_SIGNAL (clicked()),this,TQT_SLOT (applyFilterClicked()) ); connect(refreshListButton,TQT_SIGNAL (clicked()),this,TQT_SLOT (refreshList()) ); connect(saveListButton,TQT_SIGNAL (clicked()),this,TQT_SLOT (saveList()) ); connect(joinChannelButton,TQT_SIGNAL (clicked()),this,TQT_SLOT (joinChannelClicked()) ); connect(this,TQT_SIGNAL (updateNumUsers(const TQString&)),usersLabel,TQT_SLOT (setText(const TQString&)) ); connect(this,TQT_SIGNAL (updateNumChannels(const TQString&)),channelsLabel,TQT_SLOT (setText(const TQString&)) ); updateUsersChannels(); } ChannelListPanel::~ChannelListPanel() { } void ChannelListPanel::refreshList() { channelListView->clear(); setNumChannels(0); setNumUsers(0); setVisibleChannels(0); setVisibleUsers(0); updateUsersChannels(); /* No good idea: If the server is "temporary loaded" they stay disabled :-( applyFilter->setEnabled(false); refreshListButton->setEnabled(false); */ emit refreshChannelList(); } void ChannelListPanel::saveList() { // Ask user for file name TQString fileName=KFileDialog::getSaveFileName( TQString(), TQString(), this, i18n("Save Channel List")); if(!fileName.isEmpty()) { // first find the longest channel name and nick number for clean table layouting unsigned int maxChannelWidth=0; unsigned int maxNicksWidth=0; TQListViewItem* item = channelListView->firstChild(); while(item) { if(item->isVisible()) { if(item->text(0).length()>maxChannelWidth) { maxChannelWidth = item->text(0).length(); } if(item->text(1).length()>maxNicksWidth) { maxNicksWidth = item->text(1).length(); } } item = item->nextSibling(); } // now save the list to disk TQFile listFile(fileName); listFile.open(IO_WriteOnly); // wrap the file into a stream TQTextStream stream(&listFile); TQString header(i18n("Konversation Channel List: %1 - %2\n\n") .arg(m_server->getServerName()) .arg(TQDateTime::currentDateTime().toString())); // send header to stream stream << header; item = channelListView->firstChild(); while(item) { if(item->isVisible()) { TQString channelName; channelName.fill(' ',maxChannelWidth); channelName.replace(0,item->text(0).length(),item->text(0)); TQString nicksPad; nicksPad.fill(' ',maxNicksWidth); TQString nicksNum(nicksPad+item->text(1)); nicksNum=nicksNum.right(maxNicksWidth); TQString line(channelName+' '+nicksNum+' '+item->text(2)+'\n'); // send final line to stream stream << line; } item = item->nextSibling(); } listFile.close(); } } void ChannelListPanel::joinChannelClicked() { TQListViewItem* item=channelListView->selectedItem(); if(item) { emit joinChannel(item->text(0)); } } void ChannelListPanel::addToChannelList(const TQString& channel,int users,const TQString& topic) { pendingChannels.append(channel + ' ' + TQString::number(users) + ' ' + Konversation::removeIrcMarkup(topic)); // set internal numbers of channels and users, display will be updated by a timer setNumChannels(getNumChannels()+1); setNumUsers(getNumUsers()+users); if(!updateTimer.isActive()) { updateTimer.start(10); if(channelListView->sortColumn() != -1) m_oldSortColumn = channelListView->sortColumn(); channelListView->setSortColumn(-1); //Disable sorting } } void ChannelListPanel::updateDisplay() { if(!pendingChannels.isEmpty()) { // fetch next channel line TQString channelLine = pendingChannels.first(); // split it up into the single parts we need TQString channel = channelLine.section(' ',0,0); TQString users = channelLine.section(' ',1,1); TQString topic = channelLine.section(' ',2); ChannelListViewItem* item = new ChannelListViewItem(channelListView, channel, users, topic); applyFilterToItem(item); pendingChannels.pop_front(); } if(pendingChannels.isEmpty()) { updateTimer.stop(); updateUsersChannels(); channelListView->setSortColumn(m_oldSortColumn); //Disable sorting applyFilter->setEnabled(true); refreshListButton->setEnabled(true); } } void ChannelListPanel::filterTextChanged(const TQString& newText) { filterText=newText; } int ChannelListPanel::getNumChannels() { return numChannels; } int ChannelListPanel::getNumUsers() { return numUsers; } void ChannelListPanel::setNumChannels(int num) { numChannels=num; } void ChannelListPanel::setNumUsers(int num) { numUsers=num; } int ChannelListPanel::getVisibleChannels() { return visibleChannels; } int ChannelListPanel::getVisibleUsers() { return visibleUsers; } void ChannelListPanel::setVisibleChannels(int num) { visibleChannels=num; } void ChannelListPanel::setVisibleUsers(int num) { visibleUsers=num; } int ChannelListPanel::getMinUsers() { return minUsers; } int ChannelListPanel::getMaxUsers() { return maxUsers; } bool ChannelListPanel::getChannelTarget() { return channelTarget; } bool ChannelListPanel::getTopicTarget() { return topicTarget; } bool ChannelListPanel::getRegExp() { return regExp; } const TQString& ChannelListPanel::getFilterText() { return filterText; } void ChannelListPanel::setMinUsers(int num) { minUsers=num; } void ChannelListPanel::setMaxUsers(int num) { maxUsers=num; } void ChannelListPanel::setChannelTarget(bool state) { channelTarget=state; } void ChannelListPanel::setTopicTarget(bool state) { topicTarget=state; } void ChannelListPanel::setRegExp(bool state) { regExp=state; } void ChannelListPanel::channelTargetClicked() { setChannelTarget(channelFilter->state()==2); } void ChannelListPanel::topicTargetClicked() { setTopicTarget(topicFilter->state()==2); } void ChannelListPanel::regExpClicked() { setRegExp(regexpCheck->state()==2); } void ChannelListPanel::applyFilterToItem(TQListViewItem* item) { bool visible=true; if(getMinUsers() || getMaxUsers()) { if(item->text(1).toInt()=getMinUsers() && item->text(1).toInt()>getMaxUsers())) visible=false; } if(!getFilterText().isEmpty()) { if(getChannelTarget()) { if(item->text(0).find(TQRegExp(getFilterText(),false,!getRegExp()))==-1) visible=false; } if(getTopicTarget()) { if(item->text(2).find(TQRegExp(getFilterText(),false,!getRegExp()))==-1) visible=false; } } item->setVisible(visible); if(visible) { setVisibleUsers(getVisibleUsers()+item->text(1).toInt()); setVisibleChannels(getVisibleChannels()+1); } } void ChannelListPanel::applyFilterClicked() { if(!getNumChannels()) { refreshList(); return; } else { TQListViewItem* item = channelListView->firstChild(); setVisibleChannels(0); setVisibleUsers(0); while(item) { applyFilterToItem(item); item = item->nextSibling(); } updateUsersChannels(); } } void ChannelListPanel::updateUsersChannels() { emit updateNumChannels(i18n("Channels: %1 (%2 shown)").arg(getNumChannels()).arg(getVisibleChannels())); emit updateNumUsers(i18n("Non-unique users: %1 (%2 shown)").arg(getNumUsers()).arg(getVisibleUsers())); } bool ChannelListPanel::closeYourself() { // make the server delete us so server can reset the pointer to us m_server->closeChannelListPanel(); return true; } void ChannelListPanel::childAdjustFocus() { } void ChannelListPanel::contextMenu (TDEListView* /* l */, TQListViewItem* i, const TQPoint& p) { if(!i) return; TDEPopupMenu* showURLmenu = new TDEPopupMenu(this); showURLmenu->insertTitle( i18n("Open URL") ); TQString filteredLine(i->text(2)); TQRegExp pattern("((http://|https://|ftp://|nntp://|news://|gopher://|www\\.|ftp\\.)" // IP Address "([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}|" // Decimal IP address "[0-9]{1,12}|" // Standard host name "[a-z0-9][\\.@%a-z0-9_-]+\\.[a-z]{2,}" // Port number, path to document ")(:[0-9]{1,5})?(/[^)>\"'\\s]*)?|" // eDonkey2000 links need special treatment "ed2k://\\|([^|]+\\|){4})"); pattern.setCaseSensitive(false); int pos=0; while(static_cast(pos) < filteredLine.length()) { if(pattern.search(filteredLine,pos)!=-1) { // Remember where we found the url pos=pattern.pos(); // Extract url TQString url=pattern.capturedTexts()[0]; TQString href(url); // clean up href for browser if(href.startsWith("www.")) href="http://"+href; else if(href.startsWith("ftp.")) href="ftp://"+href; // Replace all spaces with %20 in href href.replace(' ', "%20"); href.replace('&', "&&"); // next search begins right after the link pos+=url.length(); // tell the program that we have found a new url showURLmenu->insertItem(href); } else { pos++; } } if (showURLmenu->count()==1) { showURLmenu->insertItem(i18n("<>"),5); showURLmenu->setItemEnabled(5,false); } int selected = showURLmenu->exec(p); if (selected!=-1) { TQMenuItem* item = showURLmenu->findItem( selected ); new KRun(KURL(item->text().replace("&&","&"))); } delete showURLmenu; } void ChannelListPanel::appendInputText(const TQString& text, bool fromCursor) { Q_UNUSED(fromCursor); filterInput->setText(filterInput->text() + text); } //Used to disable functions when not connected void ChannelListPanel::serverOnline(bool online) { refreshListButton->setEnabled(online); applyFilter->setEnabled(online); joinChannelButton->setEnabled(online); } void ChannelListPanel::emitUpdateInfo() { TQString info; info = i18n("Channel List for %1").arg(m_server->getDisplayName()); emit updateInfo(info); } void ChannelListPanel::setFilter(const TQString& filter) { filterInput->setText(filter); } #include "channellistpanel.moc"