/******************************************************************* aListBox $$Id$$ List box that outputs a right click mouse so I can popup a qpopupmenu. Does special sorting, and maintains a two part list, one for ops, other for users. nothing special. *******************************************************************/ #include "alistbox.h" #include "nickColourMaker.h" #include #include #include #include #include aListBox::aListBox(TQWidget *parent, const char *name ) : TQListBox(parent,name) { clear(); p_scroll = TQPalette(palette()); setAcceptDrops( true ); connect(this, TQT_SIGNAL(selected (const TQString&)), this, TQT_SIGNAL(selectedNick(const TQString&))); m_nickListDirty = true; updateNickPrefixWidth(); connect( this, TQT_SIGNAL( contextMenuRequested( TQListBoxItem *, const TQPoint & ) ), this, TQT_SLOT( reEmitContextMenuRequest( TQListBoxItem * ) ) ); } aListBox::~aListBox() { } void aListBox::reEmitContextMenuRequest( TQListBoxItem *item ) { emit contextMenuRequested( index( item ) ); } void aListBox::clear() { TQListBox::clear(); } void aListBox::inSort ( nickListItem *lbi) { int insert; bool found; insert = searchFor(lbi->text(), found, lbi->op()); if(found == TRUE){ //kdDebug(5008) << lbi->text() << " is already in nick list!" << endl; return; } insertItem(lbi, insert); // for(uint index = 0; index < count(); index++){ // debug("%d is %s", index, text(index)); // } m_nickListDirty = true; } void aListBox::inSort ( TQString text, bool top) { nickListItem *nli = new nickListItem(); nli->setText(text); if(top == TRUE) nli->setOp(TRUE); inSort(nli); } int aListBox::findSep() { uint i = 0; for(; i < count(); i++) if(item(i)->op() == FALSE) break; // stop now return i; } int aListBox::searchFor(const TQString &nick, bool &found, bool top) { int min = 0, max = 0; int current = 0, compare = 0; int real_max = 0; int insert; found = FALSE; // If there's nothing in the list, don't try and search it, etc if(count() == 0){ insert = 0; } else{ int sep = findSep(); if(sep >= 0){ if(top == TRUE){ min = 0; max = (sep >= 1) ? sep - 1 : 0; } else{ min = sep; max = count() - 1; } } else current = -1; real_max = max; current = (min + max)/2; // + (max-min)%2; insert = current; int last_current = -1; uint loop = 0; // Most loops should be log_2 count(), but... do { if(current == last_current){ // debug("Insert looping on %s", nick.data()); // current++; break; // we're looping, so stop } if(current >= max) break; // Don't go too far last_current = current; compare = text(current).lower().compare(nick.lower()); if(compare < 0){ min = current; insert = current + 1; // debug("1 < 0: %s is greater then: %s, min: %d max: %d current: %d", nick.data(), text(current), min, max, current); } else if(compare > 0){ max = current; insert = current; // debug("1 > 0: %s is less then: %s, min: %d max: %d current: %d", nick.data(), text(current), min, max, current); } else {// We got a match? insert = current; min = current; found = TRUE; break; } current = (min + max)/2; loop++; // Infinite loop detector increment } while(max != min && loop < count()); if(current >= real_max - 1){ compare = text(real_max).lower().compare(nick.lower()); if(compare < 0){ min = current; insert = real_max + 1; // debug("End check got one!"); } else if (compare == 0){// We got a match insert = real_max + 1; min = real_max; found = TRUE; } } // Sanity check if((top == TRUE && insert > sep) || (top == FALSE && insert < sep)){ insert = sep; } if(loop == count()) { // debug("Loop inifitly on: %s", nick.data()); } if(found == TRUE){ // debug("Found %s", nick.data()); return min; // We found one, so return the number found } } // debug("%s is at %d", nick.data(), insert); return insert; } bool aListBox::isTop(int index) { if(index >= findSep()) return FALSE; else return TRUE; } int aListBox::findNick(const TQString &str) { bool found; int index; index = searchFor(str, found, TRUE); if(found == TRUE) return index; index = searchFor(str, found, FALSE); if(found == TRUE) return index; // debug("Did not find: %s", str.data()); return -1; } nickListItem *aListBox::item(int index){ return (nickListItem *) TQListBox::item(index); } void aListBox::dragMoveEvent( TQDragMoveEvent *e ) { bool ok = (count() > 0 && KURLDrag::canDecode( e )); if(!ok) ok = TQTextDrag::canDecode(e); e->accept( ok ); if ( ok ) setCurrentItem( itemAt( e->pos() )); } void aListBox::dropEvent( TQDropEvent *e ) { TQListBoxItem *item = itemAt( e->pos() ); if ( !item ) return; setCurrentItem( item ); TQStringList urls; KURLDrag::decodeLocalFiles( e, urls ); TQString text; if ( !urls.isEmpty() ) emit urlsDropped( urls, item->text() ); else if(TQTextDrag::decode(e, text)){ emit textDropped( item, text); } } bool aListBox::needNickPrefix() const { if ( m_nickListDirty ) { updateNeedNickPrefixFlag(); const_cast( this )->updateNickPrefixWidth(); } return m_needNickPrefix; } void aListBox::updateNeedNickPrefixFlag() const { m_needNickPrefix = false; if(ksopts->useColourNickList == false){ TQListBoxItem *item = firstItem(); for (; item; item = item->next() ) { nickListItem *nickItem = static_cast( item ); if ( nickItem->op() || nickItem->voice() || nickItem->away() || nickItem->ircOp() ) { m_needNickPrefix = true; break; } } } m_nickListDirty = false; } void aListBox::fontChange( const TQFont &f ) { TQListBox::fontChange( f ); updateNickPrefixWidth(); } void aListBox::updateNickPrefixWidth() { TQFontMetrics metrics( font() ); m_nickPrefixWidth = 0; if(ksopts->useColourNickList == false){ nickListItem *item = static_cast( firstItem() ); for ( ; item; item = static_cast( item->next() ) ) m_nickPrefixWidth = kMax( m_nickPrefixWidth, metrics.width( item->nickPrefix() ) ); // padding } m_nickPrefixWidth += metrics.width( " " ); } void aListBox::clearAdvOps() { nickListItem *item = static_cast( firstItem() ); for ( ; item; item = static_cast( item->next() ) ){ if(item->away() || item->ircOp()){ item->setIrcOp(false); item->setAway(false); updateItem(item); } } triggerUpdate(false); m_nickListDirty = true; } nickListItem::nickListItem() : TQListBoxItem() { is_op = FALSE; is_voice = FALSE; is_away = FALSE; is_ircop = FALSE; forcedCol = 0x0; } nickListItem::nickListItem(const nickListItem &old) : TQListBoxItem() { is_op = old.is_op; is_voice = old.is_voice; is_away = old.is_away; is_ircop = old.is_ircop; string = old.string; forcedCol = old.forcedCol; } nickListItem::~nickListItem() { string.truncate(0); } void nickListItem::setOp(bool _op) { is_op = _op; if ( listBox() ) static_cast( listBox() )->setNickListDirty(); } void nickListItem::setVoice(bool _voice) { is_voice = _voice; if ( listBox() ) static_cast( listBox() )->setNickListDirty(); } void nickListItem::setAway(bool _away) { is_away = _away; if ( listBox() ) static_cast( listBox() )->setNickListDirty(); } void nickListItem::setIrcOp(bool _ircop) { is_ircop = _ircop; if ( listBox() ) static_cast( listBox() )->setNickListDirty(); } void nickListItem::forceColour(const TQColor *col) { forcedCol = col; } void nickListItem::paint(TQPainter *p) { TQFontMetrics fm = p->fontMetrics(); int yPos; // vertical text position int nickPosX = 3; yPos = fm.ascent() + fm.leading()/2; TQPen pen = p->pen(); TQFont font = p->font(); if(ksopts->useColourNickList == true) { if(ksopts->nickColourization){ if(!isSelected()) { if(forcedCol && forcedCol->isValid()) p->setPen(*forcedCol); else p->setPen(nickColourMaker::colourMaker()->findFg(text())); } else { p->setPen(ksopts->selForegroundColor); } if(is_voice == TRUE){ TQPen open = p->pen(); p->setPen(ksopts->channelColor); p->drawText( nickPosX, yPos, TQString("+") ); nickPosX += fm.width( "+" ); p->setPen(open); // p->fillRect(0,0, listBox()->maxItemWidth(), height(listBox()), TQBrush(ksopts->channelColor, TQt::Dense7Pattern)); } if(is_op == TRUE) { TQPen open = p->pen(); p->setPen(ksopts->errorColor); p->drawText( nickPosX, yPos, TQString("@") ); nickPosX += fm.width( "@" ); p->setPen(open); // p->fillRect(0,0, listBox()->maxItemWidth(), height(listBox()), TQBrush(ksopts->errorColor, TQt::Dense7Pattern)); } if(is_away == TRUE) p->setPen(p->pen().color().dark(150)); if(is_ircop == TRUE){ TQPen open = p->pen(); p->setPen(ksopts->errorColor); p->drawText( nickPosX, yPos, TQString("*") ); nickPosX += fm.width( "*" ); p->setPen(open); } } else { if(is_voice == TRUE) p->setPen(ksopts->channelColor); if(is_op == TRUE) p->setPen(ksopts->errorColor); if(is_away == TRUE) p->setPen(p->pen().color().dark(150)); if(is_ircop == TRUE){ TQFont bfont = font; bfont.setBold(TRUE); p->setFont(bfont); } } } else { } if(ksopts->useColourNickList == false) { aListBox *lb = static_cast( listBox() ); if ( lb->needNickPrefix() ) { p->drawText( 3, yPos, nickPrefix() ); nickPosX += lb->nickPrefixWidth(); } } p->drawText( nickPosX, yPos, text() ); p->setPen(pen); p->setFont(font); } TQString nickListItem::nickPrefix() const { TQString prefix; if ( voice() ) prefix += aListBox::nickPrefixVoice(); if ( op() ) prefix += aListBox::nickPrefixOp(); if ( away() ) prefix += aListBox::nickPrefixAway(); if ( ircOp() ) prefix += aListBox::nickPrefixIrcOp(); if ( !prefix.isEmpty() ) prefix.prepend( "+" ); return prefix; } int nickListItem::height(const TQListBox *lb ) const { return lb->fontMetrics().lineSpacing() + 1; } int nickListItem::width(const TQListBox *lb ) const { return static_cast( lb )->nickPrefixWidth() + lb->fontMetrics().width( text() ) + 6; } const TQPixmap* nickListItem::pixmap() const { return 0l; } nickListItem &nickListItem::operator= (const nickListItem &nli) { string = nli.string; is_op = nli.is_op; is_voice = nli.is_voice; is_away = nli.is_away; is_ircop = nli.is_ircop; return (*this); } #include "alistbox.moc"