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