/* * This file is part of the DOM implementation for KDE. * * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2000 Dirk Mueller (mueller@kde.org) * (C) 2006 Maksim Orlovich (maksim@kde.org) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */ #include <kcompletionbox.h> #include <kcursor.h> #include <kdebug.h> #include <kfiledialog.h> #include <kfind.h> #include <kfinddialog.h> #include <kiconloader.h> #include <klocale.h> #include <kmessagebox.h> #include <kreplace.h> #include <kreplacedialog.h> #include <kspell.h> #include <kurlcompletion.h> #include <kwin.h> #include <tqstyle.h> #include "misc/helper.h" #include "xml/dom2_eventsimpl.h" #include "html/html_formimpl.h" #include "misc/htmlhashes.h" #include "rendering/render_form.h" #include <assert.h> #include "khtmlview.h" #include "khtml_ext.h" #include "xml/dom_docimpl.h" #include <tqpopupmenu.h> #include <tqbitmap.h> using namespace khtml; RenderFormElement::RenderFormElement(HTMLGenericFormElementImpl *element) : RenderWidget(element) { // init RenderObject attributes setInline(true); // our object is Inline m_state = 0; } RenderFormElement::~RenderFormElement() { } short RenderFormElement::baselinePosition( bool f ) const { return RenderWidget::baselinePosition( f ) - 2 - style()->fontMetrics().descent(); } void RenderFormElement::updateFromElement() { m_widget->setEnabled(!element()->disabled()); RenderWidget::updateFromElement(); } void RenderFormElement::layout() { KHTMLAssert( needsLayout() ); KHTMLAssert( minMaxKnown() ); // minimum height m_height = 0; calcWidth(); calcHeight(); if ( m_widget ) resizeWidget(m_width-borderLeft()-borderRight()-paddingLeft()-paddingRight(), m_height-borderTop()-borderBottom()-paddingTop()-paddingBottom()); setNeedsLayout(false); } TQ_Alignment RenderFormElement::textAlignment() const { switch (style()->textAlign()) { case LEFT: case KHTML_LEFT: return Qt::AlignLeft; case RIGHT: case KHTML_RIGHT: return Qt::AlignRight; case CENTER: case KHTML_CENTER: return Qt::AlignHCenter; case JUSTIFY: // Just fall into the auto code for justify. case TAAUTO: return style()->direction() == RTL ? Qt::AlignRight : Qt::AlignLeft; } assert(false); // Should never be reached. return Qt::AlignLeft; } // ------------------------------------------------------------------------- RenderButton::RenderButton(HTMLGenericFormElementImpl *element) : RenderFormElement(element) { } short RenderButton::baselinePosition( bool f ) const { return RenderWidget::baselinePosition( f ) - 2; } // ------------------------------------------------------------------------------- RenderCheckBox::RenderCheckBox(HTMLInputElementImpl *element) : RenderButton(element) { TQCheckBox* b = new TQCheckBox(view()->viewport(), "__khtml"); b->setAutoMask(true); b->setMouseTracking(true); setQWidget(b); // prevent firing toggled() signals on initialization b->setChecked(element->checked()); connect(b,TQT_SIGNAL(stateChanged(int)),this,TQT_SLOT(slotStateChanged(int))); } void RenderCheckBox::calcMinMaxWidth() { KHTMLAssert( !minMaxKnown() ); TQCheckBox *cb = static_cast<TQCheckBox *>( m_widget ); TQSize s( cb->tqstyle().tqpixelMetric( TQStyle::PM_IndicatorWidth ), cb->tqstyle().tqpixelMetric( TQStyle::PM_IndicatorHeight ) ); setIntrinsicWidth( s.width() ); setIntrinsicHeight( s.height() ); RenderButton::calcMinMaxWidth(); } void RenderCheckBox::updateFromElement() { widget()->setChecked(element()->checked()); RenderButton::updateFromElement(); } void RenderCheckBox::slotStateChanged(int state) { element()->setChecked(state == TQButton::On); element()->setIndeterminate(state == TQButton::NoChange); ref(); element()->onChange(); deref(); } // ------------------------------------------------------------------------------- RenderRadioButton::RenderRadioButton(HTMLInputElementImpl *element) : RenderButton(element) { TQRadioButton* b = new TQRadioButton(view()->viewport(), "__khtml"); b->setMouseTracking(true); setQWidget(b); // prevent firing toggled() signals on initialization b->setChecked(element->checked()); connect(b,TQT_SIGNAL(toggled(bool)),this,TQT_SLOT(slotToggled(bool))); } void RenderRadioButton::updateFromElement() { widget()->setChecked(element()->checked()); RenderButton::updateFromElement(); } void RenderRadioButton::calcMinMaxWidth() { KHTMLAssert( !minMaxKnown() ); TQRadioButton *rb = static_cast<TQRadioButton *>( m_widget ); TQSize s( rb->tqstyle().tqpixelMetric( TQStyle::PM_ExclusiveIndicatorWidth ), rb->tqstyle().tqpixelMetric( TQStyle::PM_ExclusiveIndicatorHeight ) ); setIntrinsicWidth( s.width() ); setIntrinsicHeight( s.height() ); RenderButton::calcMinMaxWidth(); } void RenderRadioButton::slotToggled(bool activated) { if(activated) { ref(); element()->onChange(); deref(); } } // ------------------------------------------------------------------------------- RenderSubmitButton::RenderSubmitButton(HTMLInputElementImpl *element) : RenderButton(element) { TQPushButton* p = new TQPushButton(view()->viewport(), "__khtml"); setQWidget(p); p->setAutoMask(true); p->setMouseTracking(true); } TQString RenderSubmitButton::rawText() { TQString value = element()->valueWithDefault().string(); value = value.stripWhiteSpace(); TQString raw; for(unsigned int i = 0; i < value.length(); i++) { raw += value[i]; if(value[i] == '&') raw += '&'; } return raw; } void RenderSubmitButton::calcMinMaxWidth() { KHTMLAssert( !minMaxKnown() ); TQString raw = rawText(); TQPushButton* pb = static_cast<TQPushButton*>(m_widget); pb->setText(raw); pb->setFont(style()->font()); bool empty = raw.isEmpty(); if ( empty ) raw = TQString::tqfromLatin1("X"); TQFontMetrics fm = pb->fontMetrics(); TQSize ts = fm.size( ShowPrefix, raw); TQSize s(pb->tqstyle().tqsizeFromContents( TQStyle::CT_PushButton, pb, ts ) .expandedTo(TQApplication::globalStrut())); int margin = pb->tqstyle().tqpixelMetric( TQStyle::PM_ButtonMargin, pb) + pb->tqstyle().tqpixelMetric( TQStyle::PM_DefaultFrameWidth, pb ) * 2; int w = ts.width() + margin; int h = s.height(); if (pb->isDefault() || pb->autoDefault()) { int dbw = pb->tqstyle().tqpixelMetric( TQStyle::PM_ButtonDefaultIndicator, pb ) * 2; w += dbw; } // add 30% margins to the width (heuristics to make it look similar to IE) s = TQSize( w*13/10, h ).expandedTo(TQApplication::globalStrut()); setIntrinsicWidth( s.width() ); setIntrinsicHeight( s.height() ); RenderButton::calcMinMaxWidth(); } void RenderSubmitButton::updateFromElement() { TQString oldText = static_cast<TQPushButton*>(m_widget)->text(); TQString newText = rawText(); static_cast<TQPushButton*>(m_widget)->setText(newText); if ( oldText != newText ) setNeedsLayoutAndMinMaxRecalc(); RenderFormElement::updateFromElement(); } short RenderSubmitButton::baselinePosition( bool f ) const { return RenderFormElement::baselinePosition( f ); } // ------------------------------------------------------------------------------- RenderResetButton::RenderResetButton(HTMLInputElementImpl *element) : RenderSubmitButton(element) { } // ------------------------------------------------------------------------------- LineEditWidget::LineEditWidget(DOM::HTMLInputElementImpl* input, KHTMLView* view, TQWidget* parent) : KLineEdit(parent, "__khtml"), m_input(input), m_view(view), m_spell(0) { setMouseTracking(true); KActionCollection *ac = new KActionCollection(this); m_spellAction = KStdAction::spelling( TQT_TQOBJECT(this), TQT_SLOT( slotCheckSpelling() ), ac ); } LineEditWidget::~LineEditWidget() { delete m_spell; m_spell = 0L; } void LineEditWidget::slotCheckSpelling() { if ( text().isEmpty() ) { return; } delete m_spell; m_spell = new KSpell( this, i18n( "Spell Checking" ), TQT_TQOBJECT(this), TQT_SLOT( slotSpellCheckReady( KSpell *) ), 0, true, true); connect( m_spell, TQT_SIGNAL( death() ),this, TQT_SLOT( spellCheckerFinished() ) ); connect( m_spell, TQT_SIGNAL( misspelling( const TQString &, const TQStringList &, unsigned int ) ),this, TQT_SLOT( spellCheckerMisspelling( const TQString &, const TQStringList &, unsigned int ) ) ); connect( m_spell, TQT_SIGNAL( corrected( const TQString &, const TQString &, unsigned int ) ),this, TQT_SLOT( spellCheckerCorrected( const TQString &, const TQString &, unsigned int ) ) ); } void LineEditWidget::spellCheckerMisspelling( const TQString &_text, const TQStringList &, unsigned int pos) { highLightWord( _text.length(),pos ); } void LineEditWidget::highLightWord( unsigned int length, unsigned int pos ) { setSelection ( pos, length ); } void LineEditWidget::spellCheckerCorrected( const TQString &old, const TQString &corr, unsigned int pos ) { if( old!= corr ) { setSelection ( pos, old.length() ); insert( corr ); setSelection ( pos, corr.length() ); } } void LineEditWidget::spellCheckerFinished() { } void LineEditWidget::slotSpellCheckReady( KSpell *s ) { s->check( text() ); connect( s, TQT_SIGNAL( done( const TQString & ) ), this, TQT_SLOT( slotSpellCheckDone( const TQString & ) ) ); } void LineEditWidget::slotSpellCheckDone( const TQString &s ) { if( s != text() ) setText( s ); } TQPopupMenu *LineEditWidget::createPopupMenu() { TQPopupMenu *popup = KLineEdit::createPopupMenu(); if ( !popup ) { return 0L; } connect( popup, TQT_SIGNAL( activated( int ) ), this, TQT_SLOT( extendedMenuActivated( int ) ) ); if (m_input->autoComplete()) { popup->insertSeparator(); int id = popup->insertItem( SmallIconSet("edit"), i18n("&Edit History..."), EditHistory ); popup->setItemEnabled( id, (compObj() && !compObj()->isEmpty()) ); id = popup->insertItem( SmallIconSet("history_clear"), i18n("Clear &History"), ClearHistory ); popup->setItemEnabled( id, (compObj() && !compObj()->isEmpty()) ); } if (echoMode() == TQLineEdit::Normal && !isReadOnly()) { popup->insertSeparator(); m_spellAction->plug(popup); m_spellAction->setEnabled( !text().isEmpty() ); } return popup; } void LineEditWidget::extendedMenuActivated( int id) { switch ( id ) { case ClearHistory: m_view->clearCompletionHistory(m_input->name().string()); if (compObj()) compObj()->clear(); case EditHistory: { KHistoryComboEditor dlg( compObj() ? compObj()->items() : TQStringList(), this ); connect( &dlg, TQT_SIGNAL( removeFromHistory(const TQString&) ), TQT_SLOT( slotRemoveFromHistory(const TQString&)) ); dlg.exec(); } default: break; } } void LineEditWidget::slotRemoveFromHistory(const TQString &entry) { m_view->removeFormCompletionItem(m_input->name().string(), entry); if (compObj()) compObj()->removeItem(entry); } bool LineEditWidget::event( TQEvent *e ) { if (KLineEdit::event(e)) return true; if ( e->type() == TQEvent::AccelAvailable && isReadOnly() ) { TQKeyEvent* ke = (TQKeyEvent*) e; if ( ke->state() & ControlButton ) { switch ( ke->key() ) { case Key_Left: case Key_Right: case Key_Up: case Key_Down: case Key_Home: case Key_End: ke->accept(); default: break; } } } return false; } void LineEditWidget::mouseMoveEvent(TQMouseEvent *e) { // hack to prevent Qt from calling setCursor on the widget setDragEnabled(false); KLineEdit::mouseMoveEvent(e); setDragEnabled(true); } // ----------------------------------------------------------------------------- RenderLineEdit::RenderLineEdit(HTMLInputElementImpl *element) : RenderFormElement(element) { LineEditWidget *edit = new LineEditWidget(element, view(), view()->viewport()); connect(edit,TQT_SIGNAL(returnPressed()), this, TQT_SLOT(slotReturnPressed())); connect(edit,TQT_SIGNAL(textChanged(const TQString &)),this,TQT_SLOT(slotTextChanged(const TQString &))); if(element->inputType() == HTMLInputElementImpl::PASSWORD) edit->setEchoMode( TQLineEdit::Password ); if ( element->autoComplete() ) { TQStringList completions = view()->formCompletionItems(element->name().string()); if (completions.count()) { edit->completionObject()->setItems(completions); edit->setContextMenuEnabled(true); edit->completionBox()->setTabHandling( false ); } } setQWidget(edit); } void RenderLineEdit::setStyle(RenderStyle* _style) { RenderFormElement::setStyle( _style ); widget()->tqsetAlignment(textAlignment()); } void RenderLineEdit::highLightWord( unsigned int length, unsigned int pos ) { LineEditWidget* w = static_cast<LineEditWidget*>(m_widget); if ( w ) w->highLightWord( length, pos ); } void RenderLineEdit::slotReturnPressed() { // don't submit the form when return was pressed in a completion-popup KCompletionBox *box = widget()->completionBox(false); if ( box && box->isVisible() && box->currentItem() != -1 ) { box->hide(); return; } // Emit onChange if necessary // Works but might not be enough, dirk said he had another solution at // hand (can't remember which) - David handleFocusOut(); HTMLFormElementImpl* fe = element()->form(); if ( fe ) fe->submitFromKeyboard(); } void RenderLineEdit::handleFocusOut() { if ( widget() && widget()->edited() ) { element()->onChange(); widget()->setEdited( false ); } } void RenderLineEdit::calcMinMaxWidth() { KHTMLAssert( !minMaxKnown() ); const TQFontMetrics &fm = style()->fontMetrics(); TQSize s; int size = element()->size(); int h = fm.lineSpacing(); int w = fm.width( 'x' ) * (size > 0 ? size+1 : 17); // "some" s = TQSize(w + 2 + 2*widget()->frameWidth(), kMax(h, 14) + 2 + 2*widget()->frameWidth()) .expandedTo(TQApplication::globalStrut()); setIntrinsicWidth( s.width() ); setIntrinsicHeight( s.height() ); RenderFormElement::calcMinMaxWidth(); } void RenderLineEdit::updateFromElement() { int ml = element()->maxLength(); if ( ml < 0 ) ml = 32767; if ( widget()->maxLength() != ml ) { widget()->setMaxLength( ml ); } if (element()->value().string() != widget()->text()) { widget()->blockSignals(true); int pos = widget()->cursorPosition(); widget()->setText(element()->value().string()); widget()->setEdited( false ); widget()->setCursorPosition(pos); widget()->blockSignals(false); } widget()->setReadOnly(element()->readOnly()); RenderFormElement::updateFromElement(); } void RenderLineEdit::slotTextChanged(const TQString &string) { // don't use setValue here! element()->m_value = string; element()->m_unsubmittedFormChange = true; } void RenderLineEdit::select() { static_cast<LineEditWidget*>(m_widget)->selectAll(); } long RenderLineEdit::selectionStart() { LineEditWidget* w = static_cast<LineEditWidget*>(m_widget); if (w->hasSelectedText()) return w->selectionStart(); else return w->cursorPosition(); } long RenderLineEdit::selectionEnd() { LineEditWidget* w = static_cast<LineEditWidget*>(m_widget); if (w->hasSelectedText()) return w->selectionStart() + w->selectedText().length(); else return w->cursorPosition(); } void RenderLineEdit::setSelectionStart(long pos) { LineEditWidget* w = static_cast<LineEditWidget*>(m_widget); //See whether we have a non-empty selection now. long end = selectionEnd(); if (end > pos) w->setSelection(pos, end - pos); w->setCursorPosition(pos); } void RenderLineEdit::setSelectionEnd(long pos) { LineEditWidget* w = static_cast<LineEditWidget*>(m_widget); //See whether we have a non-empty selection now. long start = selectionStart(); if (start < pos) w->setSelection(start, pos - start); w->setCursorPosition(pos); } void RenderLineEdit::setSelectionRange(long start, long end) { LineEditWidget* w = static_cast<LineEditWidget*>(m_widget); w->setCursorPosition(end); w->setSelection(start, end - start); } // --------------------------------------------------------------------------- RenderFieldset::RenderFieldset(HTMLGenericFormElementImpl *element) : RenderBlock(element) { } RenderObject* RenderFieldset::layoutLegend(bool relayoutChildren) { RenderObject* legend = findLegend(); if (legend) { if (relayoutChildren) legend->setNeedsLayout(true); legend->layoutIfNeeded(); int xPos = borderLeft() + paddingLeft() + legend->marginLeft(); if (style()->direction() == RTL) xPos = m_width - paddingRight() - borderRight() - legend->width() - legend->marginRight(); int b = borderTop(); int h = legend->height(); legend->setPos(xPos, kMax((b-h)/2, 0)); m_height = kMax(b,h) + paddingTop(); } return legend; } RenderObject* RenderFieldset::findLegend() { for (RenderObject* legend = firstChild(); legend; legend = legend->nextSibling()) { if (!legend->isFloatingOrPositioned() && legend->element() && legend->element()->id() == ID_LEGEND) return legend; } return 0; } void RenderFieldset::paintBoxDecorations(PaintInfo& pI, int _tx, int _ty) { //kdDebug( 6040 ) << renderName() << "::paintDecorations()" << endl; RenderObject* legend = findLegend(); if (!legend) return RenderBlock::paintBoxDecorations(pI, _tx, _ty); int w = width(); int h = height() + borderTopExtra() + borderBottomExtra(); int yOff = (legend->yPos() > 0) ? 0 : (legend->height()-borderTop())/2; h -= yOff; _ty += yOff - borderTopExtra(); int my = kMax(_ty,pI.r.y()); int end = kMin( pI.r.y() + pI.r.height(), _ty + h ); int mh = end - my; paintBackground(pI.p, style()->backgroundColor(), style()->backgroundLayers(), my, mh, _tx, _ty, w, h); if ( style()->hasBorder() ) paintBorderMinusLegend(pI.p, _tx, _ty, w, h, style(), legend->xPos(), legend->width()); } void RenderFieldset::paintBorderMinusLegend(TQPainter *p, int _tx, int _ty, int w, int h, const RenderStyle* style, int lx, int lw) { const TQColor& tc = style->borderTopColor(); const TQColor& bc = style->borderBottomColor(); EBorderStyle ts = style->borderTopStyle(); EBorderStyle bs = style->borderBottomStyle(); EBorderStyle ls = style->borderLeftStyle(); EBorderStyle rs = style->borderRightStyle(); bool render_t = ts > BHIDDEN; bool render_l = ls > BHIDDEN; bool render_r = rs > BHIDDEN; bool render_b = bs > BHIDDEN; if(render_t) { drawBorder(p, _tx, _ty, _tx + lx, _ty + style->borderTopWidth(), BSTop, tc, style->color(), ts, (render_l && (ls == DOTTED || ls == DASHED || ls == DOUBLE)?style->borderLeftWidth():0), 0); drawBorder(p, _tx+lx+lw, _ty, _tx + w, _ty + style->borderTopWidth(), BSTop, tc, style->color(), ts, 0, (render_r && (rs == DOTTED || rs == DASHED || rs == DOUBLE)?style->borderRightWidth():0)); } if(render_b) drawBorder(p, _tx, _ty + h - style->borderBottomWidth(), _tx + w, _ty + h, BSBottom, bc, style->color(), bs, (render_l && (ls == DOTTED || ls == DASHED || ls == DOUBLE)?style->borderLeftWidth():0), (render_r && (rs == DOTTED || rs == DASHED || rs == DOUBLE)?style->borderRightWidth():0)); if(render_l) { const TQColor& lc = style->borderLeftColor(); bool ignore_top = (tc == lc) && (ls >= OUTSET) && (ts == DOTTED || ts == DASHED || ts == SOLID || ts == OUTSET); bool ignore_bottom = (bc == lc) && (ls >= OUTSET) && (bs == DOTTED || bs == DASHED || bs == SOLID || bs == INSET); drawBorder(p, _tx, _ty, _tx + style->borderLeftWidth(), _ty + h, BSLeft, lc, style->color(), ls, ignore_top?0:style->borderTopWidth(), ignore_bottom?0:style->borderBottomWidth()); } if(render_r) { const TQColor& rc = style->borderRightColor(); bool ignore_top = (tc == rc) && (rs >= DOTTED || rs == INSET) && (ts == DOTTED || ts == DASHED || ts == SOLID || ts == OUTSET); bool ignore_bottom = (bc == rc) && (rs >= DOTTED || rs == INSET) && (bs == DOTTED || bs == DASHED || bs == SOLID || bs == INSET); drawBorder(p, _tx + w - style->borderRightWidth(), _ty, _tx + w, _ty + h, BSRight, rc, style->color(), rs, ignore_top?0:style->borderTopWidth(), ignore_bottom?0:style->borderBottomWidth()); } } void RenderFieldset::setStyle(RenderStyle* _style) { RenderBlock::setStyle(_style); // WinIE renders fieldsets with display:inline like they're inline-blocks. For us, // an inline-block is just a block element with replaced set to true and inline set // to true. Ensure that if we ended up being inline that we set our replaced flag // so that we're treated like an inline-block. if (isInline()) setReplaced(true); } // ------------------------------------------------------------------------- RenderFileButton::RenderFileButton(HTMLInputElementImpl *element) : RenderFormElement(element) { KURLRequester* w = new KURLRequester( view()->viewport(), "__khtml" ); w->setMode(KFile::File | KFile::ExistingOnly); w->completionObject()->setDir(KGlobalSettings::documentPath()); connect(w->lineEdit(), TQT_SIGNAL(returnPressed()), this, TQT_SLOT(slotReturnPressed())); connect(w->lineEdit(), TQT_SIGNAL(textChanged(const TQString &)),this,TQT_SLOT(slotTextChanged(const TQString &))); connect(w, TQT_SIGNAL(urlSelected(const TQString &)),this,TQT_SLOT(slotUrlSelected(const TQString &))); setQWidget(w); m_haveFocus = false; } void RenderFileButton::calcMinMaxWidth() { KHTMLAssert( !minMaxKnown() ); const TQFontMetrics &fm = style()->fontMetrics(); int size = element()->size(); int h = fm.lineSpacing(); int w = fm.width( 'x' ) * (size > 0 ? size+1 : 17); // "some" KLineEdit* edit = static_cast<KURLRequester*>( m_widget )->lineEdit(); TQSize s = edit->tqstyle().tqsizeFromContents(TQStyle::CT_LineEdit, edit, TQSize(w + 2 + 2*edit->frameWidth(), kMax(h, 14) + 2 + 2*edit->frameWidth())) .expandedTo(TQApplication::globalStrut()); TQSize bs = static_cast<KURLRequester*>( m_widget )->tqminimumSizeHint() - edit->tqminimumSizeHint(); setIntrinsicWidth( s.width() + bs.width() ); setIntrinsicHeight( kMax(s.height(), bs.height()) ); RenderFormElement::calcMinMaxWidth(); } void RenderFileButton::handleFocusOut() { if ( widget()->lineEdit() && widget()->lineEdit()->edited() ) { element()->onChange(); widget()->lineEdit()->setEdited( false ); } } void RenderFileButton::updateFromElement() { KLineEdit* edit = widget()->lineEdit(); edit->blockSignals(true); edit->setText(element()->value().string()); edit->blockSignals(false); edit->setEdited( false ); RenderFormElement::updateFromElement(); } void RenderFileButton::slotReturnPressed() { handleFocusOut(); if (element()->form()) element()->form()->submitFromKeyboard(); } void RenderFileButton::slotTextChanged(const TQString &/*string*/) { element()->m_value = KURL( widget()->url() ).prettyURL( 0, KURL::StripFileProtocol ); } void RenderFileButton::slotUrlSelected(const TQString &) { element()->onChange(); } void RenderFileButton::select() { widget()->lineEdit()->selectAll(); } // ------------------------------------------------------------------------- RenderLabel::RenderLabel(HTMLGenericFormElementImpl *element) : RenderFormElement(element) { } // ------------------------------------------------------------------------- RenderLegend::RenderLegend(HTMLGenericFormElementImpl *element) : RenderBlock(element) { } // ------------------------------------------------------------------------------- ComboBoxWidget::ComboBoxWidget(TQWidget *parent) : KComboBox(false, parent, "__khtml") { setAutoMask(true); if (listBox()) listBox()->installEventFilter(this); setMouseTracking(true); } bool ComboBoxWidget::event(TQEvent *e) { if (KComboBox::event(e)) return true; if (e->type()==TQEvent::KeyPress) { TQKeyEvent *ke = TQT_TQKEYEVENT(e); switch(ke->key()) { case Key_Return: case Key_Enter: popup(); ke->accept(); return true; default: return false; } } return false; } bool ComboBoxWidget::eventFilter(TQObject *dest, TQEvent *e) { if (TQT_BASE_OBJECT(dest)==TQT_BASE_OBJECT(listBox()) && e->type()==TQEvent::KeyPress) { TQKeyEvent *ke = TQT_TQKEYEVENT(e); bool forward = false; switch(ke->key()) { case Key_Tab: forward=true; case Key_BackTab: // ugly hack. emulate popdownlistbox() (private in TQComboBox) // we re-use ke here to store the reference to the generated event. ke = new TQKeyEvent(TQEvent::KeyPress, Key_Escape, 0, 0); TQApplication::sendEvent(dest,ke); focusNextPrevChild(forward); delete ke; return true; default: return KComboBox::eventFilter(dest, e); } } return KComboBox::eventFilter(dest, e); } // ------------------------------------------------------------------------- RenderSelect::RenderSelect(HTMLSelectElementImpl *element) : RenderFormElement(element) { m_ignoreSelectEvents = false; m_multiple = element->multiple(); m_size = element->size(); m_useListBox = (m_multiple || m_size > 1); m_selectionChanged = true; m_optionsChanged = true; if(m_useListBox) setQWidget(createListBox()); else setQWidget(createComboBox()); } void RenderSelect::updateFromElement() { m_ignoreSelectEvents = true; // change widget type bool oldMultiple = m_multiple; unsigned oldSize = m_size; bool oldListbox = m_useListBox; m_multiple = element()->multiple(); m_size = element()->size(); m_useListBox = (m_multiple || m_size > 1); if (oldMultiple != m_multiple || oldSize != m_size) { if (m_useListBox != oldListbox) { // type of select has changed if(m_useListBox) setQWidget(createListBox()); else setQWidget(createComboBox()); } if (m_useListBox && oldMultiple != m_multiple) { static_cast<KListBox*>(m_widget)->setSelectionMode(m_multiple ? TQListBox::Extended : TQListBox::Single); } m_selectionChanged = true; m_optionsChanged = true; } // update contents listbox/combobox based on options in m_element if ( m_optionsChanged ) { if (element()->m_recalcListItems) element()->recalcListItems(); TQMemArray<HTMLGenericFormElementImpl*> listItems = element()->listItems(); int listIndex; if(m_useListBox) { static_cast<KListBox*>(m_widget)->clear(); } else static_cast<KComboBox*>(m_widget)->clear(); for (listIndex = 0; listIndex < int(listItems.size()); listIndex++) { if (listItems[listIndex]->id() == ID_OPTGROUP) { DOMString text = listItems[listIndex]->getAttribute(ATTR_LABEL); if (text.isNull()) text = ""; if(m_useListBox) { TQListBoxText *item = new TQListBoxText(TQString(text.implementation()->s, text.implementation()->l)); static_cast<KListBox*>(m_widget) ->insertItem(item, listIndex); item->setSelectable(false); } else { static_cast<KComboBox*>(m_widget) ->insertItem(TQString(text.implementation()->s, text.implementation()->l), listIndex); static_cast<KComboBox*>(m_widget)->listBox()->item(listIndex)->setSelectable(false); } } else if (listItems[listIndex]->id() == ID_OPTION) { HTMLOptionElementImpl* optElem = static_cast<HTMLOptionElementImpl*>(listItems[listIndex]); TQString text = optElem->text().string(); if (optElem->parentNode()->id() == ID_OPTGROUP) { // Prefer label if set DOMString label = optElem->getAttribute(ATTR_LABEL); if (!label.isEmpty()) text = label.string(); text = TQString::tqfromLatin1(" ")+text; } if(m_useListBox) { KListBox *l = static_cast<KListBox*>(m_widget); l->insertItem(text, listIndex); DOMString disabled = optElem->getAttribute(ATTR_DISABLED); if (!disabled.isNull() && l->item( listIndex )) { l->item( listIndex )->setSelectable( false ); } } else static_cast<KComboBox*>(m_widget)->insertItem(text, listIndex); } else KHTMLAssert(false); m_selectionChanged = true; } // TQComboBox caches the size hint unless you call setFont (ref: TT docu) if(!m_useListBox) { KComboBox *that = static_cast<KComboBox*>(m_widget); that->setFont( that->font() ); } setNeedsLayoutAndMinMaxRecalc(); m_optionsChanged = false; } // update selection if (m_selectionChanged) { updateSelection(); } m_ignoreSelectEvents = false; RenderFormElement::updateFromElement(); } void RenderSelect::calcMinMaxWidth() { KHTMLAssert( !minMaxKnown() ); if (m_optionsChanged) updateFromElement(); // ### ugly HACK FIXME!!! setMinMaxKnown(); layoutIfNeeded(); setNeedsLayoutAndMinMaxRecalc(); // ### end FIXME RenderFormElement::calcMinMaxWidth(); } void RenderSelect::layout( ) { KHTMLAssert(needsLayout()); KHTMLAssert(minMaxKnown()); // ### maintain selection properly between type/size changes, and work // out how to handle multiselect->singleselect (probably just select // first selected one) // calculate size if(m_useListBox) { KListBox* w = static_cast<KListBox*>(m_widget); TQListBoxItem* p = w->firstItem(); int width = 0; int height = 0; while(p) { width = kMax(width, p->width(p->listBox())); height = kMax(height, p->height(p->listBox())); p = p->next(); } if ( !height ) height = w->fontMetrics().height(); if ( !width ) width = w->fontMetrics().width( 'x' ); int size = m_size; // check if multiple and size was not given or invalid // Internet Exploder sets size to kMin(number of elements, 4) // Netscape seems to simply set it to "number of elements" // the average of that is IMHO kMin(number of elements, 10) // so I did that ;-) if(size < 1) size = kMin(static_cast<KListBox*>(m_widget)->count(), 10u); width += 2*w->frameWidth() + w->verticalScrollBar()->tqsizeHint().width(); height = size*height + 2*w->frameWidth(); setIntrinsicWidth( width ); setIntrinsicHeight( height ); } else { TQSize s(m_widget->tqsizeHint()); setIntrinsicWidth( s.width() ); setIntrinsicHeight( s.height() ); } /// uuh, ignore the following line.. setNeedsLayout(true); RenderFormElement::layout(); // and now disable the widget in case there is no <option> given TQMemArray<HTMLGenericFormElementImpl*> listItems = element()->listItems(); bool foundOption = false; for (uint i = 0; i < listItems.size() && !foundOption; i++) foundOption = (listItems[i]->id() == ID_OPTION); m_widget->setEnabled(foundOption && ! element()->disabled()); } void RenderSelect::slotSelected(int index) // emitted by the combobox only { if ( m_ignoreSelectEvents ) return; KHTMLAssert( !m_useListBox ); TQMemArray<HTMLGenericFormElementImpl*> listItems = element()->listItems(); if(index >= 0 && index < int(listItems.size())) { bool found = ( listItems[index]->id() == ID_OPTION ); if ( !found ) { // this one is not selectable, we need to find an option element while ( ( unsigned ) index < listItems.size() ) { if ( listItems[index]->id() == ID_OPTION ) { found = true; break; } ++index; } if ( !found ) { while ( index >= 0 ) { if ( listItems[index]->id() == ID_OPTION ) { found = true; break; } --index; } } } if ( found ) { bool changed = false; for ( unsigned int i = 0; i < listItems.size(); ++i ) if ( listItems[i]->id() == ID_OPTION && i != (unsigned int) index ) { HTMLOptionElementImpl* opt = static_cast<HTMLOptionElementImpl*>( listItems[i] ); changed |= (opt->m_selected == true); opt->m_selected = false; } HTMLOptionElementImpl* opt = static_cast<HTMLOptionElementImpl*>(listItems[index]); changed |= (opt->m_selected == false); opt->m_selected = true; if ( index != static_cast<ComboBoxWidget*>( m_widget )->currentItem() ) static_cast<ComboBoxWidget*>( m_widget )->setCurrentItem( index ); // When selecting an optgroup item, and we move forward to we // shouldn't emit onChange. Hence this bool, the if above doesn't do it. if ( changed ) { ref(); element()->onChange(); deref(); } } } } void RenderSelect::slotSelectionChanged() // emitted by the listbox only { if ( m_ignoreSelectEvents ) return; // don't use listItems() here as we have to avoid recalculations - changing the // option list will make use update options not in the way the user expects them TQMemArray<HTMLGenericFormElementImpl*> listItems = element()->m_listItems; for ( unsigned i = 0; i < listItems.count(); i++ ) // don't use setSelected() here because it will cause us to be called // again with updateSelection. if ( listItems[i]->id() == ID_OPTION ) static_cast<HTMLOptionElementImpl*>( listItems[i] ) ->m_selected = static_cast<KListBox*>( m_widget )->isSelected( i ); ref(); element()->onChange(); deref(); } void RenderSelect::setOptionsChanged(bool _optionsChanged) { m_optionsChanged = _optionsChanged; } KListBox* RenderSelect::createListBox() { KListBox *lb = new KListBox(view()->viewport(), "__khtml"); lb->setSelectionMode(m_multiple ? TQListBox::Extended : TQListBox::Single); // ### looks broken //lb->setAutoMask(true); connect( lb, TQT_SIGNAL( selectionChanged() ), this, TQT_SLOT( slotSelectionChanged() ) ); // connect( lb, TQT_SIGNAL( clicked( TQListBoxItem * ) ), this, TQT_SLOT( slotClicked() ) ); m_ignoreSelectEvents = false; lb->setMouseTracking(true); return lb; } ComboBoxWidget *RenderSelect::createComboBox() { ComboBoxWidget *cb = new ComboBoxWidget(view()->viewport()); connect(cb, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotSelected(int))); return cb; } void RenderSelect::updateSelection() { TQMemArray<HTMLGenericFormElementImpl*> listItems = element()->listItems(); int i; if (m_useListBox) { // if multi-select, we select only the new selected index KListBox *listBox = static_cast<KListBox*>(m_widget); for (i = 0; i < int(listItems.size()); i++) listBox->setSelected(i,listItems[i]->id() == ID_OPTION && static_cast<HTMLOptionElementImpl*>(listItems[i])->selected()); } else { bool found = false; unsigned firstOption = listItems.size(); i = listItems.size(); while (i--) if (listItems[i]->id() == ID_OPTION) { if (found) static_cast<HTMLOptionElementImpl*>(listItems[i])->m_selected = false; else if (static_cast<HTMLOptionElementImpl*>(listItems[i])->selected()) { static_cast<KComboBox*>( m_widget )->setCurrentItem(i); found = true; } firstOption = i; } Q_ASSERT(firstOption == listItems.size() || found); } m_selectionChanged = false; } // ------------------------------------------------------------------------- TextAreaWidget::TextAreaWidget(int wrap, TQWidget* parent) : KTextEdit(parent, "__khtml"), m_findDlg(0), m_find(0), m_repDlg(0), m_replace(0) { if(wrap != DOM::HTMLTextAreaElementImpl::ta_NoWrap) { setWordWrap(TQTextEdit::WidgetWidth); setHScrollBarMode( AlwaysOff ); setVScrollBarMode( AlwaysOn ); } else { setWordWrap(TQTextEdit::NoWrap); setHScrollBarMode( Auto ); setVScrollBarMode( Auto ); } KCursor::setAutoHideCursor(viewport(), true); setTextFormat(TQTextEdit::PlainText); setAutoMask(true); setMouseTracking(true); KActionCollection *ac = new KActionCollection(this); m_findAction = KStdAction::find( TQT_TQOBJECT(this), TQT_SLOT( slotFind() ), ac ); m_findNextAction = KStdAction::findNext( TQT_TQOBJECT(this), TQT_SLOT( slotFindNext() ), ac ); m_replaceAction = KStdAction::replace( TQT_TQOBJECT(this), TQT_SLOT( slotReplace() ), ac ); } TextAreaWidget::~TextAreaWidget() { delete m_replace; m_replace = 0L; delete m_find; m_find = 0L; delete m_repDlg; m_repDlg = 0L; delete m_findDlg; m_findDlg = 0L; } TQPopupMenu *TextAreaWidget::createPopupMenu(const TQPoint& pos) { TQPopupMenu *popup = KTextEdit::createPopupMenu(pos); if ( !popup ) { return 0L; } if (!isReadOnly()) { popup->insertSeparator(); m_findAction->plug(popup); m_findAction->setEnabled( !text().isEmpty() ); m_findNextAction->plug(popup); m_findNextAction->setEnabled( m_find != 0 ); m_replaceAction->plug(popup); m_replaceAction->setEnabled( !text().isEmpty() ); } return popup; } void TextAreaWidget::slotFindHighlight(const TQString& text, int matchingIndex, int matchingLength) { Q_UNUSED(text) //kdDebug() << "Highlight: [" << text << "] mi:" << matchingIndex << " ml:" << matchingLength << endl; if (sender() == m_replace) { setSelection(m_repPara, matchingIndex, m_repPara, matchingIndex + matchingLength); setCursorPosition(m_repPara, matchingIndex); } else { setSelection(m_findPara, matchingIndex, m_findPara, matchingIndex + matchingLength); setCursorPosition(m_findPara, matchingIndex); } ensureCursorVisible(); } void TextAreaWidget::slotReplaceText(const TQString &text, int replacementIndex, int /*replacedLength*/, int matchedLength) { Q_UNUSED(text) //kdDebug() << "Replace: [" << text << "] ri:" << replacementIndex << " rl:" << replacedLength << " ml:" << matchedLength << endl; setSelection(m_repPara, replacementIndex, m_repPara, replacementIndex + matchedLength); removeSelectedText(); insertAt(m_repDlg->replacement(), m_repPara, replacementIndex); if (m_replace->options() & KReplaceDialog::PromptOnReplace) { ensureCursorVisible(); } } void TextAreaWidget::slotDoReplace() { if (!m_repDlg) { // Should really assert() return; } delete m_replace; m_replace = new KReplace(m_repDlg->pattern(), m_repDlg->replacement(), m_repDlg->options(), this); if (m_replace->options() & KFindDialog::FromCursor) { getCursorPosition(&m_repPara, &m_repIndex); } else if (m_replace->options() & KFindDialog::FindBackwards) { m_repPara = paragraphs() - 1; m_repIndex = paragraphLength(m_repPara) - 1; } else { m_repPara = 0; m_repIndex = 0; } // Connect highlight signal to code which handles highlighting // of found text. connect(m_replace, TQT_SIGNAL(highlight(const TQString &, int, int)), this, TQT_SLOT(slotFindHighlight(const TQString &, int, int))); connect(m_replace, TQT_SIGNAL(findNext()), this, TQT_SLOT(slotReplaceNext())); connect(m_replace, TQT_SIGNAL(replace(const TQString &, int, int, int)), this, TQT_SLOT(slotReplaceText(const TQString &, int, int, int))); m_repDlg->close(); slotReplaceNext(); } void TextAreaWidget::slotReplaceNext() { if (!m_replace) { // assert? return; } if (!(m_replace->options() & KReplaceDialog::PromptOnReplace)) { viewport()->tqsetUpdatesEnabled(false); } KFind::Result res = KFind::NoMatch; while (res == KFind::NoMatch) { // If we're done..... if (m_replace->options() & KFindDialog::FindBackwards) { if (m_repIndex == 0 && m_repPara == 0) { break; } } else { if (m_repPara == paragraphs() - 1 && m_repIndex == paragraphLength(m_repPara) - 1) { break; } } if (m_replace->needData()) { m_replace->setData(text(m_repPara), m_repIndex); } res = m_replace->replace(); if (res == KFind::NoMatch) { if (m_replace->options() & KFindDialog::FindBackwards) { if (m_repPara == 0) { m_repIndex = 0; } else { m_repPara--; m_repIndex = paragraphLength(m_repPara) - 1; } } else { if (m_repPara == paragraphs() - 1) { m_repIndex = paragraphLength(m_repPara) - 1; } else { m_repPara++; m_repIndex = 0; } } } } if (!(m_replace->options() & KReplaceDialog::PromptOnReplace)) { viewport()->tqsetUpdatesEnabled(true); tqrepaintChanged(); } if (res == KFind::NoMatch) { // at end m_replace->displayFinalDialog(); delete m_replace; m_replace = 0; ensureCursorVisible(); //or if ( m_replace->shouldRestart() ) { reinit (w/o FromCursor) and call slotReplaceNext(); } } else { //m_replace->closeReplaceNextDialog(); } } void TextAreaWidget::slotDoFind() { if (!m_findDlg) { // Should really assert() return; } delete m_find; m_find = new KFind(m_findDlg->pattern(), m_findDlg->options(), this); if (m_find->options() & KFindDialog::FromCursor) { getCursorPosition(&m_findPara, &m_findIndex); } else if (m_find->options() & KFindDialog::FindBackwards) { m_findPara = paragraphs() - 1; m_findIndex = paragraphLength(m_findPara) - 1; } else { m_findPara = 0; m_findIndex = 0; } // Connect highlight signal to code which handles highlighting // of found text. connect(m_find, TQT_SIGNAL(highlight(const TQString &, int, int)), this, TQT_SLOT(slotFindHighlight(const TQString &, int, int))); connect(m_find, TQT_SIGNAL(findNext()), this, TQT_SLOT(slotFindNext())); m_findDlg->close(); m_find->closeFindNextDialog(); slotFindNext(); } void TextAreaWidget::slotFindNext() { if (!m_find) { // assert? return; } KFind::Result res = KFind::NoMatch; while (res == KFind::NoMatch) { // If we're done..... if (m_find->options() & KFindDialog::FindBackwards) { if (m_findIndex == 0 && m_findPara == 0) { break; } } else { if (m_findPara == paragraphs() - 1 && m_findIndex == paragraphLength(m_findPara) - 1) { break; } } if (m_find->needData()) { m_find->setData(text(m_findPara), m_findIndex); } res = m_find->find(); if (res == KFind::NoMatch) { if (m_find->options() & KFindDialog::FindBackwards) { if (m_findPara == 0) { m_findIndex = 0; } else { m_findPara--; m_findIndex = paragraphLength(m_findPara) - 1; } } else { if (m_findPara == paragraphs() - 1) { m_findIndex = paragraphLength(m_findPara) - 1; } else { m_findPara++; m_findIndex = 0; } } } } if (res == KFind::NoMatch) { // at end m_find->displayFinalDialog(); delete m_find; m_find = 0; //or if ( m_find->shouldRestart() ) { reinit (w/o FromCursor) and call slotFindNext(); } } else { //m_find->closeFindNextDialog(); } } void TextAreaWidget::slotFind() { if( text().isEmpty() ) // saves having to track the text changes return; if ( m_findDlg ) { KWin::activateWindow( m_findDlg->winId() ); } else { m_findDlg = new KFindDialog(false, this, "KHTML Text Area Find Dialog"); connect( m_findDlg, TQT_SIGNAL(okClicked()), this, TQT_SLOT(slotDoFind()) ); } m_findDlg->show(); } void TextAreaWidget::slotReplace() { if( text().isEmpty() ) // saves having to track the text changes return; if ( m_repDlg ) { KWin::activateWindow( m_repDlg->winId() ); } else { m_repDlg = new KReplaceDialog(this, "KHTMLText Area Replace Dialog", 0, TQStringList(), TQStringList(), false); connect( m_repDlg, TQT_SIGNAL(okClicked()), this, TQT_SLOT(slotDoReplace()) ); } m_repDlg->show(); } bool TextAreaWidget::event( TQEvent *e ) { if ( e->type() == TQEvent::AccelAvailable && isReadOnly() ) { TQKeyEvent* ke = (TQKeyEvent*) e; if ( ke->state() & ControlButton ) { switch ( ke->key() ) { case Key_Left: case Key_Right: case Key_Up: case Key_Down: case Key_Home: case Key_End: ke->accept(); default: break; } } } return KTextEdit::event( e ); } // ------------------------------------------------------------------------- RenderTextArea::RenderTextArea(HTMLTextAreaElementImpl *element) : RenderFormElement(element) { scrollbarsStyled = false; TextAreaWidget *edit = new TextAreaWidget(element->wrap(), view()); setQWidget(edit); const KHTMLSettings *settings = view()->part()->settings(); edit->setCheckSpellingEnabled( settings->autoSpellCheck() ); edit->setTabChangesFocus( ! settings->allowTabulation() ); connect(edit,TQT_SIGNAL(textChanged()),this,TQT_SLOT(slotTextChanged())); } RenderTextArea::~RenderTextArea() { if ( element()->m_dirtyvalue ) { element()->m_value = text(); element()->m_dirtyvalue = false; } } void RenderTextArea::handleFocusOut() { TextAreaWidget* w = static_cast<TextAreaWidget*>(m_widget); if ( w && element()->m_dirtyvalue ) { element()->m_value = text(); element()->m_dirtyvalue = false; } if ( w && element()->m_changed ) { element()->m_changed = false; element()->onChange(); } } void RenderTextArea::calcMinMaxWidth() { KHTMLAssert( !minMaxKnown() ); TextAreaWidget* w = static_cast<TextAreaWidget*>(m_widget); const TQFontMetrics &m = style()->fontMetrics(); w->setTabStopWidth(8 * m.width(" ")); TQSize size( kMax(element()->cols(), 1L)*m.width('x') + w->frameWidth() + w->verticalScrollBar()->tqsizeHint().width(), kMax(element()->rows(), 1L)*m.lineSpacing() + w->frameWidth()*4 + (w->wordWrap() == TQTextEdit::NoWrap ? w->horizontalScrollBar()->tqsizeHint().height() : 0) ); setIntrinsicWidth( size.width() ); setIntrinsicHeight( size.height() ); RenderFormElement::calcMinMaxWidth(); } void RenderTextArea::setStyle(RenderStyle* _style) { bool unsubmittedFormChange = element()->m_unsubmittedFormChange; RenderFormElement::setStyle(_style); widget()->blockSignals(true); widget()->tqsetAlignment(textAlignment()); widget()->blockSignals(false); scrollbarsStyled = false; element()->m_unsubmittedFormChange = unsubmittedFormChange; } void RenderTextArea::layout() { KHTMLAssert( needsLayout() ); RenderFormElement::layout(); TextAreaWidget* w = static_cast<TextAreaWidget*>(m_widget); if (!scrollbarsStyled) { w->horizontalScrollBar()->setPalette(style()->palette()); w->verticalScrollBar()->setPalette(style()->palette()); scrollbarsStyled=true; } } void RenderTextArea::updateFromElement() { TextAreaWidget* w = static_cast<TextAreaWidget*>(m_widget); w->setReadOnly(element()->readOnly()); TQString elementText = element()->value().string(); if ( elementText != text() ) { w->blockSignals(true); int line, col; w->getCursorPosition( &line, &col ); int cx = w->contentsX(); int cy = w->contentsY(); w->setText( elementText ); w->setCursorPosition( line, col ); w->scrollBy( cx, cy ); w->blockSignals(false); } element()->m_dirtyvalue = false; RenderFormElement::updateFromElement(); } void RenderTextArea::close( ) { element()->setValue( element()->defaultValue() ); RenderFormElement::close(); } TQString RenderTextArea::text() { TQString txt; TextAreaWidget* w = static_cast<TextAreaWidget*>(m_widget); if(element()->wrap() == DOM::HTMLTextAreaElementImpl::ta_Physical) { // yeah, TQTextEdit has no accessor for getting the visually wrapped text for (int p=0; p < w->paragraphs(); ++p) { int ll = 0; int lindex = w->lineOfChar(p, 0); TQString paragraphText = w->text(p); int pl = w->paragraphLength(p); paragraphText = paragraphText.left(pl); //Snip invented space. for (int l = 0; l < pl; ++l) { if (lindex != w->lineOfChar(p, l)) { paragraphText.insert(l+ll++, TQString::tqfromLatin1("\n")); lindex = w->lineOfChar(p, l); } } txt += paragraphText; if (p < w->paragraphs() - 1) txt += TQString::tqfromLatin1("\n"); } } else txt = w->text(); return txt; } int RenderTextArea::queryParagraphInfo(int para, Mode m, int param) { /* We have to be a bit careful here, as we need to match up the positions to what our value returns here*/ TextAreaWidget* w = static_cast<TextAreaWidget*>(m_widget); int length = 0; bool physWrap = element()->wrap() == DOM::HTMLTextAreaElementImpl::ta_Physical; TQString paragraphText = w->text(para); int pl = w->paragraphLength(para); int physicalPL = pl; if (m == ParaPortionLength) pl = param; if (physWrap) { //Go through all the chars of paragraph, and count line changes, chars, etc. int lindex = w->lineOfChar(para, 0); for (int c = 0; c < pl; ++c) { ++length; // Is there a change after this char? if (c+1 < physicalPL && lindex != w->lineOfChar(para, c+1)) { lindex = w->lineOfChar(para, c+1); ++length; } if (m == ParaPortionOffset && length > param) return c; } } else { //Make sure to count the LF, CR as appropriate. ### this is stupid now, simplify for (int c = 0; c < pl; ++c) { ++length; if (m == ParaPortionOffset && length > param) return c; } } if (m == ParaPortionOffset) return pl; if (m == ParaPortionLength) return length; return length + 1; } long RenderTextArea::computeCharOffset(int para, int index) { if (para < 0) return 0; long pos = 0; for (int cp = 0; cp < para; ++cp) pos += queryParagraphInfo(cp, ParaLength); if (index >= 0) pos += queryParagraphInfo(para, ParaPortionLength, index); return pos; } void RenderTextArea::computeParagraphAndIndex(long offset, int* para, int* index) { TextAreaWidget* w = static_cast<TextAreaWidget*>(m_widget); if (!w->paragraphs()) { *para = -1; *index = -1; return; } //Find the paragraph that contains us.. int containingPar = 0; long endPos = 0; long startPos = 0; for (int p = 0; p < w->paragraphs(); ++p) { int len = queryParagraphInfo(p, ParaLength); endPos += len; if (endPos > offset) { containingPar = p; break; } startPos += len; } *para = containingPar; //Now, scan within the paragraph to find the position.. long localOffset = offset - startPos; *index = queryParagraphInfo(containingPar, ParaPortionOffset, localOffset); } void RenderTextArea::highLightWord( unsigned int length, unsigned int pos ) { TextAreaWidget* w = static_cast<TextAreaWidget*>(m_widget); if ( w ) w->highLightWord( length, pos ); } void RenderTextArea::slotTextChanged() { element()->m_dirtyvalue = true; element()->m_changed = true; if (element()->m_value != text()) element()->m_unsubmittedFormChange = true; } void RenderTextArea::select() { static_cast<TextAreaWidget *>(m_widget)->selectAll(); } long RenderTextArea::selectionStart() { TextAreaWidget* w = static_cast<TextAreaWidget*>(m_widget); int para, index, dummy1, dummy2; w->getSelection(¶, &index, &dummy1, &dummy2); if (para == -1 || index == -1) w->getCursorPosition(¶, &index); return computeCharOffset(para, index); } long RenderTextArea::selectionEnd() { TextAreaWidget* w = static_cast<TextAreaWidget*>(m_widget); int para, index, dummy1, dummy2; w->getSelection(&dummy1, &dummy2, ¶, &index); if (para == -1 || index == -1) w->getCursorPosition(¶, &index); return computeCharOffset(para, index); } void RenderTextArea::setSelectionStart(long offset) { TextAreaWidget* w = static_cast<TextAreaWidget*>(m_widget); int fromPara, fromIndex, toPara, toIndex; w->getSelection(&fromPara, &fromIndex, &toPara, &toIndex); computeParagraphAndIndex(offset, &fromPara, &fromIndex); if (toPara == -1 || toIndex == -1) { toPara = fromPara; toIndex = fromIndex; } w->setSelection(fromPara, fromIndex, toPara, toIndex); } void RenderTextArea::setSelectionEnd(long offset) { TextAreaWidget* w = static_cast<TextAreaWidget*>(m_widget); int fromPara, fromIndex, toPara, toIndex; w->getSelection(&fromPara, &fromIndex, &toPara, &toIndex); computeParagraphAndIndex(offset, &toPara, &toIndex); w->setSelection(fromPara, fromIndex, toPara, toIndex); } void RenderTextArea::setSelectionRange(long start, long end) { TextAreaWidget* w = static_cast<TextAreaWidget*>(m_widget); int fromPara, fromIndex, toPara, toIndex; computeParagraphAndIndex(start, &fromPara, &fromIndex); computeParagraphAndIndex(end, &toPara, &toIndex); w->setSelection(fromPara, fromIndex, toPara, toIndex); } // --------------------------------------------------------------------------- #include "render_form.moc"