/************************************************************************ AHistLineEdit $$Id$$ An extended KLineEdit with history scroll back and focus controls. Function: Each time a line is saved, to a max of 256, when the user hits enter. The arrow keys are used to scroll through the history list, rolling around at the end. When focus is gained or lost it emits the appropriate signals. This is so the toplevel can track who has focus. signals: gotFocus: duh! lostFocus: no shit sherlock Implementation: protected: keyPressEvent: Filter key presses looking for up arrow, down arrow or enter. UpArrow saves the current line at the end then scroll. No more processing. DownArrow does the opposite. Enter saves the line, but then passes on the event for normal processing. focusInEvent: emits needed signal focusOutEvent: ditto Variables: TQStrList: current list of history items. current: what I think is the current list item. *************************************************************************/ #include "ahistlineedit.h" #include "colorpicker.h" #include "ksopts.h" #include #include #include #include #include #include #include #include #include #include aHistLineEdit::aHistLineEdit(TQWidget *parent, const char *name) : TQTextEdit(parent, name) { m_drawrect = false; m_height = 0; current = hist.append(TQString()); // Set the current as blank setWrapPolicy(TQTextEdit::AtWordOrDocumentBoundary); setVScrollBarMode( AlwaysOff ); setHScrollBarMode( AlwaysOff ); // connect( this, TQT_SIGNAL( returnPressed () ), this, TQT_SLOT( slotReturn() ) ); connect( this, TQT_SIGNAL( textChanged () ), this, TQT_SLOT( slotMaybeResize() ) ); setTabChangesFocus(true); setTextFormat(PlainText); slotMaybeResize(); // setup initial size. setLineWidth(2); } void aHistLineEdit::setCursorPosition ( int index ) { TQTextEdit::setCursorPosition(0, index); } int aHistLineEdit::cursorPosition() const { int par, index; TQTextEdit::getCursorPosition(&par, &index); return index; } void aHistLineEdit::slotMaybeResize() { /* if(TQTextEdit::text().contains("\n")){ setText(text()); setCursorPosition(text().length()); } */ if(text().length() > IRC_SAFE_MAX_LINE){ if(m_drawrect == false){ m_drawrect = true; repaint(); } } else { if(m_drawrect == true){ m_drawrect = false; repaint(); } } TQFontMetrics metrics( currentFont() ); // int h = metrics.height() * lines(); int h = metrics.lineSpacing() * lines()+8; // only grow if we are less than 1/4 the size of the toplevel if(h > (topLevelWidget()->height() >> 2)) { if(this != topLevelWidget()) { h = topLevelWidget()->height() >> 2; setVScrollBarMode( Auto ); } } else { setVScrollBarMode( AlwaysOff ); } if(h != m_height){ m_height = h; TQSize s = size(); s.setHeight(h); resize(s); setFixedHeight( h ); TQLayout *l = topLevelWidget()->layout(); if(l){ l->invalidate(); l->activate(); } emit resized(); } } void aHistLineEdit::keyPressEvent( TQKeyEvent *e ) { bool accept = true; bool ignore = false; bool callKeyPressEvent = false; // kdDebug(5008) << "Got key: " << e->text() << "/" << e->key() << "-" << e->state() << endl; if ( ! (e->key() == Key_Tab || e->key() == Key_Shift || e->state() == ShiftButton || e->key() == 0)) { // kdDebug(5008) << "Sending notTab() " << e->text() << endl; emit notTab(); } // those keycodes correspond to the ones in ksirc.pl in sub hook_fixcolours if ( e->state() == ControlButton ) { TQString s = text(); int curPos = cursorPosition(); switch ( e->key() ) { case Key_K: if ( ksopts->colorPicker ) ColourPickerPopUp(); else { s.insert( cursorPosition(), 0x03 ); setText(s); setCursorPosition(curPos + 1); } break; case Key_I: s.insert( cursorPosition(), "~i"); setText(s); setCursorPosition(curPos + 2); break; case Key_Return: case Key_Enter: doEnterKey(); callKeyPressEvent = false; break; default: accept = false; ignore = false; callKeyPressEvent = true; } } else if(e->state() == 0){ switch(e->key()){ case Key_Return: case Key_Enter: doEnterKey(); callKeyPressEvent = false; break; case Key_Up: if(ksopts->oneLineEntry){ if ((*current) != text()) { // change in hist <-> text() then save text *current = text(); } if (current == hist.begin()) { // if at begin of list then wrap around current = hist.fromLast(); } else --current; // previous entry setText(*current); setCursorPosition((*current).length()); break; } case Key_Down: if(ksopts->oneLineEntry){ if ((*current) != text()) { // change in hist <-> text() then save text *current = text(); } if (current == hist.fromLast()) { // if at end of list then wrap around current = hist.begin(); } else ++current; // next entry setText(*current); setCursorPosition((*current).length()); break; } default: accept = false; ignore = false; callKeyPressEvent = true; } } // TQLineEdit falsely converts Alt+C to the character 'c', so to work around // this, we just don't pass any Alt+? key on to the keyPressEvent() method. else if (e->state() == AltButton) { switch(e->key()){ case Key_Return: case Key_Enter: doEnterKey(); callKeyPressEvent = false; break; case Key_Up: if ((*current) != text()) { // change in hist <-> text() then save text *current = text(); } if (current == hist.begin()) { // if at begin of list then wrap around current = hist.fromLast(); } else --current; // previous entry setText(*current); setCursorPosition((*current).length()); break; case Key_Down: if ((*current) != text()) { // change in hist <-> text() then save text *current = text(); } if (current == hist.fromLast()) { // if at end of list then wrap around current = hist.begin(); } else ++current; // next entry setText(*current); setCursorPosition((*current).length()); break; default: accept = false; callKeyPressEvent = true; } } else if (e->state() == ShiftButton){ switch(e->key()){ case Key_Return: case Key_Enter: doEnterKey(); callKeyPressEvent = false; break; default: accept = false; ignore = false; callKeyPressEvent = true; } } else { switch(e->key()){ case Key_Return: case Key_Enter: doEnterKey(); callKeyPressEvent = false; break; default: accept = false; ignore = false; callKeyPressEvent = true; } } // kdDebug(5008) << "Accept: " << accept << " Ignore: " << ignore << " callKPE: " << callKeyPressEvent << endl; if ( accept ) { e->accept(); } else { if ( ignore ) { e->ignore(); } else { if ( callKeyPressEvent ) { TQTextEdit::keyPressEvent(e); } } } } bool aHistLineEdit::processKeyEvent( TQKeyEvent *e ) { /* * Only put key sequences in here you * want us to ignore and to pass upto * parent widgets for handling */ bool eat = false; // kdDebug(5008) << "Key: " << TDEShortcut( KKey( e ) ).toString() << " StdAccel: " << TDEStdAccel::paste().toString() << endl; if ( TDEStdAccel::paste().contains(KKey( e ))) { e->ignore(); eat = true; } return eat; } void aHistLineEdit::ColourPickerPopUp() { ColorPicker picker( this ); if ( picker.exec() == TQDialog::Accepted ) { TQString s = text(); // int curPos = cursorPosition(); int curPos, p; getCursorPosition(&p, &curPos); TQString colString = picker.colorString(); colString.prepend( 0x03 ); s.insert( curPos, colString ); setText( s ); setCursorPosition( curPos + colString.length() ); } } void aHistLineEdit::focusInEvent(TQFocusEvent *e) { TQTextEdit::focusInEvent(e); emit gotFocus(); } void aHistLineEdit::focusOutEvent(TQFocusEvent *e) { TQTextEdit::focusOutEvent(e); emit lostFocus(); } #if 0 void aHistLineEdit::mousePressEvent ( TQMouseEvent *e ) { if(e->button() == MidButton){ /* * emit pasteText(TQApplication::clipboard()->text(TQClipboard::Selection)); */ } else{ TQTextEdit::mousePressEvent(e); } } #endif bool aHistLineEdit::eventFilter( TQObject *o, TQEvent *e ) { if ( TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(this) && e->type() == TQEvent::AccelOverride ) if(processKeyEvent( TQT_TQKEYEVENT( e ) ) == true) return true; return TQTextEdit::eventFilter( o, e ); } TQString aHistLineEdit::text() const { TQString s = TQTextEdit::text(); s.remove("\n"); return s; } // Called upon MMB on the lineedit void aHistLineEdit::paste() { /* we let the top level take it */ if(ksopts->oneLineEntry) { emit pasteText(TQApplication::clipboard()->text(TQClipboard::Selection)); } else { TQString paste = TQApplication::clipboard()->text(TQClipboard::Selection); paste.replace("\n", " ~ "); insert(paste); } } void aHistLineEdit::paintEvent ( TQPaintEvent *p ) { TQTextEdit::paintEvent(p); if(m_drawrect == true){ TQPainter paint(this); TQPen pen = paint.pen(); pen.setWidth(5); pen.setStyle(Qt::SolidLine); pen.setColor(palette().active().highlight()); paint.setPen(pen); TQRect r = frameRect(); paint.drawRect(r); } } void aHistLineEdit::doEnterKey() { // strategy: always append an empty line to the end if ((*current).isEmpty()) { // current is empty if (!text().isEmpty()) { // text() has something -> store it in current and add a new empty one *current = text(); hist.append(TQString()); // always add empty line at end if (hist.count() >= 256) { // if appended check if it will go beyond the max number of entries hist.remove(hist.begin()); // if so then delete the first entry } } } else { // current has content if (!text().isEmpty()) { // both !isEmpty() and != -> append at end current = hist.fromLast(); // goto last entry which is empty *current = text(); // change content to text() hist.append(TQString()); // always add empty line at end if (hist.count() >= 256) { // if appended check if it will go beyond the max number of entries hist.remove(hist.begin()); // if so then delete the first entry } } } current = hist.fromLast(); // set current history item back to the last item in the list emit gotReturnPressed(); } #include "ahistlineedit.moc"