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     assert(!attached());
00792     assert(!m_render);
00793     assert(parentNode());
00794     RenderStyle* _style = getDocument()->styleSelector()->styleForElement(this);
00795     _style->ref();
00796     if (parentNode()->renderer() && _style->display() != NONE) {
00797         m_render = new RenderCustomButton(this);
00798         m_render->setStyle(_style);
00799     }
00800     HTMLGenericFormElementImpl::attach();
00801     _style->deref();
00802 }
00803 
00804 void HTMLButtonElementImpl::defaultEventHandler(EventImpl *evt)
00805 {
00806     if (m_type != BUTTON && (evt->id() == EventImpl::DOMACTIVATE_EVENT) && !m_disabled)
00807         activate();
00808     HTMLGenericFormElementImpl::defaultEventHandler(evt);
00809 }
00810 
00811 void HTMLButtonElementImpl::activate()
00812 {
00813     m_clicked = true;
00814 
00815     if(m_form && m_type == SUBMIT) {
00816         m_activeSubmit = true;
00817         m_form->prepareSubmit();
00818         m_activeSubmit = false; // in case we were canceled
00819     }
00820     if(m_form && m_type == RESET)
00821         m_form->reset();
00822 }
00823 
00824 bool HTMLButtonElementImpl::encoding(const QTextCodec* codec, khtml::encodingList& encoding, bool /*multipart*/)
00825 {
00826     if (m_type != SUBMIT || name().isEmpty() || !m_activeSubmit)
00827         return false;
00828 
00829     encoding += fixUpfromUnicode(codec, name().string());
00830     QString enc_str = m_currValue.isNull() ? QString("") : m_currValue;
00831     encoding += fixUpfromUnicode(codec, enc_str);
00832 
00833     return true;
00834 }
00835 
00836 
00837 // -------------------------------------------------------------------------
00838 
00839 HTMLFieldSetElementImpl::HTMLFieldSetElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
00840     : HTMLGenericFormElementImpl(doc, f), m_legend(0)
00841 {
00842 }
00843 
00844 HTMLFieldSetElementImpl::~HTMLFieldSetElementImpl()
00845 {
00846 }
00847 
00848 NodeImpl::Id HTMLFieldSetElementImpl::id() const
00849 {
00850     return ID_FIELDSET;
00851 }
00852 
00853 void HTMLFieldSetElementImpl::attach()
00854 {
00855     assert(!attached());
00856     assert(!m_render);
00857     assert(parentNode());
00858     addCSSProperty(CSS_PROP_BORDER_TOP_STYLE, CSS_VAL_SOLID);
00859     addCSSProperty(CSS_PROP_BORDER_BOTTOM_STYLE, CSS_VAL_SOLID);
00860     addCSSProperty(CSS_PROP_BORDER_LEFT_STYLE, CSS_VAL_SOLID);
00861     addCSSProperty(CSS_PROP_BORDER_RIGHT_STYLE, CSS_VAL_SOLID);
00862     addCSSProperty(CSS_PROP_BORDER_WIDTH, "1px");
00863     addCSSProperty(CSS_PROP_PADDING_LEFT, "4px");
00864     addCSSProperty(CSS_PROP_PADDING_RIGHT, "4px");
00865     addCSSProperty(CSS_PROP_PADDING_BOTTOM, "4px");
00866 
00867 
00868     RenderStyle* _style = getDocument()->styleSelector()->styleForElement(this);
00869     _style->ref();
00870     if (parentNode()->renderer() && _style->display() != NONE) {
00871         m_render = new RenderFieldset(this);
00872         m_render->setStyle(_style);
00873     }
00874     HTMLGenericFormElementImpl::attach();
00875     _style->deref();
00876 }
00877 
00878 NodeImpl *HTMLFieldSetElementImpl::addChild(NodeImpl *child)
00879 {
00880     if(!m_legend && child->id() == ID_LEGEND) {
00881         int exceptioncode = 0;
00882         NodeImpl* r = insertBefore( child, firstChild(), exceptioncode );
00883         m_legend = child;
00884         return r;
00885     }
00886     return HTMLGenericFormElementImpl::addChild(child);
00887 }
00888 
00889 void HTMLFieldSetElementImpl::parseAttribute(AttributeImpl *attr)
00890 {
00891     HTMLElementImpl::parseAttribute(attr);
00892 }
00893 
00894 // -------------------------------------------------------------------------
00895 
00896 HTMLInputElementImpl::HTMLInputElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
00897     : HTMLGenericFormElementImpl(doc, f)
00898 {
00899     m_type = TEXT;
00900     m_maxLen = -1;
00901     m_size = 20;
00902     m_clicked = false;
00903     m_checked = false;
00904 
00905     m_activeSubmit = false;
00906     m_autocomplete = true;
00907     m_inited = false;
00908 
00909     xPos = 0;
00910     yPos = 0;
00911 
00912     if ( m_form )
00913         m_autocomplete = f->autoComplete();
00914 }
00915 
00916 HTMLInputElementImpl::~HTMLInputElementImpl()
00917 {
00918     if (getDocument()) getDocument()->deregisterMaintainsState(this);
00919 }
00920 
00921 NodeImpl::Id HTMLInputElementImpl::id() const
00922 {
00923     return ID_INPUT;
00924 }
00925 
00926 void HTMLInputElementImpl::setType(const DOMString& /*t*/)
00927 {
00928     // ###
00929 }
00930 
00931 DOMString HTMLInputElementImpl::type() const
00932 {
00933     // needs to be lowercase according to DOM spec
00934     switch (m_type) {
00935     case TEXT: return "text";
00936     case PASSWORD: return "password";
00937     case CHECKBOX: return "checkbox";
00938     case RADIO: return "radio";
00939     case SUBMIT: return "submit";
00940     case RESET: return "reset";
00941     case FILE: return "file";
00942     case HIDDEN: return "hidden";
00943     case IMAGE: return "image";
00944     case BUTTON: return "button";
00945     default: return "";
00946     }
00947 }
00948 
00949 QString HTMLInputElementImpl::state( )
00950 {
00951     switch (m_type) {
00952     case PASSWORD:
00953         return QString::fromLatin1("."); // empty string, avoid restoring
00954     case CHECKBOX:
00955     case RADIO:
00956         return QString::fromLatin1(m_checked ? "on" : "off");
00957     default:
00958         return value().string()+'.'; // Make sure the string is not empty!
00959     }
00960 }
00961 
00962 void HTMLInputElementImpl::restoreState(const QString &state)
00963 {
00964     switch (m_type) {
00965     case CHECKBOX:
00966     case RADIO:
00967         setChecked((state == QString::fromLatin1("on")));
00968         break;
00969     case FILE:
00970         m_value = DOMString(state.left(state.length()-1));
00971         setChanged();
00972         break;
00973     default:
00974         setValue(DOMString(state.left(state.length()-1)));
00975         break;
00976     }
00977 }
00978 
00979 void HTMLInputElementImpl::select(  )
00980 {
00981     if(!m_render) return;
00982 
00983     if (m_type == TEXT || m_type == PASSWORD)
00984         static_cast<RenderLineEdit*>(m_render)->select();
00985     else if (m_type == FILE)
00986         static_cast<RenderFileButton*>(m_render)->select();
00987 }
00988 
00989 void HTMLInputElementImpl::click(  )
00990 {
00991     // ###
00992 #ifdef FORMS_DEBUG
00993     kdDebug( 6030 ) << " HTMLInputElementImpl::click(  )" << endl;
00994 #endif
00995 }
00996 
00997 void HTMLInputElementImpl::parseAttribute(AttributeImpl *attr)
00998 {
00999     switch(attr->id())
01000     {
01001     case ATTR_AUTOCOMPLETE:
01002         m_autocomplete = strcasecmp( attr->value(), "off" );
01003         break;
01004     case ATTR_TYPE:
01005         // ignore to avoid that javascript can change a type field to file
01006         break;
01007     case ATTR_VALUE:
01008     case ATTR_CHECKED:
01009         // these are the defaults, don't change them
01010         break;
01011     case ATTR_MAXLENGTH:
01012     {
01013         m_maxLen = -1;
01014         if (!attr->val()) break;
01015         bool ok;
01016         int ml = attr->val()->toInt(&ok);
01017         if (ml > 0 && ml < 1024)
01018             m_maxLen = ml;
01019         else if (ok && ml <= 0)
01020             m_maxLen = 0;
01021         setChanged();
01022     }
01023     break;
01024     case ATTR_SIZE:
01025         m_size = attr->val() ? attr->val()->toInt() : 20;
01026         break;
01027     case ATTR_ALT:
01028     case ATTR_SRC:
01029         if (m_render && m_type == IMAGE) m_render->updateFromElement();
01030         break;
01031     case ATTR_USEMAP:
01032     case ATTR_ACCESSKEY:
01033         // ### ignore for the moment
01034         break;
01035     case ATTR_ALIGN:
01036         addHTMLAlignment( attr->value() );
01037         break;
01038     case ATTR_WIDTH:
01039         // ignore this attribute,  do _not_ add
01040         // a CSS_PROP_WIDTH here!
01041         // webdesigner are stupid - and IE/NS behave the same ( Dirk )
01042         break;
01043     case ATTR_HEIGHT:
01044         addCSSLength(CSS_PROP_HEIGHT, attr->value() );
01045         break;
01046     case ATTR_ONFOCUS:
01047         setHTMLEventListener(EventImpl::FOCUS_EVENT,
01048             getDocument()->createHTMLEventListener(attr->value().string()));
01049         break;
01050     case ATTR_ONBLUR:
01051         setHTMLEventListener(EventImpl::BLUR_EVENT,
01052             getDocument()->createHTMLEventListener(attr->value().string()));
01053         break;
01054     case ATTR_ONSELECT:
01055         setHTMLEventListener(EventImpl::SELECT_EVENT,
01056             getDocument()->createHTMLEventListener(attr->value().string()));
01057         break;
01058     case ATTR_ONCHANGE:
01059         setHTMLEventListener(EventImpl::CHANGE_EVENT,
01060             getDocument()->createHTMLEventListener(attr->value().string()));
01061         break;
01062     default:
01063         HTMLGenericFormElementImpl::parseAttribute(attr);
01064     }
01065 }
01066 
01067 void HTMLInputElementImpl::attach()
01068 {
01069     assert(!attached());
01070     assert(!m_render);
01071     assert(parentNode());
01072 
01073     if (!m_inited) {
01074         DOMString type = getAttribute(ATTR_TYPE);
01075         if ( strcasecmp( type, "password" ) == 0 )
01076             m_type = PASSWORD;
01077         else if ( strcasecmp( type, "checkbox" ) == 0 )
01078             m_type = CHECKBOX;
01079         else if ( strcasecmp( type, "radio" ) == 0 )
01080             m_type = RADIO;
01081         else if ( strcasecmp( type, "submit" ) == 0 )
01082             m_type = SUBMIT;
01083         else if ( strcasecmp( type, "reset" ) == 0 )
01084             m_type = RESET;
01085         else if ( strcasecmp( type, "file" ) == 0 )
01086             m_type = FILE;
01087         else if ( strcasecmp( type, "hidden" ) == 0 )
01088             m_type = HIDDEN;
01089         else if ( strcasecmp( type, "image" ) == 0 )
01090             m_type = IMAGE;
01091         else if ( strcasecmp( type, "button" ) == 0 )
01092             m_type = BUTTON;
01093         else if ( strcasecmp( type, "khtml_isindex" ) == 0 )
01094             m_type = ISINDEX;
01095         else
01096             m_type = TEXT;
01097 
01098         if (m_type != FILE) m_value = getAttribute(ATTR_VALUE);
01099         if ((uint) m_type <= ISINDEX && !m_value.isEmpty()) {
01100             QString value = m_value.string();
01101             // remove newline stuff..
01102             QString nvalue;
01103             for (unsigned int i = 0; i < value.length(); ++i)
01104                 if (value[i] >= ' ')
01105                     nvalue += value[i];
01106             m_value = nvalue;
01107         }
01108         m_checked = (getAttribute(ATTR_CHECKED) != 0);
01109         m_inited = true;
01110     }
01111 
01112     // make sure we don't inherit a color to the form elements
01113     // by adding a non-CSS color property. this his higher
01114     // priority than inherited color, but lesser priority than
01115     // any color specified by CSS for the elements.
01116     switch( m_type ) {
01117     case TEXT:
01118     case PASSWORD:
01119         addCSSProperty(CSS_PROP_FONT_FAMILY,  "monospace");
01120         /* nobreak */
01121     case ISINDEX:
01122     case FILE:
01123         addCSSProperty(CSS_PROP_COLOR, "text");
01124         break;
01125     case SUBMIT:
01126     case RESET:
01127     case BUTTON:
01128     case CHECKBOX:
01129     case RADIO:
01130         addCSSProperty(CSS_PROP_COLOR, "buttontext" );
01131     case HIDDEN:
01132     case IMAGE:
01133         if (!getAttribute(ATTR_WIDTH).isNull())
01134             addCSSLength(CSS_PROP_WIDTH, getAttribute(ATTR_WIDTH));
01135         break;
01136     };
01137 
01138     RenderStyle* _style = getDocument()->styleSelector()->styleForElement(this);
01139     _style->ref();
01140     if (parentNode()->renderer() && _style->display() != NONE) {
01141         switch(m_type)
01142         {
01143         case TEXT:
01144         case PASSWORD:
01145         case ISINDEX:      m_render = new RenderLineEdit(this);   break;
01146         case CHECKBOX:  m_render = new RenderCheckBox(this); break;
01147         case RADIO:        m_render = new RenderRadioButton(this); break;
01148         case SUBMIT:      m_render = new RenderSubmitButton(this); break;
01149         case IMAGE:       m_render =  new RenderImageButton(this); break;
01150         case RESET:      m_render = new RenderResetButton(this);   break;
01151         case FILE:         m_render =  new RenderFileButton(this);    break;
01152         case BUTTON:  m_render = new RenderPushButton(this);
01153         case HIDDEN:   break;
01154         }
01155     }
01156 
01157     if (m_render)
01158         m_render->setStyle(_style);
01159 
01160     HTMLGenericFormElementImpl::attach();
01161     _style->deref();
01162 }
01163 
01164 DOMString HTMLInputElementImpl::altText() const
01165 {
01166     // http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#altgen
01167     // also heavily discussed by Hixie on bugzilla
01168     // note this is intentionally different to HTMLImageElementImpl::altText()
01169     DOMString alt = getAttribute( ATTR_ALT );
01170     // fall back to title attribute
01171     if ( alt.isNull() )
01172         alt = getAttribute( ATTR_TITLE );
01173     if ( alt.isNull() )
01174         alt = getAttribute( ATTR_VALUE );
01175     if ( alt.isEmpty() )
01176         alt = i18n( "Submit" );
01177 
01178     return alt;
01179 }
01180 
01181 bool HTMLInputElementImpl::encoding(const QTextCodec* codec, khtml::encodingList& encoding, bool multipart)
01182 {
01183     QString nme = name().string();
01184 
01185     // image generates its own name's
01186     if (nme.isEmpty() && m_type != IMAGE) return false;
01187 
01188     // IMAGE needs special handling later
01189     if(m_type != IMAGE) encoding += fixUpfromUnicode(codec, nme);
01190 
01191     switch (m_type) {
01192         case CHECKBOX:
01193 
01194             if( checked() ) {
01195                 encoding += fixUpfromUnicode(codec, value().string());
01196                 return true;
01197             }
01198             break;
01199 
01200         case RADIO:
01201 
01202             if( checked() ) {
01203                 encoding += fixUpfromUnicode(codec, value().string());
01204                 return true;
01205             }
01206             break;
01207 
01208         case BUTTON:
01209         case RESET:
01210             // those buttons are never successful
01211             return false;
01212 
01213         case IMAGE:
01214 
01215             if(m_clicked)
01216             {
01217                 m_clicked = false;
01218                 QString astr(nme.isEmpty() ? QString::fromLatin1("x") : nme + ".x");
01219 
01220                 encoding += fixUpfromUnicode(codec, astr);
01221                 astr.setNum(KMAX( clickX(), 0 ));
01222                 encoding += fixUpfromUnicode(codec, astr);
01223                 astr = nme.isEmpty() ? QString::fromLatin1("y") : nme + ".y";
01224                 encoding += fixUpfromUnicode(codec, astr);
01225                 astr.setNum(KMAX( clickY(), 0 ) );
01226                 encoding += fixUpfromUnicode(codec, astr);
01227 
01228                 return true;
01229             }
01230             break;
01231 
01232         case SUBMIT:
01233 
01234             if (m_activeSubmit)
01235             {
01236                 QString enc_str = m_value.isNull() ?
01237                     static_cast<RenderSubmitButton*>(m_render)->defaultLabel() : value().string();
01238 
01239                 if(!enc_str.isEmpty())
01240                 {
01241                     encoding += fixUpfromUnicode(codec, enc_str);
01242                     return true;
01243                 }
01244             }
01245             break;
01246 
01247         case FILE:
01248         {
01249             // don't submit if display: none or display: hidden
01250             if(!renderer() || renderer()->style()->visibility() != khtml::VISIBLE)
01251                 return false;
01252 
01253             QString local;
01254             QCString dummy("");
01255 
01256             KURL fileurl(value().string());
01257             KIO::UDSEntry filestat;
01258 
01259             // can't submit file in www-url-form encoded
01260             if (multipart && KIO::NetAccess::stat(fileurl, filestat)) {
01261                 KFileItem fileitem(filestat, fileurl, true, false);
01262 
01263                 if ( fileitem.isFile() && KIO::NetAccess::download(KURL(value().string()), local) ) {
01264                     QFile file(local);
01265                     if (file.open(IO_ReadOnly)) {
01266                         QCString filearray(file.size()+1);
01267                         int readbytes = file.readBlock( filearray.data(), file.size());
01268                         if ( readbytes >= 0 )
01269                             filearray[readbytes] = '\0';
01270                         file.close();
01271 
01272                         encoding += filearray;
01273                         KIO::NetAccess::removeTempFile( local );
01274 
01275                         return true;
01276                     }
01277                 }
01278             }
01279             // else fall through
01280         }
01281         case HIDDEN:
01282         case TEXT:
01283         case PASSWORD:
01284             // always successful
01285             encoding += fixUpfromUnicode(codec, value().string());
01286             return true;
01287         case ISINDEX:
01288             encoding += fixUpfromUnicode(codec, m_value.string());
01289             return true;
01290     }
01291     return false;
01292 }
01293 
01294 void HTMLInputElementImpl::reset()
01295 {
01296     setValue(getAttribute(ATTR_VALUE));
01297     setChecked(getAttribute(ATTR_CHECKED) != 0);
01298 }
01299 
01300 void HTMLInputElementImpl::setChecked(bool _checked)
01301 {
01302     if (m_form && m_type == RADIO && _checked && !name().isEmpty())
01303         m_form->radioClicked(this);
01304 
01305     if (m_checked == _checked) return;
01306     m_checked = _checked;
01307     setChanged();
01308 }
01309 
01310 
01311 DOMString HTMLInputElementImpl::value() const
01312 {
01313     if(m_value.isNull())
01314         return (m_type == CHECKBOX || m_type ==RADIO) ?
01315             DOMString("on") : DOMString("");
01316 
01317     return m_value;
01318 }
01319 
01320 
01321 void HTMLInputElementImpl::setValue(DOMString val)
01322 {
01323     if (m_type == FILE) return;
01324 
01325     m_value = (val.isNull() ? DOMString("") : val);
01326     setChanged();
01327 }
01328 
01329 void HTMLInputElementImpl::blur()
01330 {
01331     if(getDocument()->focusNode() == this)
01332         getDocument()->setFocusNode(0);
01333 }
01334 
01335 void HTMLInputElementImpl::focus()
01336 {
01337     getDocument()->setFocusNode(this);
01338 }
01339 
01340 void HTMLInputElementImpl::defaultEventHandler(EventImpl *evt)
01341 {
01342     if ( !m_disabled )
01343     {
01344         if (evt->isMouseEvent() &&
01345             evt->id() == EventImpl::CLICK_EVENT && m_type == IMAGE && m_render) {
01346             // record the mouse position for when we get the DOMActivate event
01347             MouseEventImpl *me = static_cast<MouseEventImpl*>(evt);
01348             int offsetX, offsetY;
01349             m_render->absolutePosition(offsetX,offsetY);
01350             xPos = me->clientX()-offsetX;
01351             yPos = me->clientY()-offsetY;
01352         }
01353 
01354         // DOMActivate events cause the input to be "activated" - in the case of image and submit inputs, this means
01355         // actually submitting the form. For reset inputs, the form is reset. These events are sent when the user clicks
01356         // on the element, or presses enter while it is the active element. Javascript code wishing to activate the element
01357         // must dispatch a DOMActivate event - a click event will not do the job.
01358         if ((evt->id() == EventImpl::DOMACTIVATE_EVENT) &&
01359             (m_type == IMAGE || m_type == SUBMIT || m_type == RESET))
01360             activate();
01361     }
01362     HTMLGenericFormElementImpl::defaultEventHandler(evt);
01363 }
01364 
01365 void HTMLInputElementImpl::activate()
01366 {
01367     if (!m_form || !m_render)
01368         return;
01369 
01370     m_clicked = true;
01371     if (m_type == RESET) {
01372         m_form->reset();
01373     }
01374     else {
01375         m_activeSubmit = true;
01376         if (!m_form->prepareSubmit()) {
01377             xPos = 0;
01378             yPos = 0;
01379         }
01380         m_activeSubmit = false;
01381     }
01382 }
01383 
01384 bool HTMLInputElementImpl::isEditable()
01385 {
01386     return ((m_type == TEXT) || (m_type == PASSWORD) || (m_type == ISINDEX) || (m_type == FILE));
01387 }
01388 
01389 // -------------------------------------------------------------------------
01390 
01391 HTMLLabelElementImpl::HTMLLabelElementImpl(DocumentPtr *doc)
01392     : HTMLGenericFormElementImpl(doc)
01393 {
01394 }
01395 
01396 HTMLLabelElementImpl::~HTMLLabelElementImpl()
01397 {
01398 }
01399 
01400 NodeImpl::Id HTMLLabelElementImpl::id() const
01401 {
01402     return ID_LABEL;
01403 }
01404 
01405 void HTMLLabelElementImpl::parseAttribute(AttributeImpl *attr)
01406 {
01407     switch(attr->id())
01408     {
01409     case ATTR_ONFOCUS:
01410         setHTMLEventListener(EventImpl::FOCUS_EVENT,
01411             getDocument()->createHTMLEventListener(attr->value().string()));
01412         break;
01413     case ATTR_ONBLUR:
01414         setHTMLEventListener(EventImpl::BLUR_EVENT,
01415             getDocument()->createHTMLEventListener(attr->value().string()));
01416         break;
01417     default:
01418         HTMLElementImpl::parseAttribute(attr);
01419     }
01420 }
01421 
01422 void HTMLLabelElementImpl::attach()
01423 {
01424     // skip the generic handler
01425     HTMLElementImpl::attach();
01426 }
01427 
01428 #if 0
01429 ElementImpl *HTMLLabelElementImpl::formElement()
01430 {
01431     DOMString formElementId = getAttribute(ATTR_FOR);
01432     if (formElementId.isEmpty())
01433         return 0;
01434     return getDocument()->getElementById(formElementId);
01435 }
01436 #endif
01437 
01438 // -------------------------------------------------------------------------
01439 
01440 HTMLLegendElementImpl::HTMLLegendElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
01441     : HTMLGenericFormElementImpl(doc, f)
01442 {
01443 }
01444 
01445 HTMLLegendElementImpl::~HTMLLegendElementImpl()
01446 {
01447 }
01448 
01449 NodeImpl::Id HTMLLegendElementImpl::id() const
01450 {
01451     return ID_LEGEND;
01452 }
01453 
01454 void HTMLLegendElementImpl::attach()
01455 {
01456     assert(!attached());
01457     assert(!m_render);
01458     assert(parentNode());
01459     addCSSProperty(CSS_PROP_PADDING_LEFT, "1px");
01460     addCSSProperty(CSS_PROP_PADDING_RIGHT, "1px");
01461     RenderStyle* _style = getDocument()->styleSelector()->styleForElement(this);
01462     _style->ref();
01463     if (parentNode()->renderer() && _style->display() != NONE) {
01464         m_render = new RenderLegend(this);
01465         m_render->setStyle(_style);
01466     }
01467     HTMLGenericFormElementImpl::attach();
01468     _style->deref();
01469 }
01470 
01471 void HTMLLegendElementImpl::parseAttribute(AttributeImpl *attr)
01472 {
01473     switch(attr->id())
01474     {
01475     case ATTR_ACCESSKEY:
01476         // ### ignore for the moment
01477         break;
01478     default:
01479         HTMLElementImpl::parseAttribute(attr);
01480     }
01481 }
01482 
01483 // -------------------------------------------------------------------------
01484 
01485 HTMLSelectElementImpl::HTMLSelectElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
01486     : HTMLGenericFormElementImpl(doc, f)
01487 {
01488     m_multiple = false;
01489     m_recalcListItems = false;
01490     // 0 means invalid (i.e. not set)
01491     m_size = 0;
01492     m_minwidth = 0;
01493 }
01494 
01495 HTMLSelectElementImpl::~HTMLSelectElementImpl()
01496 {
01497     if (getDocument()) getDocument()->deregisterMaintainsState(this);
01498 }
01499 
01500 NodeImpl::Id HTMLSelectElementImpl::id() const
01501 {
01502     return ID_SELECT;
01503 }
01504 
01505 DOMString HTMLSelectElementImpl::type() const
01506 {
01507     return (m_multiple ? "select-multiple" : "select-one");
01508 }
01509 
01510 long HTMLSelectElementImpl::selectedIndex() const
01511 {
01512     // return the number of the first option selected
01513     uint o = 0;
01514     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
01515     for (unsigned int i = 0; i < items.size(); i++) {
01516         if (items[i]->id() == ID_OPTION) {
01517             if (static_cast<HTMLOptionElementImpl*>(items[i])->selected())
01518                 return o;
01519             o++;
01520         }
01521     }
01522     Q_ASSERT(m_multiple || items.isEmpty());
01523     return -1;
01524 }
01525 
01526 void HTMLSelectElementImpl::setSelectedIndex( long  index )
01527 {
01528     // deselect all other options and select only the new one
01529     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
01530     int listIndex;
01531     for (listIndex = 0; listIndex < int(items.size()); listIndex++) {
01532         if (items[listIndex]->id() == ID_OPTION)
01533             static_cast<HTMLOptionElementImpl*>(items[listIndex])->setSelected(false);
01534     }
01535     listIndex = optionToListIndex(index);
01536     if (listIndex >= 0)
01537         static_cast<HTMLOptionElementImpl*>(items[listIndex])->setSelected(true);
01538 
01539     setChanged(true);
01540 }
01541 
01542 long HTMLSelectElementImpl::length() const
01543 {
01544     int len = 0;
01545     uint i;
01546     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
01547     for (i = 0; i < items.size(); i++) {
01548         if (items[i]->id() == ID_OPTION)
01549             len++;
01550     }
01551     return len;
01552 }
01553 
01554 void HTMLSelectElementImpl::add( const HTMLElement &element, const HTMLElement &before, int& exceptioncode )
01555 {
01556     if(element.isNull() || element.handle()->id() != ID_OPTION)
01557         return;
01558 
01559     insertBefore(element.handle(), before.handle(), exceptioncode );
01560     if (!exceptioncode)
01561         setRecalcListItems();
01562 }
01563 
01564 void HTMLSelectElementImpl::remove( long index )
01565 {
01566     int exceptioncode = 0;
01567     int listIndex = optionToListIndex(index);
01568 
01569     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
01570     if(listIndex < 0 || index >= int(items.size()))
01571         return; // ### what should we do ? remove the last item?
01572 
01573     removeChild(items[listIndex], exceptioncode);
01574     if( !exceptioncode )
01575         setRecalcListItems();
01576 }
01577 
01578 void HTMLSelectElementImpl::blur()
01579 {
01580     if(getDocument()->focusNode() == this)
01581         getDocument()->setFocusNode(0);
01582 }
01583 
01584 void HTMLSelectElementImpl::focus()
01585 {
01586     getDocument()->setFocusNode(this);
01587 }
01588 
01589 DOMString HTMLSelectElementImpl::value( )
01590 {
01591     uint i;
01592     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
01593     for (i = 0; i < items.size(); i++) {
01594         if ( items[i]->id() == ID_OPTION
01595             && static_cast<HTMLOptionElementImpl*>(items[i])->selected())
01596             return static_cast<HTMLOptionElementImpl*>(items[i])->value();
01597     }
01598     return DOMString("");
01599 }
01600 
01601 void HTMLSelectElementImpl::setValue(DOMStringImpl* /*value*/)
01602 {
01603     // ### find the option with value() matching the given parameter
01604     // and make it the current selection.
01605     kdWarning() << "Unimplemented HTMLSelectElementImpl::setValue called" << endl;
01606 }
01607 
01608 QString HTMLSelectElementImpl::state( )
01609 {
01610     QString state;
01611     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
01612 
01613     int l = items.count();
01614 
01615     state.fill('.', l);
01616     for(int i = 0; i < l; i++)
01617         if(items[i]->id() == ID_OPTION && static_cast<HTMLOptionElementImpl*>(items[i])->selected())
01618             state[i] = 'X';
01619 
01620     return state;
01621 }
01622 
01623 void HTMLSelectElementImpl::restoreState(const QString &_state)
01624 {
01625     recalcListItems();
01626 
01627     QString state = _state;
01628     if(!state.isEmpty() && !state.contains('X') && !m_multiple && m_size <= 1) {
01629         qWarning("should not happen in restoreState!");
01630         state[0] = 'X';
01631     }
01632 
01633     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
01634 
01635     int l = items.count();
01636     for(int i = 0; i < l; i++) {
01637         if(items[i]->id() == ID_OPTION) {
01638             HTMLOptionElementImpl* oe = static_cast<HTMLOptionElementImpl*>(items[i]);
01639             oe->setSelected(state[i] == 'X');
01640         }
01641     }
01642     setChanged(true);
01643 }
01644 
01645 NodeImpl *HTMLSelectElementImpl::insertBefore ( NodeImpl *newChild, NodeImpl *refChild, int &exceptioncode )
01646 {
01647     NodeImpl *result = HTMLGenericFormElementImpl::insertBefore(newChild,refChild, exceptioncode );
01648     if (!exceptioncode)
01649         setRecalcListItems();
01650     return result;
01651 }
01652 
01653 NodeImpl *HTMLSelectElementImpl::replaceChild ( NodeImpl *newChild, NodeImpl *oldChild, int &exceptioncode )
01654 {
01655     NodeImpl *result = HTMLGenericFormElementImpl::replaceChild(newChild,oldChild, exceptioncode);
01656     if( !exceptioncode )
01657         setRecalcListItems();
01658     return result;
01659 }
01660 
01661 NodeImpl *HTMLSelectElementImpl::removeChild ( NodeImpl *oldChild, int &exceptioncode )
01662 {
01663     NodeImpl *result = HTMLGenericFormElementImpl::removeChild(oldChild, exceptioncode);
01664     if( !exceptioncode )
01665         setRecalcListItems();
01666     return result;
01667 }
01668 
01669 NodeImpl *HTMLSelectElementImpl::appendChild ( NodeImpl *newChild, int &exceptioncode )
01670 {
01671     NodeImpl *result = HTMLGenericFormElementImpl::appendChild(newChild, exceptioncode);
01672     if( !exceptioncode )
01673         setRecalcListItems();
01674     setChanged(true);
01675     return result;
01676 }
01677 
01678 NodeImpl* HTMLSelectElementImpl::addChild(NodeImpl* newChild)
01679 {
01680     setRecalcListItems();
01681     return HTMLGenericFormElementImpl::addChild(newChild);
01682 }
01683 
01684 void HTMLSelectElementImpl::parseAttribute(AttributeImpl *attr)
01685 {
01686     switch(attr->id())
01687     {
01688     case ATTR_SIZE:
01689         m_size = QMAX( attr->val()->toInt(), 1 );
01690         break;
01691     case ATTR_WIDTH:
01692         m_minwidth = QMAX( attr->val()->toInt(), 0 );
01693         break;
01694     case ATTR_MULTIPLE:
01695         m_multiple = (attr->val() != 0);
01696         break;
01697     case ATTR_ACCESSKEY:
01698         // ### ignore for the moment
01699         break;
01700     case ATTR_ONFOCUS:
01701         setHTMLEventListener(EventImpl::FOCUS_EVENT,
01702             getDocument()->createHTMLEventListener(attr->value().string()));
01703         break;
01704     case ATTR_ONBLUR:
01705         setHTMLEventListener(EventImpl::BLUR_EVENT,
01706             getDocument()->createHTMLEventListener(attr->value().string()));
01707         break;
01708     case ATTR_ONCHANGE:
01709         setHTMLEventListener(EventImpl::CHANGE_EVENT,
01710             getDocument()->createHTMLEventListener(attr->value().string()));
01711         break;
01712     default:
01713         HTMLGenericFormElementImpl::parseAttribute(attr);
01714     }
01715 }
01716 
01717 void HTMLSelectElementImpl::attach()
01718 {
01719     assert(!attached());
01720     assert(parentNode());
01721     assert(!renderer());
01722 
01723     addCSSProperty(CSS_PROP_COLOR, "text");
01724 
01725     RenderStyle* _style = getDocument()->styleSelector()->styleForElement(this);
01726     _style->ref();
01727     if (parentNode()->renderer() && _style->display() != NONE) {
01728         m_render = new RenderSelect(this);
01729         m_render->setStyle(_style);
01730     }
01731 
01732     HTMLGenericFormElementImpl::attach();
01733     _style->deref();
01734 }
01735 
01736 bool HTMLSelectElementImpl::encoding(const QTextCodec* codec, khtml::encodingList& encoded_values, bool)
01737 {
01738     bool successful = false;
01739     QCString enc_name = fixUpfromUnicode(codec, name().string());
01740     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
01741 
01742     uint i;
01743     for (i = 0; i < items.size(); i++) {
01744         if (items[i]->id() == ID_OPTION) {
01745             HTMLOptionElementImpl *option = static_cast<HTMLOptionElementImpl*>(items[i]);
01746             if (option->selected()) {
01747                 encoded_values += enc_name;
01748                 encoded_values += fixUpfromUnicode(codec, option->value().string());
01749                 successful = true;
01750             }
01751         }
01752     }
01753 
01754     // ### this case should not happen. make sure that we select the first option
01755     // in any case. otherwise we have no consistency with the DOM interface. FIXME!
01756     // we return the first one if it was a combobox select
01757     if (!successful && !m_multiple && m_size <= 1 && items.size() &&
01758         (items[0]->id() == ID_OPTION) ) {
01759         HTMLOptionElementImpl *option = static_cast<HTMLOptionElementImpl*>(items[0]);
01760         encoded_values += enc_name;
01761         if (option->value().isNull())
01762             encoded_values += fixUpfromUnicode(codec, option->text().string().stripWhiteSpace());
01763         else
01764             encoded_values += fixUpfromUnicode(codec, option->value().string());
01765         successful = true;
01766     }
01767 
01768     return successful;
01769 }
01770 
01771 int HTMLSelectElementImpl::optionToListIndex(int optionIndex) const
01772 {
01773     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
01774     if (optionIndex < 0 || optionIndex >= int(items.size()))
01775         return -1;
01776 
01777     int listIndex = 0;
01778     int optionIndex2 = 0;
01779     for (;
01780          optionIndex2 < int(items.size()) && optionIndex2 <= optionIndex;
01781          listIndex++) { // not a typo!
01782         if (items[listIndex]->id() == ID_OPTION)
01783             optionIndex2++;
01784     }
01785     listIndex--;
01786     return listIndex;
01787 }
01788 
01789 int HTMLSelectElementImpl::listToOptionIndex(int listIndex) const
01790 {
01791     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
01792     if (listIndex < 0 || listIndex >= int(items.size()) ||
01793         items[listIndex]->id() != ID_OPTION)
01794         return -1;
01795 
01796     int optionIndex = 0; // actual index of option not counting OPTGROUP entries that may be in list
01797     int i;
01798     for (i = 0; i < listIndex; i++)
01799         if (items[i]->id() == ID_OPTION)
01800             optionIndex++;
01801     return optionIndex;
01802 }
01803 
01804 void HTMLSelectElementImpl::recalcListItems()
01805 {
01806     NodeImpl* current = firstChild();
01807     m_listItems.resize(0);
01808     HTMLOptionElementImpl* foundSelected = 0;
01809     while(current) {
01810         if (current->id() == ID_OPTGROUP && current->firstChild()) {
01811             // ### what if optgroup contains just comments? don't want one of no options in it...
01812             m_listItems.resize(m_listItems.size()+1);
01813             m_listItems[m_listItems.size()-1] = static_cast<HTMLGenericFormElementImpl*>(current);
01814             current = current->firstChild();
01815         }
01816         if (current->id() == ID_OPTION) {
01817             m_listItems.resize(m_listItems.size()+1);
01818             m_listItems[m_listItems.size()-1] = static_cast<HTMLGenericFormElementImpl*>(current);
01819             if (!foundSelected && !m_multiple && m_size <= 1) {
01820                 foundSelected = static_cast<HTMLOptionElementImpl*>(current);
01821                 foundSelected->m_selected = true;
01822             }
01823             else if (foundSelected && !m_multiple && static_cast<HTMLOptionElementImpl*>(current)->selected()) {
01824                 foundSelected->m_selected = false;
01825                 foundSelected = static_cast<HTMLOptionElementImpl*>(current);
01826             }
01827         }
01828         NodeImpl *parent = current->parentNode();
01829         current = current->nextSibling();
01830         if (!current) {
01831             if (parent != this)
01832                 current = parent->nextSibling();
01833         }
01834     }
01835     m_recalcListItems = false;
01836 }
01837 
01838 void HTMLSelectElementImpl::childrenChanged()
01839 {
01840     setRecalcListItems();
01841 
01842     HTMLGenericFormElementImpl::childrenChanged();
01843 }
01844 
01845 void HTMLSelectElementImpl::setRecalcListItems()
01846 {
01847     m_recalcListItems = true;
01848     if (m_render)
01849         static_cast<khtml::RenderSelect*>(m_render)->setOptionsChanged(true);
01850     setChanged();
01851 }
01852 
01853 void HTMLSelectElementImpl::reset()
01854 {
01855     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
01856     uint i;
01857     for (i = 0; i < items.size(); i++) {
01858         if (items[i]->id() == ID_OPTION) {
01859             HTMLOptionElementImpl *option = static_cast<HTMLOptionElementImpl*>(items[i]);
01860             bool selected = (!option->getAttribute(ATTR_SELECTED).isNull());
01861             option->setSelected(selected);
01862         }
01863     }
01864     if ( m_render )
01865         static_cast<RenderSelect*>(m_render)->setSelectionChanged(true);
01866     setChanged( true );
01867 }
01868 
01869 void HTMLSelectElementImpl::notifyOptionSelected(HTMLOptionElementImpl *selectedOption, bool selected)
01870 {
01871     if (selected && !m_multiple) {
01872         // deselect all other options
01873         QMemArray<HTMLGenericFormElementImpl*> items = listItems();
01874         uint i;
01875         for (i = 0; i < items.size(); i++) {
01876             if (items[i]->id() == ID_OPTION)
01877                 static_cast<HTMLOptionElementImpl*>(items[i])->m_selected = (items[i] == selectedOption);
01878         }
01879     }
01880     if (m_render)
01881         static_cast<RenderSelect*>(m_render)->setSelectionChanged(true);
01882 
01883     setChanged(true);
01884 }
01885 
01886 // -------------------------------------------------------------------------
01887 
01888 HTMLKeygenElementImpl::HTMLKeygenElementImpl(DocumentPtr* doc, HTMLFormElementImpl* f)
01889     : HTMLSelectElementImpl(doc, f)
01890 {
01891     QStringList keys = KSSLKeyGen::supportedKeySizes();
01892     for (QStringList::Iterator i = keys.begin(); i != keys.end(); ++i) {
01893         HTMLOptionElementImpl* o = new HTMLOptionElementImpl(doc, form());
01894         addChild(o);
01895         o->addChild(doc->document()->createTextNode(DOMString(*i).implementation()));
01896     }
01897 }
01898 
01899 NodeImpl::Id HTMLKeygenElementImpl::id() const
01900 {
01901     return ID_KEYGEN;
01902 }
01903 
01904 void HTMLKeygenElementImpl::parseAttribute(AttributeImpl* attr)
01905 {
01906     switch(attr->id())
01907     {
01908     case ATTR_CHALLENGE:
01909         break;
01910     default:
01911         // skip HTMLSelectElementImpl parsing!
01912         HTMLGenericFormElementImpl::parseAttribute(attr);
01913     }
01914 }
01915 
01916 bool HTMLKeygenElementImpl::encoding(const QTextCodec* codec, khtml::encodingList& encoded_values, bool)
01917 {
01918     bool successful = false;
01919     QCString enc_name = fixUpfromUnicode(codec, name().string());
01920 
01921     encoded_values += enc_name;
01922 
01923     // pop up the fancy certificate creation dialog here
01924     KSSLKeyGen *kg = new KSSLKeyGen(static_cast<RenderWidget *>(m_render)->widget(), "Key Generator", true);
01925 
01926     kg->setKeySize(0);
01927     successful = (QDialog::Accepted == kg->exec());
01928 
01929     delete kg;
01930 
01931     encoded_values += "deadbeef";
01932 
01933     return successful;
01934 }
01935 
01936 // -------------------------------------------------------------------------
01937 
01938 NodeImpl::Id HTMLOptGroupElementImpl::id() const
01939 {
01940     return ID_OPTGROUP;
01941 }
01942 
01943 // -------------------------------------------------------------------------
01944 
01945 HTMLOptionElementImpl::HTMLOptionElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
01946     : HTMLGenericFormElementImpl(doc, f)
01947 {
01948     m_selected = false;
01949 }
01950 
01951 NodeImpl::Id HTMLOptionElementImpl::id() const
01952 {
01953     return ID_OPTION;
01954 }
01955 
01956 DOMString HTMLOptionElementImpl::text() const
01957 {
01958     if (firstChild() && firstChild()->nodeType() == Node::TEXT_NODE) {
01959         if (firstChild()->nextSibling()) {
01960             DOMString ret = "";
01961             NodeImpl *n = firstChild();
01962             for (; n; n = n->nextSibling()) {
01963                 if (n->nodeType() == Node::TEXT_NODE ||
01964                     n->nodeType() == Node::CDATA_SECTION_NODE)
01965                     ret += n->nodeValue();
01966             }
01967             return ret;
01968         }
01969         else
01970             return firstChild()->nodeValue();
01971     }
01972     return "";
01973 }
01974 
01975 long HTMLOptionElementImpl::index() const
01976 {
01977     // Let's do this dynamically. Might be a bit slow, but we're sure
01978     // we won't forget to update a member variable in some cases...
01979     QMemArray<HTMLGenericFormElementImpl*> items = getSelect()->listItems();
01980     int l = items.count();
01981     int optionIndex = 0;
01982     for(int i = 0; i < l; i++) {
01983         if(items[i]->id() == ID_OPTION)
01984         {
01985             if (static_cast<HTMLOptionElementImpl*>(items[i]) == this)
01986                 return optionIndex;
01987             optionIndex++;
01988         }
01989     }
01990     kdWarning() << "HTMLOptionElementImpl::index(): option not found!" << endl;
01991     return 0;
01992 }
01993 
01994 void HTMLOptionElementImpl::setIndex( long  )
01995 {
01996     kdWarning() << "Unimplemented HTMLOptionElementImpl::setIndex(long) called" << endl;
01997     // ###
01998 }
01999 
02000 void HTMLOptionElementImpl::parseAttribute(AttributeImpl *attr)
02001 {
02002     switch(attr->id())
02003     {
02004     case ATTR_SELECTED:
02005         m_selected = (attr->val() != 0);
02006         break;
02007     case ATTR_VALUE:
02008         m_value = attr->value();
02009         break;
02010     default:
02011         HTMLGenericFormElementImpl::parseAttribute(attr);
02012     }
02013 }
02014 
02015 DOMString HTMLOptionElementImpl::value() const
02016 {
02017     if ( !m_value.isNull() )
02018         return m_value;
02019     // Use the text if the value wasn't set.
02020     return text().string().simplifyWhiteSpace();
02021 }
02022 
02023 void HTMLOptionElementImpl::setValue(DOMStringImpl* value)
02024 {
02025     setAttribute(ATTR_VALUE, value);
02026 }
02027 
02028 void HTMLOptionElementImpl::setSelected(bool _selected)
02029 {
02030     if(m_selected == _selected)
02031         return;
02032     m_selected = _selected;
02033     HTMLSelectElementImpl *select = getSelect();
02034     if (select)
02035         select->notifyOptionSelected(this,_selected);
02036 }
02037 
02038 HTMLSelectElementImpl *HTMLOptionElementImpl::getSelect() const
02039 {
02040     NodeImpl *select = parentNode();
02041     while (select && select->id() != ID_SELECT)
02042         select = select->parentNode();
02043     return static_cast<HTMLSelectElementImpl*>(select);
02044 }
02045 
02046 // -------------------------------------------------------------------------
02047 
02048 HTMLTextAreaElementImpl::HTMLTextAreaElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
02049     : HTMLGenericFormElementImpl(doc, f)
02050 {
02051     // DTD requires rows & cols be specified, but we will provide reasonable defaults
02052     m_rows = 2;
02053     m_cols = 20;
02054     m_wrap = ta_Virtual;
02055     m_dirtyvalue = true;
02056 }
02057 
02058 HTMLTextAreaElementImpl::~HTMLTextAreaElementImpl()
02059 {
02060     if (getDocument()) getDocument()->deregisterMaintainsState(this);
02061 }
02062 
02063 NodeImpl::Id HTMLTextAreaElementImpl::id() const
02064 {
02065     return ID_TEXTAREA;
02066 }
02067 
02068 DOMString HTMLTextAreaElementImpl::type() const
02069 {
02070     return "textarea";
02071 }
02072 
02073 QString HTMLTextAreaElementImpl::state( )
02074 {
02075     // Make sure the string is not empty!
02076     return value().string()+'.';
02077 }
02078 
02079 void HTMLTextAreaElementImpl::restoreState(const QString &state)
02080 {
02081     setDefaultValue(state.left(state.length()-1));
02082     // the close() in the rendertree will take care of transferring defaultvalue to 'value'
02083 }
02084 
02085 void HTMLTextAreaElementImpl::select(  )
02086 {
02087     if (m_render)
02088         static_cast<RenderTextArea*>(m_render)->select();
02089     onSelect();
02090 }
02091 
02092 void HTMLTextAreaElementImpl::parseAttribute(AttributeImpl *attr)
02093 {
02094     switch(attr->id())
02095     {
02096     case ATTR_ROWS:
02097         m_rows = attr->val() ? attr->val()->toInt() : 3;
02098         break;
02099     case ATTR_COLS:
02100         m_cols = attr->val() ? attr->val()->toInt() : 60;
02101         break;
02102     case ATTR_WRAP:
02103         // virtual / physical is Netscape extension of HTML 3.0, now deprecated
02104         // soft/ hard / off is recommendation for HTML 4 extension by IE and NS 4
02105         if ( strcasecmp( attr->value(), "virtual" ) == 0  || strcasecmp( attr->value(), "soft") == 0)
02106             m_wrap = ta_Virtual;
02107         else if ( strcasecmp ( attr->value(), "physical" ) == 0 || strcasecmp( attr->value(), "hard") == 0)
02108             m_wrap = ta_Physical;
02109         else if(strcasecmp( attr->value(), "on" ) == 0)
02110             m_wrap = ta_Physical;
02111         else if(strcasecmp( attr->value(), "off") == 0)
02112             m_wrap = ta_NoWrap;
02113         break;
02114     case ATTR_ACCESSKEY:
02115         // ignore for the moment
02116         break;
02117     case ATTR_ONFOCUS:
02118         setHTMLEventListener(EventImpl::FOCUS_EVENT,
02119             getDocument()->createHTMLEventListener(attr->value().string()));
02120         break;
02121     case ATTR_ONBLUR:
02122         setHTMLEventListener(EventImpl::BLUR_EVENT,
02123             getDocument()->createHTMLEventListener(attr->value().string()));
02124         break;
02125     case ATTR_ONSELECT:
02126         setHTMLEventListener(EventImpl::SELECT_EVENT,
02127             getDocument()->createHTMLEventListener(attr->value().string()));
02128         break;
02129     case ATTR_ONCHANGE:
02130         setHTMLEventListener(EventImpl::CHANGE_EVENT,
02131             getDocument()->createHTMLEventListener(attr->value().string()));
02132         break;
02133     default:
02134         HTMLGenericFormElementImpl::parseAttribute(attr);
02135     }
02136 }
02137 
02138 void HTMLTextAreaElementImpl::attach()
02139 {
02140     assert(!attached());
02141     assert(!m_render);
02142     assert(parentNode());
02143 
02144     addCSSProperty(CSS_PROP_COLOR, "text");
02145     addCSSProperty( CSS_PROP_FONT_FAMILY, "monospace" );
02146 
02147     RenderStyle* _style = getDocument()->styleSelector()->styleForElement(this);
02148     _style->ref();
02149     if (parentNode()->renderer() && _style->display() != NONE) {
02150         m_render = new RenderTextArea(this);
02151         m_render->setStyle(_style);
02152     }
02153 
02154     HTMLGenericFormElementImpl::attach();
02155     _style->deref();
02156 }
02157 
02158 bool HTMLTextAreaElementImpl::encoding(const QTextCodec* codec, encodingList& encoding, bool)
02159 {
02160     if (name().isEmpty() || !m_render) return false;
02161 
02162     encoding += fixUpfromUnicode(codec, name().string());
02163     encoding += fixUpfromUnicode(codec, value().string());
02164 
02165     return true;
02166 }
02167 
02168 void HTMLTextAreaElementImpl::reset()
02169 {
02170     setValue(defaultValue());
02171 }
02172 
02173 DOMString HTMLTextAreaElementImpl::value()
02174 {
02175     if ( m_dirtyvalue) {
02176         if ( m_render )  m_value = static_cast<RenderTextArea*>( m_render )->text();
02177         m_dirtyvalue = false;
02178     }
02179 
02180     if ( m_value.isNull() ) return "";
02181 
02182     return m_value;
02183 }
02184 
02185 void HTMLTextAreaElementImpl::setValue(DOMString _value)
02186 {
02187     // \r\n -> \n, \r -> \n
02188     QString str = _value.string().replace( "\r\n", "\n" );
02189     m_value = str.replace( "\r", "\n" );
02190     m_dirtyvalue = false;
02191     setChanged(true);
02192 }
02193 
02194 
02195 DOMString HTMLTextAreaElementImpl::defaultValue()
02196 {
02197     DOMString val = "";
02198     // there may be comments - just grab the text nodes
02199     NodeImpl *n;
02200     for (n = firstChild(); n; n = n->nextSibling())
02201         if (n->isTextNode())
02202             val += static_cast<TextImpl*>(n)->data();
02203     if (val[0] == '\r' && val[1] == '\n') {
02204         val = val.copy();
02205         val.remove(0,2);
02206     }
02207     else if (val[0] == '\r' || val[0] == '\n') {
02208         val = val.copy();
02209         val.remove(0,1);
02210     }
02211 
02212     return val;
02213 }
02214 
02215 void HTMLTextAreaElementImpl::setDefaultValue(DOMString _defaultValue)
02216 {
02217     // there may be comments - remove all the text nodes and replace them with one
02218     QPtrList<NodeImpl> toRemove;
02219     NodeImpl *n;
02220     for (n = firstChild(); n; n = n->nextSibling())
02221         if (n->isTextNode())
02222             toRemove.append(n);
02223     QPtrListIterator<NodeImpl> it(toRemove);
02224     int exceptioncode = 0;
02225     for (; it.current(); ++it) {
02226         removeChild(it.current(), exceptioncode);
02227     }
02228     insertBefore(getDocument()->createTextNode(_defaultValue.implementation()),firstChild(), exceptioncode);
02229     setValue(_defaultValue);
02230 }
02231 
02232 void HTMLTextAreaElementImpl::blur()
02233 {
02234     if(getDocument()->focusNode() == this)
02235         getDocument()->setFocusNode(0);
02236 }
02237 
02238 void HTMLTextAreaElementImpl::focus()
02239 {
02240     getDocument()->setFocusNode(this);
02241 }
02242 
02243 bool HTMLTextAreaElementImpl::isEditable()
02244 {
02245     return true;
02246 }
02247 
02248 // -------------------------------------------------------------------------
02249 
02250 HTMLIsIndexElementImpl::HTMLIsIndexElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
02251     : HTMLInputElementImpl(doc, f)
02252 {
02253     m_type = TEXT;
02254     setName("isindex");
02255 }
02256 
02257 HTMLIsIndexElementImpl::~HTMLIsIndexElementImpl()
02258 {
02259 }
02260 
02261 NodeImpl::Id HTMLIsIndexElementImpl::id() const
02262 {
02263     return ID_ISINDEX;
02264 }
02265 
02266 void HTMLIsIndexElementImpl::parseAttribute(AttributeImpl* attr)
02267 {
02268     // don't call HTMLInputElement::parseAttribute here, as it would
02269     // accept attributes this element does not support
02270     HTMLGenericFormElementImpl::parseAttribute(attr);
02271 }
02272 
02273 DOMString HTMLIsIndexElementImpl::prompt() const
02274 {
02275     // When IsIndex is parsed, <HR/>Prompt: <ISINDEX/><HR/> is created.
02276     // So we have to look at the previous sibling to find the prompt text
02277     DOM::NodeImpl* prev = previousSibling();
02278     if ( prev && prev->nodeType() == DOM::Node::TEXT_NODE)
02279         return prev->nodeValue();
02280     return "";
02281 }
02282 
02283 void HTMLIsIndexElementImpl::setPrompt(const DOMString& str)
02284 {
02285     // When IsIndex is parsed, <HR/>Prompt: <ISINDEX/><HR/> is created.
02286     // So we have to look at the previous sibling to find the prompt text
02287     int exceptioncode = 0;
02288     DOM::NodeImpl* prev = previousSibling();
02289     if ( prev && prev->nodeType() == DOM::Node::TEXT_NODE)
02290         static_cast<DOM::TextImpl *>(prev)->setData(str, exceptioncode);
02291 }
02292 
02293 // -------------------------------------------------------------------------
02294 
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 13:33:53 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001