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