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