khtml Library API Documentation

html_formimpl.cpp

00001 /*
00002  * This file is part of the DOM implementation for KDE.
00003  *
00004  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
00005  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
00006  *           (C) 2001 Dirk Mueller (mueller@kde.org)
00007  *
00008  * This library is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Library General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2 of the License, or (at your option) any later version.
00012  *
00013  * This library is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Library General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Library General Public License
00019  * along with this library; see the file COPYING.LIB.  If not, write to
00020  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00021  * Boston, MA 02111-1307, USA.
00022  *
00023  * $Id: html_formimpl.cpp,v 1.300.2.4 2003/01/18 20:02:51 mueller Exp $
00024  */
00025 
00026 #undef FORMS_DEBUG
00027 //#define FORMS_DEBUG
00028 
00029 #include "html/html_formimpl.h"
00030 
00031 #include "khtmlview.h"
00032 #include "khtml_part.h"
00033 #include "html/html_documentimpl.h"
00034 #include "khtml_settings.h"
00035 #include "misc/htmlhashes.h"
00036 
00037 #include "css/cssstyleselector.h"
00038 #include "css/cssproperties.h"
00039 #include "css/cssvalues.h"
00040 #include "css/csshelper.h"
00041 #include "xml/dom_textimpl.h"
00042 #include "xml/dom_docimpl.h"
00043 #include "xml/dom2_eventsimpl.h"
00044 #include "khtml_ext.h"
00045 
00046 #include "rendering/render_form.h"
00047 
00048 #include <kcharsets.h>
00049 #include <kglobal.h>
00050 #include <kdebug.h>
00051 #include <kmimetype.h>
00052 #include <kmessagebox.h>
00053 #include <klocale.h>
00054 #include <netaccess.h>
00055 #include <kfileitem.h>
00056 #include <qfile.h>
00057 #include <qtextcodec.h>
00058 
00059 // for keygen
00060 #include <qstring.h>
00061 #include <ksslkeygen.h>
00062 
00063 #include <assert.h>
00064 
00065 using namespace DOM;
00066 using namespace khtml;
00067 
00068 HTMLFormElementImpl::HTMLFormElementImpl(DocumentPtr *doc, bool implicit)
00069     : HTMLElementImpl(doc)
00070 {
00071     m_implicit = implicit;
00072     m_post = false;
00073     m_multipart = false;
00074     m_autocomplete = true;
00075     m_insubmit = false;
00076     m_doingsubmit = false;
00077     m_inreset = false;
00078     m_enctype = "application/x-www-form-urlencoded";
00079     m_boundary = "----------0xKhTmLbOuNdArY";
00080     m_acceptcharset = "UNKNOWN";
00081 }
00082 
00083 HTMLFormElementImpl::~HTMLFormElementImpl()
00084 {
00085     QPtrListIterator<HTMLGenericFormElementImpl> it(formElements);
00086     for (; it.current(); ++it)
00087         it.current()->m_form = 0;
00088 }
00089 
00090 NodeImpl::Id HTMLFormElementImpl::id() const
00091 {
00092     return ID_FORM;
00093 }
00094 
00095 long HTMLFormElementImpl::length() const
00096 {
00097     int len = 0;
00098     QPtrListIterator<HTMLGenericFormElementImpl> it(formElements);
00099     for (; it.current(); ++it)
00100     if (it.current()->isEnumeratable())
00101         ++len;
00102 
00103     return len;
00104 }
00105 
00106 static QCString encodeCString(const QCString& e)
00107 {
00108     // http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1
00109     // safe characters like NS handles them for compatibility
00110     static const char *safe = "-._*";
00111     QCString encoded(( e.length()+e.contains( '\n' ) )*3
00112                      +e.contains('\r') * 3 + 1);
00113     int enclen = 0;
00114     bool crmissing = false;
00115     unsigned char oldc;
00116     unsigned char c ='\0';
00117 
00118     //QCString orig(e.data(), e.size());
00119 
00120     for(unsigned pos = 0; pos < e.length(); pos++) {
00121         oldc = c;
00122         c = e[pos];
00123 
00124         if (crmissing && c != '\n') {
00125             encoded[enclen++] = '%';
00126             encoded[enclen++] = '0';
00127             encoded[enclen++] = 'D';
00128             crmissing = false;
00129         }
00130 
00131         if ( (( c >= 'A') && ( c <= 'Z')) ||
00132              (( c >= 'a') && ( c <= 'z')) ||
00133              (( c >= '0') && ( c <= '9')) ||
00134              (strchr(safe, c))
00135             )
00136             encoded[enclen++] = c;
00137         else if ( c == ' ' )
00138             encoded[enclen++] = '+';
00139         else if ( c == '\n' )
00140         {
00141             encoded[enclen++] = '%';
00142             encoded[enclen++] = '0';
00143             encoded[enclen++] = 'D';
00144             encoded[enclen++] = '%';
00145             encoded[enclen++] = '0';
00146             encoded[enclen++] = 'A';
00147             crmissing = false;
00148         }
00149         else if (c == '\r' && oldc != '\n') {
00150             crmissing = true;
00151         }
00152         else if ( c != '\r' )
00153         {
00154             encoded[enclen++] = '%';
00155             unsigned int h = c / 16;
00156             h += (h > 9) ? ('A' - 10) : '0';
00157             encoded[enclen++] = h;
00158 
00159             unsigned int l = c % 16;
00160             l += (l > 9) ? ('A' - 10) : '0';
00161             encoded[enclen++] = l;
00162         }
00163     }
00164     encoded[enclen++] = '\0';
00165     encoded.truncate(enclen);
00166 
00167     return encoded;
00168 }
00169 
00170 inline static QCString fixUpfromUnicode(const QTextCodec* codec, const QString& s)
00171 {
00172     QCString str = codec->fromUnicode(s);
00173     str.truncate(str.length());
00174     return str;
00175 }
00176 
00177 QByteArray HTMLFormElementImpl::formData(bool& ok)
00178 {
00179 #ifdef FORMS_DEBUG
00180     kdDebug( 6030 ) << "form: formData()" << endl;
00181 #endif
00182 
00183     QByteArray form_data(0);
00184     QCString enc_string = ""; // used for non-multipart data
00185 
00186     // find out the QTextcodec to use
00187     QString str = m_acceptcharset.string();
00188     QChar space(' ');
00189     for(unsigned int i=0; i < str.length(); i++) if(str[i].latin1() == ',') str[i] = space;
00190     QStringList charsets = QStringList::split(' ', str);
00191     QTextCodec* codec = 0;
00192     KHTMLView *view = getDocument()->view();
00193     for ( QStringList::Iterator it = charsets.begin(); it != charsets.end(); ++it )
00194     {
00195         QString enc = (*it);
00196         if(enc.contains("UNKNOWN"))
00197         {
00198             // use standard document encoding
00199             enc = "ISO 8859-1";
00200             if(view && view->part())
00201                 enc = view->part()->encoding();
00202         }
00203         if((codec = KGlobal::charsets()->codecForName(enc.latin1())))
00204             break;
00205     }
00206 
00207     if(!codec)
00208         codec = QTextCodec::codecForLocale();
00209 
00210     // we need to map visual hebrew to logical hebrew, as the web
00211     // server alsways expects responses in logical ordering
00212     if ( codec->mibEnum() == 11 )
00213     codec = QTextCodec::codecForMib( 85 );
00214 
00215     m_encCharset = codec->name();
00216     for(unsigned int i=0; i < m_encCharset.length(); i++)
00217         m_encCharset[i] = m_encCharset[i].latin1() == ' ' ? QChar('-') : m_encCharset[i].lower();
00218 
00219     QStringList fileUploads;
00220 
00221     for (QPtrListIterator<HTMLGenericFormElementImpl> it(formElements); it.current(); ++it) {
00222         HTMLGenericFormElementImpl* current = it.current();
00223         khtml::encodingList lst;
00224 
00225         if (!current->disabled() && current->encoding(codec, lst, m_multipart))
00226         {
00227             //kdDebug(6030) << "adding name " << current->name().string() << endl;
00228             khtml::encodingList::Iterator it;
00229             for( it = lst.begin(); it != lst.end(); ++it )
00230             {
00231                 if (!m_multipart)
00232                 {
00233                     // handle ISINDEX / <input name=isindex> special
00234                     // but only if its the first entry
00235                     if ( enc_string.isEmpty() && *it == "isindex" ) {
00236                         ++it;
00237                         enc_string += encodeCString( *it );
00238                     }
00239                     else {
00240                         if(!enc_string.isEmpty())
00241                             enc_string += '&';
00242 
00243                         enc_string += encodeCString(*it);
00244                         enc_string += "=";
00245                         ++it;
00246                         enc_string += encodeCString(*it);
00247                     }
00248                 }
00249                 else
00250                 {
00251                     QCString hstr("--");
00252                     hstr += m_boundary.string().latin1();
00253                     hstr += "\r\n";
00254                     hstr += "Content-Disposition: form-data; name=\"";
00255                     hstr += (*it).data();
00256                     hstr += "\"";
00257 
00258                     // if the current type is FILE, then we also need to
00259                     // include the filename
00260                     if (current->nodeType() == Node::ELEMENT_NODE && current->id() == ID_INPUT &&
00261                         static_cast<HTMLInputElementImpl*>(current)->inputType() == HTMLInputElementImpl::FILE)
00262                     {
00263                         QString path = static_cast<HTMLInputElementImpl*>(current)->value().string();
00264                         if (path.length()) fileUploads << path;
00265                         QString onlyfilename = path.mid(path.findRev('/')+1);
00266 
00267                         hstr += ("; filename=\"" + onlyfilename + "\"").ascii();
00268                         if(!static_cast<HTMLInputElementImpl*>(current)->value().isEmpty())
00269                         {
00270                             hstr += "\r\nContent-Type: ";
00271                             KMimeType::Ptr ptr = KMimeType::findByURL(KURL(path));
00272                             hstr += ptr->name().ascii();
00273                         }
00274                     }
00275 
00276                     hstr += "\r\n\r\n";
00277                     ++it;
00278 
00279                     // append body
00280                     unsigned int old_size = form_data.size();
00281                     form_data.resize( old_size + hstr.length() + (*it).size() + 1);
00282                     memcpy(form_data.data() + old_size, hstr.data(), hstr.length());
00283                     memcpy(form_data.data() + old_size + hstr.length(), *it, (*it).size());
00284                     form_data[form_data.size()-2] = '\r';
00285                     form_data[form_data.size()-1] = '\n';
00286                 }
00287             }
00288         }
00289     }
00290 
00291     if (fileUploads.count()) {
00292         int result = KMessageBox::warningContinueCancelList( 0,
00293                                                              i18n("You're about to transfer the following files from "
00294                                                                   "your local computer to the Internet.\n"
00295                                                                   "Do you really want to continue?"),
00296                                                              fileUploads);
00297 
00298 
00299         if (result == KMessageBox::Cancel) {
00300             ok = false;
00301             return QByteArray();
00302         }
00303     }
00304 
00305     if (m_multipart)
00306         enc_string = ("--" + m_boundary.string() + "--\r\n").ascii();
00307 
00308     int old_size = form_data.size();
00309     form_data.resize( form_data.size() + enc_string.length() );
00310     memcpy(form_data.data() + old_size, enc_string.data(), enc_string.length() );
00311 
00312     ok = true;
00313     return form_data;
00314 }
00315 
00316 void HTMLFormElementImpl::setEnctype( const DOMString& type )
00317 {
00318     if(type.string().find("multipart", 0, false) != -1 || type.string().find("form-data", 0, false) != -1)
00319     {
00320         m_enctype = "multipart/form-data";
00321         m_multipart = true;
00322         m_post = true;
00323     } else if (type.string().find("text", 0, false) != -1 || type.string().find("plain", 0, false) != -1)
00324     {
00325         m_enctype = "text/plain";
00326         m_multipart = false;
00327     }
00328     else
00329     {
00330         m_enctype = "application/x-www-form-urlencoded";
00331         m_multipart = false;
00332     }
00333     m_encCharset = QString::null;
00334 }
00335 
00336 void HTMLFormElementImpl::setBoundary( const DOMString& bound )
00337 {
00338     m_boundary = bound;
00339 }
00340 
00341 void HTMLFormElementImpl::submitFromKeyboard()
00342 {
00343     // Activate the first submit button - like other browsers do
00344     for (QPtrListIterator<HTMLGenericFormElementImpl> it(formElements); it.current(); ++it) {
00345         if (it.current()->id() == ID_BUTTON) {
00346             HTMLButtonElementImpl* current = static_cast<HTMLButtonElementImpl *>(it.current());
00347             if (current->buttonType() == HTMLButtonElementImpl::SUBMIT && !current->disabled()) {
00348                 current->activate();
00349                 return;
00350             }
00351         } else if (it.current()->id() == ID_INPUT) {
00352             HTMLInputElementImpl* current = static_cast<HTMLInputElementImpl *>(it.current());
00353             if (current->inputType() == HTMLInputElementImpl::SUBMIT && !current->disabled()) {
00354                 current->activate();
00355                 return;
00356             }
00357         }
00358     }
00359 
00360     prepareSubmit();
00361 }
00362 
00363 bool HTMLFormElementImpl::prepareSubmit()
00364 {
00365     KHTMLView *view = getDocument()->view();
00366     if(m_insubmit || !view || !view->part() || view->part()->onlyLocalReferences())
00367         return m_insubmit;
00368 
00369     m_insubmit = true;
00370     m_doingsubmit = false;
00371 
00372     if ( dispatchHTMLEvent(EventImpl::SUBMIT_EVENT,true,true) && !m_doingsubmit )
00373         m_doingsubmit = true;
00374 
00375     m_insubmit = false;
00376 
00377     if ( m_doingsubmit )
00378         submit();
00379 
00380     return m_doingsubmit;
00381 }
00382 
00383 void HTMLFormElementImpl::submit(  )
00384 {
00385     if ( m_insubmit ) {
00386         m_doingsubmit = true;
00387         return;
00388     }
00389 
00390     m_insubmit = true;
00391 
00392 #ifdef FORMS_DEBUG
00393     kdDebug( 6030 ) << "submitting!" << endl;
00394 #endif
00395 
00396     KHTMLView *view = getDocument()->view();
00397     for (QPtrListIterator<HTMLGenericFormElementImpl> it(formElements); it.current(); ++it) {
00398         HTMLGenericFormElementImpl* current = it.current();
00399         if (current->id() == ID_INPUT &&
00400             static_cast<HTMLInputElementImpl*>(current)->inputType() == HTMLInputElementImpl::TEXT &&
00401             static_cast<HTMLInputElementImpl*>(current)->autoComplete() )
00402         {
00403             HTMLInputElementImpl *input = static_cast<HTMLInputElementImpl *>(current);
00404             view->addFormCompletionItem(input->name().string(), input->value().string());
00405         }
00406     }
00407 
00408     bool ok;
00409     QByteArray form_data = formData(ok);
00410     if (ok) {
00411         DOMString url(khtml::parseURL(getAttribute(ATTR_ACTION)));
00412         if(m_post) {
00413             view->part()->submitForm( "post", url.string(), form_data,
00414                                       m_target.string(),
00415                                       enctype().string(),
00416                                       boundary().string() );
00417         }
00418         else {
00419             view->part()->submitForm( "get", url.string(), form_data,
00420                                       m_target.string() );
00421         }
00422     }
00423 
00424     m_doingsubmit = m_insubmit = false;
00425 }
00426 
00427 void HTMLFormElementImpl::reset(  )
00428 {
00429     KHTMLView *view = getDocument()->view();
00430     if(m_inreset || !view || !view->part()) return;
00431 
00432     m_inreset = true;
00433 
00434 #ifdef FORMS_DEBUG
00435     kdDebug( 6030 ) << "reset pressed!" << endl;
00436 #endif
00437 
00438     // ### DOM2 labels this event as not cancelable, however
00439     // common browsers( sick! ) allow it be cancelled.
00440     if ( !dispatchHTMLEvent(EventImpl::RESET_EVENT,true, true) ) {
00441         m_inreset = false;
00442         return;
00443     }
00444 
00445     for (QPtrListIterator<HTMLGenericFormElementImpl> it(formElements); it.current(); ++it)
00446         it.current()->reset();
00447 
00448     m_inreset = false;
00449 }
00450 
00451 void HTMLFormElementImpl::parseAttribute(AttributeImpl *attr)
00452 {
00453     switch(attr->id())
00454     {
00455     case ATTR_ACTION:
00456         break;
00457     case ATTR_TARGET:
00458         m_target = attr->value();
00459         break;
00460     case ATTR_METHOD:
00461         m_post = ( strcasecmp( attr->value(), "post" ) == 0 );
00462         break;
00463     case ATTR_ENCTYPE:
00464         setEnctype( attr->value() );
00465         break;
00466     case ATTR_ACCEPT_CHARSET:
00467         // space separated list of charsets the server
00468         // accepts - see rfc2045
00469         m_acceptcharset = attr->value();
00470         break;
00471     case ATTR_ACCEPT:
00472         // ignore this one for the moment...
00473         break;
00474     case ATTR_AUTOCOMPLETE:
00475         m_autocomplete = strcasecmp( attr->value(), "off" );
00476         break;
00477     case ATTR_ONSUBMIT:
00478         setHTMLEventListener(EventImpl::SUBMIT_EVENT,
00479         getDocument()->createHTMLEventListener(attr->value().string()));
00480         break;
00481     case ATTR_ONRESET:
00482         setHTMLEventListener(EventImpl::RESET_EVENT,
00483         getDocument()->createHTMLEventListener(attr->value().string()));
00484         break;
00485     case ATTR_ID:
00486     case ATTR_NAME:
00487     break;
00488     default:
00489         HTMLElementImpl::parseAttribute(attr);
00490     }
00491 }
00492 
00493 void HTMLFormElementImpl::radioClicked( HTMLGenericFormElementImpl *caller )
00494 {
00495     for (QPtrListIterator<HTMLGenericFormElementImpl> it(formElements); it.current(); ++it) {
00496         HTMLGenericFormElementImpl *current = it.current();
00497         if (current->id() == ID_INPUT &&
00498             static_cast<HTMLInputElementImpl*>(current)->inputType() == HTMLInputElementImpl::RADIO &&
00499             current != caller && current->form() == caller->form() && current->name() == caller->name()) {
00500             static_cast<HTMLInputElementImpl*>(current)->setChecked(false);
00501         }
00502     }
00503 }
00504 
00505 void HTMLFormElementImpl::registerFormElement(HTMLGenericFormElementImpl *e)
00506 {
00507     formElements.append(e);
00508 }
00509 
00510 void HTMLFormElementImpl::removeFormElement(HTMLGenericFormElementImpl *e)
00511 {
00512     formElements.remove(e);
00513 }
00514 
00515 // -------------------------------------------------------------------------
00516 
00517 HTMLGenericFormElementImpl::HTMLGenericFormElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
00518     : HTMLElementImpl(doc)
00519 {
00520     m_disabled = m_readOnly = false;
00521     m_name = 0;
00522 
00523     if (f)
00524     m_form = f;
00525     else
00526     m_form = getForm();
00527     if (m_form)
00528         m_form->registerFormElement(this);
00529 }
00530 
00531 void HTMLGenericFormElementImpl::insertedIntoDocument()
00532 {
00533     HTMLElementImpl::insertedIntoDocument();
00534 
00535     HTMLFormElementImpl* newform = getForm();
00536 
00537     if (!m_form && newform) {
00538         m_form = newform;
00539         m_form->registerFormElement(this);
00540     }
00541 }
00542 
00543 void HTMLGenericFormElementImpl::removedFromDocument()
00544 {
00545     HTMLElementImpl::removedFromDocument();
00546 
00547     if (m_form)
00548         m_form->removeFormElement(this);
00549 
00550     m_form = 0;
00551 }
00552 
00553 HTMLGenericFormElementImpl::~HTMLGenericFormElementImpl()
00554 {
00555     if (m_form)
00556         m_form->removeFormElement(this);
00557 }
00558 
00559 void HTMLGenericFormElementImpl::parseAttribute(AttributeImpl *attr)
00560 {
00561     switch(attr->id())
00562     {
00563     case ATTR_NAME:
00564         break;
00565     case ATTR_DISABLED:
00566         setDisabled( attr->val() != 0 );
00567         break;
00568     case ATTR_READONLY:
00569     {
00570         bool m_oldreadOnly = m_readOnly;
00571         m_readOnly = attr->val() != 0;
00572         if (m_oldreadOnly != m_readOnly) setChanged();
00573         break;
00574     }
00575     default:
00576         HTMLElementImpl::parseAttribute(attr);
00577     }
00578 }
00579 
00580 void HTMLGenericFormElementImpl::attach()
00581 {
00582     assert(!attached());
00583 
00584     if (m_render) {
00585         assert(m_render->style());
00586         parentNode()->renderer()->addChild(m_render, nextRenderer());
00587         m_render->updateFromElement();
00588     }
00589 
00590     NodeBaseImpl::attach();
00591 }
00592 
00593 HTMLFormElementImpl *HTMLGenericFormElementImpl::getForm() const
00594 {
00595     NodeImpl *p = parentNode();
00596     while(p)
00597     {
00598         if( p->id() == ID_FORM )
00599             return static_cast<HTMLFormElementImpl *>(p);
00600         p = p->parentNode();
00601     }
00602 #ifdef FORMS_DEBUG
00603     kdDebug( 6030 ) << "couldn't find form!" << endl;
00604     kdDebug( 6030 ) << kdBacktrace() << endl;
00605 #endif
00606     return 0;
00607 }
00608 
00609 DOMString HTMLGenericFormElementImpl::name() const
00610 {
00611     if (m_name) return m_name;
00612 
00613 // ###
00614 //     DOMString n = getDocument()->htmlMode() != DocumentImpl::XHtml ?
00615 //                   getAttribute(ATTR_NAME) : getAttribute(ATTR_ID);
00616     DOMString n = getAttribute(ATTR_NAME);
00617     if (n.isNull())
00618         return new DOMStringImpl("");
00619 
00620     return n;
00621 }
00622 
00623 void HTMLGenericFormElementImpl::setName(const DOMString& name)
00624 {
00625     if (m_name) m_name->deref();
00626     m_name = name.implementation();
00627     if (m_name) m_name->ref();
00628 }
00629 
00630 void HTMLGenericFormElementImpl::onSelect()
00631 {
00632     // ### make this work with new form events architecture
00633     dispatchHTMLEvent(EventImpl::SELECT_EVENT,true,false);
00634 }
00635 
00636 void HTMLGenericFormElementImpl::onChange()
00637 {
00638     // ### make this work with new form events architecture
00639     dispatchHTMLEvent(EventImpl::CHANGE_EVENT,true,false);
00640 }
00641 
00642 void HTMLGenericFormElementImpl::setDisabled( bool _disabled )
00643 {
00644     if ( m_disabled != _disabled ) {
00645         m_disabled = _disabled;
00646         setChanged();
00647     }
00648 }
00649 
00650 bool HTMLGenericFormElementImpl::isSelectable() const
00651 {
00652     return  m_render && m_render->isWidget() &&
00653         static_cast<RenderWidget*>(m_render)->widget() &&
00654         static_cast<RenderWidget*>(m_render)->widget()->focusPolicy() >= QWidget::TabFocus;
00655 }
00656 
00657 void HTMLGenericFormElementImpl::defaultEventHandler(EventImpl *evt)
00658 {
00659     if (evt->target()==this && !m_disabled)
00660     {
00661         // Report focus in/out changes to the browser extension (editable widgets only)
00662         KHTMLView *view = getDocument()->view();
00663         if (evt->id()==EventImpl::DOMFOCUSIN_EVENT && isEditable() && m_render && m_render->isWidget()) {
00664             KHTMLPartBrowserExtension *ext = static_cast<KHTMLPartBrowserExtension *>(view->part()->browserExtension());
00665             QWidget *widget = static_cast<RenderWidget*>(m_render)->widget();
00666             if (ext)
00667                 ext->editableWidgetFocused(widget);
00668         }
00669         if (evt->id()==EventImpl::MOUSEDOWN_EVENT || evt->id()==EventImpl::KHTML_KEYDOWN_EVENT)
00670         {
00671             setActive();
00672         }
00673         else if (evt->id() == EventImpl::MOUSEUP_EVENT || evt->id()==EventImpl::KHTML_KEYUP_EVENT)
00674         {
00675         if (m_active)
00676         {
00677         setActive(false);
00678         setFocus();
00679         }
00680         else {
00681                 setActive(false);
00682             }
00683         }
00684 
00685     if (evt->id()==EventImpl::KHTML_KEYDOWN_EVENT ||
00686         evt->id()==EventImpl::KHTML_KEYUP_EVENT)
00687     {
00688         TextEventImpl * k = static_cast<TextEventImpl *>(evt);
00689         if (k->keyVal() == QChar('\n').unicode() && m_render && m_render->isWidget() && k->qKeyEvent)
00690         QApplication::sendEvent(static_cast<RenderWidget *>(m_render)->widget(), k->qKeyEvent);
00691     }
00692 
00693     if (evt->id()==EventImpl::DOMFOCUSOUT_EVENT && isEditable() && m_render && m_render->isWidget()) {
00694         KHTMLPartBrowserExtension *ext = static_cast<KHTMLPartBrowserExtension *>(view->part()->browserExtension());
00695         QWidget *widget = static_cast<RenderWidget*>(m_render)->widget();
00696         if (ext)
00697         ext->editableWidgetBlurred(widget);
00698 
00699         // ### Don't count popup as a valid reason for losing the focus (example: opening the options of a select
00700         // combobox shouldn't emit onblur)
00701     }
00702     }
00703     if (evt->target() == this && evt->isMouseEvent() && renderer())
00704         evt->setDefaultHandled();
00705 
00706     HTMLElementImpl::defaultEventHandler(evt);
00707 }
00708 
00709 bool HTMLGenericFormElementImpl::isEditable()
00710 {
00711     return false;
00712 }
00713 
00714 // -------------------------------------------------------------------------
00715 
00716 HTMLButtonElementImpl::HTMLButtonElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
00717     : HTMLGenericFormElementImpl(doc, f)
00718 {
00719     m_clicked = false;
00720     m_type = SUBMIT;
00721     m_dirty = true;
00722     m_activeSubmit = false;
00723 }
00724 
00725 HTMLButtonElementImpl::~HTMLButtonElementImpl()
00726 {
00727 }
00728 
00729 NodeImpl::Id HTMLButtonElementImpl::id() const
00730 {
00731     return ID_BUTTON;
00732 }
00733 
00734 DOMString HTMLButtonElementImpl::type() const
00735 {
00736     return getAttribute(ATTR_TYPE);
00737 }
00738 
00739 void HTMLButtonElementImpl::parseAttribute(AttributeImpl *attr)
00740 {
00741     switch(attr->id())
00742     {
00743     case ATTR_TYPE:
00744         if ( strcasecmp( attr->value(), "submit" ) == 0 )
00745             m_type = SUBMIT;
00746         else if ( strcasecmp( attr->value(), "reset" ) == 0 )
00747             m_type = RESET;
00748         else if ( strcasecmp( attr->value(), "button" ) == 0 )
00749             m_type = BUTTON;
00750         break;
00751     case ATTR_VALUE:
00752         m_value = attr->value();
00753         m_currValue = m_value.string();
00754         break;
00755     case ATTR_ACCESSKEY:
00756         break;
00757     case ATTR_ONFOCUS:
00758         setHTMLEventListener(EventImpl::FOCUS_EVENT,
00759             getDocument()->createHTMLEventListener(attr->value().string()));
00760         break;
00761     case ATTR_ONBLUR:
00762         setHTMLEventListener(EventImpl::BLUR_EVENT,
00763             getDocument()->createHTMLEventListener(attr->value().string()));
00764         break;
00765     default:
00766         HTMLGenericFormElementImpl::parseAttribute(attr);
00767     }
00768 }
00769 
00770 void HTMLButtonElementImpl::attach()
00771 {
00772     // skip the generic handler
00773     HTMLElementImpl::attach();
00774     // doesn't work yet in the renderer ### fixme
00775     if (renderer())
00776         renderer()->setReplaced(true);
00777 }
00778 
00779 void HTMLButtonElementImpl::defaultEventHandler(EventImpl *evt)
00780 {
00781     if (m_type != BUTTON && (evt->id() == EventImpl::DOMACTIVATE_EVENT) && !m_disabled)
00782         activate();
00783     HTMLGenericFormElementImpl::defaultEventHandler(evt);
00784 }
00785 
00786 void HTMLButtonElementImpl::activate()
00787 {
00788     m_clicked = true;
00789 
00790     if(m_form && m_type == SUBMIT) {
00791         m_activeSubmit = true;
00792         m_form->prepareSubmit();
00793         m_activeSubmit = false; // in case we were canceled
00794     }
00795     if(m_form && m_type == RESET)
00796         m_form->reset();
00797 }
00798 
00799 bool HTMLButtonElementImpl::encoding(const QTextCodec* codec, khtml::encodingList& encoding, bool /*multipart*/)
00800 {
00801     if (m_type != SUBMIT || name().isEmpty() || !m_activeSubmit)
00802         return false;
00803 
00804     encoding += fixUpfromUnicode(codec, name().string());
00805     QString enc_str = m_currValue.isNull() ? QString("") : m_currValue;
00806     encoding += fixUpfromUnicode(codec, enc_str);
00807 
00808     return true;
00809 }
00810 
00811 
00812 // -------------------------------------------------------------------------
00813 
00814 HTMLFieldSetElementImpl::HTMLFieldSetElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
00815     : HTMLGenericFormElementImpl(doc, f), m_legend(0)
00816 {
00817 }
00818 
00819 HTMLFieldSetElementImpl::~HTMLFieldSetElementImpl()
00820 {
00821 }
00822 
00823 NodeImpl::Id HTMLFieldSetElementImpl::id() const
00824 {
00825     return ID_FIELDSET;
00826 }
00827 
00828 void HTMLFieldSetElementImpl::attach()
00829 {
00830     assert(!attached());
00831     assert(!m_render);
00832     assert(parentNode());
00833     addCSSProperty(CSS_PROP_BORDER_TOP_STYLE, CSS_VAL_SOLID);
00834     addCSSProperty(CSS_PROP_BORDER_BOTTOM_STYLE, CSS_VAL_SOLID);
00835     addCSSProperty(CSS_PROP_BORDER_LEFT_STYLE, CSS_VAL_SOLID);
00836     addCSSProperty(CSS_PROP_BORDER_RIGHT_STYLE, CSS_VAL_SOLID);
00837     addCSSProperty(CSS_PROP_BORDER_WIDTH, "1px");
00838     addCSSProperty(CSS_PROP_PADDING_LEFT, "4px");
00839     addCSSProperty(CSS_PROP_PADDING_RIGHT, "4px");
00840     addCSSProperty(CSS_PROP_PADDING_BOTTOM, "4px");
00841 
00842 
00843     RenderStyle* _style = getDocument()->styleSelector()->styleForElement(this);
00844     _style->ref();
00845     if (parentNode()->renderer() && _style->display() != NONE) {
00846         m_render = new RenderFieldset(this);
00847         m_render->setStyle(_style);
00848     }
00849     HTMLGenericFormElementImpl::attach();
00850     _style->deref();
00851 }
00852 
00853 NodeImpl *HTMLFieldSetElementImpl::addChild(NodeImpl *child)
00854 {
00855     if(!m_legend && child->id() == ID_LEGEND) {
00856         int exceptioncode = 0;
00857         NodeImpl* r = insertBefore( child, firstChild(), exceptioncode );
00858         m_legend = child;
00859         return r;
00860     }
00861     return HTMLGenericFormElementImpl::addChild(child);
00862 }
00863 
00864 void HTMLFieldSetElementImpl::parseAttribute(AttributeImpl *attr)
00865 {
00866     HTMLElementImpl::parseAttribute(attr);
00867 }
00868 
00869 // -------------------------------------------------------------------------
00870 
00871 HTMLInputElementImpl::HTMLInputElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
00872     : HTMLGenericFormElementImpl(doc, f)
00873 {
00874     m_type = TEXT;
00875     m_maxLen = -1;
00876     m_size = 20;
00877     m_clicked = false;
00878     m_checked = false;
00879 
00880     m_activeSubmit = false;
00881     m_autocomplete = true;
00882     m_inited = false;
00883 
00884     xPos = 0;
00885     yPos = 0;
00886 
00887     if ( m_form )
00888         m_autocomplete = f->autoComplete();
00889 }
00890 
00891 HTMLInputElementImpl::~HTMLInputElementImpl()
00892 {
00893     if (getDocument()) getDocument()->deregisterMaintainsState(this);
00894 }
00895 
00896 NodeImpl::Id HTMLInputElementImpl::id() const
00897 {
00898     return ID_INPUT;
00899 }
00900 
00901 void HTMLInputElementImpl::setType(const DOMString& /*t*/)
00902 {
00903     // ###
00904 }
00905 
00906 DOMString HTMLInputElementImpl::type() const
00907 {
00908     // needs to be lowercase according to DOM spec
00909     switch (m_type) {
00910     case TEXT: return "text";
00911     case PASSWORD: return "password";
00912     case CHECKBOX: return "checkbox";
00913     case RADIO: return "radio";
00914     case SUBMIT: return "submit";
00915     case RESET: return "reset";
00916     case FILE: return "file";
00917     case HIDDEN: return "hidden";
00918     case IMAGE: return "image";
00919     case BUTTON: return "button";
00920     default: return "";
00921     }
00922 }
00923 
00924 QString HTMLInputElementImpl::state( )
00925 {
00926     switch (m_type) {
00927     case PASSWORD:
00928         return QString::fromLatin1("."); // empty string, avoid restoring
00929     case CHECKBOX:
00930     case RADIO:
00931         return QString::fromLatin1(m_checked ? "on" : "off");
00932     default:
00933         return value().string()+'.'; // Make sure the string is not empty!
00934     }
00935 }
00936 
00937 void HTMLInputElementImpl::restoreState(const QString &state)
00938 {
00939     switch (m_type) {
00940     case CHECKBOX:
00941     case RADIO:
00942         setChecked((state == QString::fromLatin1("on")));
00943         break;
00944     case FILE:
00945         m_value = DOMString(state.left(state.length()-1));
00946         setChanged();
00947         break;
00948     default:
00949         setValue(DOMString(state.left(state.length()-1)));
00950         break;
00951     }
00952 }
00953 
00954 void HTMLInputElementImpl::select(  )
00955 {
00956     if(!m_render) return;
00957 
00958     if (m_type == TEXT || m_type == PASSWORD)
00959         static_cast<RenderLineEdit*>(m_render)->select();
00960     else if (m_type == FILE)
00961         static_cast<RenderFileButton*>(m_render)->select();
00962 }
00963 
00964 void HTMLInputElementImpl::click(  )
00965 {
00966     // ###
00967 #ifdef FORMS_DEBUG
00968     kdDebug( 6030 ) << " HTMLInputElementImpl::click(  )" << endl;
00969 #endif
00970 }
00971 
00972 void HTMLInputElementImpl::parseAttribute(AttributeImpl *attr)
00973 {
00974     switch(attr->id())
00975     {
00976     case ATTR_AUTOCOMPLETE:
00977         m_autocomplete = strcasecmp( attr->value(), "off" );
00978         break;
00979     case ATTR_TYPE:
00980         // ignore to avoid that javascript can change a type field to file
00981         break;
00982     case ATTR_VALUE:
00983     case ATTR_CHECKED:
00984         // these are the defaults, don't change them
00985         break;
00986     case ATTR_MAXLENGTH:
00987     {
00988         m_maxLen = -1;
00989         if (!attr->val()) break;
00990         bool ok;
00991         m_maxLen = attr->val()->toInt(&ok);
00992         if (!ok)
00993             m_maxLen = -1;
00994         else if (m_maxLen < 0)
00995             m_maxLen = 0;
00996         setChanged();
00997     }
00998     break;
00999     case ATTR_SIZE:
01000         m_size = attr->val() ? attr->val()->toInt() : 20;
01001         break;
01002     case ATTR_ALT:
01003     case ATTR_SRC:
01004         if (m_render && m_type == IMAGE) m_render->updateFromElement();
01005         break;
01006     case ATTR_USEMAP:
01007     case ATTR_ACCESSKEY:
01008         // ### ignore for the moment
01009         break;
01010     case ATTR_ALIGN:
01011         addHTMLAlignment( attr->value() );
01012         break;
01013     case ATTR_WIDTH:
01014         // ignore this attribute,  do _not_ add
01015         // a CSS_PROP_WIDTH here!
01016         // webdesigner are stupid - and IE/NS behave the same ( Dirk )
01017         break;
01018     case ATTR_HEIGHT:
01019         addCSSLength(CSS_PROP_HEIGHT, attr->value() );
01020         break;
01021     case ATTR_ONFOCUS:
01022         setHTMLEventListener(EventImpl::FOCUS_EVENT,
01023             getDocument()->createHTMLEventListener(attr->value().string()));
01024         break;
01025     case ATTR_ONBLUR:
01026         setHTMLEventListener(EventImpl::BLUR_EVENT,
01027             getDocument()->createHTMLEventListener(attr->value().string()));
01028         break;
01029     case ATTR_ONSELECT:
01030         setHTMLEventListener(EventImpl::SELECT_EVENT,
01031             getDocument()->createHTMLEventListener(attr->value().string()));
01032         break;
01033     case ATTR_ONCHANGE:
01034         setHTMLEventListener(EventImpl::CHANGE_EVENT,
01035             getDocument()->createHTMLEventListener(attr->value().string()));
01036         break;
01037     default:
01038         HTMLGenericFormElementImpl::parseAttribute(attr);
01039     }
01040 }
01041 
01042 void HTMLInputElementImpl::attach()
01043 {
01044     assert(!attached());
01045     assert(!m_render);
01046     assert(parentNode());
01047 
01048     if (!m_inited) {
01049         DOMString type = getAttribute(ATTR_TYPE);
01050         if ( strcasecmp( type, "password" ) == 0 )
01051             m_type = PASSWORD;
01052         else if ( strcasecmp( type, "checkbox" ) == 0 )
01053             m_type = CHECKBOX;
01054         else if ( strcasecmp( type, "radio" ) == 0 )
01055             m_type = RADIO;
01056         else if ( strcasecmp( type, "submit" ) == 0 )
01057             m_type = SUBMIT;
01058         else if ( strcasecmp( type, "reset" ) == 0 )
01059             m_type = RESET;
01060         else if ( strcasecmp( type, "file" ) == 0 )
01061             m_type = FILE;
01062         else if ( strcasecmp( type, "hidden" ) == 0 )
01063             m_type = HIDDEN;
01064         else if ( strcasecmp( type, "image" ) == 0 )
01065             m_type = IMAGE;
01066         else if ( strcasecmp( type, "button" ) == 0 )
01067             m_type = BUTTON;
01068         else if ( strcasecmp( type, "khtml_isindex" ) == 0 )
01069             m_type = ISINDEX;
01070         else
01071             m_type = TEXT;
01072 
01073         if (m_type != FILE) m_value = getAttribute(ATTR_VALUE);
01074         if ((uint) m_type <= ISINDEX && !m_value.isEmpty()) {
01075             QString value = m_value.string();
01076             // remove newline stuff..
01077             QString nvalue;
01078             for (unsigned int i = 0; i < value.length(); ++i)
01079                 if (value[i] >= ' ')
01080                     nvalue += value[i];
01081             m_value = nvalue;
01082         }
01083         m_checked = (getAttribute(ATTR_CHECKED) != 0);
01084         m_inited = true;
01085     }
01086 
01087     // make sure we don't inherit a color to the form elements
01088     // by adding a non-CSS color property. this his higher
01089     // priority than inherited color, but lesser priority than
01090     // any color specified by CSS for the elements.
01091     switch( m_type ) {
01092     case TEXT:
01093     case PASSWORD:
01094         addCSSProperty(CSS_PROP_FONT_FAMILY,  "monospace");
01095         /* nobreak */
01096     case ISINDEX:
01097     case FILE:
01098         addCSSProperty(CSS_PROP_COLOR, "text");
01099         break;
01100     case SUBMIT:
01101     case RESET:
01102     case BUTTON:
01103     case CHECKBOX:
01104     case RADIO:
01105         addCSSProperty(CSS_PROP_COLOR, "buttontext" );
01106     case HIDDEN:
01107     case IMAGE:
01108         if (!getAttribute(ATTR_WIDTH).isNull())
01109             addCSSLength(CSS_PROP_WIDTH, getAttribute(ATTR_WIDTH));
01110         break;
01111     };
01112 
01113     RenderStyle* _style = getDocument()->styleSelector()->styleForElement(this);
01114     _style->ref();
01115     if (parentNode()->renderer() && _style->display() != NONE) {
01116         switch(m_type)
01117         {
01118         case TEXT:
01119         case PASSWORD:
01120         case ISINDEX:      m_render = new RenderLineEdit(this);   break;
01121         case CHECKBOX:  m_render = new RenderCheckBox(this); break;
01122         case RADIO:        m_render = new RenderRadioButton(this); break;
01123         case SUBMIT:      m_render = new RenderSubmitButton(this); break;
01124         case IMAGE:       m_render =  new RenderImageButton(this); break;
01125         case RESET:      m_render = new RenderResetButton(this);   break;
01126         case FILE:         m_render =  new RenderFileButton(this);    break;
01127         case BUTTON:  m_render = new RenderPushButton(this);
01128         case HIDDEN:   break;
01129         }
01130     }
01131 
01132     if (m_render)
01133         m_render->setStyle(_style);
01134 
01135     HTMLGenericFormElementImpl::attach();
01136     _style->deref();
01137 }
01138 
01139 DOMString HTMLInputElementImpl::altText() const
01140 {
01141     // http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#altgen
01142     // also heavily discussed by Hixie on bugzilla
01143     // note this is intentionally different to HTMLImageElementImpl::altText()
01144     DOMString alt = getAttribute( ATTR_ALT );
01145     // fall back to title attribute
01146     if ( alt.isNull() )
01147         alt = getAttribute( ATTR_TITLE );
01148     if ( alt.isNull() )
01149         alt = getAttribute( ATTR_VALUE );
01150     if ( alt.isEmpty() )
01151         alt = i18n( "Submit" );
01152 
01153     return alt;
01154 }
01155 
01156 bool HTMLInputElementImpl::encoding(const QTextCodec* codec, khtml::encodingList& encoding, bool multipart)
01157 {
01158     QString nme = name().string();
01159 
01160     // image generates its own name's
01161     if (nme.isEmpty() && m_type != IMAGE) return false;
01162 
01163     // IMAGE needs special handling later
01164     if(m_type != IMAGE) encoding += fixUpfromUnicode(codec, nme);
01165 
01166     switch (m_type) {
01167         case CHECKBOX:
01168 
01169             if( checked() ) {
01170                 encoding += fixUpfromUnicode(codec, value().string());
01171                 return true;
01172             }
01173             break;
01174 
01175         case RADIO:
01176 
01177             if( checked() ) {
01178                 encoding += fixUpfromUnicode(codec, value().string());
01179                 return true;
01180             }
01181             break;
01182 
01183         case BUTTON:
01184         case RESET:
01185             // those buttons are never successful
01186             return false;
01187 
01188         case IMAGE:
01189 
01190             if(m_clicked && clickX() != -1)
01191             {
01192                 m_clicked = false;
01193                 QString astr(nme.isEmpty() ? QString::fromLatin1("x") : nme + ".x");
01194 
01195                 encoding += fixUpfromUnicode(codec, astr);
01196                 astr.setNum(clickX());
01197                 encoding += fixUpfromUnicode(codec, astr);
01198                 astr = nme.isEmpty() ? QString::fromLatin1("y") : nme + ".y";
01199                 encoding += fixUpfromUnicode(codec, astr);
01200                 astr.setNum(clickY());
01201                 encoding += fixUpfromUnicode(codec, astr);
01202 
01203                 return true;
01204             }
01205             break;
01206 
01207         case SUBMIT:
01208 
01209             if (m_activeSubmit)
01210             {
01211                 QString enc_str = m_value.isNull() ?
01212                     static_cast<RenderSubmitButton*>(m_render)->defaultLabel() : value().string();
01213 
01214                 if(!enc_str.isEmpty())
01215                 {
01216                     encoding += fixUpfromUnicode(codec, enc_str);
01217                     return true;
01218                 }
01219             }
01220             break;
01221 
01222         case FILE:
01223         {
01224             // don't submit if display: none or display: hidden
01225             if(!renderer() || renderer()->style()->visibility() != khtml::VISIBLE)
01226                 return false;
01227 
01228             QString local;
01229             QCString dummy("");
01230 
01231             KURL fileurl(value().string());
01232             KIO::UDSEntry filestat;
01233 
01234             // can't submit file in www-url-form encoded
01235             if (multipart && KIO::NetAccess::stat(fileurl, filestat)) {
01236                 KFileItem fileitem(filestat, fileurl, true, false);
01237 
01238                 if ( fileitem.isFile() && KIO::NetAccess::download(KURL(value().string()), local) ) {
01239                     QFile file(local);
01240                     if (file.open(IO_ReadOnly)) {
01241                         QCString filearray(file.size()+1);
01242                         int readbytes = file.readBlock( filearray.data(), file.size());
01243                         if ( readbytes >= 0 )
01244                             filearray[readbytes] = '\0';
01245                         file.close();
01246 
01247                         encoding += filearray;
01248                         KIO::NetAccess::removeTempFile( local );
01249 
01250                         return true;
01251                     }
01252                 }
01253             }
01254             // else fall through
01255         }
01256         case HIDDEN:
01257         case TEXT:
01258         case PASSWORD:
01259             // always successful
01260             encoding += fixUpfromUnicode(codec, value().string());
01261             return true;
01262         case ISINDEX:
01263             encoding += fixUpfromUnicode(codec, m_value.string());
01264             return true;
01265     }
01266     return false;
01267 }
01268 
01269 void HTMLInputElementImpl::reset()
01270 {
01271     setValue(getAttribute(ATTR_VALUE));
01272     setChecked(getAttribute(ATTR_CHECKED) != 0);
01273 }
01274 
01275 void HTMLInputElementImpl::setChecked(bool _checked)
01276 {
01277     if (m_form && m_type == RADIO && _checked && !name().isEmpty())
01278         m_form->radioClicked(this);
01279 
01280     if (m_checked == _checked) return;
01281     m_checked = _checked;
01282     setChanged();
01283 }
01284 
01285 
01286 DOMString HTMLInputElementImpl::value() const
01287 {
01288     if(m_value.isNull())
01289         return (m_type == CHECKBOX || m_type ==RADIO) ?
01290             DOMString("on") : DOMString("");
01291 
01292     return m_value;
01293 }
01294 
01295 
01296 void HTMLInputElementImpl::setValue(DOMString val)
01297 {
01298     if (m_type == FILE) return;
01299 
01300     m_value = (val.isNull() ? DOMString("") : val);
01301     setChanged();
01302 }
01303 
01304 void HTMLInputElementImpl::blur()
01305 {
01306     if(getDocument()->focusNode() == this)
01307     getDocument()->setFocusNode(0);
01308 }
01309 
01310 void HTMLInputElementImpl::focus()
01311 {
01312     getDocument()->setFocusNode(this);
01313 }
01314 
01315 void HTMLInputElementImpl::defaultEventHandler(EventImpl *evt)
01316 {
01317     if ( !m_disabled )
01318     {
01319         if (evt->isMouseEvent() &&
01320             evt->id() == EventImpl::CLICK_EVENT && m_type == IMAGE && m_render) {
01321             // record the mouse position for when we get the DOMActivate event
01322             MouseEventImpl *me = static_cast<MouseEventImpl*>(evt);
01323             int offsetX, offsetY;
01324             m_render->absolutePosition(offsetX,offsetY);
01325             xPos = me->clientX()-offsetX;
01326             yPos = me->clientY()-offsetY;
01327         }
01328 
01329         // DOMActivate events cause the input to be "activated" - in the case of image and submit inputs, this means
01330         // actually submitting the form. For reset inputs, the form is reset. These events are sent when the user clicks
01331         // on the element, or presses enter while it is the active element. Javascript code wishing to activate the element
01332         // must dispatch a DOMActivate event - a click event will not do the job.
01333         if ((evt->id() == EventImpl::DOMACTIVATE_EVENT) &&
01334             (m_type == IMAGE || m_type == SUBMIT || m_type == RESET)){
01335             activate();
01336         }
01337     }
01338     HTMLGenericFormElementImpl::defaultEventHandler(evt);
01339 }
01340 
01341 void HTMLInputElementImpl::activate()
01342 {
01343     if (!m_form || !m_render)
01344         return;
01345 
01346     m_clicked = true;
01347     if (m_type == RESET) {
01348         m_form->reset();
01349     }
01350     else {
01351         m_activeSubmit = true;
01352         if (!m_form->prepareSubmit()) {
01353             xPos = 0;
01354             yPos = 0;
01355         }
01356         m_activeSubmit = false;
01357     }
01358 }
01359 
01360 bool HTMLInputElementImpl::isEditable()
01361 {
01362     return ((m_type == TEXT) || (m_type == PASSWORD) || (m_type == ISINDEX) || (m_type == FILE));
01363 }
01364 
01365 // -------------------------------------------------------------------------
01366 
01367 HTMLLabelElementImpl::HTMLLabelElementImpl(DocumentPtr *doc)
01368     : HTMLGenericFormElementImpl(doc)
01369 {
01370 }
01371 
01372 HTMLLabelElementImpl::~HTMLLabelElementImpl()
01373 {
01374 }
01375 
01376 NodeImpl::Id HTMLLabelElementImpl::id() const
01377 {
01378     return ID_LABEL;
01379 }
01380 
01381 void HTMLLabelElementImpl::parseAttribute(AttributeImpl *attr)
01382 {
01383     switch(attr->id())
01384     {
01385     case ATTR_ONFOCUS:
01386         setHTMLEventListener(EventImpl::FOCUS_EVENT,
01387             getDocument()->createHTMLEventListener(attr->value().string()));
01388         break;
01389     case ATTR_ONBLUR:
01390         setHTMLEventListener(EventImpl::BLUR_EVENT,
01391             getDocument()->createHTMLEventListener(attr->value().string()));
01392         break;
01393     default:
01394         HTMLElementImpl::parseAttribute(attr);
01395     }
01396 }
01397 
01398 void HTMLLabelElementImpl::attach()
01399 {
01400     // skip the generic handler
01401     HTMLElementImpl::attach();
01402 }
01403 
01404 #if 0
01405 ElementImpl *HTMLLabelElementImpl::formElement()
01406 {
01407     DOMString formElementId = getAttribute(ATTR_FOR);
01408     if (formElementId.isEmpty())
01409         return 0;
01410     return getDocument()->getElementById(formElementId);
01411 }
01412 #endif
01413 
01414 // -------------------------------------------------------------------------
01415 
01416 HTMLLegendElementImpl::HTMLLegendElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
01417     : HTMLGenericFormElementImpl(doc, f)
01418 {
01419 }
01420 
01421 HTMLLegendElementImpl::~HTMLLegendElementImpl()
01422 {
01423 }
01424 
01425 NodeImpl::Id HTMLLegendElementImpl::id() const
01426 {
01427     return ID_LEGEND;
01428 }
01429 
01430 void HTMLLegendElementImpl::attach()
01431 {
01432     assert(!attached());
01433     assert(!m_render);
01434     assert(parentNode());
01435     addCSSProperty(CSS_PROP_PADDING_LEFT, "1px");
01436     addCSSProperty(CSS_PROP_PADDING_RIGHT, "1px");
01437     RenderStyle* _style = getDocument()->styleSelector()->styleForElement(this);
01438     _style->ref();
01439     if (parentNode()->renderer() && _style->display() != NONE) {
01440         m_render = new RenderLegend(this);
01441         m_render->setStyle(_style);
01442     }
01443     HTMLGenericFormElementImpl::attach();
01444     _style->deref();
01445 }
01446 
01447 void HTMLLegendElementImpl::parseAttribute(AttributeImpl *attr)
01448 {
01449     switch(attr->id())
01450     {
01451     case ATTR_ACCESSKEY:
01452         // ### ignore for the moment
01453         break;
01454     default:
01455         HTMLElementImpl::parseAttribute(attr);
01456     }
01457 }
01458 
01459 // -------------------------------------------------------------------------
01460 
01461 HTMLSelectElementImpl::HTMLSelectElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
01462     : HTMLGenericFormElementImpl(doc, f)
01463 {
01464     m_multiple = false;
01465     m_recalcListItems = false;
01466     // 0 means invalid (i.e. not set)
01467     m_size = 0;
01468     m_minwidth = 0;
01469 }
01470 
01471 HTMLSelectElementImpl::~HTMLSelectElementImpl()
01472 {
01473     if (getDocument()) getDocument()->deregisterMaintainsState(this);
01474 }
01475 
01476 NodeImpl::Id HTMLSelectElementImpl::id() const
01477 {
01478     return ID_SELECT;
01479 }
01480 
01481 DOMString HTMLSelectElementImpl::type() const
01482 {
01483     return (m_multiple ? "select-multiple" : "select-one");
01484 }
01485 
01486 long HTMLSelectElementImpl::selectedIndex() const
01487 {
01488     // return the number of the first option selected
01489     uint o = 0;
01490     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
01491     for (unsigned int i = 0; i < items.size(); i++) {
01492         if (items[i]->id() == ID_OPTION) {
01493             if (static_cast<HTMLOptionElementImpl*>(items[i])->selected())
01494                 return o;
01495             o++;
01496         }
01497     }
01498     Q_ASSERT(m_multiple || items.isEmpty());
01499     return -1;
01500 }
01501 
01502 void HTMLSelectElementImpl::setSelectedIndex( long  index )
01503 {
01504     // deselect all other options and select only the new one
01505     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
01506     int listIndex;
01507     for (listIndex = 0; listIndex < int(items.size()); listIndex++) {
01508         if (items[listIndex]->id() == ID_OPTION)
01509             static_cast<HTMLOptionElementImpl*>(items[listIndex])->setSelected(false);
01510     }
01511     listIndex = optionToListIndex(index);
01512     if (listIndex >= 0)
01513         static_cast<HTMLOptionElementImpl*>(items[listIndex])->setSelected(true);
01514 
01515     setChanged(true);
01516 }
01517 
01518 long HTMLSelectElementImpl::length() const
01519 {
01520     int len = 0;
01521     uint i;
01522     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
01523     for (i = 0; i < items.size(); i++) {
01524         if (items[i]->id() == ID_OPTION)
01525             len++;
01526     }
01527     return len;
01528 }
01529 
01530 void HTMLSelectElementImpl::add( const HTMLElement &element, const HTMLElement &before, int& exceptioncode )
01531 {
01532     if(element.isNull() || element.handle()->id() != ID_OPTION)
01533         return;
01534 
01535     insertBefore(element.handle(), before.handle(), exceptioncode );
01536     if (!exceptioncode)
01537         setRecalcListItems();
01538 }
01539 
01540 void HTMLSelectElementImpl::remove( long index )
01541 {
01542     int exceptioncode = 0;
01543     int listIndex = optionToListIndex(index);
01544 
01545     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
01546     if(listIndex < 0 || index >= int(items.size()))
01547         return; // ### what should we do ? remove the last item?
01548 
01549     removeChild(items[listIndex], exceptioncode);
01550     if( !exceptioncode )
01551         setRecalcListItems();
01552 }
01553 
01554 void HTMLSelectElementImpl::blur()
01555 {
01556     if(getDocument()->focusNode() == this)
01557     getDocument()->setFocusNode(0);
01558 }
01559 
01560 void HTMLSelectElementImpl::focus()
01561 {
01562     getDocument()->setFocusNode(this);
01563 }
01564 
01565 DOMString HTMLSelectElementImpl::value( )
01566 {
01567     uint i;
01568     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
01569     for (i = 0; i < items.size(); i++) {
01570         if ( items[i]->id() == ID_OPTION
01571             && static_cast<HTMLOptionElementImpl*>(items[i])->selected())
01572             return static_cast<HTMLOptionElementImpl*>(items[i])->value();
01573     }
01574     return DOMString();
01575 }
01576 
01577 void HTMLSelectElementImpl::setValue(DOMStringImpl* /*value*/)
01578 {
01579     // ### find the option with value() matching the given parameter
01580     // and make it the current selection.
01581     kdWarning() << "Unimplemented HTMLSelectElementImpl::setValue called" << endl;
01582 }
01583 
01584 QString HTMLSelectElementImpl::state( )
01585 {
01586     QString state;
01587     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
01588 
01589     int l = items.count();
01590 
01591     state.fill('.', l);
01592     for(int i = 0; i < l; i++)
01593         if(items[i]->id() == ID_OPTION && static_cast<HTMLOptionElementImpl*>(items[i])->selected())
01594             state[i] = 'X';
01595 
01596     return state;
01597 }
01598 
01599 void HTMLSelectElementImpl::restoreState(const QString &_state)
01600 {
01601     recalcListItems();
01602 
01603     QString state = _state;
01604     if(!state.isEmpty() && !state.contains('X') && !m_multiple && m_size <= 1) {
01605         qWarning("should not happen in restoreState!");
01606         state[0] = 'X';
01607     }
01608 
01609     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
01610 
01611     int l = items.count();
01612     for(int i = 0; i < l; i++) {
01613         if(items[i]->id() == ID_OPTION) {
01614             HTMLOptionElementImpl* oe = static_cast<HTMLOptionElementImpl*>(items[i]);
01615             oe->setSelected(state[i] == 'X');
01616         }
01617     }
01618     setChanged(true);
01619 }
01620 
01621 NodeImpl *HTMLSelectElementImpl::insertBefore ( NodeImpl *newChild, NodeImpl *refChild, int &exceptioncode )
01622 {
01623     NodeImpl *result = HTMLGenericFormElementImpl::insertBefore(newChild,refChild, exceptioncode );
01624     if (!exceptioncode)
01625         setRecalcListItems();
01626     return result;
01627 }
01628 
01629 NodeImpl *HTMLSelectElementImpl::replaceChild ( NodeImpl *newChild, NodeImpl *oldChild, int &exceptioncode )
01630 {
01631     NodeImpl *result = HTMLGenericFormElementImpl::replaceChild(newChild,oldChild, exceptioncode);
01632     if( !exceptioncode )
01633         setRecalcListItems();
01634     return result;
01635 }
01636 
01637 NodeImpl *HTMLSelectElementImpl::removeChild ( NodeImpl *oldChild, int &exceptioncode )
01638 {
01639     NodeImpl *result = HTMLGenericFormElementImpl::removeChild(oldChild, exceptioncode);
01640     if( !exceptioncode )
01641         setRecalcListItems();
01642     return result;
01643 }
01644 
01645 NodeImpl *HTMLSelectElementImpl::appendChild ( NodeImpl *newChild, int &exceptioncode )
01646 {
01647     NodeImpl *result = HTMLGenericFormElementImpl::appendChild(newChild, exceptioncode);
01648     if( !exceptioncode )
01649         setRecalcListItems();
01650     setChanged(true);
01651     return result;
01652 }
01653 
01654 NodeImpl* HTMLSelectElementImpl::addChild(NodeImpl* newChild)
01655 {
01656     setRecalcListItems();
01657     return HTMLGenericFormElementImpl::addChild(newChild);
01658 }
01659 
01660 void HTMLSelectElementImpl::parseAttribute(AttributeImpl *attr)
01661 {
01662     switch(attr->id())
01663     {
01664     case ATTR_SIZE:
01665         m_size = QMAX( attr->val()->toInt(), 1 );
01666         break;
01667     case ATTR_WIDTH:
01668         m_minwidth = QMAX( attr->val()->toInt(), 0 );
01669         break;
01670     case ATTR_MULTIPLE:
01671         m_multiple = (attr->val() != 0);
01672         break;
01673     case ATTR_ACCESSKEY:
01674         // ### ignore for the moment
01675         break;
01676     case ATTR_ONFOCUS:
01677         setHTMLEventListener(EventImpl::FOCUS_EVENT,
01678             getDocument()->createHTMLEventListener(attr->value().string()));
01679         break;
01680     case ATTR_ONBLUR:
01681         setHTMLEventListener(EventImpl::BLUR_EVENT,
01682             getDocument()->createHTMLEventListener(attr->value().string()));
01683         break;
01684     case ATTR_ONCHANGE:
01685         setHTMLEventListener(EventImpl::CHANGE_EVENT,
01686             getDocument()->createHTMLEventListener(attr->value().string()));
01687         break;
01688     default:
01689         HTMLGenericFormElementImpl::parseAttribute(attr);
01690     }
01691 }
01692 
01693 void HTMLSelectElementImpl::attach()
01694 {
01695     assert(!attached());
01696     assert(parentNode());
01697     assert(!renderer());
01698 
01699     addCSSProperty(CSS_PROP_COLOR, "text");
01700 
01701     RenderStyle* _style = getDocument()->styleSelector()->styleForElement(this);
01702     _style->ref();
01703     if (parentNode()->renderer() && _style->display() != NONE) {
01704         m_render = new RenderSelect(this);
01705         m_render->setStyle(_style);
01706     }
01707 
01708     HTMLGenericFormElementImpl::attach();
01709     _style->deref();
01710 }
01711 
01712 bool HTMLSelectElementImpl::encoding(const QTextCodec* codec, khtml::encodingList& encoded_values, bool)
01713 {
01714     bool successful = false;
01715     QCString enc_name = fixUpfromUnicode(codec, name().string());
01716     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
01717 
01718     uint i;
01719     for (i = 0; i < items.size(); i++) {
01720         if (items[i]->id() == ID_OPTION) {
01721             HTMLOptionElementImpl *option = static_cast<HTMLOptionElementImpl*>(items[i]);
01722             if (option->selected()) {
01723                 encoded_values += enc_name;
01724                 encoded_values += fixUpfromUnicode(codec, option->value().string());
01725                 successful = true;
01726             }
01727         }
01728     }
01729 
01730     // ### this case should not happen. make sure that we select the first option
01731     // in any case. otherwise we have no consistency with the DOM interface. FIXME!
01732     // we return the first one if it was a combobox select
01733     if (!successful && !m_multiple && m_size <= 1 && items.size() &&
01734         (items[0]->id() == ID_OPTION) ) {
01735         HTMLOptionElementImpl *option = static_cast<HTMLOptionElementImpl*>(items[0]);
01736         encoded_values += enc_name;
01737         if (option->value().isNull())
01738             encoded_values += fixUpfromUnicode(codec, option->text().string().stripWhiteSpace());
01739         else
01740             encoded_values += fixUpfromUnicode(codec, option->value().string());
01741         successful = true;
01742     }
01743 
01744     return successful;
01745 }
01746 
01747 int HTMLSelectElementImpl::optionToListIndex(int optionIndex) const
01748 {
01749     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
01750     if (optionIndex < 0 || optionIndex >= int(items.size()))
01751         return -1;
01752 
01753     int listIndex = 0;
01754     int optionIndex2 = 0;
01755     for (;
01756          optionIndex2 < int(items.size()) && optionIndex2 <= optionIndex;
01757          listIndex++) { // not a typo!
01758         if (items[listIndex]->id() == ID_OPTION)
01759             optionIndex2++;
01760     }
01761     listIndex--;
01762     return listIndex;
01763 }
01764 
01765 int HTMLSelectElementImpl::listToOptionIndex(int listIndex) const
01766 {
01767     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
01768     if (listIndex < 0 || listIndex >= int(items.size()) ||
01769         items[listIndex]->id() != ID_OPTION)
01770         return -1;
01771 
01772     int optionIndex = 0; // actual index of option not counting OPTGROUP entries that may be in list
01773     int i;
01774     for (i = 0; i < listIndex; i++)
01775         if (items[i]->id() == ID_OPTION)
01776             optionIndex++;
01777     return optionIndex;
01778 }
01779 
01780 void HTMLSelectElementImpl::recalcListItems()
01781 {
01782     NodeImpl* current = firstChild();
01783     m_listItems.resize(0);
01784     HTMLOptionElementImpl* foundSelected = 0;
01785     while(current) {
01786         if (current->id() == ID_OPTGROUP && current->firstChild()) {
01787             // ### what if optgroup contains just comments? don't want one of no options in it...
01788             m_listItems.resize(m_listItems.size()+1);
01789             m_listItems[m_listItems.size()-1] = static_cast<HTMLGenericFormElementImpl*>(current);
01790             current = current->firstChild();
01791         }
01792         if (current->id() == ID_OPTION) {
01793             m_listItems.resize(m_listItems.size()+1);
01794             m_listItems[m_listItems.size()-1] = static_cast<HTMLGenericFormElementImpl*>(current);
01795             if (!foundSelected && !m_multiple && m_size <= 1) {
01796                 foundSelected = static_cast<HTMLOptionElementImpl*>(current);
01797                 foundSelected->m_selected = true;
01798             }
01799             else if (foundSelected && !m_multiple && static_cast<HTMLOptionElementImpl*>(current)->selected()) {
01800                 foundSelected->m_selected = false;
01801                 foundSelected = static_cast<HTMLOptionElementImpl*>(current);
01802             }
01803         }
01804         NodeImpl *parent = current->parentNode();
01805         current = current->nextSibling();
01806         if (!current) {
01807             if (parent != this)
01808                 current = parent->nextSibling();
01809         }
01810     }
01811     m_recalcListItems = false;
01812 }
01813 
01814 void HTMLSelectElementImpl::childrenChanged()
01815 {
01816     setRecalcListItems();
01817 
01818     HTMLGenericFormElementImpl::childrenChanged();
01819 }
01820 
01821 void HTMLSelectElementImpl::setRecalcListItems()
01822 {
01823     m_recalcListItems = true;
01824     if (m_render)
01825         static_cast<khtml::RenderSelect*>(m_render)->setOptionsChanged(true);
01826     setChanged();
01827 }
01828 
01829 void HTMLSelectElementImpl::reset()
01830 {
01831     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
01832     uint i;
01833     for (i = 0; i < items.size(); i++) {
01834         if (items[i]->id() == ID_OPTION) {
01835             HTMLOptionElementImpl *option = static_cast<HTMLOptionElementImpl*>(items[i]);
01836             bool selected = (!option->getAttribute(ATTR_SELECTED).isNull());
01837             option->setSelected(selected);
01838         }
01839     }
01840     if ( m_render )
01841         static_cast<RenderSelect*>(m_render)->setSelectionChanged(true);
01842     setChanged( true );
01843 }
01844 
01845 void HTMLSelectElementImpl::notifyOptionSelected(HTMLOptionElementImpl *selectedOption, bool selected)
01846 {
01847     if (selected && !m_multiple) {
01848         // deselect all other options
01849         QMemArray<HTMLGenericFormElementImpl*> items = listItems();
01850         uint i;
01851         for (i = 0; i < items.size(); i++) {
01852             if (items[i]->id() == ID_OPTION)
01853                 static_cast<HTMLOptionElementImpl*>(items[i])->m_selected = (items[i] == selectedOption);
01854         }
01855     }
01856     if (m_render)
01857         static_cast<RenderSelect*>(m_render)->setSelectionChanged(true);
01858 
01859     setChanged(true);
01860 }
01861 
01862 // -------------------------------------------------------------------------
01863 
01864 HTMLKeygenElementImpl::HTMLKeygenElementImpl(DocumentPtr* doc, HTMLFormElementImpl* f)
01865     : HTMLSelectElementImpl(doc, f)
01866 {
01867     QStringList keys = KSSLKeyGen::supportedKeySizes();
01868     for (QStringList::Iterator i = keys.begin(); i != keys.end(); ++i) {
01869         HTMLOptionElementImpl* o = new HTMLOptionElementImpl(doc, form());
01870         addChild(o);
01871         o->addChild(doc->document()->createTextNode(DOMString(*i).implementation()));
01872     }
01873 }
01874 
01875 NodeImpl::Id HTMLKeygenElementImpl::id() const
01876 {
01877     return ID_KEYGEN;
01878 }
01879 
01880 void HTMLKeygenElementImpl::parseAttribute(AttributeImpl* attr)
01881 {
01882     switch(attr->id())
01883     {
01884     case ATTR_CHALLENGE:
01885         break;
01886     default:
01887         // skip HTMLSelectElementImpl parsing!
01888         HTMLGenericFormElementImpl::parseAttribute(attr);
01889     }
01890 }
01891 
01892 bool HTMLKeygenElementImpl::encoding(const QTextCodec* codec, khtml::encodingList& encoded_values, bool)
01893 {
01894     bool successful = false;
01895     QCString enc_name = fixUpfromUnicode(codec, name().string());
01896 
01897     encoded_values += enc_name;
01898 
01899     // pop up the fancy certificate creation dialog here
01900     KSSLKeyGen *kg = new KSSLKeyGen(static_cast<RenderWidget *>(m_render)->widget(), "Key Generator", true);
01901 
01902     kg->setKeySize(0);
01903     successful = (QDialog::Accepted == kg->exec());
01904 
01905     delete kg;
01906 
01907     encoded_values += "deadbeef";
01908 
01909     return successful;
01910 }
01911 
01912 // -------------------------------------------------------------------------
01913 
01914 NodeImpl::Id HTMLOptGroupElementImpl::id() const
01915 {
01916     return ID_OPTGROUP;
01917 }
01918 
01919 // -------------------------------------------------------------------------
01920 
01921 HTMLOptionElementImpl::HTMLOptionElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
01922     : HTMLGenericFormElementImpl(doc, f)
01923 {
01924     m_selected = false;
01925 }
01926 
01927 NodeImpl::Id HTMLOptionElementImpl::id() const
01928 {
01929     return ID_OPTION;
01930 }
01931 
01932 DOMString HTMLOptionElementImpl::text() const
01933 {
01934     if (firstChild() && firstChild()->nodeType() == Node::TEXT_NODE) {
01935     if (firstChild()->nextSibling()) {
01936         DOMString ret = "";
01937         NodeImpl *n = firstChild();
01938         for (; n; n = n->nextSibling()) {
01939         if (n->nodeType() == Node::TEXT_NODE ||
01940             n->nodeType() == Node::CDATA_SECTION_NODE)
01941             ret += n->nodeValue();
01942         }
01943         return ret;
01944     }
01945     else
01946         return firstChild()->nodeValue();
01947     }
01948     return "";
01949 }
01950 
01951 long HTMLOptionElementImpl::index() const
01952 {
01953     // Let's do this dynamically. Might be a bit slow, but we're sure
01954     // we won't forget to update a member variable in some cases...
01955     QMemArray<HTMLGenericFormElementImpl*> items = getSelect()->listItems();
01956     int l = items.count();
01957     int optionIndex = 0;
01958     for(int i = 0; i < l; i++) {
01959         if(items[i]->id() == ID_OPTION)
01960         {
01961             if (static_cast<HTMLOptionElementImpl*>(items[i]) == this)
01962                 return optionIndex;
01963             optionIndex++;
01964         }
01965     }
01966     kdWarning() << "HTMLOptionElementImpl::index(): option not found!" << endl;
01967     return 0;
01968 }
01969 
01970 void HTMLOptionElementImpl::setIndex( long  )
01971 {
01972     kdWarning() << "Unimplemented HTMLOptionElementImpl::setIndex(long) called" << endl;
01973     // ###
01974 }
01975 
01976 void HTMLOptionElementImpl::parseAttribute(AttributeImpl *attr)
01977 {
01978     switch(attr->id())
01979     {
01980     case ATTR_SELECTED:
01981         m_selected = (attr->val() != 0);
01982         break;
01983     case ATTR_VALUE:
01984         m_value = attr->value();
01985         break;
01986     default:
01987         HTMLGenericFormElementImpl::parseAttribute(attr);
01988     }
01989 }
01990 
01991 DOMString HTMLOptionElementImpl::value() const
01992 {
01993     if ( !m_value.isNull() )
01994         return m_value;
01995     // Use the text if the value wasn't set.
01996     return text().string().simplifyWhiteSpace();
01997 }
01998 
01999 void HTMLOptionElementImpl::setValue(DOMStringImpl* value)
02000 {
02001     setAttribute(ATTR_VALUE, value);
02002 }
02003 
02004 void HTMLOptionElementImpl::setSelected(bool _selected)
02005 {
02006     if(m_selected == _selected)
02007         return;
02008     m_selected = _selected;
02009     HTMLSelectElementImpl *select = getSelect();
02010     if (select)
02011         select->notifyOptionSelected(this,_selected);
02012 }
02013 
02014 HTMLSelectElementImpl *HTMLOptionElementImpl::getSelect() const
02015 {
02016     NodeImpl *select = parentNode();
02017     while (select && select->id() != ID_SELECT)
02018         select = select->parentNode();
02019     return static_cast<HTMLSelectElementImpl*>(select);
02020 }
02021 
02022 // -------------------------------------------------------------------------
02023 
02024 HTMLTextAreaElementImpl::HTMLTextAreaElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
02025     : HTMLGenericFormElementImpl(doc, f)
02026 {
02027     // DTD requires rows & cols be specified, but we will provide reasonable defaults
02028     m_rows = 2;
02029     m_cols = 20;
02030     m_wrap = ta_Virtual;
02031     m_dirtyvalue = true;
02032 }
02033 
02034 HTMLTextAreaElementImpl::~HTMLTextAreaElementImpl()
02035 {
02036     if (getDocument()) getDocument()->deregisterMaintainsState(this);
02037 }
02038 
02039 NodeImpl::Id HTMLTextAreaElementImpl::id() const
02040 {
02041     return ID_TEXTAREA;
02042 }
02043 
02044 DOMString HTMLTextAreaElementImpl::type() const
02045 {
02046     return "textarea";
02047 }
02048 
02049 QString HTMLTextAreaElementImpl::state( )
02050 {
02051     // Make sure the string is not empty!
02052     return value().string()+'.';
02053 }
02054 
02055 void HTMLTextAreaElementImpl::restoreState(const QString &state)
02056 {
02057     setDefaultValue(state.left(state.length()-1));
02058     // the close() in the rendertree will take care of transferring defaultvalue to 'value'
02059 }
02060 
02061 void HTMLTextAreaElementImpl::select(  )
02062 {
02063     if (m_render)
02064         static_cast<RenderTextArea*>(m_render)->select();
02065     onSelect();
02066 }
02067 
02068 void HTMLTextAreaElementImpl::parseAttribute(AttributeImpl *attr)
02069 {
02070     switch(attr->id())
02071     {
02072     case ATTR_ROWS:
02073         m_rows = attr->val() ? attr->val()->toInt() : 3;
02074         break;
02075     case ATTR_COLS:
02076         m_cols = attr->val() ? attr->val()->toInt() : 60;
02077         break;
02078     case ATTR_WRAP:
02079         // virtual / physical is Netscape extension of HTML 3.0, now deprecated
02080         // soft/ hard / off is recommendation for HTML 4 extension by IE and NS 4
02081         if ( strcasecmp( attr->value(), "virtual" ) == 0  || strcasecmp( attr->value(), "soft") == 0)
02082             m_wrap = ta_Virtual;
02083         else if ( strcasecmp ( attr->value(), "physical" ) == 0 || strcasecmp( attr->value(), "hard") == 0)
02084             m_wrap = ta_Physical;
02085         else if(strcasecmp( attr->value(), "on" ) == 0)
02086             m_wrap = ta_Physical;
02087         else if(strcasecmp( attr->value(), "off") == 0)
02088             m_wrap = ta_NoWrap;
02089         break;
02090     case ATTR_ACCESSKEY:
02091         // ignore for the moment
02092         break;
02093     case ATTR_ONFOCUS:
02094         setHTMLEventListener(EventImpl::FOCUS_EVENT,
02095         getDocument()->createHTMLEventListener(attr->value().string()));
02096         break;
02097     case ATTR_ONBLUR:
02098         setHTMLEventListener(EventImpl::BLUR_EVENT,
02099         getDocument()->createHTMLEventListener(attr->value().string()));
02100         break;
02101     case ATTR_ONSELECT:
02102         setHTMLEventListener(EventImpl::SELECT_EVENT,
02103         getDocument()->createHTMLEventListener(attr->value().string()));
02104         break;
02105     case ATTR_ONCHANGE:
02106         setHTMLEventListener(EventImpl::CHANGE_EVENT,
02107         getDocument()->createHTMLEventListener(attr->value().string()));
02108         break;
02109     default:
02110         HTMLGenericFormElementImpl::parseAttribute(attr);
02111     }
02112 }
02113 
02114 void HTMLTextAreaElementImpl::attach()
02115 {
02116     assert(!attached());
02117     assert(!m_render);
02118     assert(parentNode());
02119 
02120     addCSSProperty(CSS_PROP_COLOR, "text");
02121 
02122     RenderStyle* _style = getDocument()->styleSelector()->styleForElement(this);
02123     _style->ref();
02124     if (parentNode()->renderer() && _style->display() != NONE) {
02125         m_render = new RenderTextArea(this);
02126         m_render->setStyle(_style);
02127     }
02128 
02129     HTMLGenericFormElementImpl::attach();
02130     _style->deref();
02131 }
02132 
02133 bool HTMLTextAreaElementImpl::encoding(const QTextCodec* codec, encodingList& encoding, bool)
02134 {
02135     if (name().isEmpty() || !m_render) return false;
02136 
02137     encoding += fixUpfromUnicode(codec, name().string());
02138     encoding += fixUpfromUnicode(codec, value().string());
02139 
02140     return true;
02141 }
02142 
02143 void HTMLTextAreaElementImpl::reset()
02144 {
02145     setValue(defaultValue());
02146 }
02147 
02148 DOMString HTMLTextAreaElementImpl::value()
02149 {
02150     if ( m_dirtyvalue) {
02151         if ( m_render )  m_value = static_cast<RenderTextArea*>( m_render )->text();
02152         m_dirtyvalue = false;
02153     }
02154 
02155     if ( m_value.isNull() ) return "";
02156 
02157     return m_value;
02158 }
02159 
02160 void HTMLTextAreaElementImpl::setValue(DOMString _value)
02161 {
02162     // \r\n -> \n, \r -> \n
02163     QString str = _value.string().replace( "\r\n", "\n" );
02164     m_value = str.replace( "\r", "\n" );
02165     m_dirtyvalue = false;
02166     setChanged(true);
02167 }
02168 
02169 
02170 DOMString HTMLTextAreaElementImpl::defaultValue()
02171 {
02172     DOMString val = "";
02173     // there may be comments - just grab the text nodes
02174     NodeImpl *n;
02175     for (n = firstChild(); n; n = n->nextSibling())
02176         if (n->isTextNode())
02177             val += static_cast<TextImpl*>(n)->data();
02178     if (val[0] == '\r' && val[1] == '\n') {
02179     val = val.copy();
02180     val.remove(0,2);
02181     }
02182     else if (val[0] == '\r' || val[0] == '\n') {
02183     val = val.copy();
02184     val.remove(0,1);
02185     }
02186 
02187     return val;
02188 }
02189 
02190 void HTMLTextAreaElementImpl::setDefaultValue(DOMString _defaultValue)
02191 {
02192     // there may be comments - remove all the text nodes and replace them with one
02193     QPtrList<NodeImpl> toRemove;
02194     NodeImpl *n;
02195     for (n = firstChild(); n; n = n->nextSibling())
02196         if (n->isTextNode())
02197             toRemove.append(n);
02198     QPtrListIterator<NodeImpl> it(toRemove);
02199     int exceptioncode = 0;
02200     for (; it.current(); ++it) {
02201         removeChild(it.current(), exceptioncode);
02202     }
02203     insertBefore(getDocument()->createTextNode(_defaultValue.implementation()),firstChild(), exceptioncode);
02204     setValue(_defaultValue);
02205 }
02206 
02207 void HTMLTextAreaElementImpl::blur()
02208 {
02209     if(getDocument()->focusNode() == this)
02210     getDocument()->setFocusNode(0);
02211 }
02212 
02213 void HTMLTextAreaElementImpl::focus()
02214 {
02215     getDocument()->setFocusNode(this);
02216 }
02217 
02218 bool HTMLTextAreaElementImpl::isEditable()
02219 {
02220     return true;
02221 }
02222 
02223 // -------------------------------------------------------------------------
02224 
02225 HTMLIsIndexElementImpl::HTMLIsIndexElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
02226     : HTMLInputElementImpl(doc, f)
02227 {
02228     m_type = TEXT;
02229     setName("isindex");
02230 }
02231 
02232 HTMLIsIndexElementImpl::~HTMLIsIndexElementImpl()
02233 {
02234 }
02235 
02236 NodeImpl::Id HTMLIsIndexElementImpl::id() const
02237 {
02238     return ID_ISINDEX;
02239 }
02240 
02241 void HTMLIsIndexElementImpl::parseAttribute(AttributeImpl* attr)
02242 {
02243     // don't call HTMLInputElement::parseAttribute here, as it would
02244     // accept attributes this element does not support
02245     HTMLGenericFormElementImpl::parseAttribute(attr);
02246 }
02247 
02248 DOMString HTMLIsIndexElementImpl::prompt() const
02249 {
02250     // When IsIndex is parsed, <HR/>Prompt: <ISINDEX/><HR/> is created.
02251     // So we have to look at the previous sibling to find the prompt text
02252     DOM::NodeImpl* prev = previousSibling();
02253     if ( prev && prev->nodeType() == DOM::Node::TEXT_NODE)
02254         return prev->nodeValue();
02255     return "";
02256 }
02257 
02258 void HTMLIsIndexElementImpl::setPrompt(const DOMString& str)
02259 {
02260     // When IsIndex is parsed, <HR/>Prompt: <ISINDEX/><HR/> is created.
02261     // So we have to look at the previous sibling to find the prompt text
02262     int exceptioncode = 0;
02263     DOM::NodeImpl* prev = previousSibling();
02264     if ( prev && prev->nodeType() == DOM::Node::TEXT_NODE)
02265         static_cast<DOM::TextImpl *>(prev)->setData(str, exceptioncode);
02266 }
02267 
02268 // -------------------------------------------------------------------------
02269 
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.0.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Oct 8 12:22:37 2003 by doxygen 1.2.18 written by Dimitri van Heesch, © 1997-2001