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