Fixed: <rdar://problem/3811187> REGRESSION (Mail): Control-click past end of documen...
[WebKit-https.git] / WebCore / khtml / html / html_formimpl.cpp
1 /*
2  * This file is part of the DOM implementation for KDE.
3  *
4  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
5  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
6  *           (C) 2001 Dirk Mueller (mueller@kde.org)
7  * Copyright (C) 2004 Apple Computer, Inc.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB.  If not, write to
21  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  *
24  */
25
26 #undef FORMS_DEBUG
27 //#define FORMS_DEBUG
28
29 #include "html/html_formimpl.h"
30
31 #include "khtmlview.h"
32 #include "khtml_part.h"
33 #include "html/html_documentimpl.h"
34 #include "html_imageimpl.h"
35 #include "khtml_settings.h"
36 #include "misc/htmlhashes.h"
37 #include "misc/formdata.h"
38
39 #include "css/cssstyleselector.h"
40 #include "css/cssproperties.h"
41 #include "css/csshelper.h"
42 #include "xml/dom_textimpl.h"
43 #include "xml/dom2_eventsimpl.h"
44 #include "khtml_ext.h"
45
46 #include "rendering/render_form.h"
47
48 #include <kcharsets.h>
49 #include <kglobal.h>
50 #include <kdebug.h>
51 #include <kmimetype.h>
52 #include <kmessagebox.h>
53 #include <klocale.h>
54 #include <netaccess.h>
55 #include <kfileitem.h>
56 #include <qfile.h>
57 #include <qtextcodec.h>
58
59 // for keygen
60 #include <qstring.h>
61 #include <ksslkeygen.h>
62
63 #include <assert.h>
64
65 using namespace khtml;
66
67 namespace DOM {
68
69 class FormDataList {
70 public:
71     FormDataList(QTextCodec *);
72
73     void appendData(const DOMString &key, const DOMString &value)
74         { appendString(key.string()); appendString(value.string()); }
75     void appendData(const DOMString &key, const QString &value)
76         { appendString(key.string()); appendString(value); }
77     void appendData(const DOMString &key, const QCString &value)
78         { appendString(key.string()); appendString(value); }
79     void appendData(const DOMString &key, int value)
80         { appendString(key.string()); appendString(QString::number(value)); }
81     void appendFile(const DOMString &key, const DOMString &filename);
82
83     // Temporary API.
84     QValueListConstIterator<QCString> begin() const;
85     QValueListConstIterator<QCString> end() const;
86
87 private:
88     void appendString(const QCString &s);
89     void appendString(const QString &s);
90
91     QTextCodec *m_codec;
92     QValueList<QCString> m_strings;
93 };
94
95 HTMLFormElementImpl::HTMLFormElementImpl(DocumentPtr *doc)
96     : HTMLElementImpl(doc)
97 {
98     m_post = false;
99     m_multipart = false;
100     m_autocomplete = true;
101     m_insubmit = false;
102     m_doingsubmit = false;
103     m_inreset = false;
104     m_enctype = "application/x-www-form-urlencoded";
105     m_boundary = "----------0xKhTmLbOuNdArY";
106     m_acceptcharset = "UNKNOWN";
107     m_malformed = false;
108 }
109
110 HTMLFormElementImpl::~HTMLFormElementImpl()
111 {
112     QPtrListIterator<HTMLGenericFormElementImpl> it(formElements);
113     for (; it.current(); ++it)
114         it.current()->m_form = 0;
115 }
116
117 NodeImpl::Id HTMLFormElementImpl::id() const
118 {
119     return ID_FORM;
120 }
121
122 #if APPLE_CHANGES
123
124 bool HTMLFormElementImpl::formWouldHaveSecureSubmission(const DOMString &url)
125 {
126     if (url.isNull()) {
127         return false;
128     }
129     return getDocument()->completeURL(url.string()).startsWith("https:", false);
130 }
131
132 #endif
133
134 void HTMLFormElementImpl::attach()
135 {
136     HTMLElementImpl::attach();
137
138     if (getDocument()->isHTMLDocument()) {
139         HTMLDocumentImpl *document = static_cast<HTMLDocumentImpl *>(getDocument());
140         document->addNamedImageOrForm(oldNameAttr);
141         document->addNamedImageOrForm(oldIdAttr);
142     }
143
144 #if APPLE_CHANGES
145     // note we don't deal with calling secureFormRemoved() on detach, because the timing
146     // was such that it cleared our state too early
147     if (formWouldHaveSecureSubmission(m_url))
148         getDocument()->secureFormAdded();
149 #endif
150 }
151
152 void HTMLFormElementImpl::detach()
153 {
154     if (getDocument()->isHTMLDocument()) {
155         HTMLDocumentImpl *document = static_cast<HTMLDocumentImpl *>(getDocument());
156         document->removeNamedImageOrForm(oldNameAttr);
157         document->removeNamedImageOrForm(oldIdAttr);
158     }
159
160     HTMLElementImpl::detach();
161 }
162
163 long HTMLFormElementImpl::length() const
164 {
165     int len = 0;
166     QPtrListIterator<HTMLGenericFormElementImpl> it(formElements);
167     for (; it.current(); ++it)
168         if (it.current()->isEnumeratable())
169             ++len;
170
171     return len;
172 }
173
174 #if APPLE_CHANGES
175
176 void HTMLFormElementImpl::submitClick()
177 {
178     bool submitFound = false;
179     QPtrListIterator<HTMLGenericFormElementImpl> it(formElements);
180     for (; it.current(); ++it) {
181         if (it.current()->id() == ID_INPUT) {
182             HTMLInputElementImpl *element = static_cast<HTMLInputElementImpl *>(it.current());
183             if (element->isSuccessfulSubmitButton() && element->renderer()) {
184                 submitFound = true;
185                 element->click();
186                 break;
187             }
188         }
189     }
190     if (!submitFound) // submit the form without a submit or image input
191         prepareSubmit();
192 }
193
194 #endif // APPLE_CHANGES
195
196 static QCString encodeCString(const QCString& e)
197 {
198     // http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1
199     // safe characters like NS handles them for compatibility
200     static const char *safe = "-._*";
201     int elen = e.length();
202     QCString encoded(( elen+e.contains( '\n' ) )*3+1);
203     int enclen = 0;
204
205     //QCString orig(e.data(), e.size());
206
207     for(int pos = 0; pos < elen; pos++) {
208         unsigned char c = e[pos];
209
210         if ( (( c >= 'A') && ( c <= 'Z')) ||
211              (( c >= 'a') && ( c <= 'z')) ||
212              (( c >= '0') && ( c <= '9')) ||
213              (strchr(safe, c))
214             )
215             encoded[enclen++] = c;
216         else if ( c == ' ' )
217             encoded[enclen++] = '+';
218         else if ( c == '\n' || ( c == '\r' && e[pos+1] != '\n' ) )
219         {
220             encoded[enclen++] = '%';
221             encoded[enclen++] = '0';
222             encoded[enclen++] = 'D';
223             encoded[enclen++] = '%';
224             encoded[enclen++] = '0';
225             encoded[enclen++] = 'A';
226         }
227         else if ( c != '\r' )
228         {
229             encoded[enclen++] = '%';
230             unsigned int h = c / 16;
231             h += (h > 9) ? ('A' - 10) : '0';
232             encoded[enclen++] = h;
233
234             unsigned int l = c % 16;
235             l += (l > 9) ? ('A' - 10) : '0';
236             encoded[enclen++] = l;
237         }
238     }
239     encoded[enclen++] = '\0';
240     encoded.truncate(enclen);
241
242     return encoded;
243 }
244
245 // Change plain CR and plain LF to CRLF pairs.
246 static QCString fixLineBreaks(const QCString &s)
247 {
248     // Compute the length.
249     unsigned newLen = 0;
250     const char *p = s.data();
251     while (char c = *p++) {
252         if (c == '\r') {
253             // Safe to look ahead because of trailing '\0'.
254             if (*p != '\n') {
255                 // Turn CR into CRLF.
256                 newLen += 2;
257             }
258         } else if (c == '\n') {
259             // Turn LF into CRLF.
260             newLen += 2;
261         } else {
262             // Leave other characters alone.
263             newLen += 1;
264         }
265     }
266     if (newLen == s.length()) {
267         return s;
268     }
269     
270     // Make a copy of the string.
271     p = s.data();
272     QCString result(newLen + 1);
273     char *q = result.data();
274     while (char c = *p++) {
275         if (c == '\r') {
276             // Safe to look ahead because of trailing '\0'.
277             if (*p != '\n') {
278                 // Turn CR into CRLF.
279                 *q++ = '\r';
280                 *q++ = '\n';
281             }
282         } else if (c == '\n') {
283             // Turn LF into CRLF.
284             *q++ = '\r';
285             *q++ = '\n';
286         } else {
287             // Leave other characters alone.
288             *q++ = c;
289         }
290     }
291     return result;
292 }
293
294 #if !APPLE_CHANGES
295
296 void HTMLFormElementImpl::i18nData()
297 {
298     QString foo1 = i18n( "You're about to send data to the Internet "
299                          "via an unencrypted connection. It might be possible "
300                          "for others to see this information.\n"
301                          "Do you want to continue?");
302     QString foo2 = i18n("KDE Web browser");
303     QString foo3 = i18n("When you send a password unencrypted to the Internet, "
304                         "it might be possible for others to capture it as plain text.\n"
305                         "Do you want to continue?");
306     QString foo5 = i18n("Your data submission is redirected to "
307                         "an insecure site. The data is sent unencrypted.\n"
308                         "Do you want to continue?");
309     QString foo6 = i18n("The page contents expired. You can repost the form"
310                         "data by using <a href=\"javascript:go(0);\">Reload</a>");
311 }
312
313 #endif
314
315 bool HTMLFormElementImpl::formData(FormData &form_data) const
316 {
317 #ifdef FORMS_DEBUG
318     kdDebug( 6030 ) << "form: formData()" << endl;
319 #endif
320
321     QCString enc_string = ""; // used for non-multipart data
322
323     // find out the QTextcodec to use
324     QString str = m_acceptcharset.string();
325     str.replace(',', ' ');
326     QStringList charsets = QStringList::split(' ', str);
327     QTextCodec* codec = 0;
328     KHTMLPart *part = getDocument()->part();
329     for ( QStringList::Iterator it = charsets.begin(); it != charsets.end(); ++it )
330     {
331         QString enc = (*it);
332         if(enc.contains("UNKNOWN"))
333         {
334             // use standard document encoding
335             enc = "ISO-8859-1";
336             if (part)
337                 enc = part->encoding();
338         }
339         if((codec = KGlobal::charsets()->codecForName(enc.latin1())))
340             break;
341     }
342
343     if(!codec)
344         codec = QTextCodec::codecForLocale();
345
346 #if !APPLE_CHANGES
347     QStringList fileUploads;
348 #endif
349
350     for (QPtrListIterator<HTMLGenericFormElementImpl> it(formElements); it.current(); ++it) {
351         HTMLGenericFormElementImpl* current = it.current();
352         FormDataList lst(codec);
353
354         if (!current->disabled() && current->appendFormData(lst, m_multipart))
355         {
356             //kdDebug(6030) << "adding name " << current->name().string() << endl;
357             for(QValueListConstIterator<QCString> it = lst.begin(); it != lst.end(); ++it )
358             {
359                 if (!m_multipart)
360                 {
361                     // handle ISINDEX / <input name=isindex> special
362                     // but only if its the first entry
363                     if ( enc_string.isEmpty() && *it == "isindex" ) {
364                         ++it;
365                         enc_string += encodeCString( *it );
366                     }
367                     else {
368                         if(!enc_string.isEmpty())
369                             enc_string += '&';
370
371                         enc_string += encodeCString(*it);
372                         enc_string += "=";
373                         ++it;
374                         enc_string += encodeCString(*it);
375                     }
376                 }
377                 else
378                 {
379                     QCString hstr("--");
380                     hstr += m_boundary.string().latin1();
381                     hstr += "\r\n";
382                     hstr += "Content-Disposition: form-data; name=\"";
383                     hstr += (*it).data();
384                     hstr += "\"";
385
386                     // if the current type is FILE, then we also need to
387                     // include the filename
388                     if (current->nodeType() == Node::ELEMENT_NODE && current->id() == ID_INPUT &&
389                         static_cast<HTMLInputElementImpl*>(current)->inputType() == HTMLInputElementImpl::FILE)
390                     {
391                         QString path = static_cast<HTMLInputElementImpl*>(current)->value().string();
392 #if !APPLE_CHANGES
393                         if (path.length()) fileUploads << path;
394 #endif
395
396                         // FIXME: This won't work if the filename includes a " mark,
397                         // or control characters like CR or LF. This also does strange
398                         // things if the filename includes characters you can't encode
399                         // in the website's character set.
400                         hstr += "; filename=\"";
401                         hstr += codec->fromUnicode(path.mid(path.findRev('/') + 1));
402                         hstr += "\"";
403
404                         if(!static_cast<HTMLInputElementImpl*>(current)->value().isEmpty())
405                         {
406 #if APPLE_CHANGES
407                             QString mimeType = part ? KWQ(part)->mimeTypeForFileName(path) : QString();
408 #else
409                             KMimeType::Ptr ptr = KMimeType::findByURL(KURL(path));
410                             QString mimeType = ptr->name();
411 #endif
412                             if (!mimeType.isEmpty()) {
413                                 hstr += "\r\nContent-Type: ";
414                                 hstr += mimeType.ascii();
415                             }
416                         }
417                     }
418
419                     hstr += "\r\n\r\n";
420                     ++it;
421
422                     // append body
423                     form_data.appendData(hstr.data(), hstr.length());
424                     form_data.appendData(*it, (*it).size() - 1);
425                     form_data.appendData("\r\n", 2);
426                 }
427             }
428         }
429     }
430
431 #if !APPLE_CHANGES
432     if (fileUploads.count()) {
433         int result = KMessageBox::warningContinueCancelList( 0,
434                                                              i18n("You're about to transfer the following files from "
435                                                                   "your local computer to the Internet.\n"
436                                                                   "Do you really want to continue?"),
437                                                              fileUploads);
438
439
440         if (result == KMessageBox::Cancel) {
441             return false;
442         }
443     }
444 #endif
445
446     if (m_multipart)
447         enc_string = ("--" + m_boundary.string() + "--\r\n").ascii();
448
449     form_data.appendData(enc_string.data(), enc_string.length());
450     return true;
451 }
452
453 void HTMLFormElementImpl::setEnctype( const DOMString& type )
454 {
455     if(type.string().find("multipart", 0, false) != -1 || type.string().find("form-data", 0, false) != -1)
456     {
457         m_enctype = "multipart/form-data";
458         m_multipart = true;
459         m_post = true;
460     } else if (type.string().find("text", 0, false) != -1 || type.string().find("plain", 0, false) != -1)
461     {
462         m_enctype = "text/plain";
463         m_multipart = false;
464     }
465     else
466     {
467         m_enctype = "application/x-www-form-urlencoded";
468         m_multipart = false;
469     }
470 }
471
472 void HTMLFormElementImpl::setBoundary( const DOMString& bound )
473 {
474     m_boundary = bound;
475 }
476
477 bool HTMLFormElementImpl::prepareSubmit()
478 {
479     KHTMLPart *part = getDocument()->part();
480     if(m_insubmit || !part || part->onlyLocalReferences())
481         return m_insubmit;
482
483     m_insubmit = true;
484     m_doingsubmit = false;
485
486     if ( dispatchHTMLEvent(EventImpl::SUBMIT_EVENT,false,true) && !m_doingsubmit )
487         m_doingsubmit = true;
488
489     m_insubmit = false;
490
491     if ( m_doingsubmit )
492         submit(true);
493
494     return m_doingsubmit;
495 }
496
497 void HTMLFormElementImpl::submit( bool activateSubmitButton )
498 {
499     KHTMLView *view = getDocument()->view();
500     KHTMLPart *part = getDocument()->part();
501     if (!view || !part) {
502         return;
503     }
504
505     if ( m_insubmit ) {
506         m_doingsubmit = true;
507         return;
508     }
509
510     m_insubmit = true;
511
512 #ifdef FORMS_DEBUG
513     kdDebug( 6030 ) << "submitting!" << endl;
514 #endif
515
516     HTMLGenericFormElementImpl* firstSuccessfulSubmitButton = 0;
517     bool needButtonActivation = activateSubmitButton;   // do we need to activate a submit button?
518     
519 #if APPLE_CHANGES
520     KWQ(part)->clearRecordedFormValues();
521 #endif
522     for (QPtrListIterator<HTMLGenericFormElementImpl> it(formElements); it.current(); ++it) {
523         HTMLGenericFormElementImpl* current = it.current();
524 #if APPLE_CHANGES
525         // Our app needs to get form values for password fields for doing password autocomplete,
526         // so we are more lenient in pushing values, and let the app decide what to save when.
527         if (current->id() == ID_INPUT) {
528             HTMLInputElementImpl *input = static_cast<HTMLInputElementImpl*>(current);
529             if (input->inputType() == HTMLInputElementImpl::TEXT
530                 || input->inputType() ==  HTMLInputElementImpl::PASSWORD
531                 || input->inputType() == HTMLInputElementImpl::SEARCH)
532             {
533                 KWQ(part)->recordFormValue(input->name().string(), input->value().string(), this);
534                 if (input->renderer() && input->inputType() == HTMLInputElementImpl::SEARCH)
535                     static_cast<RenderLineEdit*>(input->renderer())->addSearchResult();
536             }
537         }
538 #else
539         if (current->id() == ID_INPUT &&
540             static_cast<HTMLInputElementImpl*>(current)->inputType() == HTMLInputElementImpl::TEXT &&
541             static_cast<HTMLInputElementImpl*>(current)->autoComplete() )
542         {
543             HTMLInputElementImpl *input = static_cast<HTMLInputElementImpl *>(current);
544             view->addFormCompletionItem(input->name().string(), input->value().string());
545         }
546 #endif
547
548         if (needButtonActivation) {
549             if (current->isActivatedSubmit()) {
550                 needButtonActivation = false;
551             } else if (firstSuccessfulSubmitButton == 0 && current->isSuccessfulSubmitButton()) {
552                 firstSuccessfulSubmitButton = current;
553             }
554         }
555     }
556
557     if (needButtonActivation && firstSuccessfulSubmitButton) {
558         firstSuccessfulSubmitButton->setActivatedSubmit(true);
559     }
560
561     FormData form_data;
562     if (formData(form_data)) {
563         if(m_post) {
564             part->submitForm( "post", m_url.string(), form_data,
565                                       m_target.string(),
566                                       enctype().string(),
567                                       boundary().string() );
568         }
569         else {
570             part->submitForm( "get", m_url.string(), form_data,
571                                       m_target.string() );
572         }
573     }
574
575     if (needButtonActivation && firstSuccessfulSubmitButton) {
576         firstSuccessfulSubmitButton->setActivatedSubmit(false);
577     }
578     
579     m_doingsubmit = m_insubmit = false;
580 }
581
582 void HTMLFormElementImpl::reset(  )
583 {
584     KHTMLPart *part = getDocument()->part();
585     if(m_inreset || !part) return;
586
587     m_inreset = true;
588
589 #ifdef FORMS_DEBUG
590     kdDebug( 6030 ) << "reset pressed!" << endl;
591 #endif
592
593     // ### DOM2 labels this event as not cancelable, however
594     // common browsers( sick! ) allow it be cancelled.
595     if ( !dispatchHTMLEvent(EventImpl::RESET_EVENT,true, true) ) {
596         m_inreset = false;
597         return;
598     }
599
600     for (QPtrListIterator<HTMLGenericFormElementImpl> it(formElements); it.current(); ++it)
601         it.current()->reset();
602
603     m_inreset = false;
604 }
605
606 void HTMLFormElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
607 {
608     switch(attr->id())
609     {
610     case ATTR_ACTION:
611 #if APPLE_CHANGES
612         {
613         bool oldURLWasSecure = formWouldHaveSecureSubmission(m_url);
614 #endif
615         m_url = khtml::parseURL(attr->value());
616 #if APPLE_CHANGES
617         bool newURLIsSecure = formWouldHaveSecureSubmission(m_url);
618
619         if (m_attached && (oldURLWasSecure != newURLIsSecure))
620             if (newURLIsSecure)
621                 getDocument()->secureFormAdded();
622             else
623                 getDocument()->secureFormRemoved();
624         }
625 #endif
626         break;
627     case ATTR_TARGET:
628         m_target = attr->value();
629         break;
630     case ATTR_METHOD:
631         if ( strcasecmp( attr->value(), "post" ) == 0 )
632             m_post = true;
633         else if ( strcasecmp( attr->value(), "get" ) == 0 )
634             m_post = false;
635         break;
636     case ATTR_ENCTYPE:
637         setEnctype( attr->value() );
638         break;
639     case ATTR_ACCEPT_CHARSET:
640         // space separated list of charsets the server
641         // accepts - see rfc2045
642         m_acceptcharset = attr->value();
643         break;
644     case ATTR_ACCEPT:
645         // ignore this one for the moment...
646         break;
647     case ATTR_AUTOCOMPLETE:
648         m_autocomplete = strcasecmp( attr->value(), "off" );
649         break;
650     case ATTR_ONSUBMIT:
651         setHTMLEventListener(EventImpl::SUBMIT_EVENT,
652             getDocument()->createHTMLEventListener(attr->value().string()));
653         break;
654     case ATTR_ONRESET:
655         setHTMLEventListener(EventImpl::RESET_EVENT,
656             getDocument()->createHTMLEventListener(attr->value().string()));
657         break;
658     case ATTR_NAME:
659         {
660             QString newNameAttr = attr->value().string();
661             if (attached() && getDocument()->isHTMLDocument()) {
662                 HTMLDocumentImpl *document = static_cast<HTMLDocumentImpl *>(getDocument());
663                 document->removeNamedImageOrForm(oldNameAttr);
664                 document->addNamedImageOrForm(newNameAttr);
665             }
666             oldNameAttr = newNameAttr;
667         }
668         break;
669     case ATTR_ID:
670         {
671             QString newIdAttr = attr->value().string();
672             if (attached() && getDocument()->isHTMLDocument()) {
673                 HTMLDocumentImpl *document = static_cast<HTMLDocumentImpl *>(getDocument());
674                 document->removeNamedImageOrForm(oldIdAttr);
675                 document->addNamedImageOrForm(newIdAttr);
676             }
677             oldIdAttr = newIdAttr;
678         }
679         // fall through
680     default:
681         HTMLElementImpl::parseHTMLAttribute(attr);
682     }
683 }
684
685 void HTMLFormElementImpl::radioClicked( HTMLGenericFormElementImpl *caller )
686 {
687     for (QPtrListIterator<HTMLGenericFormElementImpl> it(formElements); it.current(); ++it) {
688         HTMLGenericFormElementImpl *current = it.current();
689         if (current->id() == ID_INPUT &&
690             static_cast<HTMLInputElementImpl*>(current)->inputType() == HTMLInputElementImpl::RADIO &&
691             current != caller && current->form() == caller->form() && current->name() == caller->name()) {
692             static_cast<HTMLInputElementImpl*>(current)->setChecked(false);
693         }
694     }
695 }
696
697 void HTMLFormElementImpl::registerFormElement(HTMLGenericFormElementImpl *e)
698 {
699     formElements.append(e);
700 }
701
702 void HTMLFormElementImpl::removeFormElement(HTMLGenericFormElementImpl *e)
703 {
704     formElements.remove(e);
705 }
706
707 bool HTMLFormElementImpl::isURLAttribute(AttributeImpl *attr) const
708 {
709     return attr->id() == ATTR_ACTION;
710 }
711
712 // -------------------------------------------------------------------------
713
714 HTMLGenericFormElementImpl::HTMLGenericFormElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
715     : HTMLElementImpl(doc)
716 {
717     m_disabled = m_readOnly = false;
718     m_name = 0;
719
720     if (f)
721         m_form = f;
722     else
723         m_form = getForm();
724     if (m_form)
725         m_form->registerFormElement(this);
726 }
727
728 HTMLGenericFormElementImpl::~HTMLGenericFormElementImpl()
729 {
730     if (m_form)
731         m_form->removeFormElement(this);
732 }
733
734 void HTMLGenericFormElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
735 {
736     switch(attr->id())
737     {
738     case ATTR_NAME:
739         break;
740     case ATTR_DISABLED:
741         setDisabled( !attr->isNull() );
742         break;
743     case ATTR_READONLY:
744     {
745         bool m_oldreadOnly = m_readOnly;
746         m_readOnly = !attr->isNull();
747         if (m_oldreadOnly != m_readOnly) setChanged();
748         break;
749     }
750     default:
751         HTMLElementImpl::parseHTMLAttribute(attr);
752     }
753 }
754
755 void HTMLGenericFormElementImpl::attach()
756 {
757     assert(!attached());
758
759     // FIXME: This handles the case of a new form element being created by
760     // JavaScript and inserted inside a form. What it does not handle is
761     // a form element being moved from inside a form to outside, or from one
762     // inside one form to another. The reason this other case is hard to fix
763     // is that during parsing, we may have been passed a form that we are not
764     // inside, DOM-tree-wise. If so, it's hard for us to know when we should
765     // be removed from that form's element list.
766     if (!m_form) {
767         m_form = getForm();
768         if (m_form)
769             m_form->registerFormElement(this);
770     }
771
772     HTMLElementImpl::attach();
773
774     // The call to updateFromElement() needs to go after the call through
775     // to the base class's attach() because that can sometimes do a close
776     // on the renderer.
777     if (m_render) {
778         m_render->updateFromElement();
779     
780         // Delayed attachment in order to prevent FOUC can result in an object being
781         // programmatically focused before it has a render object.  If we have been focused
782         // (i.e., if we are the focusNode) then go ahead and focus our corresponding native widget.
783         // (Attach/detach can also happen as a result of display type changes, e.g., making a widget
784         // block instead of inline, and focus should be restored in that case as well.)
785         if (getDocument()->focusNode() == this && m_render->isWidget() && 
786             static_cast<RenderWidget*>(renderer())->widget())
787             static_cast<RenderWidget*>(renderer())->widget()->setFocus();
788     }
789 }
790
791 void HTMLGenericFormElementImpl::removedFromDocument()
792 {
793     if (m_form)
794         m_form->removeFormElement(this);
795     m_form = 0;
796    
797     HTMLElementImpl::removedFromDocument();
798 }
799
800 HTMLFormElementImpl *HTMLGenericFormElementImpl::getForm() const
801 {
802     NodeImpl *p = parentNode();
803     while(p)
804     {
805         if( p->id() == ID_FORM )
806             return static_cast<HTMLFormElementImpl *>(p);
807         p = p->parentNode();
808     }
809 #ifdef FORMS_DEBUG
810     kdDebug( 6030 ) << "couldn't find form!" << endl;
811 #endif
812     return 0;
813 }
814
815 DOMString HTMLGenericFormElementImpl::name() const
816 {
817     if (m_name) return m_name;
818
819 // ###
820 //     DOMString n = getDocument()->htmlMode() != DocumentImpl::XHtml ?
821 //                   getAttribute(ATTR_NAME) : getAttribute(ATTR_ID);
822     DOMString n = getAttribute(ATTR_NAME);
823     if (n.isNull())
824         return new DOMStringImpl("");
825
826     return n;
827 }
828
829 void HTMLGenericFormElementImpl::setName(const DOMString& name)
830 {
831     if (m_name) m_name->deref();
832     m_name = name.implementation();
833     if (m_name) m_name->ref();
834 }
835
836 void HTMLGenericFormElementImpl::onSelect()
837 {
838     // ### make this work with new form events architecture
839     dispatchHTMLEvent(EventImpl::SELECT_EVENT,true,false);
840 }
841
842 void HTMLGenericFormElementImpl::onChange()
843 {
844     // ### make this work with new form events architecture
845     dispatchHTMLEvent(EventImpl::CHANGE_EVENT,true,false);
846 }
847
848 bool HTMLGenericFormElementImpl::disabled() const
849 {
850     return m_disabled;
851 }
852
853 void HTMLGenericFormElementImpl::setDisabled( bool _disabled )
854 {
855     if ( m_disabled != _disabled ) {
856         m_disabled = _disabled;
857         setChanged();
858     }
859 }
860
861 void HTMLGenericFormElementImpl::recalcStyle( StyleChange ch )
862 {
863     //bool changed = changed();
864     HTMLElementImpl::recalcStyle( ch );
865
866     if (m_render /*&& changed*/)
867         m_render->updateFromElement();
868 }
869
870 bool HTMLGenericFormElementImpl::isFocusable() const
871 {
872     if (!m_render || (m_render->style() && m_render->style()->visibility() != VISIBLE))
873         return false;
874     return true;
875 }
876
877 bool HTMLGenericFormElementImpl::isKeyboardFocusable() const
878 {
879     if (isFocusable()) {
880         if (m_render->isWidget()) {
881             return static_cast<RenderWidget*>(m_render)->widget() &&
882                 (static_cast<RenderWidget*>(m_render)->widget()->focusPolicy() & QWidget::TabFocus);
883         }
884         if (getDocument()->part())
885             return getDocument()->part()->tabsToAllControls();
886     }
887     return false;
888 }
889
890 bool HTMLGenericFormElementImpl::isMouseFocusable() const
891 {
892     if (isFocusable()) {
893         if (m_render->isWidget()) {
894             return static_cast<RenderWidget*>(m_render)->widget() &&
895                 (static_cast<RenderWidget*>(m_render)->widget()->focusPolicy() & QWidget::ClickFocus);
896         }
897 #if APPLE_CHANGES
898         // For <input type=image> and <button>, we will assume no mouse focusability.  This is
899         // consistent with OS X behavior for buttons.
900         return false;
901 #else
902         return true;
903 #endif
904     }
905     return false;
906 }
907
908 void HTMLGenericFormElementImpl::defaultEventHandler(EventImpl *evt)
909 {
910     if (evt->target()==this)
911     {
912         // Report focus in/out changes to the browser extension (editable widgets only)
913         KHTMLPart *part = getDocument()->part();
914         if (evt->id()==EventImpl::DOMFOCUSIN_EVENT && isEditable() && part && m_render && m_render->isWidget()) {
915             KHTMLPartBrowserExtension *ext = static_cast<KHTMLPartBrowserExtension *>(part->browserExtension());
916             QWidget *widget = static_cast<RenderWidget*>(m_render)->widget();
917             if (ext)
918                 ext->editableWidgetFocused(widget);
919         }
920
921 #if APPLE_CHANGES
922         // We don't want this default key event handling, we'll count on
923         // Cocoa event dispatch if the event doesn't get blocked.
924 #else
925         if (evt->id()==EventImpl::KEYDOWN_EVENT ||
926             evt->id()==EventImpl::KEYUP_EVENT)
927         {
928             KeyboardEventImpl * k = static_cast<KeyboardEventImpl *>(evt);
929             if (k->keyVal() == QChar('\n').unicode() && m_render && m_render->isWidget() && k->qKeyEvent)
930                 QApplication::sendEvent(static_cast<RenderWidget *>(m_render)->widget(), k->qKeyEvent);
931         }
932 #endif
933
934         if (evt->id()==EventImpl::DOMFOCUSOUT_EVENT && isEditable() && part && m_render && m_render->isWidget()) {
935             KHTMLPartBrowserExtension *ext = static_cast<KHTMLPartBrowserExtension *>(part->browserExtension());
936             QWidget *widget = static_cast<RenderWidget*>(m_render)->widget();
937             if (ext)
938                 ext->editableWidgetBlurred(widget);
939
940             // ### Don't count popup as a valid reason for losing the focus (example: opening the options of a select
941             // combobox shouldn't emit onblur)
942         }
943     }
944     HTMLElementImpl::defaultEventHandler(evt);
945 }
946
947 bool HTMLGenericFormElementImpl::isEditable()
948 {
949     return false;
950 }
951
952 // Special chars used to encode form state strings.
953 // We pick chars that are unlikely to be used in an HTML attr, so we rarely have to really encode.
954 const char stateSeparator = '&';
955 const char stateEscape = '<';
956 static const char stateSeparatorMarker[] = "<A";
957 static const char stateEscapeMarker[] = "<<";
958
959 // Encode an element name so we can put it in a state string without colliding
960 // with our separator char.
961 static QString encodedElementName(QString str)
962 {
963     int sepLoc = str.find(stateSeparator);
964     int escLoc = str.find(stateSeparator);
965     if (sepLoc >= 0 || escLoc >= 0) {
966         QString newStr = str;
967         //   replace "<" with "<<"
968         while (escLoc >= 0) {
969             newStr.replace(escLoc, 1, stateEscapeMarker);
970             escLoc = str.find(stateSeparator, escLoc+1);
971         }
972         //   replace "&" with "<A"
973         while (sepLoc >= 0) {
974             newStr.replace(sepLoc, 1, stateSeparatorMarker);
975             sepLoc = str.find(stateSeparator, sepLoc+1);
976         }
977         return newStr;
978     } else {
979         return str;
980     }
981 }
982
983 QString HTMLGenericFormElementImpl::state( )
984 {
985     // Build a string that contains ElementName&ElementType&
986     return encodedElementName(name().string()) + stateSeparator + type().string() + stateSeparator;
987 }
988
989 QString HTMLGenericFormElementImpl::findMatchingState(QStringList &states)
990 {
991     QString encName = encodedElementName(name().string());
992     QString typeStr = type().string();
993     for (QStringList::Iterator it = states.begin(); it != states.end(); ++it) {
994         QString state = *it;
995         int sep1 = state.find(stateSeparator);
996         int sep2 = state.find(stateSeparator, sep1+1);
997         assert(sep1 >= 0);
998         assert(sep2 >= 0);
999
1000         QString nameAndType = state.left(sep2);
1001         if (encName.length() + typeStr.length() + 1 == (uint)sep2
1002             && nameAndType.startsWith(encName)
1003             && nameAndType.endsWith(typeStr))
1004         {
1005             states.remove(it);
1006             return state.mid(sep2+1);
1007         }
1008     }
1009     return QString::null;
1010 }
1011
1012 // -------------------------------------------------------------------------
1013
1014 HTMLButtonElementImpl::HTMLButtonElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
1015     : HTMLGenericFormElementImpl(doc, f)
1016 {
1017     m_type = SUBMIT;
1018     m_dirty = true;
1019     m_activeSubmit = false;
1020 }
1021
1022 HTMLButtonElementImpl::~HTMLButtonElementImpl()
1023 {
1024 }
1025
1026 NodeImpl::Id HTMLButtonElementImpl::id() const
1027 {
1028     return ID_BUTTON;
1029 }
1030
1031 DOMString HTMLButtonElementImpl::type() const
1032 {
1033     return getAttribute(ATTR_TYPE);
1034 }
1035
1036 void HTMLButtonElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
1037 {
1038     switch(attr->id())
1039     {
1040     case ATTR_TYPE:
1041         if ( strcasecmp( attr->value(), "submit" ) == 0 )
1042             m_type = SUBMIT;
1043         else if ( strcasecmp( attr->value(), "reset" ) == 0 )
1044             m_type = RESET;
1045         else if ( strcasecmp( attr->value(), "button" ) == 0 )
1046             m_type = BUTTON;
1047         break;
1048     case ATTR_VALUE:
1049         m_value = attr->value();
1050         m_currValue = m_value;
1051         break;
1052     case ATTR_ACCESSKEY:
1053         break;
1054     case ATTR_ONFOCUS:
1055         setHTMLEventListener(EventImpl::FOCUS_EVENT,
1056             getDocument()->createHTMLEventListener(attr->value().string()));
1057         break;
1058     case ATTR_ONBLUR:
1059         setHTMLEventListener(EventImpl::BLUR_EVENT,
1060             getDocument()->createHTMLEventListener(attr->value().string()));
1061         break;
1062     default:
1063         HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
1064     }
1065 }
1066
1067 void HTMLButtonElementImpl::defaultEventHandler(EventImpl *evt)
1068 {
1069     if (m_type != BUTTON && (evt->id() == EventImpl::DOMACTIVATE_EVENT)) {
1070
1071         if(m_form && m_type == SUBMIT) {
1072             m_activeSubmit = true;
1073             m_form->prepareSubmit();
1074             m_activeSubmit = false; // in case we were canceled
1075         }
1076         if(m_form && m_type == RESET) m_form->reset();
1077     }
1078     HTMLGenericFormElementImpl::defaultEventHandler(evt);
1079 }
1080
1081 bool HTMLButtonElementImpl::isSuccessfulSubmitButton() const
1082 {
1083     // HTML spec says that buttons must have names
1084     // to be considered successful. However, other browsers
1085     // do not impose this constraint. Therefore, we behave
1086     // differently and can use different buttons than the 
1087     // author intended. 
1088     // Remove the name constraint for now.
1089     // Was: m_type == SUBMIT && !m_disabled && !name().isEmpty()
1090     return m_type == SUBMIT && !m_disabled;
1091 }
1092
1093 bool HTMLButtonElementImpl::isActivatedSubmit() const
1094 {
1095     return m_activeSubmit;
1096 }
1097
1098 void HTMLButtonElementImpl::setActivatedSubmit(bool flag)
1099 {
1100     m_activeSubmit = flag;
1101 }
1102
1103 bool HTMLButtonElementImpl::appendFormData(FormDataList& encoding, bool /*multipart*/)
1104 {
1105     if (m_type != SUBMIT || name().isEmpty() || !m_activeSubmit)
1106         return false;
1107     encoding.appendData(name(), m_currValue);
1108     return true;
1109 }
1110
1111 void HTMLButtonElementImpl::click()
1112 {
1113 #if APPLE_CHANGES
1114     QWidget *widget;
1115     if (renderer() && (widget = static_cast<RenderWidget *>(renderer())->widget())) {
1116         // using this method gives us nice Cocoa user interface feedback
1117         static_cast<QButton *>(widget)->click();
1118     }
1119     else
1120 #endif
1121         HTMLGenericFormElementImpl::click();
1122 }
1123
1124 void HTMLButtonElementImpl::accessKeyAction()
1125 {   
1126     click();
1127 }
1128
1129 // -------------------------------------------------------------------------
1130
1131 HTMLFieldSetElementImpl::HTMLFieldSetElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
1132    : HTMLGenericFormElementImpl(doc, f)
1133 {
1134 }
1135
1136 HTMLFieldSetElementImpl::~HTMLFieldSetElementImpl()
1137 {
1138 }
1139
1140 bool HTMLFieldSetElementImpl::isFocusable() const
1141 {
1142     return false;
1143 }
1144
1145 NodeImpl::Id HTMLFieldSetElementImpl::id() const
1146 {
1147     return ID_FIELDSET;
1148 }
1149
1150 DOMString HTMLFieldSetElementImpl::type() const
1151 {
1152     return "fieldset";
1153 }
1154
1155 RenderObject* HTMLFieldSetElementImpl::createRenderer(RenderArena* arena, RenderStyle* style)
1156 {
1157     return new (arena) RenderFieldset(this);
1158 }
1159
1160 // -------------------------------------------------------------------------
1161
1162 HTMLInputElementImpl::HTMLInputElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
1163     : HTMLGenericFormElementImpl(doc, f), m_imageLoader(0)
1164 {
1165     m_type = TEXT;
1166     m_maxLen = -1;
1167     m_size = 20;
1168     m_checked = false;
1169     m_defaultChecked = false;
1170     m_useDefaultChecked = true;
1171     
1172     m_haveType = false;
1173     m_activeSubmit = false;
1174     m_autocomplete = true;
1175     m_inited = false;
1176
1177     xPos = 0;
1178     yPos = 0;
1179
1180 #if APPLE_CHANGES
1181     m_maxResults = 0;
1182 #endif
1183
1184     if ( m_form )
1185         m_autocomplete = f->autoComplete();
1186 }
1187
1188 HTMLInputElementImpl::~HTMLInputElementImpl()
1189 {
1190     if (getDocument()) getDocument()->deregisterMaintainsState(this);
1191     delete m_imageLoader;
1192 }
1193
1194 NodeImpl::Id HTMLInputElementImpl::id() const
1195 {
1196     return ID_INPUT;
1197 }
1198
1199 void HTMLInputElementImpl::setType(const DOMString& t)
1200 {
1201     typeEnum newType;
1202     
1203     if ( strcasecmp( t, "password" ) == 0 )
1204         newType = PASSWORD;
1205     else if ( strcasecmp( t, "checkbox" ) == 0 )
1206         newType = CHECKBOX;
1207     else if ( strcasecmp( t, "radio" ) == 0 )
1208         newType = RADIO;
1209     else if ( strcasecmp( t, "submit" ) == 0 )
1210         newType = SUBMIT;
1211     else if ( strcasecmp( t, "reset" ) == 0 )
1212         newType = RESET;
1213     else if ( strcasecmp( t, "file" ) == 0 )
1214         newType = FILE;
1215     else if ( strcasecmp( t, "hidden" ) == 0 )
1216         newType = HIDDEN;
1217     else if ( strcasecmp( t, "image" ) == 0 )
1218         newType = IMAGE;
1219     else if ( strcasecmp( t, "button" ) == 0 )
1220         newType = BUTTON;
1221     else if ( strcasecmp( t, "khtml_isindex" ) == 0 )
1222         newType = ISINDEX;
1223 #if APPLE_CHANGES
1224     else if ( strcasecmp( t, "search" ) == 0 )
1225         newType = SEARCH;
1226     else if ( strcasecmp( t, "range" ) == 0 )
1227         newType = RANGE;
1228 #endif
1229     else
1230         newType = TEXT;
1231
1232     // ### IMPORTANT: Don't allow the type to be changed to FILE after the first
1233     // type change, otherwise a JavaScript programmer would be able to set a text
1234     // field's value to something like /etc/passwd and then change it to a file field.
1235     if (m_type != newType) {
1236         if (newType == FILE && m_haveType) {
1237             // Set the attribute back to the old value.
1238             // Useful in case we were called from inside parseHTMLAttribute.
1239             setAttribute(ATTR_TYPE, type());
1240         } else {
1241             m_type = newType;
1242         }
1243     }
1244     m_haveType = true;
1245 }
1246
1247 DOMString HTMLInputElementImpl::type() const
1248 {
1249     // needs to be lowercase according to DOM spec
1250     switch (m_type) {
1251     case TEXT: return "text";
1252     case PASSWORD: return "password";
1253     case CHECKBOX: return "checkbox";
1254     case RADIO: return "radio";
1255     case SUBMIT: return "submit";
1256     case RESET: return "reset";
1257     case FILE: return "file";
1258     case HIDDEN: return "hidden";
1259     case IMAGE: return "image";
1260     case BUTTON: return "button";
1261 #if APPLE_CHANGES
1262     case SEARCH: return "search";
1263     case RANGE: return "range";
1264 #endif
1265     default: return "";
1266     }
1267 }
1268
1269 QString HTMLInputElementImpl::state( )
1270 {
1271     assert(m_type != PASSWORD);         // should never save/restore password fields
1272
1273     QString state = HTMLGenericFormElementImpl::state();
1274     switch (m_type) {
1275     case CHECKBOX:
1276     case RADIO:
1277         return state + (checked() ? "on" : "off");
1278     default:
1279         return state + value().string()+'.'; // Make sure the string is not empty!
1280     }
1281 }
1282
1283 void HTMLInputElementImpl::restoreState(QStringList &states)
1284 {
1285     assert(m_type != PASSWORD);         // should never save/restore password fields
1286     
1287     QString state = HTMLGenericFormElementImpl::findMatchingState(states);
1288     if (state.isNull()) return;
1289
1290     switch (m_type) {
1291     case CHECKBOX:
1292     case RADIO:
1293         setChecked((state == "on"));
1294         break;
1295     default:
1296         setValue(DOMString(state.left(state.length()-1)));
1297         break;
1298     }
1299 }
1300
1301 void HTMLInputElementImpl::select(  )
1302 {
1303     if(!m_render) return;
1304
1305     if (m_type == TEXT || m_type == PASSWORD)
1306         static_cast<RenderLineEdit*>(m_render)->select();
1307     else if (m_type == FILE)
1308         static_cast<RenderFileButton*>(m_render)->select();
1309 }
1310
1311 void HTMLInputElementImpl::click()
1312 {
1313     switch (inputType()) {
1314         case HIDDEN:
1315             // a no-op for this type
1316             break;
1317         case CHECKBOX:
1318         case RADIO:
1319         case SUBMIT:
1320         case RESET:
1321         case BUTTON: 
1322 #if APPLE_CHANGES
1323         {
1324             QWidget *widget;
1325             if (renderer() && (widget = static_cast<RenderWidget *>(renderer())->widget())) {
1326                 // using this method gives us nice Cocoa user interface feedback
1327                 static_cast<QButton *>(widget)->click();
1328                 break;
1329             }
1330         }
1331 #endif
1332             HTMLGenericFormElementImpl::click();
1333             break;
1334         case FILE:
1335 #if APPLE_CHANGES
1336             if (renderer()) {
1337                 static_cast<RenderFileButton *>(renderer())->click();
1338                 break;
1339             }
1340 #endif
1341             HTMLGenericFormElementImpl::click();
1342             break;
1343         case IMAGE:
1344         case ISINDEX:
1345         case PASSWORD:
1346 #if APPLE_CHANGES
1347         case SEARCH:
1348         case RANGE:
1349 #endif
1350         case TEXT:
1351             HTMLGenericFormElementImpl::click();
1352             break;
1353     }
1354 }
1355
1356 void HTMLInputElementImpl::accessKeyAction()
1357 {
1358     switch (inputType()) {
1359         case HIDDEN:
1360             // a no-op for this type
1361             break;
1362         case TEXT:
1363         case PASSWORD:
1364 #if APPLE_CHANGES
1365         case SEARCH:
1366 #endif
1367         case ISINDEX:
1368             focus();
1369             break;
1370         case CHECKBOX:
1371         case RADIO:
1372         case SUBMIT:
1373         case RESET:
1374         case IMAGE:
1375         case BUTTON:
1376         case FILE:
1377 #if APPLE_CHANGES
1378         case RANGE:
1379 #endif
1380             // focus and click
1381             focus();
1382             click();
1383             break;
1384     }
1385 }
1386
1387 bool HTMLInputElementImpl::mapToEntry(NodeImpl::Id attr, MappedAttributeEntry& result) const
1388 {
1389     switch (attr) {
1390         case ATTR_WIDTH:
1391         case ATTR_HEIGHT:
1392         case ATTR_VSPACE:
1393         case ATTR_HSPACE:
1394             result = eUniversal;
1395             return false;
1396         case ATTR_ALIGN:
1397             result = eReplaced; // Share with <img> since the alignment behavior is the same.
1398             return false;
1399         default:
1400             break;
1401     }
1402     
1403     return HTMLElementImpl::mapToEntry(attr, result);
1404 }
1405
1406 void HTMLInputElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
1407 {
1408     switch(attr->id())
1409     {
1410     case ATTR_AUTOCOMPLETE:
1411         m_autocomplete = strcasecmp( attr->value(), "off" );
1412         break;
1413     case ATTR_TYPE:
1414         setType(attr->value());
1415         if (m_type != IMAGE && m_imageLoader) {
1416             delete m_imageLoader;
1417             m_imageLoader = 0;
1418         }
1419         break;
1420     case ATTR_VALUE:
1421         if (m_value.isNull()) // We only need to setChanged if the form is looking
1422             setChanged();     // at the default value right now.
1423         break;
1424     case ATTR_CHECKED:
1425         m_defaultChecked = !attr->isNull();
1426         if (m_useDefaultChecked) {
1427             setChecked(m_defaultChecked);
1428             m_useDefaultChecked = true;
1429         }
1430         break;
1431     case ATTR_MAXLENGTH:
1432         m_maxLen = !attr->isNull() ? attr->value().toInt() : -1;
1433         setChanged();
1434         break;
1435     case ATTR_SIZE:
1436         m_size = !attr->isNull() ? attr->value().toInt() : 20;
1437         break;
1438     case ATTR_ALT:
1439         if (m_render && m_type == IMAGE)
1440             static_cast<RenderImage*>(m_render)->updateAltText();
1441         break;
1442     case ATTR_SRC:
1443         if (m_render && m_type == IMAGE) {
1444             if (!m_imageLoader)
1445                 m_imageLoader = new HTMLImageLoader(this);
1446             m_imageLoader->updateFromElement();
1447         }
1448         break;
1449     case ATTR_USEMAP:
1450     case ATTR_ACCESSKEY:
1451         // ### ignore for the moment
1452         break;
1453     case ATTR_VSPACE:
1454         addCSSLength(attr, CSS_PROP_MARGIN_TOP, attr->value());
1455         addCSSLength(attr, CSS_PROP_MARGIN_BOTTOM, attr->value());
1456         break;
1457     case ATTR_HSPACE:
1458         addCSSLength(attr, CSS_PROP_MARGIN_LEFT, attr->value());
1459         addCSSLength(attr, CSS_PROP_MARGIN_RIGHT, attr->value());
1460         break;        
1461     case ATTR_ALIGN:
1462         addHTMLAlignment(attr);
1463         break;
1464     case ATTR_WIDTH:
1465         addCSSLength(attr, CSS_PROP_WIDTH, attr->value() );
1466         break;
1467     case ATTR_HEIGHT:
1468         addCSSLength(attr, CSS_PROP_HEIGHT, attr->value() );
1469         break;
1470     case ATTR_ONFOCUS:
1471         setHTMLEventListener(EventImpl::FOCUS_EVENT,
1472             getDocument()->createHTMLEventListener(attr->value().string()));
1473         break;
1474     case ATTR_ONBLUR:
1475         setHTMLEventListener(EventImpl::BLUR_EVENT,
1476             getDocument()->createHTMLEventListener(attr->value().string()));
1477         break;
1478     case ATTR_ONSELECT:
1479         setHTMLEventListener(EventImpl::SELECT_EVENT,
1480             getDocument()->createHTMLEventListener(attr->value().string()));
1481         break;
1482     case ATTR_ONCHANGE:
1483         setHTMLEventListener(EventImpl::CHANGE_EVENT,
1484             getDocument()->createHTMLEventListener(attr->value().string()));
1485         break;
1486     case ATTR_ONINPUT:
1487         setHTMLEventListener(EventImpl::INPUT_EVENT,
1488                              getDocument()->createHTMLEventListener(attr->value().string()));
1489         break;
1490 #if APPLE_CHANGES
1491     // Search field and slider attributes all just cause updateFromElement to be called through style
1492     // recalcing.
1493     case ATTR_ONSEARCH:
1494         setHTMLEventListener(EventImpl::SEARCH_EVENT,
1495                              getDocument()->createHTMLEventListener(attr->value().string()));
1496         break;
1497     case ATTR_RESULTS:
1498         m_maxResults = !attr->isNull() ? attr->value().toInt() : 0;
1499         /* Fall through */
1500     case ATTR_AUTOSAVE:
1501     case ATTR_INCREMENTAL:
1502     case ATTR_PLACEHOLDER:
1503     case ATTR_MIN:
1504     case ATTR_MAX:
1505     case ATTR_PRECISION:
1506         setChanged();
1507         break;
1508 #endif
1509     default:
1510         HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
1511     }
1512 }
1513
1514 bool HTMLInputElementImpl::rendererIsNeeded(RenderStyle *style)
1515 {
1516     switch(m_type)
1517     {
1518     case TEXT:
1519     case PASSWORD:
1520 #if APPLE_CHANGES
1521     case SEARCH:
1522     case RANGE:
1523 #endif
1524     case ISINDEX:
1525     case CHECKBOX:
1526     case RADIO:
1527     case SUBMIT:
1528     case IMAGE:
1529     case RESET:
1530     case FILE:
1531     case BUTTON:   return HTMLGenericFormElementImpl::rendererIsNeeded(style);
1532     case HIDDEN:   return false;
1533     }
1534     assert(false);
1535     return false;
1536 }
1537
1538 RenderObject *HTMLInputElementImpl::createRenderer(RenderArena *arena, RenderStyle *style)
1539 {
1540     switch(m_type)
1541     {
1542     case TEXT:
1543     case PASSWORD:
1544 #if APPLE_CHANGES
1545     case SEARCH:
1546 #endif
1547     case ISINDEX:  return new (arena) RenderLineEdit(this);
1548     case CHECKBOX: return new (arena) RenderCheckBox(this);
1549     case RADIO:    return new (arena) RenderRadioButton(this);
1550     case SUBMIT:   return new (arena) RenderSubmitButton(this);
1551     case IMAGE:    return new (arena) RenderImageButton(this);
1552     case RESET:    return new (arena) RenderResetButton(this);
1553     case FILE:     return new (arena) RenderFileButton(this);
1554     case BUTTON:   return new (arena) RenderPushButton(this);
1555 #if APPLE_CHANGES
1556     case RANGE:    return new (arena) RenderSlider(this);
1557 #endif
1558     case HIDDEN:   break;
1559     }
1560     assert(false);
1561     return 0;
1562 }
1563
1564 void HTMLInputElementImpl::attach()
1565 {
1566     if (!m_inited) {
1567         if (!m_haveType)
1568             setType(getAttribute(ATTR_TYPE));
1569
1570         // FIXME: This needs to be dynamic, doesn't it, since someone could set this
1571         // after attachment?
1572         DOMString val = getAttribute(ATTR_VALUE);
1573         if ((uint) m_type <= ISINDEX && !val.isEmpty()) {
1574             // remove newline stuff..
1575             QString nvalue;
1576             for (unsigned int i = 0; i < val.length(); ++i)
1577                 if (val[i] >= ' ')
1578                     nvalue += val[i];
1579
1580             if (val.length() != nvalue.length())
1581                 setAttribute(ATTR_VALUE, nvalue);
1582         }
1583
1584         m_defaultChecked = (!getAttribute(ATTR_CHECKED).isNull());
1585         
1586         m_inited = true;
1587     }
1588
1589     // Disallow the width attribute on inputs other than HIDDEN and IMAGE.
1590     // Dumb Web sites will try to set the width as an attribute on form controls that aren't
1591     // images or hidden.
1592     if (hasMappedAttributes() && m_type != HIDDEN && m_type != IMAGE && !getAttribute(ATTR_WIDTH).isEmpty()) {
1593         int excCode;
1594         removeAttribute(ATTR_WIDTH, excCode);
1595     }
1596
1597     HTMLGenericFormElementImpl::attach();
1598
1599     if (m_type == IMAGE) {
1600         if (!m_imageLoader)
1601             m_imageLoader = new HTMLImageLoader(this);
1602         m_imageLoader->updateFromElement();
1603         if (renderer()) {
1604             RenderImage* imageObj = static_cast<RenderImage*>(renderer());
1605             imageObj->setImage(m_imageLoader->image());    
1606         }
1607     }
1608
1609 #if APPLE_CHANGES
1610     // note we don't deal with calling passwordFieldRemoved() on detach, because the timing
1611     // was such that it cleared our state too early
1612     if (m_type == PASSWORD)
1613         getDocument()->passwordFieldAdded();
1614 #endif
1615 }
1616
1617 DOMString HTMLInputElementImpl::altText() const
1618 {
1619     // http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#altgen
1620     // also heavily discussed by Hixie on bugzilla
1621     // note this is intentionally different to HTMLImageElementImpl::altText()
1622     DOMString alt = getAttribute( ATTR_ALT );
1623     // fall back to title attribute
1624     if ( alt.isNull() )
1625         alt = getAttribute( ATTR_TITLE );
1626     if ( alt.isNull() )
1627         alt = getAttribute( ATTR_VALUE );
1628     if ( alt.isEmpty() )
1629 #if APPLE_CHANGES
1630         alt = inputElementAltText();
1631 #else
1632         alt = i18n( "Submit" );
1633 #endif
1634
1635     return alt;
1636 }
1637
1638 bool HTMLInputElementImpl::isSuccessfulSubmitButton() const
1639 {
1640     // HTML spec says that buttons must have names
1641     // to be considered successful. However, other browsers
1642     // do not impose this constraint. Therefore, we behave
1643     // differently and can use different buttons than the 
1644     // author intended. 
1645     // Was: (m_type == SUBMIT && !name().isEmpty())
1646     return !m_disabled && (m_type == IMAGE || m_type == SUBMIT);
1647 }
1648
1649 bool HTMLInputElementImpl::isActivatedSubmit() const
1650 {
1651     return m_activeSubmit;
1652 }
1653
1654 void HTMLInputElementImpl::setActivatedSubmit(bool flag)
1655 {
1656     m_activeSubmit = flag;
1657 }
1658
1659 bool HTMLInputElementImpl::appendFormData(FormDataList &encoding, bool multipart)
1660 {
1661     // image generates its own names
1662     if (name().isEmpty() && m_type != IMAGE) return false;
1663
1664     switch (m_type) {
1665         case HIDDEN:
1666         case TEXT:
1667 #if APPLE_CHANGES
1668         case SEARCH:
1669         case RANGE:
1670 #endif
1671         case PASSWORD:
1672             // always successful
1673             encoding.appendData(name(), value());
1674             return true;
1675
1676         case CHECKBOX:
1677         case RADIO:
1678             if (checked()) {
1679                 encoding.appendData(name(), value());
1680                 return true;
1681             }
1682             break;
1683
1684         case BUTTON:
1685         case RESET:
1686             // those buttons are never successful
1687             return false;
1688
1689         case IMAGE:
1690             if (m_activeSubmit)
1691             {
1692                 encoding.appendData(name().isEmpty() ? QString::fromLatin1("x") : (name().string() + ".x"), clickX());
1693                 encoding.appendData(name().isEmpty() ? QString::fromLatin1("y") : (name().string() + ".y"), clickY());
1694                 return true;
1695             }
1696             break;
1697
1698         case SUBMIT:
1699             if (m_activeSubmit)
1700             {
1701                 QString enc_str = value().string();
1702                 if (enc_str.isEmpty())
1703                     enc_str = static_cast<RenderSubmitButton*>(m_render)->defaultLabel();
1704                 if (!enc_str.isEmpty()) {
1705                     encoding.appendData(name(), enc_str);
1706                     return true;
1707                 }
1708             }
1709             break;
1710
1711         case FILE:
1712         {
1713             // can't submit file on GET
1714             // don't submit if display: none or display: hidden
1715             if(!multipart || !renderer() || renderer()->style()->visibility() != khtml::VISIBLE)
1716                 return false;
1717
1718             // if no filename at all is entered, return successful, however empty
1719             // null would be more logical but netscape posts an empty file. argh.
1720             if (value().isEmpty()) {
1721                 encoding.appendData(name(), QString(""));
1722                 return true;
1723             }
1724
1725             KURL fileurl("file:///");
1726             fileurl.setPath(value().string());
1727             KIO::UDSEntry filestat;
1728
1729             if (!KIO::NetAccess::stat(fileurl, filestat)) {
1730 #if APPLE_CHANGES
1731                 // FIXME: Figure out how to report this error.
1732 #else
1733                 KMessageBox::sorry(0L, i18n("Error fetching file for submission:\n%1").arg(KIO::NetAccess::lastErrorString()));
1734 #endif
1735                 return false;
1736             }
1737
1738             KFileItem fileitem(filestat, fileurl, true, false);
1739             if (fileitem.isDir()) {
1740                 return false;
1741             }
1742
1743             QString local;
1744             if ( KIO::NetAccess::download(fileurl, local) )
1745             {
1746                 QFile file(local);
1747                 if (file.open(IO_ReadOnly))
1748                 {
1749                     QCString filearray(file.size()+1);
1750                     int readbytes = file.readBlock( filearray.data(), file.size());
1751                     if ( readbytes >= 0 )
1752                         filearray[readbytes] = '\0';
1753                     file.close();
1754
1755                     encoding.appendData(name(), filearray);
1756                     KIO::NetAccess::removeTempFile( local );
1757
1758                     return true;
1759                 }
1760                 return false;
1761             }
1762             else {
1763 #if APPLE_CHANGES
1764                 // FIXME: Figure out how to report this error.
1765 #else
1766                 KMessageBox::sorry(0L, i18n("Error fetching file for submission:\n%1").arg(KIO::NetAccess::lastErrorString()));
1767 #endif
1768                 return false;
1769             }
1770             break;
1771         }
1772         case ISINDEX:
1773             encoding.appendData(name(), value());
1774             return true;
1775     }
1776     return false;
1777 }
1778
1779 void HTMLInputElementImpl::reset()
1780 {
1781     setValue(DOMString());
1782     setChecked(m_defaultChecked);
1783     m_useDefaultChecked = true;
1784 }
1785
1786 void HTMLInputElementImpl::setChecked(bool _checked)
1787 {
1788     if (checked() == _checked) return;
1789
1790     if (m_form && m_type == RADIO && _checked && !name().isEmpty())
1791         m_form->radioClicked(this);
1792
1793     m_useDefaultChecked = false;
1794     m_checked = _checked;
1795     setChanged();
1796 }
1797
1798
1799 DOMString HTMLInputElementImpl::value() const
1800 {
1801     if (m_type == CHECKBOX || m_type == RADIO) {
1802         DOMString val = getAttribute(ATTR_VALUE);
1803
1804         // If no attribute exists, then just use "on" or "" based off the checked() state
1805         // of the control.
1806         if (val.isNull()) {
1807             if (checked())
1808                 return DOMString("on");
1809             else
1810                 return DOMString("");
1811         }
1812         return val;
1813     }
1814
1815     // It's important *not* to fall back to the value attribute for file inputs,
1816     // because that would allow a malicious web page to upload files by setting the
1817     // value attribute in markup.
1818     if (m_value.isNull() && m_type != FILE)
1819         return getAttribute(ATTR_VALUE);
1820     return m_value;
1821 }
1822
1823
1824 void HTMLInputElementImpl::setValue(DOMString val)
1825 {
1826     if (m_type == FILE) return;
1827
1828     m_value = val;
1829     setChanged();
1830 }
1831
1832 void HTMLInputElementImpl::blur()
1833 {
1834     if(getDocument()->focusNode() == this)
1835         getDocument()->setFocusNode(0);
1836 }
1837
1838 void HTMLInputElementImpl::focus()
1839 {
1840     getDocument()->setFocusNode(this);
1841 }
1842
1843 void HTMLInputElementImpl::defaultEventHandler(EventImpl *evt)
1844 {
1845     if (evt->isMouseEvent() &&
1846         ( evt->id() == EventImpl::KHTML_CLICK_EVENT || evt->id() == EventImpl::KHTML_DBLCLICK_EVENT ) &&
1847         m_type == IMAGE
1848         && m_render) {
1849         // record the mouse position for when we get the DOMActivate event
1850         MouseEventImpl *me = static_cast<MouseEventImpl*>(evt);
1851         int offsetX, offsetY;
1852         m_render->absolutePosition(offsetX,offsetY);
1853         xPos = me->clientX()-offsetX;
1854         yPos = me->clientY()-offsetY;
1855
1856         me->setDefaultHandled();
1857     }
1858
1859     // DOMActivate events cause the input to be "activated" - in the case of image and submit inputs, this means
1860     // actually submitting the form. For reset inputs, the form is reset. These events are sent when the user clicks
1861     // on the element, or presses enter while it is the active element. Javacsript code wishing to activate the element
1862     // must dispatch a DOMActivate event - a click event will not do the job.
1863     if ((evt->id() == EventImpl::DOMACTIVATE_EVENT) &&
1864         (m_type == IMAGE || m_type == SUBMIT || m_type == RESET)){
1865
1866         if (!m_form || !m_render)
1867             return;
1868
1869         if (m_type == RESET) {
1870             m_form->reset();
1871         }
1872         else {
1873             m_activeSubmit = true;
1874             if (!m_form->prepareSubmit()) {
1875                 xPos = 0;
1876                 yPos = 0;
1877             }
1878             m_activeSubmit = false;
1879         }
1880     }
1881
1882 #if APPLE_CHANGES
1883     // Use key press event here since sending simulated mouse events
1884     // on key down blocks the proper sending of the key press event.
1885     if (evt->id() == EventImpl::KEYPRESS_EVENT && evt->isKeyboardEvent()) {
1886         DOMString key = static_cast<KeyboardEventImpl *>(evt)->keyIdentifier();
1887         switch (m_type) {
1888             case BUTTON:
1889             case CHECKBOX:
1890             case FILE:
1891             case IMAGE:
1892             case RADIO:
1893             case RESET:
1894             case SUBMIT:
1895                 // Simulate mouse click for enter or spacebar for these types of elements.
1896                 // The AppKit already does this for spacebar for some, but not all, of them.
1897                 if (key == "U+000020" || key == "Enter") {
1898                     click();
1899                     evt->setDefaultHandled();
1900                 }
1901                 break;
1902             case HIDDEN:
1903             case ISINDEX:
1904             case PASSWORD:
1905             case RANGE:
1906             case SEARCH:
1907             case TEXT:
1908                 // Simulate mouse click on the default form button for enter for these types of elements.
1909                 if (key == "Enter" && m_form) {
1910                     m_form->submitClick();
1911                     evt->setDefaultHandled();
1912                 }
1913                 break;
1914         }
1915     }
1916 #endif
1917
1918     HTMLGenericFormElementImpl::defaultEventHandler(evt);
1919 }
1920
1921 bool HTMLInputElementImpl::isEditable()
1922 {
1923     return ((m_type == TEXT) || (m_type == PASSWORD) ||
1924             (m_type == SEARCH) || (m_type == ISINDEX) || (m_type == FILE));
1925 }
1926
1927 bool HTMLInputElementImpl::isURLAttribute(AttributeImpl *attr) const
1928 {
1929     return (attr->id() == ATTR_SRC);
1930 }
1931
1932 // -------------------------------------------------------------------------
1933
1934 HTMLLabelElementImpl::HTMLLabelElementImpl(DocumentPtr *doc)
1935     : HTMLElementImpl(doc)
1936 {
1937 }
1938
1939 HTMLLabelElementImpl::~HTMLLabelElementImpl()
1940 {
1941 }
1942
1943 bool HTMLLabelElementImpl::isFocusable() const
1944 {
1945     return false;
1946 }
1947
1948 NodeImpl::Id HTMLLabelElementImpl::id() const
1949 {
1950     return ID_LABEL;
1951 }
1952
1953 void HTMLLabelElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
1954 {
1955     switch(attr->id())
1956     {
1957     case ATTR_ONFOCUS:
1958         setHTMLEventListener(EventImpl::FOCUS_EVENT,
1959             getDocument()->createHTMLEventListener(attr->value().string()));
1960         break;
1961     case ATTR_ONBLUR:
1962         setHTMLEventListener(EventImpl::BLUR_EVENT,
1963             getDocument()->createHTMLEventListener(attr->value().string()));
1964         break;
1965     default:
1966         HTMLElementImpl::parseHTMLAttribute(attr);
1967     }
1968 }
1969
1970 ElementImpl *HTMLLabelElementImpl::formElement()
1971 {
1972     DOMString formElementId = getAttribute(ATTR_FOR);
1973     if (formElementId.isNull()) {
1974         // Search children of the label element for a form element.
1975         NodeImpl *node = this;
1976         while ((node = node->traverseNextNode(this))) {
1977             if (node->isHTMLElement()) {
1978                 HTMLElementImpl *element = static_cast<HTMLElementImpl *>(node);
1979                 if (element->isGenericFormElement()) {
1980                     return element;
1981                 }
1982             }
1983         }
1984         return 0;
1985     }
1986     if (formElementId.isEmpty())
1987         return 0;
1988     return getDocument()->getElementById(formElementId);
1989 }
1990
1991 void HTMLLabelElementImpl::accessKeyAction()
1992 {
1993     ElementImpl *element = formElement();
1994     if (element)
1995         element->accessKeyAction();
1996 }
1997
1998 // -------------------------------------------------------------------------
1999
2000 HTMLLegendElementImpl::HTMLLegendElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
2001 : HTMLGenericFormElementImpl(doc, f)
2002 {
2003 }
2004
2005 HTMLLegendElementImpl::~HTMLLegendElementImpl()
2006 {
2007 }
2008
2009 bool HTMLLegendElementImpl::isFocusable() const
2010 {
2011     return false;
2012 }
2013
2014 NodeImpl::Id HTMLLegendElementImpl::id() const
2015 {
2016     return ID_LEGEND;
2017 }
2018
2019 RenderObject* HTMLLegendElementImpl::createRenderer(RenderArena* arena, RenderStyle* style)
2020 {
2021     return new (arena) RenderLegend(this);
2022 }
2023
2024 DOMString HTMLLegendElementImpl::type() const
2025 {
2026     return "legend";
2027 }
2028
2029 // -------------------------------------------------------------------------
2030
2031 HTMLSelectElementImpl::HTMLSelectElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
2032     : HTMLGenericFormElementImpl(doc, f), m_options(0)
2033 {
2034     m_multiple = false;
2035     m_recalcListItems = false;
2036     // 0 means invalid (i.e. not set)
2037     m_size = 0;
2038     m_minwidth = 0;
2039 }
2040
2041 HTMLSelectElementImpl::~HTMLSelectElementImpl()
2042 {
2043     if (getDocument()) getDocument()->deregisterMaintainsState(this);
2044     if (m_options) {
2045         m_options->detach();
2046         m_options->deref();
2047     }
2048 }
2049
2050 NodeImpl::Id HTMLSelectElementImpl::id() const
2051 {
2052     return ID_SELECT;
2053 }
2054
2055 void HTMLSelectElementImpl::recalcStyle( StyleChange ch )
2056 {
2057     if (hasChangedChild() && m_render) {
2058         static_cast<khtml::RenderSelect*>(m_render)->setOptionsChanged(true);
2059     }
2060
2061     HTMLGenericFormElementImpl::recalcStyle( ch );
2062 }
2063
2064
2065 DOMString HTMLSelectElementImpl::type() const
2066 {
2067     return (m_multiple ? "select-multiple" : "select-one");
2068 }
2069
2070 long HTMLSelectElementImpl::selectedIndex() const
2071 {
2072     // return the number of the first option selected
2073     uint o = 0;
2074     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2075     for (unsigned int i = 0; i < items.size(); i++) {
2076         if (items[i]->id() == ID_OPTION) {
2077             if (static_cast<HTMLOptionElementImpl*>(items[i])->selected())
2078                 return o;
2079             o++;
2080         }
2081     }
2082     Q_ASSERT(m_multiple);
2083     return -1;
2084 }
2085
2086 void HTMLSelectElementImpl::setSelectedIndex( long  index )
2087 {
2088     // deselect all other options and select only the new one
2089     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2090     int listIndex;
2091     for (listIndex = 0; listIndex < int(items.size()); listIndex++) {
2092         if (items[listIndex]->id() == ID_OPTION)
2093             static_cast<HTMLOptionElementImpl*>(items[listIndex])->setSelected(false);
2094     }
2095     listIndex = optionToListIndex(index);
2096     if (listIndex >= 0)
2097         static_cast<HTMLOptionElementImpl*>(items[listIndex])->setSelected(true);
2098
2099     setChanged(true);
2100 }
2101
2102 long HTMLSelectElementImpl::length() const
2103 {
2104     int len = 0;
2105     uint i;
2106     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2107     for (i = 0; i < items.size(); i++) {
2108         if (items[i]->id() == ID_OPTION)
2109             len++;
2110     }
2111     return len;
2112 }
2113
2114 void HTMLSelectElementImpl::add( HTMLElementImpl *element, HTMLElementImpl *before )
2115 {
2116     if (!element || element->id() != ID_OPTION)
2117         return;
2118
2119     int exceptioncode = 0;
2120     insertBefore(element, before, exceptioncode);
2121     if (!exceptioncode)
2122         setRecalcListItems();
2123 }
2124
2125 void HTMLSelectElementImpl::remove( long index )
2126 {
2127     int exceptioncode = 0;
2128     int listIndex = optionToListIndex(index);
2129
2130     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2131     if(listIndex < 0 || index >= int(items.size()))
2132         return; // ### what should we do ? remove the last item?
2133
2134     removeChild(items[listIndex], exceptioncode);
2135     if( !exceptioncode )
2136         setRecalcListItems();
2137 }
2138
2139 void HTMLSelectElementImpl::blur()
2140 {
2141     if(getDocument()->focusNode() == this)
2142         getDocument()->setFocusNode(0);
2143 }
2144
2145 void HTMLSelectElementImpl::focus()
2146 {
2147     getDocument()->setFocusNode(this);
2148 }
2149
2150 DOMString HTMLSelectElementImpl::value( )
2151 {
2152     uint i;
2153     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2154     for (i = 0; i < items.size(); i++) {
2155         if ( items[i]->id() == ID_OPTION
2156             && static_cast<HTMLOptionElementImpl*>(items[i])->selected())
2157             return static_cast<HTMLOptionElementImpl*>(items[i])->value();
2158     }
2159     return DOMString("");
2160 }
2161
2162 void HTMLSelectElementImpl::setValue(DOMStringImpl* value)
2163 {
2164     // find the option with value() matching the given parameter
2165     // and make it the current selection.
2166     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2167     for (unsigned i = 0; i < items.size(); i++)
2168         if (items[i]->id() == ID_OPTION && static_cast<HTMLOptionElementImpl*>(items[i])->value() == value) {
2169             static_cast<HTMLOptionElementImpl*>(items[i])->setSelected(true);
2170             return;
2171         }
2172 }
2173
2174 QString HTMLSelectElementImpl::state( )
2175 {
2176 #if !APPLE_CHANGES
2177     QString state;
2178 #endif
2179     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2180
2181     int l = items.count();
2182
2183 #if APPLE_CHANGES
2184     QChar stateChars[l];
2185     
2186     for(int i = 0; i < l; i++)
2187         if(items[i]->id() == ID_OPTION && static_cast<HTMLOptionElementImpl*>(items[i])->selected())
2188             stateChars[i] = 'X';
2189         else
2190             stateChars[i] = '.';
2191     QString state(stateChars, l);
2192 #else /* APPLE_CHANGES not defined */
2193     state.fill('.', l);
2194     for(int i = 0; i < l; i++)
2195         if(items[i]->id() == ID_OPTION && static_cast<HTMLOptionElementImpl*>(items[i])->selected())
2196             state[i] = 'X';
2197 #endif /* APPLE_CHANGES not defined */
2198
2199     return HTMLGenericFormElementImpl::state() + state;
2200 }
2201
2202 void HTMLSelectElementImpl::restoreState(QStringList &_states)
2203 {
2204     QString _state = HTMLGenericFormElementImpl::findMatchingState(_states);
2205     if (_state.isNull()) return;
2206
2207     recalcListItems();
2208
2209     QString state = _state;
2210     if(!state.isEmpty() && !state.contains('X') && !m_multiple) {
2211         qWarning("should not happen in restoreState!");
2212 #if APPLE_CHANGES
2213         // KWQString doesn't support this operation. Should never get here anyway.
2214         //state[0] = 'X';
2215 #else
2216         state[0] = 'X';
2217 #endif
2218     }
2219
2220     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2221
2222     int l = items.count();
2223     for(int i = 0; i < l; i++) {
2224         if(items[i]->id() == ID_OPTION) {
2225             HTMLOptionElementImpl* oe = static_cast<HTMLOptionElementImpl*>(items[i]);
2226             oe->setSelected(state[i] == 'X');
2227         }
2228     }
2229     setChanged(true);
2230 }
2231
2232 NodeImpl *HTMLSelectElementImpl::insertBefore ( NodeImpl *newChild, NodeImpl *refChild, int &exceptioncode )
2233 {
2234     NodeImpl *result = HTMLGenericFormElementImpl::insertBefore(newChild,refChild, exceptioncode );
2235     if (!exceptioncode)
2236         setRecalcListItems();
2237     return result;
2238 }
2239
2240 NodeImpl *HTMLSelectElementImpl::replaceChild ( NodeImpl *newChild, NodeImpl *oldChild, int &exceptioncode )
2241 {
2242     NodeImpl *result = HTMLGenericFormElementImpl::replaceChild(newChild,oldChild, exceptioncode);
2243     if( !exceptioncode )
2244         setRecalcListItems();
2245     return result;
2246 }
2247
2248 NodeImpl *HTMLSelectElementImpl::removeChild ( NodeImpl *oldChild, int &exceptioncode )
2249 {
2250     NodeImpl *result = HTMLGenericFormElementImpl::removeChild(oldChild, exceptioncode);
2251     if( !exceptioncode )
2252         setRecalcListItems();
2253     return result;
2254 }
2255
2256 NodeImpl *HTMLSelectElementImpl::appendChild ( NodeImpl *newChild, int &exceptioncode )
2257 {
2258     NodeImpl *result = HTMLGenericFormElementImpl::appendChild(newChild, exceptioncode);
2259     if( !exceptioncode )
2260         setRecalcListItems();
2261     setChanged(true);
2262     return result;
2263 }
2264
2265 NodeImpl* HTMLSelectElementImpl::addChild(NodeImpl* newChild)
2266 {
2267     setRecalcListItems();
2268     return HTMLGenericFormElementImpl::addChild(newChild);
2269 }
2270
2271 void HTMLSelectElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
2272 {
2273     switch(attr->id())
2274     {
2275     case ATTR_SIZE:
2276         m_size = QMAX( attr->value().toInt(), 1 );
2277         break;
2278     case ATTR_WIDTH:
2279         m_minwidth = QMAX( attr->value().toInt(), 0 );
2280         break;
2281     case ATTR_MULTIPLE:
2282         m_multiple = (!attr->isNull());
2283         break;
2284     case ATTR_ACCESSKEY:
2285         // ### ignore for the moment
2286         break;
2287     case ATTR_ONFOCUS:
2288         setHTMLEventListener(EventImpl::FOCUS_EVENT,
2289             getDocument()->createHTMLEventListener(attr->value().string()));
2290         break;
2291     case ATTR_ONBLUR:
2292         setHTMLEventListener(EventImpl::BLUR_EVENT,
2293             getDocument()->createHTMLEventListener(attr->value().string()));
2294         break;
2295     case ATTR_ONCHANGE:
2296         setHTMLEventListener(EventImpl::CHANGE_EVENT,
2297             getDocument()->createHTMLEventListener(attr->value().string()));
2298         break;
2299     default:
2300         HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
2301     }
2302 }
2303
2304 RenderObject *HTMLSelectElementImpl::createRenderer(RenderArena *arena, RenderStyle *style)
2305 {
2306     return new (arena) RenderSelect(this);
2307 }
2308
2309 bool HTMLSelectElementImpl::appendFormData(FormDataList& encoded_values, bool)
2310 {
2311     bool successful = false;
2312     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2313
2314     uint i;
2315     for (i = 0; i < items.size(); i++) {
2316         if (items[i]->id() == ID_OPTION) {
2317             HTMLOptionElementImpl *option = static_cast<HTMLOptionElementImpl*>(items[i]);
2318             if (option->selected()) {
2319                 encoded_values.appendData(name(), option->value());
2320                 successful = true;
2321             }
2322         }
2323     }
2324
2325     // ### this case should not happen. make sure that we select the first option
2326     // in any case. otherwise we have no consistency with the DOM interface. FIXME!
2327     // we return the first one if it was a combobox select
2328     if (!successful && !m_multiple && m_size <= 1 && items.size() &&
2329         (items[0]->id() == ID_OPTION) ) {
2330         HTMLOptionElementImpl *option = static_cast<HTMLOptionElementImpl*>(items[0]);
2331         if (option->value().isNull())
2332             encoded_values.appendData(name(), option->text().string().stripWhiteSpace());
2333         else
2334             encoded_values.appendData(name(), option->value());
2335         successful = true;
2336     }
2337
2338     return successful;
2339 }
2340
2341 int HTMLSelectElementImpl::optionToListIndex(int optionIndex) const
2342 {
2343     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2344     if (optionIndex < 0 || optionIndex >= int(items.size()))
2345         return -1;
2346
2347     int listIndex = 0;
2348     int optionIndex2 = 0;
2349     for (;
2350          optionIndex2 < int(items.size()) && optionIndex2 <= optionIndex;
2351          listIndex++) { // not a typo!
2352         if (items[listIndex]->id() == ID_OPTION)
2353             optionIndex2++;
2354     }
2355     listIndex--;
2356     return listIndex;
2357 }
2358
2359 int HTMLSelectElementImpl::listToOptionIndex(int listIndex) const
2360 {
2361     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2362     if (listIndex < 0 || listIndex >= int(items.size()) ||
2363         items[listIndex]->id() != ID_OPTION)
2364         return -1;
2365
2366     int optionIndex = 0; // actual index of option not counting OPTGROUP entries that may be in list
2367     int i;
2368     for (i = 0; i < listIndex; i++)
2369         if (items[i]->id() == ID_OPTION)
2370             optionIndex++;
2371     return optionIndex;
2372 }
2373
2374 HTMLOptionsCollectionImpl *HTMLSelectElementImpl::options()
2375 {
2376     if (!m_options) {
2377         m_options = new HTMLOptionsCollectionImpl(this);
2378         m_options->ref();
2379     }
2380     return m_options;
2381 }
2382
2383 void HTMLSelectElementImpl::recalcListItems()
2384 {
2385     NodeImpl* current = firstChild();
2386     m_listItems.resize(0);
2387     HTMLOptionElementImpl* foundSelected = 0;
2388     while(current) {
2389         if (current->id() == ID_OPTGROUP && current->firstChild()) {
2390             // ### what if optgroup contains just comments? don't want one of no options in it...
2391             m_listItems.resize(m_listItems.size()+1);
2392             m_listItems[m_listItems.size()-1] = static_cast<HTMLGenericFormElementImpl*>(current);
2393             current = current->firstChild();
2394         }
2395         if (current->id() == ID_OPTION) {
2396             m_listItems.resize(m_listItems.size()+1);
2397             m_listItems[m_listItems.size()-1] = static_cast<HTMLGenericFormElementImpl*>(current);
2398             if (!foundSelected && !m_multiple && m_size <= 1) {
2399                 foundSelected = static_cast<HTMLOptionElementImpl*>(current);
2400                 foundSelected->m_selected = true;
2401             }
2402             else if (foundSelected && !m_multiple && static_cast<HTMLOptionElementImpl*>(current)->selected()) {
2403                 foundSelected->m_selected = false;
2404                 foundSelected = static_cast<HTMLOptionElementImpl*>(current);
2405             }
2406         }
2407         NodeImpl *parent = current->parentNode();
2408         current = current->nextSibling();
2409         if (!current) {
2410             if (parent != this)
2411                 current = parent->nextSibling();
2412         }
2413     }
2414     m_recalcListItems = false;
2415 }
2416
2417 void HTMLSelectElementImpl::childrenChanged()
2418 {
2419     setRecalcListItems();
2420
2421     HTMLGenericFormElementImpl::childrenChanged();
2422 }
2423
2424 void HTMLSelectElementImpl::setRecalcListItems()
2425 {
2426     m_recalcListItems = true;
2427     if (m_render)
2428         static_cast<khtml::RenderSelect*>(m_render)->setOptionsChanged(true);
2429     setChanged();
2430 }
2431
2432 void HTMLSelectElementImpl::reset()
2433 {
2434     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2435     uint i;
2436     for (i = 0; i < items.size(); i++) {
2437         if (items[i]->id() == ID_OPTION) {
2438             HTMLOptionElementImpl *option = static_cast<HTMLOptionElementImpl*>(items[i]);
2439             bool selected = (!option->getAttribute(ATTR_SELECTED).isNull());
2440             option->setSelected(selected);
2441         }
2442     }
2443     if ( m_render )
2444         static_cast<RenderSelect*>(m_render)->setSelectionChanged(true);
2445     setChanged( true );
2446 }
2447
2448 void HTMLSelectElementImpl::notifyOptionSelected(HTMLOptionElementImpl *selectedOption, bool selected)
2449 {
2450     if (selected && !m_multiple) {
2451         // deselect all other options
2452         QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2453         uint i;
2454         for (i = 0; i < items.size(); i++) {
2455             if (items[i]->id() == ID_OPTION)
2456                 static_cast<HTMLOptionElementImpl*>(items[i])->m_selected = (items[i] == selectedOption);
2457         }
2458     }
2459     if (m_render)
2460         static_cast<RenderSelect*>(m_render)->setSelectionChanged(true);
2461
2462     setChanged(true);
2463 }
2464
2465 #if APPLE_CHANGES
2466
2467 void HTMLSelectElementImpl::defaultEventHandler(EventImpl *evt)
2468 {
2469     // Use key press event here since sending simulated mouse events
2470     // on key down blocks the proper sending of the key press event.
2471     if (evt->id() == EventImpl::KEYPRESS_EVENT) {
2472     
2473         if (!m_form || !m_render || !evt->isKeyboardEvent())
2474             return;
2475         
2476         DOMString key = static_cast<KeyboardEventImpl *>(evt)->keyIdentifier();
2477         
2478         if (key == "Enter") {
2479             m_form->submitClick();
2480             evt->setDefaultHandled();
2481         }
2482     }
2483     HTMLGenericFormElementImpl::defaultEventHandler(evt);
2484 }
2485
2486 #endif // APPLE_CHANGES
2487
2488 void HTMLSelectElementImpl::accessKeyAction()
2489 {
2490     focus();
2491 }
2492
2493 // -------------------------------------------------------------------------
2494
2495 HTMLKeygenElementImpl::HTMLKeygenElementImpl(DocumentPtr* doc, HTMLFormElementImpl* f)
2496     : HTMLSelectElementImpl(doc, f)
2497 {
2498     QStringList keys = KSSLKeyGen::supportedKeySizes();
2499     for (QStringList::Iterator i = keys.begin(); i != keys.end(); ++i) {
2500         HTMLOptionElementImpl* o = new HTMLOptionElementImpl(doc, form());
2501         addChild(o);
2502         o->addChild(new TextImpl(doc, DOMString(*i)));
2503     }
2504 }
2505
2506 NodeImpl::Id HTMLKeygenElementImpl::id() const
2507 {
2508     return ID_KEYGEN;
2509 }
2510
2511 DOMString HTMLKeygenElementImpl::type() const
2512 {
2513     return "keygen";
2514 }
2515
2516 void HTMLKeygenElementImpl::parseHTMLAttribute(HTMLAttributeImpl* attr)
2517 {
2518     switch(attr->id())
2519     {
2520     case ATTR_CHALLENGE:
2521         m_challenge = attr->value();
2522         break;
2523     case ATTR_KEYTYPE:
2524         m_keyType = attr->value();
2525         break;
2526     default:
2527         // skip HTMLSelectElementImpl parsing!
2528         HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
2529     }
2530 }
2531
2532 bool HTMLKeygenElementImpl::appendFormData(FormDataList& encoded_values, bool)
2533 {
2534 #if APPLE_CHANGES
2535     // Only RSA is supported at this time.
2536     if (!m_keyType.isNull() && strcasecmp(m_keyType, "rsa")) {
2537         return false;
2538     }
2539     QString value = KSSLKeyGen::signedPublicKeyAndChallengeString(selectedIndex(), m_challenge.string(), getDocument()->part()->baseURL());
2540     if (value.isNull()) {
2541         return false;
2542     }
2543     encoded_values.appendData(name(), value.utf8());
2544     return true;
2545 #else
2546     bool successful = false;
2547
2548     // pop up the fancy certificate creation dialog here
2549     KSSLKeyGen *kg = new KSSLKeyGen(static_cast<RenderWidget *>(m_render)->widget(), "Key Generator", true);
2550
2551     kg->setKeySize(0);
2552     successful = (QDialog::Accepted == kg->exec());
2553
2554     delete kg;
2555
2556     encoded_values.appendData(name(), "deadbeef");
2557     
2558     return successful;
2559 #endif
2560 }
2561
2562 // -------------------------------------------------------------------------
2563
2564 HTMLOptGroupElementImpl::HTMLOptGroupElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
2565     : HTMLGenericFormElementImpl(doc, f)
2566 {
2567 }
2568
2569 HTMLOptGroupElementImpl::~HTMLOptGroupElementImpl()
2570 {
2571 }
2572
2573 bool HTMLOptGroupElementImpl::isFocusable() const
2574 {
2575     return false;
2576 }
2577
2578 NodeImpl::Id HTMLOptGroupElementImpl::id() const
2579 {
2580     return ID_OPTGROUP;
2581 }
2582
2583 DOMString HTMLOptGroupElementImpl::type() const
2584 {
2585     return "optgroup";
2586 }
2587
2588 NodeImpl *HTMLOptGroupElementImpl::insertBefore ( NodeImpl *newChild, NodeImpl *refChild, int &exceptioncode )
2589 {
2590     NodeImpl *result = HTMLGenericFormElementImpl::insertBefore(newChild,refChild, exceptioncode);
2591     if ( !exceptioncode )
2592         recalcSelectOptions();
2593     return result;
2594 }
2595
2596 NodeImpl *HTMLOptGroupElementImpl::replaceChild ( NodeImpl *newChild, NodeImpl *oldChild, int &exceptioncode )
2597 {
2598     NodeImpl *result = HTMLGenericFormElementImpl::replaceChild(newChild,oldChild, exceptioncode);
2599     if(!exceptioncode)
2600         recalcSelectOptions();
2601     return result;
2602 }
2603
2604 NodeImpl *HTMLOptGroupElementImpl::removeChild ( NodeImpl *oldChild, int &exceptioncode )
2605 {
2606     NodeImpl *result = HTMLGenericFormElementImpl::removeChild(oldChild, exceptioncode);
2607     if( !exceptioncode )
2608         recalcSelectOptions();
2609     return result;
2610 }
2611
2612 NodeImpl *HTMLOptGroupElementImpl::appendChild ( NodeImpl *newChild, int &exceptioncode )
2613 {
2614     NodeImpl *result = HTMLGenericFormElementImpl::appendChild(newChild, exceptioncode);
2615     if( !exceptioncode )
2616         recalcSelectOptions();
2617     return result;
2618 }
2619
2620 NodeImpl* HTMLOptGroupElementImpl::addChild(NodeImpl* newChild)
2621 {
2622     recalcSelectOptions();
2623
2624     return HTMLGenericFormElementImpl::addChild(newChild);
2625 }
2626
2627 void HTMLOptGroupElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
2628 {
2629     HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
2630     recalcSelectOptions();
2631 }
2632
2633 void HTMLOptGroupElementImpl::recalcSelectOptions()
2634 {
2635     NodeImpl *select = parentNode();
2636     while (select && select->id() != ID_SELECT)
2637         select = select->parentNode();
2638     if (select)
2639         static_cast<HTMLSelectElementImpl*>(select)->setRecalcListItems();
2640 }
2641
2642 // -------------------------------------------------------------------------
2643
2644 HTMLOptionElementImpl::HTMLOptionElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
2645     : HTMLGenericFormElementImpl(doc, f)
2646 {
2647     m_selected = false;
2648 }
2649
2650 bool HTMLOptionElementImpl::isFocusable() const
2651 {
2652     return false;
2653 }
2654
2655 NodeImpl::Id HTMLOptionElementImpl::id() const
2656 {
2657     return ID_OPTION;
2658 }
2659
2660 DOMString HTMLOptionElementImpl::type() const
2661 {
2662     return "option";
2663 }
2664
2665 DOMString HTMLOptionElementImpl::text() const
2666 {
2667     DOMString label;
2668     // WinIE does not use the label attribute, so as a quirk, we ignore it.
2669     if (getDocument() && !getDocument()->inCompatMode())
2670         label = getAttribute(ATTR_LABEL);
2671     if (label.isEmpty() && firstChild() && firstChild()->nodeType() == Node::TEXT_NODE) {
2672         if (firstChild()->nextSibling()) {
2673             DOMString ret = "";
2674             NodeImpl *n = firstChild();
2675             for (; n; n = n->nextSibling()) {
2676                 if (n->nodeType() == Node::TEXT_NODE ||
2677                     n->nodeType() == Node::CDATA_SECTION_NODE)
2678                     ret += n->nodeValue();
2679             }
2680             return ret;
2681         }
2682         else
2683             return firstChild()->nodeValue();
2684     }
2685     else
2686         return label;
2687 }
2688
2689 long HTMLOptionElementImpl::index() const
2690 {
2691     // Let's do this dynamically. Might be a bit slow, but we're sure
2692     // we won't forget to update a member variable in some cases...
2693     QMemArray<HTMLGenericFormElementImpl*> items = getSelect()->listItems();
2694     int l = items.count();
2695     int optionIndex = 0;
2696     for(int i = 0; i < l; i++) {
2697         if(items[i]->id() == ID_OPTION)
2698         {
2699             if (static_cast<HTMLOptionElementImpl*>(items[i]) == this)
2700                 return optionIndex;
2701             optionIndex++;
2702         }
2703     }
2704     kdWarning() << "HTMLOptionElementImpl::index(): option not found!" << endl;
2705     return 0;
2706 }
2707
2708 void HTMLOptionElementImpl::setIndex( long  )
2709 {
2710     kdWarning() << "Unimplemented HTMLOptionElementImpl::setIndex(long) called" << endl;
2711     // ###
2712 }
2713
2714 void HTMLOptionElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
2715 {
2716     switch(attr->id())
2717     {
2718     case ATTR_SELECTED:
2719         m_selected = (!attr->isNull());
2720         break;
2721     case ATTR_VALUE:
2722         m_value = attr->value();
2723         break;
2724     default:
2725         HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
2726     }
2727 }
2728
2729 DOMString HTMLOptionElementImpl::value() const
2730 {
2731     if ( !m_value.isNull() )
2732         return m_value;
2733     // Use the text if the value wasn't set.
2734     return text().string().stripWhiteSpace();
2735 }
2736
2737 void HTMLOptionElementImpl::setValue(DOMStringImpl* value)
2738 {
2739     setAttribute(ATTR_VALUE, value);
2740 }
2741
2742 void HTMLOptionElementImpl::setSelected(bool _selected)
2743 {
2744     if(m_selected == _selected)
2745         return;
2746     m_selected = _selected;
2747     HTMLSelectElementImpl *select = getSelect();
2748     if (select)
2749         select->notifyOptionSelected(this,_selected);
2750 }
2751
2752 void HTMLOptionElementImpl::childrenChanged()
2753 {
2754    HTMLSelectElementImpl *select = getSelect();
2755    if (select)
2756        select->childrenChanged();
2757 }
2758
2759 HTMLSelectElementImpl *HTMLOptionElementImpl::getSelect() const
2760 {
2761     NodeImpl *select = parentNode();
2762     while (select && select->id() != ID_SELECT)
2763         select = select->parentNode();
2764     return static_cast<HTMLSelectElementImpl*>(select);
2765 }
2766
2767 // -------------------------------------------------------------------------
2768
2769 HTMLTextAreaElementImpl::HTMLTextAreaElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
2770     : HTMLGenericFormElementImpl(doc, f)
2771 {
2772     // DTD requires rows & cols be specified, but we will provide reasonable defaults
2773     m_rows = 2;
2774     m_cols = 20;
2775     m_wrap = ta_Virtual;
2776     m_dirtyvalue = true;
2777 }
2778
2779 HTMLTextAreaElementImpl::~HTMLTextAreaElementImpl()
2780 {
2781     if (getDocument()) getDocument()->deregisterMaintainsState(this);
2782 }
2783
2784 NodeImpl::Id HTMLTextAreaElementImpl::id() const
2785 {
2786     return ID_TEXTAREA;
2787 }
2788
2789 DOMString HTMLTextAreaElementImpl::type() const
2790 {
2791     return "textarea";
2792 }
2793
2794 QString HTMLTextAreaElementImpl::state( )
2795 {
2796     // Make sure the string is not empty!
2797     return HTMLGenericFormElementImpl::state() + value().string()+'.';
2798 }
2799
2800 void HTMLTextAreaElementImpl::restoreState(QStringList &states)
2801 {
2802     QString state = HTMLGenericFormElementImpl::findMatchingState(states);
2803     if (state.isNull()) return;
2804     setDefaultValue(state.left(state.length()-1));
2805     // the close() in the rendertree will take care of transferring defaultvalue to 'value'
2806 }
2807
2808 void HTMLTextAreaElementImpl::select(  )
2809 {
2810     if (m_render)
2811         static_cast<RenderTextArea*>(m_render)->select();
2812     onSelect();
2813 }
2814
2815 void HTMLTextAreaElementImpl::childrenChanged()
2816 {
2817     setValue(defaultValue());
2818 }
2819     
2820 void HTMLTextAreaElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
2821 {
2822     switch(attr->id())
2823     {
2824     case ATTR_ROWS:
2825         m_rows = !attr->isNull() ? attr->value().toInt() : 3;
2826         if (renderer())
2827             renderer()->setNeedsLayoutAndMinMaxRecalc();
2828         break;
2829     case ATTR_COLS:
2830         m_cols = !attr->isNull() ? attr->value().toInt() : 60;
2831         if (renderer())
2832             renderer()->setNeedsLayoutAndMinMaxRecalc();
2833         break;
2834     case ATTR_WRAP:
2835         // virtual / physical is Netscape extension of HTML 3.0, now deprecated
2836         // soft/ hard / off is recommendation for HTML 4 extension by IE and NS 4
2837         if ( strcasecmp( attr->value(), "virtual" ) == 0  || strcasecmp( attr->value(), "soft") == 0)
2838             m_wrap = ta_Virtual;
2839         else if ( strcasecmp ( attr->value(), "physical" ) == 0 || strcasecmp( attr->value(), "hard") == 0)
2840             m_wrap = ta_Physical;
2841         else if(strcasecmp( attr->value(), "on" ) == 0)
2842             m_wrap = ta_Physical;
2843         else if(strcasecmp( attr->value(), "off") == 0)
2844             m_wrap = ta_NoWrap;
2845         if (renderer())
2846             renderer()->setNeedsLayoutAndMinMaxRecalc();
2847         break;
2848     case ATTR_ACCESSKEY:
2849         // ignore for the moment
2850         break;
2851     case ATTR_ONFOCUS:
2852         setHTMLEventListener(EventImpl::FOCUS_EVENT,
2853             getDocument()->createHTMLEventListener(attr->value().string()));
2854         break;
2855     case ATTR_ONBLUR:
2856         setHTMLEventListener(EventImpl::BLUR_EVENT,
2857             getDocument()->createHTMLEventListener(attr->value().string()));
2858         break;
2859     case ATTR_ONSELECT:
2860         setHTMLEventListener(EventImpl::SELECT_EVENT,
2861             getDocument()->createHTMLEventListener(attr->value().string()));
2862         break;
2863     case ATTR_ONCHANGE:
2864         setHTMLEventListener(EventImpl::CHANGE_EVENT,
2865             getDocument()->createHTMLEventListener(attr->value().string()));
2866         break;
2867     default:
2868         HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
2869     }
2870 }
2871
2872 RenderObject *HTMLTextAreaElementImpl::createRenderer(RenderArena *arena, RenderStyle *style)
2873 {
2874     return new (arena) RenderTextArea(this);
2875 }
2876
2877 bool HTMLTextAreaElementImpl::appendFormData(FormDataList& encoding, bool)
2878 {
2879     if (name().isEmpty()) return false;
2880     encoding.appendData(name(), value());
2881     return true;
2882 }
2883
2884 void HTMLTextAreaElementImpl::reset()
2885 {
2886     setValue(defaultValue());
2887 }
2888
2889 DOMString HTMLTextAreaElementImpl::value()
2890 {
2891     if ( m_dirtyvalue) {
2892         if ( m_render )
2893             m_value = static_cast<RenderTextArea*>( m_render )->text();
2894         else
2895             m_value = defaultValue().string();
2896         m_dirtyvalue = false;
2897     }
2898
2899     if ( m_value.isNull() ) return "";
2900
2901     return m_value;
2902 }
2903
2904 void HTMLTextAreaElementImpl::setValue(DOMString _value)
2905 {
2906     m_value = _value.string();
2907     m_dirtyvalue = false;
2908     setChanged(true);
2909 }
2910
2911
2912 DOMString HTMLTextAreaElementImpl::defaultValue()
2913 {
2914     DOMString val = "";
2915     // there may be comments - just grab the text nodes
2916     NodeImpl *n;
2917     for (n = firstChild(); n; n = n->nextSibling())
2918         if (n->isTextNode())
2919             val += static_cast<TextImpl*>(n)->data();
2920     if (val[0] == '\r' && val[1] == '\n') {
2921         val = val.copy();
2922         val.remove(0,2);
2923     }
2924     else if (val[0] == '\r' || val[0] == '\n') {
2925         val = val.copy();
2926         val.remove(0,1);
2927     }
2928
2929     return val;
2930 }
2931
2932 void HTMLTextAreaElementImpl::setDefaultValue(DOMString _defaultValue)
2933 {
2934     // there may be comments - remove all the text nodes and replace them with one
2935     QPtrList<NodeImpl> toRemove;
2936     NodeImpl *n;
2937     for (n = firstChild(); n; n = n->nextSibling())
2938         if (n->isTextNode())
2939             toRemove.append(n);
2940     QPtrListIterator<NodeImpl> it(toRemove);
2941     int exceptioncode = 0;
2942     for (; it.current(); ++it) {
2943         removeChild(it.current(), exceptioncode);
2944     }
2945     insertBefore(getDocument()->createTextNode(_defaultValue),firstChild(), exceptioncode);
2946     setValue(_defaultValue);
2947 }
2948
2949 void HTMLTextAreaElementImpl::blur()
2950 {
2951     if(getDocument()->focusNode() == this)
2952         getDocument()->setFocusNode(0);
2953 }
2954
2955 void HTMLTextAreaElementImpl::focus()
2956 {
2957     getDocument()->setFocusNode(this);
2958 }
2959
2960 bool HTMLTextAreaElementImpl::isEditable()
2961 {
2962     return true;
2963 }
2964
2965 void HTMLTextAreaElementImpl::accessKeyAction()
2966 {
2967     focus();
2968 }
2969
2970 // -------------------------------------------------------------------------
2971
2972 HTMLIsIndexElementImpl::HTMLIsIndexElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
2973     : HTMLInputElementImpl(doc, f)
2974 {
2975     m_type = TEXT;
2976     setName("isindex");
2977 }
2978
2979 NodeImpl::Id HTMLIsIndexElementImpl::id() const
2980 {
2981     return ID_ISINDEX;
2982 }
2983
2984 void HTMLIsIndexElementImpl::parseHTMLAttribute(HTMLAttributeImpl* attr)
2985 {
2986     switch(attr->id())
2987     {
2988     case ATTR_PROMPT:
2989         setValue(attr->value());
2990     default:
2991         // don't call HTMLInputElement::parseHTMLAttribute here, as it would
2992         // accept attributes this element does not support
2993         HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
2994     }
2995 }
2996
2997 // -------------------------------------------------------------------------
2998
2999 unsigned long HTMLOptionsCollectionImpl::length() const
3000 {
3001     // Not yet implemented.
3002     return 0;
3003 }
3004
3005 void HTMLOptionsCollectionImpl::setLength(unsigned long length)
3006 {
3007     // Not yet implemented.
3008 }
3009
3010 NodeImpl *HTMLOptionsCollectionImpl::item(unsigned long index) const
3011 {
3012     // Not yet implemented.
3013     return 0;
3014 }
3015
3016 NodeImpl *HTMLOptionsCollectionImpl::namedItem(const DOMString &name) const
3017 {
3018     // Not yet implemented.
3019     return 0;
3020 }
3021
3022 // -------------------------------------------------------------------------
3023
3024 FormDataList::FormDataList(QTextCodec *c)
3025     : m_codec(c)
3026 {
3027 }
3028
3029 void FormDataList::appendString(const QCString &s)
3030 {
3031     m_strings.append(s);
3032 }
3033
3034 void FormDataList::appendString(const QString &s)
3035 {
3036     QCString cstr = fixLineBreaks(m_codec->fromUnicode(s));
3037     cstr.truncate(cstr.length());
3038     m_strings.append(cstr);
3039 }
3040
3041 QValueListConstIterator<QCString> FormDataList::begin() const
3042 {
3043     return m_strings.begin();
3044 }
3045
3046 QValueListConstIterator<QCString> FormDataList::end() const
3047 {
3048     return m_strings.end();
3049 }
3050
3051 } // namespace