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