00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <kdebug.h>
00027 #include <klocale.h>
00028 #include <kfiledialog.h>
00029 #include <kcompletionbox.h>
00030 #include <kcursor.h>
00031
00032 #include <qstyle.h>
00033
00034 #include "misc/helper.h"
00035 #include "xml/dom2_eventsimpl.h"
00036 #include "html/html_formimpl.h"
00037 #include "misc/htmlhashes.h"
00038
00039 #include "rendering/render_form.h"
00040 #include <assert.h>
00041
00042 #include "khtmlview.h"
00043 #include "khtml_ext.h"
00044 #include "xml/dom_docimpl.h"
00045
00046 #include <qpopupmenu.h>
00047
00048 using namespace khtml;
00049
00050 RenderFormElement::RenderFormElement(HTMLGenericFormElementImpl *element)
00051 : RenderWidget(element)
00052 {
00053
00054 setInline(true);
00055
00056 m_state = 0;
00057 m_isDoubleClick = false;
00058 }
00059
00060 RenderFormElement::~RenderFormElement()
00061 {
00062 }
00063
00064 short RenderFormElement::baselinePosition( bool f ) const
00065 {
00066 return RenderWidget::baselinePosition( f ) - 2 - style()->fontMetrics().descent();
00067 }
00068
00069
00070 void RenderFormElement::updateFromElement()
00071 {
00072 m_widget->setEnabled(!element()->disabled());
00073 RenderWidget::updateFromElement();
00074 }
00075
00076 void RenderFormElement::layout()
00077 {
00078 KHTMLAssert( !layouted() );
00079 KHTMLAssert( minMaxKnown() );
00080
00081
00082 m_height = 0;
00083
00084 calcWidth();
00085 calcHeight();
00086
00087 if ( m_widget )
00088 resizeWidget(m_width-borderLeft()-borderRight()-paddingLeft()-paddingRight(),
00089 m_height-borderTop()-borderBottom()-paddingTop()-paddingBottom());
00090
00091 if ( !style()->width().isPercent() )
00092 setLayouted();
00093 }
00094
00095 void RenderFormElement::slotClicked()
00096 {
00097 ref();
00098 QMouseEvent e2( QEvent::MouseButtonRelease, m_mousePos, 1, m_state);
00099
00100 element()->dispatchMouseEvent(&e2, EventImpl::CLICK_EVENT, m_isDoubleClick + 1);
00101 m_isDoubleClick = false;
00102 deref();
00103 }
00104
00105 void RenderFormElement::slotPressed()
00106 {
00107 ref();
00108 QMouseEvent e2( QEvent::MouseButtonPress, m_mousePos, 1, m_state);
00109 element()->dispatchMouseEvent(&e2, EventImpl::MOUSEDOWN_EVENT, 1);
00110 deref();
00111 }
00112
00113 void RenderFormElement::slotReleased()
00114 {
00115 ref();
00116 QMouseEvent e2( QEvent::MouseButtonRelease, m_mousePos, 1, m_state);
00117 element()->dispatchMouseEvent(&e2, EventImpl::MOUSEUP_EVENT, 1);
00118 deref();
00119 }
00120
00121
00122
00123 RenderButton::RenderButton(HTMLGenericFormElementImpl *element)
00124 : RenderFormElement(element)
00125 {
00126 }
00127
00128 short RenderButton::baselinePosition( bool f ) const
00129 {
00130 return RenderWidget::baselinePosition( f ) - 2;
00131 }
00132
00133
00134
00135
00136 RenderCustomButton::RenderCustomButton(HTMLGenericFormElementImpl *element)
00137 : RenderReplacedFlow(element)
00138 {
00139 }
00140
00141
00142
00143 RenderCheckBox::RenderCheckBox(HTMLInputElementImpl *element)
00144 : RenderButton(element)
00145 {
00146 QCheckBox* b = new QCheckBox(view()->viewport());
00147 b->setAutoMask(true);
00148 b->setMouseTracking(true);
00149 setQWidget(b);
00150 connect(b,SIGNAL(stateChanged(int)),this,SLOT(slotStateChanged(int)));
00151 connect(b, SIGNAL(clicked()), this, SLOT(slotClicked()));
00152 connect(b, SIGNAL(pressed()), this, SLOT(slotPressed()));
00153 connect(b, SIGNAL(released()), this, SLOT(slotReleased()));
00154 }
00155
00156
00157 void RenderCheckBox::calcMinMaxWidth()
00158 {
00159 KHTMLAssert( !minMaxKnown() );
00160
00161 QCheckBox *cb = static_cast<QCheckBox *>( m_widget );
00162 QSize s( cb->style().pixelMetric( QStyle::PM_IndicatorWidth ),
00163 cb->style().pixelMetric( QStyle::PM_IndicatorHeight ) );
00164 setIntrinsicWidth( s.width() );
00165 setIntrinsicHeight( s.height() );
00166
00167 RenderButton::calcMinMaxWidth();
00168 }
00169
00170 void RenderCheckBox::updateFromElement()
00171 {
00172 widget()->setChecked(element()->checked());
00173
00174 RenderButton::updateFromElement();
00175 }
00176
00177 void RenderCheckBox::slotStateChanged(int state)
00178 {
00179 element()->setChecked(state == 2);
00180 }
00181
00182
00183
00184 RenderRadioButton::RenderRadioButton(HTMLInputElementImpl *element)
00185 : RenderButton(element)
00186 {
00187 QRadioButton* b = new QRadioButton(view()->viewport());
00188 b->setAutoMask(true);
00189 b->setMouseTracking(true);
00190 setQWidget(b);
00191 connect(b, SIGNAL(clicked()), this, SLOT(slotClicked()));
00192 connect(b, SIGNAL(pressed()), this, SLOT(slotPressed()));
00193 connect(b, SIGNAL(released()), this, SLOT(slotReleased()));
00194 }
00195
00196 void RenderRadioButton::updateFromElement()
00197 {
00198 widget()->setChecked(element()->checked());
00199
00200 RenderButton::updateFromElement();
00201 }
00202
00203 void RenderRadioButton::slotClicked()
00204 {
00205 element()->setChecked(true);
00206
00207
00208 RenderButton::slotClicked();
00209 }
00210
00211 void RenderRadioButton::calcMinMaxWidth()
00212 {
00213 KHTMLAssert( !minMaxKnown() );
00214
00215 QRadioButton *rb = static_cast<QRadioButton *>( m_widget );
00216 QSize s( rb->style().pixelMetric( QStyle::PM_ExclusiveIndicatorWidth ),
00217 rb->style().pixelMetric( QStyle::PM_ExclusiveIndicatorHeight ) );
00218 setIntrinsicWidth( s.width() );
00219 setIntrinsicHeight( s.height() );
00220
00221 RenderButton::calcMinMaxWidth();
00222 }
00223
00224
00225
00226
00227 RenderSubmitButton::RenderSubmitButton(HTMLInputElementImpl *element)
00228 : RenderButton(element)
00229 {
00230 QPushButton* p = new QPushButton(view()->viewport());
00231 setQWidget(p);
00232 p->setAutoMask(true);
00233 p->setMouseTracking(true);
00234 connect(p, SIGNAL(clicked()), this, SLOT(slotClicked()));
00235 connect(p, SIGNAL(pressed()), this, SLOT(slotPressed()));
00236 connect(p, SIGNAL(released()), this, SLOT(slotReleased()));
00237 }
00238
00239 QString RenderSubmitButton::rawText()
00240 {
00241 QString value = element()->value().isEmpty() ? defaultLabel() : element()->value().string();
00242 value = value.stripWhiteSpace();
00243 QString raw;
00244 for(unsigned int i = 0; i < value.length(); i++) {
00245 raw += value[i];
00246 if(value[i] == '&')
00247 raw += '&';
00248 }
00249 return raw;
00250 }
00251
00252 void RenderSubmitButton::calcMinMaxWidth()
00253 {
00254 KHTMLAssert( !minMaxKnown() );
00255
00256 QString raw = rawText();
00257 QPushButton* pb = static_cast<QPushButton*>(m_widget);
00258 pb->setText(raw);
00259 pb->setFont(style()->font());
00260
00261 bool empty = raw.isEmpty();
00262 if ( empty )
00263 raw = QString::fromLatin1("X");
00264 QFontMetrics fm = pb->fontMetrics();
00265 QSize ts = fm.size( ShowPrefix, raw);
00266 QSize s(pb->style().sizeFromContents( QStyle::CT_PushButton, pb, ts )
00267 .expandedTo(QApplication::globalStrut()));
00268 int margin = pb->style().pixelMetric( QStyle::PM_ButtonMargin, pb) +
00269 pb->style().pixelMetric( QStyle::PM_DefaultFrameWidth, pb ) * 2;
00270 int w = ts.width() + margin;
00271 int h = s.height();
00272 if (pb->isDefault() || pb->autoDefault()) {
00273 int dbw = pb->style().pixelMetric( QStyle::PM_ButtonDefaultIndicator, pb ) * 2;
00274 w += dbw;
00275 }
00276
00277
00278 s = QSize( w*13/10, h ).expandedTo(QApplication::globalStrut());
00279
00280 setIntrinsicWidth( s.width() );
00281 setIntrinsicHeight( s.height() );
00282
00283 RenderButton::calcMinMaxWidth();
00284 }
00285
00286 void RenderSubmitButton::updateFromElement()
00287 {
00288 QString oldText = static_cast<QPushButton*>(m_widget)->text();
00289 QString newText = rawText();
00290 static_cast<QPushButton*>(m_widget)->setText(newText);
00291 if ( oldText != newText ) {
00292 setMinMaxKnown(false);
00293 setLayouted(false);
00294 }
00295 RenderFormElement::updateFromElement();
00296 }
00297
00298 QString RenderSubmitButton::defaultLabel() {
00299 return i18n("Submit");
00300 }
00301
00302 short RenderSubmitButton::baselinePosition( bool f ) const
00303 {
00304 return RenderFormElement::baselinePosition( f );
00305 }
00306
00307
00308
00309 RenderImageButton::RenderImageButton(HTMLInputElementImpl *element)
00310 : RenderImage(element)
00311 {
00312
00313 }
00314
00315
00316
00317
00318 RenderResetButton::RenderResetButton(HTMLInputElementImpl *element)
00319 : RenderSubmitButton(element)
00320 {
00321 }
00322
00323 QString RenderResetButton::defaultLabel() {
00324 return i18n("Reset");
00325 }
00326
00327
00328
00329
00330 RenderPushButton::RenderPushButton(HTMLInputElementImpl *element)
00331 : RenderSubmitButton(element)
00332 {
00333 }
00334
00335 QString RenderPushButton::defaultLabel()
00336 {
00337 return QString::null;
00338 }
00339
00340
00341
00342 LineEditWidget::LineEditWidget(QWidget *parent)
00343 : KLineEdit(parent)
00344 {
00345 setMouseTracking(true);
00346 }
00347
00348 QPopupMenu *LineEditWidget::createPopupMenu()
00349 {
00350 QPopupMenu *popup = KLineEdit::createPopupMenu();
00351 if ( !popup )
00352 return 0L;
00353 connect( popup, SIGNAL( activated( int ) ),
00354 this, SLOT( extendedMenuActivated( int ) ) );
00355 return popup;
00356 }
00357
00358 void LineEditWidget::extendedMenuActivated( int id)
00359 {
00360 switch ( id )
00361 {
00362 case ClearHistory:
00363 clearMenuHistory();
00364 break;
00365 default:
00366 break;
00367 }
00368 }
00369
00370 void LineEditWidget::clearMenuHistory()
00371 {
00372 emit clearCompletionHistory();
00373 }
00374
00375
00376 bool LineEditWidget::event( QEvent *e )
00377 {
00378 if ( e->type() == QEvent::AccelAvailable && isReadOnly() ) {
00379 QKeyEvent* ke = (QKeyEvent*) e;
00380 if ( ke->state() & ControlButton ) {
00381 switch ( ke->key() ) {
00382 case Key_Left:
00383 case Key_Right:
00384 case Key_Up:
00385 case Key_Down:
00386 case Key_Home:
00387 case Key_End:
00388 ke->accept();
00389 default:
00390 break;
00391 }
00392 }
00393 }
00394 else if ( e->type() == QEvent::MouseButtonPress )
00395 emit pressed();
00396 else if ( e->type() == QEvent::MouseButtonRelease )
00397 emit released();
00398 return KLineEdit::event( e );
00399 }
00400
00401
00402
00403 RenderLineEdit::RenderLineEdit(HTMLInputElementImpl *element)
00404 : RenderFormElement(element)
00405 {
00406 LineEditWidget *edit = new LineEditWidget(view()->viewport());
00407 connect(edit,SIGNAL(returnPressed()), this, SLOT(slotReturnPressed()));
00408 connect(edit,SIGNAL(textChanged(const QString &)),this,SLOT(slotTextChanged(const QString &)));
00409 connect(edit,SIGNAL(pressed()), this, SLOT(slotPressed()));
00410 connect(edit,SIGNAL(released()), this, SLOT(slotReleased()));
00411 connect(edit, SIGNAL(clearCompletionHistory()), this, SLOT( slotClearCompletionHistory()));
00412 if(element->inputType() == HTMLInputElementImpl::PASSWORD)
00413 edit->setEchoMode( QLineEdit::Password );
00414
00415 if ( element->autoComplete() ) {
00416 QStringList completions = view()->formCompletionItems(element->name().string());
00417 if (completions.count()) {
00418 edit->completionObject()->setItems(completions);
00419 edit->setContextMenuEnabled(true);
00420 }
00421 }
00422
00423 setQWidget(edit);
00424 }
00425
00426 void RenderLineEdit::slotClearCompletionHistory()
00427 {
00428 if ( element()->autoComplete() ) {
00429 view()->clearCompletionHistory(element()->name().string());
00430 static_cast<LineEditWidget*>(m_widget)->completionObject()->clear();
00431 }
00432 }
00433
00434 void RenderLineEdit::slotReturnPressed()
00435 {
00436
00437 KCompletionBox *box = widget()->completionBox(false);
00438 if ( box && box->isVisible() && box->currentItem() != -1 )
00439 return;
00440
00441
00442
00443
00444 handleFocusOut();
00445
00446 HTMLFormElementImpl* fe = element()->form();
00447 if ( fe )
00448 fe->submitFromKeyboard();
00449 }
00450
00451 void RenderLineEdit::handleFocusOut()
00452 {
00453 if ( widget() && widget()->edited() ) {
00454 element()->onChange();
00455 widget()->setEdited( false );
00456 }
00457 }
00458
00459 void RenderLineEdit::calcMinMaxWidth()
00460 {
00461 KHTMLAssert( !minMaxKnown() );
00462
00463 const QFontMetrics &fm = style()->fontMetrics();
00464 QSize s;
00465
00466 int size = element()->size();
00467
00468 int h = fm.lineSpacing();
00469 int w = fm.width( 'x' ) * (size > 0 ? size+1 : 17);
00470 s = QSize(w + 2 + 2*widget()->frameWidth(),
00471 QMAX(h, 14) + 2 + 2*widget()->frameWidth())
00472 .expandedTo(QApplication::globalStrut());
00473
00474 setIntrinsicWidth( s.width() );
00475 setIntrinsicHeight( s.height() );
00476
00477 RenderFormElement::calcMinMaxWidth();
00478 }
00479
00480 void RenderLineEdit::updateFromElement()
00481 {
00482 int ml = element()->maxLength();
00483 if ( ml < 0 || ml > 1024 )
00484 ml = 1024;
00485 if ( widget()->maxLength() != ml ) {
00486 widget()->blockSignals( true );
00487 widget()->setMaxLength( ml );
00488 widget()->blockSignals( false );
00489 }
00490
00491 if (element()->value().string() != widget()->text()) {
00492 widget()->blockSignals(true);
00493 int pos = widget()->cursorPosition();
00494 widget()->setText(element()->value().string());
00495
00496 widget()->setEdited( false );
00497
00498 widget()->setCursorPosition(pos);
00499 widget()->blockSignals(false);
00500 }
00501 widget()->setReadOnly(element()->readOnly());
00502
00503 RenderFormElement::updateFromElement();
00504 }
00505
00506 void RenderLineEdit::slotTextChanged(const QString &string)
00507 {
00508
00509 element()->m_value = string;
00510 }
00511
00512 void RenderLineEdit::select()
00513 {
00514 static_cast<LineEditWidget*>(m_widget)->selectAll();
00515 }
00516
00517
00518
00519 RenderFieldset::RenderFieldset(HTMLGenericFormElementImpl *element)
00520 : RenderFlow(element)
00521 {
00522 }
00523
00524 bool RenderFieldset::findLegend( int &lx, int &ly, int &lw, int &lh)
00525 {
00526 RenderObject *r = this, *ref = 0;
00527 int minx = 0, curx = 0, maxw = 0;
00528 if( r->firstChild() && r->firstChild()->element() &&
00529 r->firstChild()->element()->id() == ID_LEGEND)
00530 r = r->firstChild();
00531 else
00532 return false;
00533 if(!r->firstChild() || r->isSpecial())
00534 return false;
00535 ly = r->yPos();
00536 minx = r->width();
00537 curx = r->xPos();
00538 lh = r->height();
00539 ref = r;
00540
00541 while(r) {
00542 if(r->firstChild())
00543 r = r->firstChild();
00544 else if(r->nextSibling())
00545 r = r->nextSibling();
00546 else {
00547 RenderObject *next = 0;
00548 while(!next) {
00549 r = r->parent();
00550 if(!r || r == (RenderObject *)ref ) goto end;
00551 next = r->nextSibling();
00552 }
00553 r = next;
00554 }
00555 if(r->isSpecial())
00556 continue;
00557 curx += r->xPos();
00558 if(r->width() && curx<minx)
00559 minx = curx;
00560 if(curx-minx+r->width() > maxw) {
00561 maxw = curx-minx+r->width();
00562 }
00563 if(!r->childrenInline())
00564 curx -= r->xPos();
00565 }
00566 end:
00567 lx = minx - ref->paddingLeft();
00568 lw = maxw + ref->paddingLeft() + ref->paddingRight();
00569 if(lx < 0 || lx+lw > width())
00570 return false;
00571 return !!maxw;
00572 }
00573
00574 void RenderFieldset::paintBoxDecorations(QPainter *p,int, int _y,
00575 int, int _h, int _tx, int _ty)
00576 {
00577
00578
00579 int w = width();
00580 int h = height() + borderTopExtra() + borderBottomExtra();
00581 int lx = 0, ly = 0, lw = 0, lh = 0;
00582 bool legend = findLegend(lx, ly, lw, lh);
00583
00584 if(legend) {
00585 int yOff = ly + lh/2 - borderTop()/2;
00586 h -= yOff;
00587 _ty += yOff;
00588 }
00589 _ty -= borderTopExtra();
00590
00591 int my = QMAX(_ty,_y);
00592 int end = QMIN( _y + _h, _ty + h );
00593 int mh = end - my;
00594
00595 paintBackground(p, style()->backgroundColor(), style()->backgroundImage(), my, mh, _tx, _ty, w, h);
00596
00597 if ( style()->hasBorder() ) {
00598 if ( legend )
00599 paintBorderMinusLegend(p, _tx, _ty, w, h, style(), lx, lw);
00600 else
00601 paintBorder(p, _tx, _ty, w, h, style());
00602 }
00603 }
00604
00605 void RenderFieldset::paintBorderMinusLegend(QPainter *p, int _tx, int _ty, int w, int h,
00606 const RenderStyle* style, int lx, int lw)
00607 {
00608
00609 const QColor& tc = style->borderTopColor();
00610 const QColor& bc = style->borderBottomColor();
00611
00612 EBorderStyle ts = style->borderTopStyle();
00613 EBorderStyle bs = style->borderBottomStyle();
00614 EBorderStyle ls = style->borderLeftStyle();
00615 EBorderStyle rs = style->borderRightStyle();
00616
00617 bool render_t = ts > BHIDDEN;
00618 bool render_l = ls > BHIDDEN;
00619 bool render_r = rs > BHIDDEN;
00620 bool render_b = bs > BHIDDEN;
00621
00622 if(render_t) {
00623 drawBorder(p, _tx, _ty, _tx + lx, _ty + style->borderTopWidth(), BSTop, tc, style->color(), ts,
00624 (render_l && ls<=DOUBLE?style->borderLeftWidth():0), 0);
00625 drawBorder(p, _tx+lx+lw, _ty, _tx + w, _ty + style->borderTopWidth(), BSTop, tc, style->color(), ts,
00626 0, (render_r && rs<=DOUBLE?style->borderRightWidth():0));
00627 }
00628
00629 if(render_b)
00630 drawBorder(p, _tx, _ty + h - style->borderBottomWidth(), _tx + w, _ty + h, BSBottom, bc, style->color(), bs,
00631 (render_l && ls<=DOUBLE?style->borderLeftWidth():0),
00632 (render_r && rs<=DOUBLE?style->borderRightWidth():0));
00633
00634 if(render_l)
00635 {
00636 const QColor& lc = style->borderLeftColor();
00637
00638 bool ignore_top =
00639 (tc == lc) &&
00640 (ls <= OUTSET) &&
00641 (ts == DOTTED || ts == DASHED || ts == SOLID || ts == OUTSET);
00642
00643 bool ignore_bottom =
00644 (bc == lc) &&
00645 (ls <= OUTSET) &&
00646 (bs == DOTTED || bs == DASHED || bs == SOLID || bs == INSET);
00647
00648 drawBorder(p, _tx, _ty, _tx + style->borderLeftWidth(), _ty + h, BSLeft, lc, style->color(), ls,
00649 ignore_top?0:style->borderTopWidth(),
00650 ignore_bottom?0:style->borderBottomWidth());
00651 }
00652
00653 if(render_r)
00654 {
00655 const QColor& rc = style->borderRightColor();
00656
00657 bool ignore_top =
00658 (tc == rc) &&
00659 (rs <= SOLID || rs == INSET) &&
00660 (ts == DOTTED || ts == DASHED || ts == SOLID || ts == OUTSET);
00661
00662 bool ignore_bottom =
00663 (bc == rc) &&
00664 (rs <= SOLID || rs == INSET) &&
00665 (bs == DOTTED || bs == DASHED || bs == SOLID || bs == INSET);
00666
00667 drawBorder(p, _tx + w - style->borderRightWidth(), _ty, _tx + w, _ty + h, BSRight, rc, style->color(), rs,
00668 ignore_top?0:style->borderTopWidth(),
00669 ignore_bottom?0:style->borderBottomWidth());
00670 }
00671 }
00672
00673
00674
00675 RenderFileButton::RenderFileButton(HTMLInputElementImpl *element)
00676 : RenderFormElement(element)
00677 {
00678
00679 QHBox *w = new QHBox(view()->viewport());
00680
00681 m_edit = new LineEditWidget(w);
00682
00683 connect(m_edit, SIGNAL(returnPressed()), this, SLOT(slotReturnPressed()));
00684 connect(m_edit, SIGNAL(textChanged(const QString &)),this,SLOT(slotTextChanged(const QString &)));
00685
00686 m_button = new QPushButton(i18n("Browse..."), w);
00687 m_button->setFocusPolicy(QWidget::ClickFocus);
00688 connect(m_button,SIGNAL(clicked()), this, SLOT(slotClicked()));
00689 connect(m_button, SIGNAL(pressed()), this, SLOT(slotPressed()));
00690 connect(m_button, SIGNAL(released()), this, SLOT(slotReleased()));
00691
00692 w->setStretchFactor(m_edit, 2);
00693 w->setFocusProxy(m_edit);
00694
00695 setQWidget(w);
00696 m_haveFocus = false;
00697 }
00698
00699 void RenderFileButton::calcMinMaxWidth()
00700 {
00701 KHTMLAssert( !minMaxKnown() );
00702
00703 const QFontMetrics &fm = style()->fontMetrics();
00704 int size = element()->size();
00705
00706 int h = fm.lineSpacing();
00707 int w = fm.width( 'x' ) * (size > 0 ? size : 17);
00708 QSize s = m_edit->style().sizeFromContents(QStyle::CT_LineEdit, m_edit,
00709 QSize(w + 2 + 2*m_edit->frameWidth(), kMax(h, 14) + 2 + 2*m_edit->frameWidth()))
00710 .expandedTo(QApplication::globalStrut());
00711 QSize bs = m_button->sizeHint();
00712
00713 setIntrinsicWidth( s.width() + bs.width() );
00714 setIntrinsicHeight( kMax(s.height(), bs.height()) );
00715
00716 RenderFormElement::calcMinMaxWidth();
00717 }
00718
00719 void RenderFileButton::handleFocusOut()
00720 {
00721 if ( m_edit && m_edit->edited() ) {
00722 element()->onChange();
00723 m_edit->setEdited( false );
00724 }
00725 }
00726
00727 void RenderFileButton::slotClicked()
00728 {
00729 QString file_name = KFileDialog::getOpenFileName(QString::null, QString::null, 0, i18n("Browse"));
00730 if (!file_name.isNull()) {
00731 element()->m_value = DOMString(file_name);
00732 m_edit->setText(file_name);
00733 }
00734 }
00735
00736 void RenderFileButton::updateFromElement()
00737 {
00738 m_edit->blockSignals(true);
00739 m_edit->setText(element()->value().string());
00740 m_edit->blockSignals(false);
00741 int ml = element()->maxLength();
00742 if ( ml < 0 || ml > 1024 )
00743 ml = 1024;
00744 m_edit->setMaxLength( ml );
00745 m_edit->setEdited( false );
00746
00747 RenderFormElement::updateFromElement();
00748 }
00749
00750 void RenderFileButton::slotReturnPressed()
00751 {
00752 if (element()->form())
00753 element()->form()->submitFromKeyboard();
00754 }
00755
00756 void RenderFileButton::slotTextChanged(const QString &string)
00757 {
00758 element()->m_value = DOMString(string);
00759 }
00760
00761 void RenderFileButton::select()
00762 {
00763 m_edit->selectAll();
00764 }
00765
00766
00767
00768 RenderLabel::RenderLabel(HTMLGenericFormElementImpl *element)
00769 : RenderFormElement(element)
00770 {
00771
00772 }
00773
00774
00775
00776 RenderLegend::RenderLegend(HTMLGenericFormElementImpl *element)
00777 : RenderFlow(element)
00778 {
00779 setInline(false);
00780 }
00781
00782
00783
00784 ComboBoxWidget::ComboBoxWidget(QWidget *parent)
00785 : KComboBox(false, parent)
00786 {
00787 setAutoMask(true);
00788 if (listBox()) listBox()->installEventFilter(this);
00789 setMouseTracking(true);
00790 }
00791
00792 bool ComboBoxWidget::event(QEvent *e)
00793 {
00794 if (e->type()==QEvent::KeyPress)
00795 {
00796 QKeyEvent *ke = static_cast<QKeyEvent *>(e);
00797 switch(ke->key())
00798 {
00799 case Key_Return:
00800 case Key_Enter:
00801 popup();
00802 ke->accept();
00803 return true;
00804 default:
00805 return KComboBox::event(e);
00806 }
00807 }
00808 return KComboBox::event(e);
00809 }
00810
00811 bool ComboBoxWidget::eventFilter(QObject *dest, QEvent *e)
00812 {
00813 if (dest==listBox() && e->type()==QEvent::KeyPress)
00814 {
00815 QKeyEvent *ke = static_cast<QKeyEvent *>(e);
00816 bool forward = false;
00817 switch(ke->key())
00818 {
00819 case Key_Tab:
00820 forward=true;
00821 case Key_BackTab:
00822
00823
00824 ke = new QKeyEvent(QEvent::KeyPress, Key_Escape, 0, 0);
00825 QApplication::sendEvent(dest,ke);
00826 focusNextPrevChild(forward);
00827 delete ke;
00828 return true;
00829 default:
00830 return KComboBox::eventFilter(dest, e);
00831 }
00832 }
00833 return KComboBox::eventFilter(dest, e);
00834 }
00835
00836
00837
00838 RenderSelect::RenderSelect(HTMLSelectElementImpl *element)
00839 : RenderFormElement(element)
00840 {
00841 m_ignoreSelectEvents = false;
00842 m_multiple = element->multiple();
00843 m_size = element->size();
00844 m_useListBox = (m_multiple || m_size > 1);
00845 m_selectionChanged = true;
00846 m_optionsChanged = true;
00847
00848 if(m_useListBox)
00849 setQWidget(createListBox());
00850 else
00851 setQWidget(createComboBox());
00852 }
00853
00854 void RenderSelect::updateFromElement()
00855 {
00856 m_ignoreSelectEvents = true;
00857
00858
00859 bool oldMultiple = m_multiple;
00860 unsigned oldSize = m_size;
00861 bool oldListbox = m_useListBox;
00862
00863 m_multiple = element()->multiple();
00864 m_size = element()->size();
00865 m_useListBox = (m_multiple || m_size > 1);
00866
00867 if (oldMultiple != m_multiple || oldSize != m_size) {
00868 if (m_useListBox != oldListbox) {
00869
00870 if(m_useListBox)
00871 setQWidget(createListBox());
00872 else
00873 setQWidget(createComboBox());
00874 }
00875
00876 if (m_useListBox && oldMultiple != m_multiple) {
00877 static_cast<KListBox*>(m_widget)->setSelectionMode(m_multiple ? QListBox::Extended : QListBox::Single);
00878 }
00879 m_selectionChanged = true;
00880 m_optionsChanged = true;
00881 }
00882
00883
00884 if ( m_optionsChanged ) {
00885 if (element()->m_recalcListItems)
00886 element()->recalcListItems();
00887 QMemArray<HTMLGenericFormElementImpl*> listItems = element()->listItems();
00888 int listIndex;
00889
00890 if(m_useListBox) {
00891 static_cast<KListBox*>(m_widget)->clear();
00892 }
00893
00894 else
00895 static_cast<KComboBox*>(m_widget)->clear();
00896
00897 for (listIndex = 0; listIndex < int(listItems.size()); listIndex++) {
00898 if (listItems[listIndex]->id() == ID_OPTGROUP) {
00899 DOMString text = listItems[listIndex]->getAttribute(ATTR_LABEL);
00900 if (text.isNull())
00901 text = "";
00902
00903 if(m_useListBox) {
00904 QListBoxText *item = new QListBoxText(QString(text.implementation()->s, text.implementation()->l));
00905 static_cast<KListBox*>(m_widget)
00906 ->insertItem(item, listIndex);
00907 item->setSelectable(false);
00908 }
00909 else
00910 static_cast<KComboBox*>(m_widget)
00911 ->insertItem(QString(text.implementation()->s, text.implementation()->l), listIndex);
00912 }
00913 else if (listItems[listIndex]->id() == ID_OPTION) {
00914 HTMLOptionElementImpl* optElem = static_cast<HTMLOptionElementImpl*>(listItems[listIndex]);
00915 QString text = optElem->text().string();
00916 if (optElem->parentNode()->id() == ID_OPTGROUP)
00917 {
00918
00919 DOMString label = optElem->getAttribute(ATTR_LABEL);
00920 if (!label.isEmpty())
00921 text = label.string();
00922 text = QString::fromLatin1(" ")+text;
00923 }
00924
00925 if(m_useListBox)
00926 static_cast<KListBox*>(m_widget)->insertItem(text, listIndex);
00927 else
00928 static_cast<KComboBox*>(m_widget)->insertItem(text, listIndex);
00929 }
00930 else
00931 KHTMLAssert(false);
00932 m_selectionChanged = true;
00933 }
00934 setMinMaxKnown(false);
00935 setLayouted(false);
00936 m_optionsChanged = false;
00937 }
00938
00939
00940 if (m_selectionChanged) {
00941 updateSelection();
00942 }
00943
00944
00945 m_ignoreSelectEvents = false;
00946
00947 RenderFormElement::updateFromElement();
00948 }
00949
00950 void RenderSelect::calcMinMaxWidth()
00951 {
00952 KHTMLAssert( !minMaxKnown() );
00953
00954 if (m_optionsChanged)
00955 updateFromElement();
00956
00957
00958 setMinMaxKnown();
00959 if ( !layouted() )
00960 layout();
00961 setLayouted( false );
00962 setMinMaxKnown( false );
00963
00964
00965 RenderFormElement::calcMinMaxWidth();
00966 }
00967
00968 void RenderSelect::layout( )
00969 {
00970 KHTMLAssert(!layouted());
00971 KHTMLAssert(minMaxKnown());
00972
00973
00974
00975
00976
00977
00978 if(m_useListBox) {
00979 KListBox* w = static_cast<KListBox*>(m_widget);
00980
00981 QListBoxItem* p = w->firstItem();
00982 int width = 0;
00983 int height = 0;
00984 while(p) {
00985 width = QMAX(width, p->width(p->listBox()));
00986 height = QMAX(height, p->height(p->listBox()));
00987 p = p->next();
00988 }
00989
00990 int size = m_size;
00991
00992
00993
00994
00995
00996 if(size < 1)
00997 size = QMIN(static_cast<KListBox*>(m_widget)->count(), 10);
00998
00999 width += 2*w->frameWidth() + w->verticalScrollBar()->sizeHint().width();
01000 height = size*height + 2*w->frameWidth();
01001
01002 setIntrinsicWidth( width );
01003 setIntrinsicHeight( height );
01004 }
01005 else {
01006 QSize s(m_widget->sizeHint());
01007 setIntrinsicWidth( s.width() );
01008 setIntrinsicHeight( s.height() );
01009 }
01010
01012 setLayouted( false );
01013 RenderFormElement::layout();
01014
01015
01016 QMemArray<HTMLGenericFormElementImpl*> listItems = element()->listItems();
01017
01018 bool foundOption = false;
01019 for (uint i = 0; i < listItems.size() && !foundOption; i++)
01020 foundOption = (listItems[i]->id() == ID_OPTION);
01021
01022 m_widget->setEnabled(foundOption && ! element()->disabled());
01023 }
01024
01025 void RenderSelect::slotSelected(int index)
01026 {
01027 if ( m_ignoreSelectEvents ) return;
01028
01029 KHTMLAssert( !m_useListBox );
01030
01031 QMemArray<HTMLGenericFormElementImpl*> listItems = element()->listItems();
01032 if(index >= 0 && index < int(listItems.size()))
01033 {
01034 bool found = ( listItems[index]->id() == ID_OPTION );
01035
01036 if ( !found ) {
01037
01038 while ( ( unsigned ) index < listItems.size() ) {
01039 if ( listItems[index]->id() == ID_OPTION ) {
01040 found = true;
01041 break;
01042 }
01043 ++index;
01044 }
01045
01046 if ( !found ) {
01047 while ( index >= 0 ) {
01048 if ( listItems[index]->id() == ID_OPTION ) {
01049 found = true;
01050 break;
01051 }
01052 --index;
01053 }
01054 }
01055 }
01056
01057 if ( found ) {
01058 bool changed = false;
01059
01060 for ( unsigned int i = 0; i < listItems.size(); ++i )
01061 if ( listItems[i]->id() == ID_OPTION && i != (unsigned int) index )
01062 {
01063 HTMLOptionElementImpl* opt = static_cast<HTMLOptionElementImpl*>( listItems[i] );
01064 changed |= (opt->m_selected == true);
01065 opt->m_selected = false;
01066 }
01067
01068 HTMLOptionElementImpl* opt = static_cast<HTMLOptionElementImpl*>(listItems[index]);
01069 changed |= (opt->m_selected == false);
01070 opt->m_selected = true;
01071
01072 if ( index != static_cast<ComboBoxWidget*>( m_widget )->currentItem() )
01073 static_cast<ComboBoxWidget*>( m_widget )->setCurrentItem( index );
01074
01075
01076
01077 if ( changed )
01078 {
01079 ref();
01080 element()->onChange();
01081 deref();
01082 }
01083 }
01084 }
01085 }
01086
01087
01088 void RenderSelect::slotSelectionChanged()
01089 {
01090 if ( m_ignoreSelectEvents ) return;
01091
01092
01093
01094 QMemArray<HTMLGenericFormElementImpl*> listItems = element()->m_listItems;
01095 for ( unsigned i = 0; i < listItems.count(); i++ )
01096
01097
01098 if ( listItems[i]->id() == ID_OPTION )
01099 static_cast<HTMLOptionElementImpl*>( listItems[i] )
01100 ->m_selected = static_cast<KListBox*>( m_widget )->isSelected( i );
01101
01102 ref();
01103 element()->onChange();
01104 deref();
01105 }
01106
01107 void RenderSelect::setOptionsChanged(bool _optionsChanged)
01108 {
01109 m_optionsChanged = _optionsChanged;
01110 }
01111
01112 KListBox* RenderSelect::createListBox()
01113 {
01114 KListBox *lb = new KListBox(view()->viewport());
01115 lb->setSelectionMode(m_multiple ? QListBox::Extended : QListBox::Single);
01116
01117
01118 connect( lb, SIGNAL( selectionChanged() ), this, SLOT( slotSelectionChanged() ) );
01119 connect( lb, SIGNAL( clicked( QListBoxItem * ) ), this, SLOT( slotClicked() ) );
01120 m_ignoreSelectEvents = false;
01121 lb->setMouseTracking(true);
01122
01123 return lb;
01124 }
01125
01126 ComboBoxWidget *RenderSelect::createComboBox()
01127 {
01128 ComboBoxWidget *cb = new ComboBoxWidget(view()->viewport());
01129 connect(cb, SIGNAL(activated(int)), this, SLOT(slotSelected(int)));
01130 return cb;
01131 }
01132
01133 void RenderSelect::updateSelection()
01134 {
01135 QMemArray<HTMLGenericFormElementImpl*> listItems = element()->listItems();
01136 int i;
01137 if (m_useListBox) {
01138
01139 KListBox *listBox = static_cast<KListBox*>(m_widget);
01140 for (i = 0; i < int(listItems.size()); i++)
01141 listBox->setSelected(i,listItems[i]->id() == ID_OPTION &&
01142 static_cast<HTMLOptionElementImpl*>(listItems[i])->selected());
01143 }
01144 else {
01145 bool found = false;
01146 unsigned firstOption = listItems.size();
01147 i = listItems.size();
01148 while (i--)
01149 if (listItems[i]->id() == ID_OPTION) {
01150 if (found)
01151 static_cast<HTMLOptionElementImpl*>(listItems[i])->m_selected = false;
01152 else if (static_cast<HTMLOptionElementImpl*>(listItems[i])->selected()) {
01153 static_cast<KComboBox*>( m_widget )->setCurrentItem(i);
01154 found = true;
01155 }
01156 firstOption = i;
01157 }
01158
01159 Q_ASSERT(firstOption == listItems.size() || found);
01160 }
01161
01162 m_selectionChanged = false;
01163 }
01164
01165
01166
01167
01168 TextAreaWidget::TextAreaWidget(int wrap, QWidget* parent)
01169 : KTextEdit(parent)
01170 {
01171 if(wrap != DOM::HTMLTextAreaElementImpl::ta_NoWrap) {
01172 setWordWrap(QTextEdit::WidgetWidth);
01173 setHScrollBarMode( AlwaysOff );
01174 setVScrollBarMode( AlwaysOn );
01175 }
01176 else {
01177 setWordWrap(QTextEdit::NoWrap);
01178 setHScrollBarMode( Auto );
01179 setVScrollBarMode( Auto );
01180 }
01181 KCursor::setAutoHideCursor(viewport(), true);
01182 setTextFormat(QTextEdit::PlainText);
01183 setAutoMask(true);
01184 setMouseTracking(true);
01185 }
01186
01187 bool TextAreaWidget::event( QEvent *e )
01188 {
01189 if ( e->type() == QEvent::AccelAvailable && isReadOnly() ) {
01190 QKeyEvent* ke = (QKeyEvent*) e;
01191 if ( ke->state() & ControlButton ) {
01192 switch ( ke->key() ) {
01193 case Key_Left:
01194 case Key_Right:
01195 case Key_Up:
01196 case Key_Down:
01197 case Key_Home:
01198 case Key_End:
01199 ke->accept();
01200 default:
01201 break;
01202 }
01203 }
01204 }
01205 return KTextEdit::event( e );
01206 }
01207
01208
01209
01210 RenderTextArea::RenderTextArea(HTMLTextAreaElementImpl *element)
01211 : RenderFormElement(element)
01212 {
01213 TextAreaWidget *edit = new TextAreaWidget(element->wrap(), view());
01214 setQWidget(edit);
01215
01216 connect(edit,SIGNAL(textChanged()),this,SLOT(slotTextChanged()));
01217 }
01218
01219 RenderTextArea::~RenderTextArea()
01220 {
01221 if ( element()->m_dirtyvalue ) {
01222 element()->m_value = text();
01223 element()->m_dirtyvalue = false;
01224 }
01225 }
01226
01227 void RenderTextArea::handleFocusOut()
01228 {
01229 TextAreaWidget* w = static_cast<TextAreaWidget*>(m_widget);
01230 if ( w && element()->m_dirtyvalue ) {
01231 element()->m_value = text();
01232 element()->m_dirtyvalue = false;
01233 element()->onChange();
01234 }
01235 }
01236
01237 void RenderTextArea::calcMinMaxWidth()
01238 {
01239 KHTMLAssert( !minMaxKnown() );
01240
01241 TextAreaWidget* w = static_cast<TextAreaWidget*>(m_widget);
01242 const QFontMetrics &m = style()->fontMetrics();
01243 w->setTabStopWidth(8 * m.width(" "));
01244 QSize size( QMAX(element()->cols(), 1)*m.width('x') + w->frameWidth() +
01245 w->verticalScrollBar()->sizeHint().width(),
01246 QMAX(element()->rows(), 1)*m.lineSpacing() + w->frameWidth()*4 +
01247 (w->wordWrap() == QTextEdit::NoWrap ?
01248 w->horizontalScrollBar()->sizeHint().height() : 0)
01249 );
01250
01251 setIntrinsicWidth( size.width() );
01252 setIntrinsicHeight( size.height() );
01253
01254 RenderFormElement::calcMinMaxWidth();
01255 }
01256
01257 void RenderTextArea::updateFromElement()
01258 {
01259 TextAreaWidget* w = static_cast<TextAreaWidget*>(m_widget);
01260 w->setReadOnly(element()->readOnly());
01261 QString elementText = element()->value().string();
01262 if ( elementText != text() )
01263 {
01264 w->blockSignals(true);
01265 int line, col;
01266 w->getCursorPosition( &line, &col );
01267 w->setText( elementText );
01268 w->setCursorPosition( line, col );
01269 w->blockSignals(false);
01270 }
01271 element()->m_dirtyvalue = false;
01272
01273 RenderFormElement::updateFromElement();
01274 }
01275
01276 void RenderTextArea::close( )
01277 {
01278 element()->setValue( element()->defaultValue() );
01279
01280 RenderFormElement::close();
01281 }
01282
01283 QString RenderTextArea::text()
01284 {
01285 QString txt;
01286 TextAreaWidget* w = static_cast<TextAreaWidget*>(m_widget);
01287
01288 if(element()->wrap() == DOM::HTMLTextAreaElementImpl::ta_Physical) {
01289
01290 for (int p=0; p < w->paragraphs(); ++p) {
01291 int pl = w->paragraphLength(p);
01292 int ll = 0;
01293 int lindex = w->lineOfChar(p, 0);
01294 QString paragraphText = w->text(p);
01295 for (int l = 0; l < pl; ++l) {
01296 if (lindex != w->lineOfChar(p, l)) {
01297 paragraphText.insert(l+ll++, QString::fromLatin1("\n"));
01298 lindex = w->lineOfChar(p, l);
01299 }
01300 }
01301 txt += paragraphText;
01302 if (p < w->paragraphs() - 1)
01303 txt += QString::fromLatin1("\n");
01304 }
01305 }
01306 else
01307 txt = w->text();
01308
01309 return txt;
01310 }
01311
01312 void RenderTextArea::slotTextChanged()
01313 {
01314 element()->m_dirtyvalue = true;
01315 }
01316
01317 void RenderTextArea::select()
01318 {
01319 static_cast<TextAreaWidget *>(m_widget)->selectAll();
01320 }
01321
01322
01323
01324 #include "render_form.moc"