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