Reviewed by Maciej.
[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();
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::parseHTMLAttribute(HTMLAttributeImpl *attr)
1113 {
1114     switch(attr->id())
1115     {
1116     case ATTR_TYPE:
1117         if ( strcasecmp( attr->value(), "submit" ) == 0 )
1118             m_type = SUBMIT;
1119         else if ( strcasecmp( attr->value(), "reset" ) == 0 )
1120             m_type = RESET;
1121         else if ( strcasecmp( attr->value(), "button" ) == 0 )
1122             m_type = BUTTON;
1123         break;
1124     case ATTR_VALUE:
1125         m_value = attr->value();
1126         m_currValue = m_value;
1127         break;
1128     case ATTR_ACCESSKEY:
1129         break;
1130     case ATTR_ONFOCUS:
1131         setHTMLEventListener(EventImpl::FOCUS_EVENT,
1132             getDocument()->createHTMLEventListener(attr->value().string(), this));
1133         break;
1134     case ATTR_ONBLUR:
1135         setHTMLEventListener(EventImpl::BLUR_EVENT,
1136             getDocument()->createHTMLEventListener(attr->value().string(), this));
1137         break;
1138     default:
1139         HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
1140     }
1141 }
1142
1143 void HTMLButtonElementImpl::defaultEventHandler(EventImpl *evt)
1144 {
1145     if (m_type != BUTTON && (evt->id() == EventImpl::DOMACTIVATE_EVENT)) {
1146
1147         if(m_form && m_type == SUBMIT) {
1148             m_activeSubmit = true;
1149             m_form->prepareSubmit();
1150             m_activeSubmit = false; // in case we were canceled
1151         }
1152         if(m_form && m_type == RESET) m_form->reset();
1153     }
1154     HTMLGenericFormElementImpl::defaultEventHandler(evt);
1155 }
1156
1157 bool HTMLButtonElementImpl::isSuccessfulSubmitButton() const
1158 {
1159     // HTML spec says that buttons must have names
1160     // to be considered successful. However, other browsers
1161     // do not impose this constraint. Therefore, we behave
1162     // differently and can use different buttons than the 
1163     // author intended. 
1164     // Remove the name constraint for now.
1165     // Was: m_type == SUBMIT && !m_disabled && !name().isEmpty()
1166     return m_type == SUBMIT && !m_disabled;
1167 }
1168
1169 bool HTMLButtonElementImpl::isActivatedSubmit() const
1170 {
1171     return m_activeSubmit;
1172 }
1173
1174 void HTMLButtonElementImpl::setActivatedSubmit(bool flag)
1175 {
1176     m_activeSubmit = flag;
1177 }
1178
1179 bool HTMLButtonElementImpl::appendFormData(FormDataList& encoding, bool /*multipart*/)
1180 {
1181     if (m_type != SUBMIT || name().isEmpty() || !m_activeSubmit)
1182         return false;
1183     encoding.appendData(name(), m_currValue);
1184     return true;
1185 }
1186
1187 void HTMLButtonElementImpl::click()
1188 {
1189 #if APPLE_CHANGES
1190     QWidget *widget;
1191     if (renderer() && (widget = static_cast<RenderWidget *>(renderer())->widget())) {
1192         // using this method gives us nice Cocoa user interface feedback
1193         static_cast<QButton *>(widget)->click();
1194     }
1195     else
1196 #endif
1197         HTMLGenericFormElementImpl::click();
1198 }
1199
1200 void HTMLButtonElementImpl::accessKeyAction()
1201 {   
1202     click();
1203 }
1204
1205 // -------------------------------------------------------------------------
1206
1207 HTMLFieldSetElementImpl::HTMLFieldSetElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
1208    : HTMLGenericFormElementImpl(doc, f)
1209 {
1210 }
1211
1212 HTMLFieldSetElementImpl::~HTMLFieldSetElementImpl()
1213 {
1214 }
1215
1216 bool HTMLFieldSetElementImpl::isFocusable() const
1217 {
1218     return false;
1219 }
1220
1221 NodeImpl::Id HTMLFieldSetElementImpl::id() const
1222 {
1223     return ID_FIELDSET;
1224 }
1225
1226 DOMString HTMLFieldSetElementImpl::type() const
1227 {
1228     return "fieldset";
1229 }
1230
1231 RenderObject* HTMLFieldSetElementImpl::createRenderer(RenderArena* arena, RenderStyle* style)
1232 {
1233     return new (arena) RenderFieldset(this);
1234 }
1235
1236 // -------------------------------------------------------------------------
1237
1238 HTMLInputElementImpl::HTMLInputElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
1239     : HTMLGenericFormElementImpl(doc, f), m_imageLoader(0), m_valueMatchesRenderer(false)
1240 {
1241     m_type = TEXT;
1242     m_maxLen = -1;
1243     m_size = 20;
1244     m_checked = false;
1245     m_defaultChecked = false;
1246     m_useDefaultChecked = true;
1247     
1248     m_haveType = false;
1249     m_activeSubmit = false;
1250     m_autocomplete = true;
1251     m_inited = false;
1252
1253     xPos = 0;
1254     yPos = 0;
1255
1256 #if APPLE_CHANGES
1257     m_maxResults = -1;
1258 #endif
1259
1260     if ( m_form )
1261         m_autocomplete = f->autoComplete();
1262 }
1263
1264 HTMLInputElementImpl::~HTMLInputElementImpl()
1265 {
1266     if (getDocument()) getDocument()->deregisterMaintainsState(this);
1267     delete m_imageLoader;
1268 }
1269
1270 NodeImpl::Id HTMLInputElementImpl::id() const
1271 {
1272     return ID_INPUT;
1273 }
1274
1275 void HTMLInputElementImpl::setType(const DOMString& t)
1276 {
1277     typeEnum newType;
1278     
1279     if ( strcasecmp( t, "password" ) == 0 )
1280         newType = PASSWORD;
1281     else if ( strcasecmp( t, "checkbox" ) == 0 )
1282         newType = CHECKBOX;
1283     else if ( strcasecmp( t, "radio" ) == 0 )
1284         newType = RADIO;
1285     else if ( strcasecmp( t, "submit" ) == 0 )
1286         newType = SUBMIT;
1287     else if ( strcasecmp( t, "reset" ) == 0 )
1288         newType = RESET;
1289     else if ( strcasecmp( t, "file" ) == 0 )
1290         newType = FILE;
1291     else if ( strcasecmp( t, "hidden" ) == 0 )
1292         newType = HIDDEN;
1293     else if ( strcasecmp( t, "image" ) == 0 )
1294         newType = IMAGE;
1295     else if ( strcasecmp( t, "button" ) == 0 )
1296         newType = BUTTON;
1297     else if ( strcasecmp( t, "khtml_isindex" ) == 0 )
1298         newType = ISINDEX;
1299 #if APPLE_CHANGES
1300     else if ( strcasecmp( t, "search" ) == 0 )
1301         newType = SEARCH;
1302     else if ( strcasecmp( t, "range" ) == 0 )
1303         newType = RANGE;
1304 #endif
1305     else
1306         newType = TEXT;
1307
1308     // ### IMPORTANT: Don't allow the type to be changed to FILE after the first
1309     // type change, otherwise a JavaScript programmer would be able to set a text
1310     // field's value to something like /etc/passwd and then change it to a file field.
1311     if (m_type != newType) {
1312         if (newType == FILE && m_haveType) {
1313             // Set the attribute back to the old value.
1314             // Useful in case we were called from inside parseHTMLAttribute.
1315             setAttribute(ATTR_TYPE, type());
1316         } else {
1317             bool wasAttached = m_attached;
1318             if (wasAttached)
1319                 detach();
1320             bool didStoreValue = storesValueSeparateFromAttribute();
1321             m_type = newType;
1322             bool willStoreValue = storesValueSeparateFromAttribute();
1323             if (didStoreValue && !willStoreValue && !m_value.isNull()) {
1324                 setAttribute(ATTR_VALUE, m_value);
1325                 m_value = DOMString();
1326             }
1327             if (!didStoreValue && willStoreValue) {
1328                 m_value = getAttribute(ATTR_VALUE);
1329             }
1330             if (wasAttached)
1331                 attach();
1332         }
1333     }
1334     m_haveType = true;
1335 }
1336
1337 DOMString HTMLInputElementImpl::type() const
1338 {
1339     // needs to be lowercase according to DOM spec
1340     switch (m_type) {
1341     case TEXT: return "text";
1342     case PASSWORD: return "password";
1343     case CHECKBOX: return "checkbox";
1344     case RADIO: return "radio";
1345     case SUBMIT: return "submit";
1346     case RESET: return "reset";
1347     case FILE: return "file";
1348     case HIDDEN: return "hidden";
1349     case IMAGE: return "image";
1350     case BUTTON: return "button";
1351 #if APPLE_CHANGES
1352     case SEARCH: return "search";
1353     case RANGE: return "range";
1354 #endif
1355     case ISINDEX: return "";
1356     }
1357     return "";
1358 }
1359
1360 QString HTMLInputElementImpl::state( )
1361 {
1362     assert(m_type != PASSWORD);         // should never save/restore password fields
1363
1364     QString state = HTMLGenericFormElementImpl::state();
1365     switch (m_type) {
1366     case CHECKBOX:
1367     case RADIO:
1368         return state + (checked() ? "on" : "off");
1369     default:
1370         return state + value().string()+'.'; // Make sure the string is not empty!
1371     }
1372 }
1373
1374 void HTMLInputElementImpl::restoreState(QStringList &states)
1375 {
1376     assert(m_type != PASSWORD);         // should never save/restore password fields
1377     
1378     QString state = HTMLGenericFormElementImpl::findMatchingState(states);
1379     if (state.isNull()) return;
1380
1381     switch (m_type) {
1382     case CHECKBOX:
1383     case RADIO:
1384         setChecked((state == "on"));
1385         break;
1386     default:
1387         setValue(DOMString(state.left(state.length()-1)));
1388         break;
1389     }
1390 }
1391
1392 void HTMLInputElementImpl::select(  )
1393 {
1394     if(!m_render) return;
1395
1396     switch (m_type) {
1397         case FILE:
1398             static_cast<RenderFileButton*>(m_render)->select();
1399             break;
1400         case PASSWORD:
1401 #if APPLE_CHANGES
1402         case SEARCH:
1403 #endif
1404         case TEXT:
1405             static_cast<RenderLineEdit*>(m_render)->select();
1406             break;
1407         case BUTTON:
1408         case CHECKBOX:
1409         case HIDDEN:
1410         case IMAGE:
1411         case ISINDEX:
1412         case RADIO:
1413 #if APPLE_CHANGES
1414         case RANGE:
1415 #endif
1416         case RESET:
1417         case SUBMIT:
1418             break;
1419     }
1420 }
1421
1422 void HTMLInputElementImpl::click()
1423 {
1424     switch (inputType()) {
1425         case HIDDEN:
1426             // a no-op for this type
1427             break;
1428         case CHECKBOX:
1429         case RADIO:
1430         case SUBMIT:
1431         case RESET:
1432         case BUTTON: 
1433 #if APPLE_CHANGES
1434         {
1435             QWidget *widget;
1436             if (renderer() && (widget = static_cast<RenderWidget *>(renderer())->widget())) {
1437                 // using this method gives us nice Cocoa user interface feedback
1438                 static_cast<QButton *>(widget)->click();
1439                 break;
1440             }
1441         }
1442 #endif
1443             HTMLGenericFormElementImpl::click();
1444             break;
1445         case FILE:
1446 #if APPLE_CHANGES
1447             if (renderer()) {
1448                 static_cast<RenderFileButton *>(renderer())->click();
1449                 break;
1450             }
1451 #endif
1452             HTMLGenericFormElementImpl::click();
1453             break;
1454         case IMAGE:
1455         case ISINDEX:
1456         case PASSWORD:
1457 #if APPLE_CHANGES
1458         case SEARCH:
1459         case RANGE:
1460 #endif
1461         case TEXT:
1462             HTMLGenericFormElementImpl::click();
1463             break;
1464     }
1465 }
1466
1467 void HTMLInputElementImpl::accessKeyAction()
1468 {
1469     switch (inputType()) {
1470         case HIDDEN:
1471             // a no-op for this type
1472             break;
1473         case TEXT:
1474         case PASSWORD:
1475 #if APPLE_CHANGES
1476         case SEARCH:
1477 #endif
1478         case ISINDEX:
1479             focus();
1480             break;
1481         case CHECKBOX:
1482         case RADIO:
1483         case SUBMIT:
1484         case RESET:
1485         case IMAGE:
1486         case BUTTON:
1487         case FILE:
1488 #if APPLE_CHANGES
1489         case RANGE:
1490 #endif
1491             // focus and click
1492             focus();
1493             click();
1494             break;
1495     }
1496 }
1497
1498 bool HTMLInputElementImpl::mapToEntry(NodeImpl::Id attr, MappedAttributeEntry& result) const
1499 {
1500     switch (attr) {
1501         case ATTR_WIDTH:
1502         case ATTR_HEIGHT:
1503         case ATTR_VSPACE:
1504         case ATTR_HSPACE:
1505             result = eUniversal;
1506             return false;
1507         case ATTR_ALIGN:
1508             result = eReplaced; // Share with <img> since the alignment behavior is the same.
1509             return false;
1510         default:
1511             break;
1512     }
1513     
1514     return HTMLElementImpl::mapToEntry(attr, result);
1515 }
1516
1517 void HTMLInputElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
1518 {
1519     switch(attr->id())
1520     {
1521     case ATTR_AUTOCOMPLETE:
1522         m_autocomplete = strcasecmp( attr->value(), "off" );
1523         break;
1524     case ATTR_TYPE:
1525         setType(attr->value());
1526         if (m_type != IMAGE && m_imageLoader) {
1527             delete m_imageLoader;
1528             m_imageLoader = 0;
1529         }
1530         break;
1531     case ATTR_VALUE:
1532         // We only need to setChanged if the form is looking at the default value right now.
1533         if (m_value.isNull())
1534             setChanged();
1535         m_valueMatchesRenderer = false;
1536         break;
1537     case ATTR_CHECKED:
1538         m_defaultChecked = !attr->isNull();
1539         if (m_useDefaultChecked) {
1540             setChecked(m_defaultChecked);
1541             m_useDefaultChecked = true;
1542         }
1543         break;
1544     case ATTR_MAXLENGTH:
1545         m_maxLen = !attr->isNull() ? attr->value().toInt() : -1;
1546         setChanged();
1547         break;
1548     case ATTR_SIZE:
1549         m_size = !attr->isNull() ? attr->value().toInt() : 20;
1550         break;
1551     case ATTR_ALT:
1552         if (m_render && m_type == IMAGE)
1553             static_cast<RenderImage*>(m_render)->updateAltText();
1554         break;
1555     case ATTR_SRC:
1556         if (m_render && m_type == IMAGE) {
1557             if (!m_imageLoader)
1558                 m_imageLoader = new HTMLImageLoader(this);
1559             m_imageLoader->updateFromElement();
1560         }
1561         break;
1562     case ATTR_USEMAP:
1563     case ATTR_ACCESSKEY:
1564         // ### ignore for the moment
1565         break;
1566     case ATTR_VSPACE:
1567         addCSSLength(attr, CSS_PROP_MARGIN_TOP, attr->value());
1568         addCSSLength(attr, CSS_PROP_MARGIN_BOTTOM, attr->value());
1569         break;
1570     case ATTR_HSPACE:
1571         addCSSLength(attr, CSS_PROP_MARGIN_LEFT, attr->value());
1572         addCSSLength(attr, CSS_PROP_MARGIN_RIGHT, attr->value());
1573         break;        
1574     case ATTR_ALIGN:
1575         addHTMLAlignment(attr);
1576         break;
1577     case ATTR_WIDTH:
1578         addCSSLength(attr, CSS_PROP_WIDTH, attr->value() );
1579         break;
1580     case ATTR_HEIGHT:
1581         addCSSLength(attr, CSS_PROP_HEIGHT, attr->value() );
1582         break;
1583     case ATTR_ONFOCUS:
1584         setHTMLEventListener(EventImpl::FOCUS_EVENT,
1585             getDocument()->createHTMLEventListener(attr->value().string(), this));
1586         break;
1587     case ATTR_ONBLUR:
1588         setHTMLEventListener(EventImpl::BLUR_EVENT,
1589             getDocument()->createHTMLEventListener(attr->value().string(), this));
1590         break;
1591     case ATTR_ONSELECT:
1592         setHTMLEventListener(EventImpl::SELECT_EVENT,
1593             getDocument()->createHTMLEventListener(attr->value().string(), this));
1594         break;
1595     case ATTR_ONCHANGE:
1596         setHTMLEventListener(EventImpl::CHANGE_EVENT,
1597             getDocument()->createHTMLEventListener(attr->value().string(), this));
1598         break;
1599     case ATTR_ONINPUT:
1600         setHTMLEventListener(EventImpl::INPUT_EVENT,
1601                              getDocument()->createHTMLEventListener(attr->value().string(), this));
1602         break;
1603 #if APPLE_CHANGES
1604     // Search field and slider attributes all just cause updateFromElement to be called through style
1605     // recalcing.
1606     case ATTR_ONSEARCH:
1607         setHTMLEventListener(EventImpl::SEARCH_EVENT,
1608                              getDocument()->createHTMLEventListener(attr->value().string(), this));
1609         break;
1610     case ATTR_RESULTS:
1611         m_maxResults = !attr->isNull() ? attr->value().toInt() : -1;
1612         /* Fall through */
1613     case ATTR_AUTOSAVE:
1614     case ATTR_INCREMENTAL:
1615     case ATTR_PLACEHOLDER:
1616     case ATTR_MIN:
1617     case ATTR_MAX:
1618     case ATTR_PRECISION:
1619         setChanged();
1620         break;
1621 #endif
1622     default:
1623         HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
1624     }
1625 }
1626
1627 bool HTMLInputElementImpl::rendererIsNeeded(RenderStyle *style)
1628 {
1629     switch(m_type)
1630     {
1631     case TEXT:
1632     case PASSWORD:
1633 #if APPLE_CHANGES
1634     case SEARCH:
1635     case RANGE:
1636 #endif
1637     case ISINDEX:
1638     case CHECKBOX:
1639     case RADIO:
1640     case SUBMIT:
1641     case IMAGE:
1642     case RESET:
1643     case FILE:
1644     case BUTTON:   return HTMLGenericFormElementImpl::rendererIsNeeded(style);
1645     case HIDDEN:   return false;
1646     }
1647     assert(false);
1648     return false;
1649 }
1650
1651 RenderObject *HTMLInputElementImpl::createRenderer(RenderArena *arena, RenderStyle *style)
1652 {
1653     switch(m_type)
1654     {
1655     case TEXT:
1656     case PASSWORD:
1657 #if APPLE_CHANGES
1658     case SEARCH:
1659 #endif
1660     case ISINDEX:  return new (arena) RenderLineEdit(this);
1661     case CHECKBOX: return new (arena) RenderCheckBox(this);
1662     case RADIO:    return new (arena) RenderRadioButton(this);
1663     case SUBMIT:   return new (arena) RenderSubmitButton(this);
1664     case IMAGE:    return new (arena) RenderImageButton(this);
1665     case RESET:    return new (arena) RenderResetButton(this);
1666     case FILE:     return new (arena) RenderFileButton(this);
1667     case BUTTON:   return new (arena) RenderPushButton(this);
1668 #if APPLE_CHANGES
1669     case RANGE:    return new (arena) RenderSlider(this);
1670 #endif
1671     case HIDDEN:   break;
1672     }
1673     assert(false);
1674     return 0;
1675 }
1676
1677 void HTMLInputElementImpl::attach()
1678 {
1679     if (!m_inited) {
1680         if (!m_haveType)
1681             setType(getAttribute(ATTR_TYPE));
1682
1683         // FIXME: This needs to be dynamic, doesn't it, since someone could set this
1684         // after attachment?
1685         DOMString val = getAttribute(ATTR_VALUE);
1686         if ((uint) m_type <= ISINDEX && !val.isEmpty()) {
1687             // remove newline stuff..
1688             QString nvalue;
1689             for (unsigned int i = 0; i < val.length(); ++i)
1690                 if (val[i] >= ' ')
1691                     nvalue += val[i];
1692
1693             if (val.length() != nvalue.length())
1694                 setAttribute(ATTR_VALUE, nvalue);
1695         }
1696
1697         m_defaultChecked = (!getAttribute(ATTR_CHECKED).isNull());
1698         
1699         m_inited = true;
1700     }
1701
1702     // Disallow the width attribute on inputs other than HIDDEN and IMAGE.
1703     // Dumb Web sites will try to set the width as an attribute on form controls that aren't
1704     // images or hidden.
1705     if (hasMappedAttributes() && m_type != HIDDEN && m_type != IMAGE && !getAttribute(ATTR_WIDTH).isEmpty()) {
1706         int excCode;
1707         removeAttribute(ATTR_WIDTH, excCode);
1708     }
1709
1710     HTMLGenericFormElementImpl::attach();
1711
1712     if (m_type == IMAGE) {
1713         if (!m_imageLoader)
1714             m_imageLoader = new HTMLImageLoader(this);
1715         m_imageLoader->updateFromElement();
1716         if (renderer()) {
1717             RenderImage* imageObj = static_cast<RenderImage*>(renderer());
1718             imageObj->setImage(m_imageLoader->image());    
1719         }
1720     }
1721
1722 #if APPLE_CHANGES
1723     // note we don't deal with calling passwordFieldRemoved() on detach, because the timing
1724     // was such that it cleared our state too early
1725     if (m_type == PASSWORD)
1726         getDocument()->passwordFieldAdded();
1727 #endif
1728 }
1729
1730 void HTMLInputElementImpl::detach()
1731 {
1732     HTMLGenericFormElementImpl::detach();
1733     m_valueMatchesRenderer = false;
1734 }
1735
1736 DOMString HTMLInputElementImpl::altText() const
1737 {
1738     // http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#altgen
1739     // also heavily discussed by Hixie on bugzilla
1740     // note this is intentionally different to HTMLImageElementImpl::altText()
1741     DOMString alt = getAttribute( ATTR_ALT );
1742     // fall back to title attribute
1743     if ( alt.isNull() )
1744         alt = getAttribute( ATTR_TITLE );
1745     if ( alt.isNull() )
1746         alt = getAttribute( ATTR_VALUE );
1747     if ( alt.isEmpty() )
1748 #if APPLE_CHANGES
1749         alt = inputElementAltText();
1750 #else
1751         alt = i18n( "Submit" );
1752 #endif
1753
1754     return alt;
1755 }
1756
1757 bool HTMLInputElementImpl::isSuccessfulSubmitButton() const
1758 {
1759     // HTML spec says that buttons must have names
1760     // to be considered successful. However, other browsers
1761     // do not impose this constraint. Therefore, we behave
1762     // differently and can use different buttons than the 
1763     // author intended. 
1764     // Was: (m_type == SUBMIT && !name().isEmpty())
1765     return !m_disabled && (m_type == IMAGE || m_type == SUBMIT);
1766 }
1767
1768 bool HTMLInputElementImpl::isActivatedSubmit() const
1769 {
1770     return m_activeSubmit;
1771 }
1772
1773 void HTMLInputElementImpl::setActivatedSubmit(bool flag)
1774 {
1775     m_activeSubmit = flag;
1776 }
1777
1778 bool HTMLInputElementImpl::appendFormData(FormDataList &encoding, bool multipart)
1779 {
1780     // image generates its own names
1781     if (name().isEmpty() && m_type != IMAGE) return false;
1782
1783     switch (m_type) {
1784         case HIDDEN:
1785         case TEXT:
1786 #if APPLE_CHANGES
1787         case SEARCH:
1788         case RANGE:
1789 #endif
1790         case PASSWORD:
1791             // always successful
1792             encoding.appendData(name(), value());
1793             return true;
1794
1795         case CHECKBOX:
1796         case RADIO:
1797             if (checked()) {
1798                 encoding.appendData(name(), value());
1799                 return true;
1800             }
1801             break;
1802
1803         case BUTTON:
1804         case RESET:
1805             // those buttons are never successful
1806             return false;
1807
1808         case IMAGE:
1809             if (m_activeSubmit)
1810             {
1811                 encoding.appendData(name().isEmpty() ? QString::fromLatin1("x") : (name().string() + ".x"), clickX());
1812                 encoding.appendData(name().isEmpty() ? QString::fromLatin1("y") : (name().string() + ".y"), clickY());
1813                 if (!name().isEmpty() && !value().isEmpty())
1814                     encoding.appendData(name(), value());
1815                 return true;
1816             }
1817             break;
1818
1819         case SUBMIT:
1820             if (m_activeSubmit)
1821             {
1822                 QString enc_str = valueWithDefault().string();
1823                 if (!enc_str.isEmpty()) {
1824                     encoding.appendData(name(), enc_str);
1825                     return true;
1826                 }
1827             }
1828             break;
1829
1830         case FILE:
1831         {
1832             // can't submit file on GET
1833             // don't submit if display: none or display: hidden
1834             if(!multipart || !renderer() || renderer()->style()->visibility() != khtml::VISIBLE)
1835                 return false;
1836
1837             // if no filename at all is entered, return successful, however empty
1838             // null would be more logical but netscape posts an empty file. argh.
1839             if (value().isEmpty()) {
1840                 encoding.appendData(name(), QString(""));
1841                 return true;
1842             }
1843
1844 #if APPLE_CHANGES
1845             encoding.appendFile(name(), value());
1846             return true;
1847 #else
1848             KURL fileurl("file:///");
1849             fileurl.setPath(value().string());
1850             KIO::UDSEntry filestat;
1851
1852             if (!KIO::NetAccess::stat(fileurl, filestat)) {
1853                 KMessageBox::sorry(0L, i18n("Error fetching file for submission:\n%1").arg(KIO::NetAccess::lastErrorString()));
1854                 return false;
1855             }
1856
1857             KFileItem fileitem(filestat, fileurl, true, false);
1858             if (fileitem.isDir()) {
1859                 return false;
1860             }
1861
1862             QString local;
1863             if ( KIO::NetAccess::download(fileurl, local) )
1864             {
1865                 QFile file(local);
1866                 if (file.open(IO_ReadOnly))
1867                 {
1868                     QCString filearray(file.size()+1);
1869                     int readbytes = file.readBlock( filearray.data(), file.size());
1870                     if ( readbytes >= 0 )
1871                         filearray[readbytes] = '\0';
1872                     file.close();
1873
1874                     encoding.appendData(name(), filearray);
1875                     KIO::NetAccess::removeTempFile( local );
1876
1877                     return true;
1878                 }
1879                 return false;
1880             }
1881             else {
1882                 KMessageBox::sorry(0L, i18n("Error fetching file for submission:\n%1").arg(KIO::NetAccess::lastErrorString()));
1883                 return false;
1884             }
1885             break;
1886 #endif
1887         }
1888         case ISINDEX:
1889             encoding.appendData(name(), value());
1890             return true;
1891     }
1892     return false;
1893 }
1894
1895 void HTMLInputElementImpl::reset()
1896 {
1897     if (storesValueSeparateFromAttribute())
1898         setValue(DOMString());
1899     setChecked(m_defaultChecked);
1900     m_useDefaultChecked = true;
1901 }
1902
1903 void HTMLInputElementImpl::setChecked(bool _checked)
1904 {
1905     if (checked() == _checked) return;
1906
1907     if (m_form && m_type == RADIO && _checked && !name().isEmpty())
1908         m_form->radioClicked(this);
1909
1910     m_useDefaultChecked = false;
1911     m_checked = _checked;
1912     setChanged();
1913 }
1914
1915
1916 DOMString HTMLInputElementImpl::value() const
1917 {
1918     DOMString value = m_value;
1919
1920     // It's important *not* to fall back to the value attribute for file inputs,
1921     // because that would allow a malicious web page to upload files by setting the
1922     // value attribute in markup.
1923     if (value.isNull() && m_type != FILE)
1924         value = getAttribute(ATTR_VALUE);
1925
1926     // If no attribute exists, then just use "on" or "" based off the checked() state of the control.
1927     if (value.isNull() && (m_type == CHECKBOX || m_type == RADIO))
1928         return DOMString(checked() ? "on" : "");
1929
1930     return value;
1931 }
1932
1933 DOMString HTMLInputElementImpl::valueWithDefault() const
1934 {
1935     DOMString v = value();
1936     if (v.isEmpty()) {
1937         switch (m_type) {
1938             case RESET:
1939 #if APPLE_CHANGES
1940                 v = resetButtonDefaultLabel();
1941 #else
1942                 v = i18n("Reset");
1943 #endif
1944                 break;
1945
1946             case SUBMIT:
1947 #if APPLE_CHANGES
1948                 v = submitButtonDefaultLabel();
1949 #else
1950                 v = i18n("Submit");
1951 #endif
1952                 break;
1953
1954             case BUTTON:
1955             case CHECKBOX:
1956             case FILE:
1957             case HIDDEN:
1958             case IMAGE:
1959             case ISINDEX:
1960             case PASSWORD:
1961             case RADIO:
1962         #if APPLE_CHANGES
1963             case RANGE:
1964             case SEARCH:
1965         #endif
1966             case TEXT:
1967                 break;
1968         }
1969     }
1970     return v;
1971 }
1972
1973 void HTMLInputElementImpl::setValue(const DOMString &value)
1974 {
1975     if (m_type == FILE) return;
1976
1977     if (storesValueSeparateFromAttribute()) {
1978         m_value = value;
1979         setChanged();
1980     } else {
1981         setAttribute(ATTR_VALUE, value);
1982     }
1983     m_valueMatchesRenderer = false;
1984 }
1985
1986 void HTMLInputElementImpl::setValueFromRenderer(const DOMString &value)
1987 {
1988     m_value = value;
1989     m_valueMatchesRenderer = true;
1990     
1991     // Fire the "input" DOM event.
1992     dispatchHTMLEvent(EventImpl::INPUT_EVENT, true, false);
1993 }
1994
1995 bool HTMLInputElementImpl::storesValueSeparateFromAttribute() const
1996 {
1997     switch (m_type) {
1998         case BUTTON:
1999         case CHECKBOX:
2000         case FILE:
2001         case HIDDEN:
2002         case IMAGE:
2003         case RADIO:
2004 #if APPLE_CHANGES
2005         case RANGE:
2006 #endif
2007         case RESET:
2008         case SUBMIT:
2009             return false;
2010         case ISINDEX:
2011         case PASSWORD:
2012 #if APPLE_CHANGES
2013         case SEARCH:
2014 #endif
2015         case TEXT:
2016             return true;
2017     }
2018     return false;
2019 }
2020
2021 void HTMLInputElementImpl::blur()
2022 {
2023     if(getDocument()->focusNode() == this)
2024         getDocument()->setFocusNode(0);
2025 }
2026
2027 void HTMLInputElementImpl::focus()
2028 {
2029     getDocument()->setFocusNode(this);
2030 }
2031
2032 void HTMLInputElementImpl::defaultEventHandler(EventImpl *evt)
2033 {
2034     if (evt->isMouseEvent() &&
2035         ( evt->id() == EventImpl::KHTML_CLICK_EVENT || evt->id() == EventImpl::KHTML_DBLCLICK_EVENT ) &&
2036         m_type == IMAGE
2037         && m_render) {
2038         // record the mouse position for when we get the DOMActivate event
2039         MouseEventImpl *me = static_cast<MouseEventImpl*>(evt);
2040         int offsetX, offsetY;
2041         m_render->absolutePosition(offsetX,offsetY);
2042         xPos = me->clientX()-offsetX;
2043         yPos = me->clientY()-offsetY;
2044
2045         me->setDefaultHandled();
2046     }
2047
2048     // DOMActivate events cause the input to be "activated" - in the case of image and submit inputs, this means
2049     // actually submitting the form. For reset inputs, the form is reset. These events are sent when the user clicks
2050     // on the element, or presses enter while it is the active element. Javacsript code wishing to activate the element
2051     // must dispatch a DOMActivate event - a click event will not do the job.
2052     if ((evt->id() == EventImpl::DOMACTIVATE_EVENT) &&
2053         (m_type == IMAGE || m_type == SUBMIT || m_type == RESET)){
2054
2055         if (!m_form)
2056             return;
2057
2058         if (m_type == RESET) {
2059             m_form->reset();
2060         }
2061         else {
2062             m_activeSubmit = true;
2063             if (!m_form->prepareSubmit()) {
2064                 xPos = 0;
2065                 yPos = 0;
2066             }
2067             m_activeSubmit = false;
2068         }
2069     }
2070
2071 #if APPLE_CHANGES
2072     // Use key press event here since sending simulated mouse events
2073     // on key down blocks the proper sending of the key press event.
2074     if (evt->id() == EventImpl::KEYPRESS_EVENT && evt->isKeyboardEvent()) {
2075         DOMString key = static_cast<KeyboardEventImpl *>(evt)->keyIdentifier();
2076         switch (m_type) {
2077             case BUTTON:
2078             case CHECKBOX:
2079             case FILE:
2080             case IMAGE:
2081             case RADIO:
2082             case RESET:
2083             case SUBMIT:
2084                 // Simulate mouse click for enter or spacebar for these types of elements.
2085                 // The AppKit already does this for spacebar for some, but not all, of them.
2086                 if (key == "U+000020" || key == "Enter") {
2087                     click();
2088                     evt->setDefaultHandled();
2089                 }
2090                 break;
2091             case HIDDEN:
2092             case ISINDEX:
2093             case PASSWORD:
2094             case RANGE:
2095             case SEARCH:
2096             case TEXT:
2097                 // Simulate mouse click on the default form button for enter for these types of elements.
2098                 if (key == "Enter" && m_form) {
2099                     m_form->submitClick();
2100                     evt->setDefaultHandled();
2101                 }
2102                 break;
2103         }
2104     }
2105 #endif
2106
2107     HTMLGenericFormElementImpl::defaultEventHandler(evt);
2108 }
2109
2110 bool HTMLInputElementImpl::isEditable()
2111 {
2112     return ((m_type == TEXT) || (m_type == PASSWORD) ||
2113             (m_type == SEARCH) || (m_type == ISINDEX) || (m_type == FILE));
2114 }
2115
2116 bool HTMLInputElementImpl::isURLAttribute(AttributeImpl *attr) const
2117 {
2118     return (attr->id() == ATTR_SRC);
2119 }
2120
2121 // -------------------------------------------------------------------------
2122
2123 HTMLLabelElementImpl::HTMLLabelElementImpl(DocumentPtr *doc)
2124     : HTMLElementImpl(doc)
2125 {
2126 }
2127
2128 HTMLLabelElementImpl::~HTMLLabelElementImpl()
2129 {
2130 }
2131
2132 bool HTMLLabelElementImpl::isFocusable() const
2133 {
2134     return false;
2135 }
2136
2137 NodeImpl::Id HTMLLabelElementImpl::id() const
2138 {
2139     return ID_LABEL;
2140 }
2141
2142 void HTMLLabelElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
2143 {
2144     switch(attr->id())
2145     {
2146     case ATTR_ONFOCUS:
2147         setHTMLEventListener(EventImpl::FOCUS_EVENT,
2148             getDocument()->createHTMLEventListener(attr->value().string(), this));
2149         break;
2150     case ATTR_ONBLUR:
2151         setHTMLEventListener(EventImpl::BLUR_EVENT,
2152             getDocument()->createHTMLEventListener(attr->value().string(), this));
2153         break;
2154     default:
2155         HTMLElementImpl::parseHTMLAttribute(attr);
2156     }
2157 }
2158
2159 ElementImpl *HTMLLabelElementImpl::formElement()
2160 {
2161     DOMString formElementId = getAttribute(ATTR_FOR);
2162     if (formElementId.isNull()) {
2163         // Search children of the label element for a form element.
2164         NodeImpl *node = this;
2165         while ((node = node->traverseNextNode(this))) {
2166             if (node->isHTMLElement()) {
2167                 HTMLElementImpl *element = static_cast<HTMLElementImpl *>(node);
2168                 if (element->isGenericFormElement()) {
2169                     return element;
2170                 }
2171             }
2172         }
2173         return 0;
2174     }
2175     if (formElementId.isEmpty())
2176         return 0;
2177     return getDocument()->getElementById(formElementId);
2178 }
2179
2180 void HTMLLabelElementImpl::accessKeyAction()
2181 {
2182     ElementImpl *element = formElement();
2183     if (element)
2184         element->accessKeyAction();
2185 }
2186
2187 // -------------------------------------------------------------------------
2188
2189 HTMLLegendElementImpl::HTMLLegendElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
2190 : HTMLGenericFormElementImpl(doc, f)
2191 {
2192 }
2193
2194 HTMLLegendElementImpl::~HTMLLegendElementImpl()
2195 {
2196 }
2197
2198 bool HTMLLegendElementImpl::isFocusable() const
2199 {
2200     return false;
2201 }
2202
2203 NodeImpl::Id HTMLLegendElementImpl::id() const
2204 {
2205     return ID_LEGEND;
2206 }
2207
2208 RenderObject* HTMLLegendElementImpl::createRenderer(RenderArena* arena, RenderStyle* style)
2209 {
2210     return new (arena) RenderLegend(this);
2211 }
2212
2213 DOMString HTMLLegendElementImpl::type() const
2214 {
2215     return "legend";
2216 }
2217
2218 // -------------------------------------------------------------------------
2219
2220 HTMLSelectElementImpl::HTMLSelectElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
2221     : HTMLGenericFormElementImpl(doc, f), m_options(0)
2222 {
2223     m_multiple = false;
2224     m_recalcListItems = false;
2225     // 0 means invalid (i.e. not set)
2226     m_size = 0;
2227     m_minwidth = 0;
2228 }
2229
2230 HTMLSelectElementImpl::~HTMLSelectElementImpl()
2231 {
2232     if (getDocument()) getDocument()->deregisterMaintainsState(this);
2233     if (m_options) {
2234         m_options->detach();
2235         m_options->deref();
2236     }
2237 }
2238
2239 NodeImpl::Id HTMLSelectElementImpl::id() const
2240 {
2241     return ID_SELECT;
2242 }
2243
2244 void HTMLSelectElementImpl::recalcStyle( StyleChange ch )
2245 {
2246     if (hasChangedChild() && m_render) {
2247         static_cast<khtml::RenderSelect*>(m_render)->setOptionsChanged(true);
2248     }
2249
2250     HTMLGenericFormElementImpl::recalcStyle( ch );
2251 }
2252
2253
2254 DOMString HTMLSelectElementImpl::type() const
2255 {
2256     return (m_multiple ? "select-multiple" : "select-one");
2257 }
2258
2259 long HTMLSelectElementImpl::selectedIndex() const
2260 {
2261     // return the number of the first option selected
2262     uint o = 0;
2263     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2264     for (unsigned int i = 0; i < items.size(); i++) {
2265         if (items[i]->id() == ID_OPTION) {
2266             if (static_cast<HTMLOptionElementImpl*>(items[i])->selected())
2267                 return o;
2268             o++;
2269         }
2270     }
2271     Q_ASSERT(m_multiple);
2272     return -1;
2273 }
2274
2275 void HTMLSelectElementImpl::setSelectedIndex( long  index )
2276 {
2277     // deselect all other options and select only the new one
2278     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2279     int listIndex;
2280     for (listIndex = 0; listIndex < int(items.size()); listIndex++) {
2281         if (items[listIndex]->id() == ID_OPTION)
2282             static_cast<HTMLOptionElementImpl*>(items[listIndex])->setSelected(false);
2283     }
2284     listIndex = optionToListIndex(index);
2285     if (listIndex >= 0)
2286         static_cast<HTMLOptionElementImpl*>(items[listIndex])->setSelected(true);
2287
2288     setChanged(true);
2289 }
2290
2291 long HTMLSelectElementImpl::length() const
2292 {
2293     int len = 0;
2294     uint i;
2295     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2296     for (i = 0; i < items.size(); i++) {
2297         if (items[i]->id() == ID_OPTION)
2298             len++;
2299     }
2300     return len;
2301 }
2302
2303 void HTMLSelectElementImpl::add( HTMLElementImpl *element, HTMLElementImpl *before )
2304 {
2305     if (!element || element->id() != ID_OPTION)
2306         return;
2307
2308     int exceptioncode = 0;
2309     insertBefore(element, before, exceptioncode);
2310     if (!exceptioncode)
2311         setRecalcListItems();
2312 }
2313
2314 void HTMLSelectElementImpl::remove( long index )
2315 {
2316     int exceptioncode = 0;
2317     int listIndex = optionToListIndex(index);
2318
2319     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2320     if(listIndex < 0 || index >= int(items.size()))
2321         return; // ### what should we do ? remove the last item?
2322
2323     removeChild(items[listIndex], exceptioncode);
2324     if( !exceptioncode )
2325         setRecalcListItems();
2326 }
2327
2328 void HTMLSelectElementImpl::blur()
2329 {
2330     if(getDocument()->focusNode() == this)
2331         getDocument()->setFocusNode(0);
2332 }
2333
2334 void HTMLSelectElementImpl::focus()
2335 {
2336     getDocument()->setFocusNode(this);
2337 }
2338
2339 DOMString HTMLSelectElementImpl::value( )
2340 {
2341     uint i;
2342     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2343     for (i = 0; i < items.size(); i++) {
2344         if ( items[i]->id() == ID_OPTION
2345             && static_cast<HTMLOptionElementImpl*>(items[i])->selected())
2346             return static_cast<HTMLOptionElementImpl*>(items[i])->value();
2347     }
2348     return DOMString("");
2349 }
2350
2351 void HTMLSelectElementImpl::setValue(DOMStringImpl* value)
2352 {
2353     // find the option with value() matching the given parameter
2354     // and make it the current selection.
2355     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2356     for (unsigned i = 0; i < items.size(); i++)
2357         if (items[i]->id() == ID_OPTION && static_cast<HTMLOptionElementImpl*>(items[i])->value() == value) {
2358             static_cast<HTMLOptionElementImpl*>(items[i])->setSelected(true);
2359             return;
2360         }
2361 }
2362
2363 QString HTMLSelectElementImpl::state( )
2364 {
2365 #if !APPLE_CHANGES
2366     QString state;
2367 #endif
2368     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2369
2370     int l = items.count();
2371
2372 #if APPLE_CHANGES
2373     QChar stateChars[l];
2374     
2375     for(int i = 0; i < l; i++)
2376         if(items[i]->id() == ID_OPTION && static_cast<HTMLOptionElementImpl*>(items[i])->selected())
2377             stateChars[i] = 'X';
2378         else
2379             stateChars[i] = '.';
2380     QString state(stateChars, l);
2381 #else /* APPLE_CHANGES not defined */
2382     state.fill('.', l);
2383     for(int i = 0; i < l; i++)
2384         if(items[i]->id() == ID_OPTION && static_cast<HTMLOptionElementImpl*>(items[i])->selected())
2385             state[i] = 'X';
2386 #endif /* APPLE_CHANGES not defined */
2387
2388     return HTMLGenericFormElementImpl::state() + state;
2389 }
2390
2391 void HTMLSelectElementImpl::restoreState(QStringList &_states)
2392 {
2393     QString _state = HTMLGenericFormElementImpl::findMatchingState(_states);
2394     if (_state.isNull()) return;
2395
2396     recalcListItems();
2397
2398     QString state = _state;
2399     if(!state.isEmpty() && !state.contains('X') && !m_multiple) {
2400         qWarning("should not happen in restoreState!");
2401 #if APPLE_CHANGES
2402         // KWQString doesn't support this operation. Should never get here anyway.
2403         //state[0] = 'X';
2404 #else
2405         state[0] = 'X';
2406 #endif
2407     }
2408
2409     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2410
2411     int l = items.count();
2412     for(int i = 0; i < l; i++) {
2413         if(items[i]->id() == ID_OPTION) {
2414             HTMLOptionElementImpl* oe = static_cast<HTMLOptionElementImpl*>(items[i]);
2415             oe->setSelected(state[i] == 'X');
2416         }
2417     }
2418     setChanged(true);
2419 }
2420
2421 NodeImpl *HTMLSelectElementImpl::insertBefore ( NodeImpl *newChild, NodeImpl *refChild, int &exceptioncode )
2422 {
2423     NodeImpl *result = HTMLGenericFormElementImpl::insertBefore(newChild,refChild, exceptioncode );
2424     if (!exceptioncode)
2425         setRecalcListItems();
2426     return result;
2427 }
2428
2429 NodeImpl *HTMLSelectElementImpl::replaceChild ( NodeImpl *newChild, NodeImpl *oldChild, int &exceptioncode )
2430 {
2431     NodeImpl *result = HTMLGenericFormElementImpl::replaceChild(newChild,oldChild, exceptioncode);
2432     if( !exceptioncode )
2433         setRecalcListItems();
2434     return result;
2435 }
2436
2437 NodeImpl *HTMLSelectElementImpl::removeChild ( NodeImpl *oldChild, int &exceptioncode )
2438 {
2439     NodeImpl *result = HTMLGenericFormElementImpl::removeChild(oldChild, exceptioncode);
2440     if( !exceptioncode )
2441         setRecalcListItems();
2442     return result;
2443 }
2444
2445 NodeImpl *HTMLSelectElementImpl::appendChild ( NodeImpl *newChild, int &exceptioncode )
2446 {
2447     NodeImpl *result = HTMLGenericFormElementImpl::appendChild(newChild, exceptioncode);
2448     if( !exceptioncode )
2449         setRecalcListItems();
2450     setChanged(true);
2451     return result;
2452 }
2453
2454 NodeImpl* HTMLSelectElementImpl::addChild(NodeImpl* newChild)
2455 {
2456     setRecalcListItems();
2457     return HTMLGenericFormElementImpl::addChild(newChild);
2458 }
2459
2460 void HTMLSelectElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
2461 {
2462     switch(attr->id())
2463     {
2464     case ATTR_SIZE:
2465         m_size = QMAX( attr->value().toInt(), 1 );
2466         break;
2467     case ATTR_WIDTH:
2468         m_minwidth = QMAX( attr->value().toInt(), 0 );
2469         break;
2470     case ATTR_MULTIPLE:
2471         m_multiple = (!attr->isNull());
2472         break;
2473     case ATTR_ACCESSKEY:
2474         // ### ignore for the moment
2475         break;
2476     case ATTR_ONFOCUS:
2477         setHTMLEventListener(EventImpl::FOCUS_EVENT,
2478             getDocument()->createHTMLEventListener(attr->value().string(), this));
2479         break;
2480     case ATTR_ONBLUR:
2481         setHTMLEventListener(EventImpl::BLUR_EVENT,
2482             getDocument()->createHTMLEventListener(attr->value().string(), this));
2483         break;
2484     case ATTR_ONCHANGE:
2485         setHTMLEventListener(EventImpl::CHANGE_EVENT,
2486             getDocument()->createHTMLEventListener(attr->value().string(), this));
2487         break;
2488     default:
2489         HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
2490     }
2491 }
2492
2493 RenderObject *HTMLSelectElementImpl::createRenderer(RenderArena *arena, RenderStyle *style)
2494 {
2495     return new (arena) RenderSelect(this);
2496 }
2497
2498 bool HTMLSelectElementImpl::appendFormData(FormDataList& encoded_values, bool)
2499 {
2500     bool successful = false;
2501     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2502
2503     uint i;
2504     for (i = 0; i < items.size(); i++) {
2505         if (items[i]->id() == ID_OPTION) {
2506             HTMLOptionElementImpl *option = static_cast<HTMLOptionElementImpl*>(items[i]);
2507             if (option->selected()) {
2508                 encoded_values.appendData(name(), option->value());
2509                 successful = true;
2510             }
2511         }
2512     }
2513
2514     // ### this case should not happen. make sure that we select the first option
2515     // in any case. otherwise we have no consistency with the DOM interface. FIXME!
2516     // we return the first one if it was a combobox select
2517     if (!successful && !m_multiple && m_size <= 1 && items.size() &&
2518         (items[0]->id() == ID_OPTION) ) {
2519         HTMLOptionElementImpl *option = static_cast<HTMLOptionElementImpl*>(items[0]);
2520         if (option->value().isNull())
2521             encoded_values.appendData(name(), option->text().string().stripWhiteSpace());
2522         else
2523             encoded_values.appendData(name(), option->value());
2524         successful = true;
2525     }
2526
2527     return successful;
2528 }
2529
2530 int HTMLSelectElementImpl::optionToListIndex(int optionIndex) const
2531 {
2532     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2533     if (optionIndex < 0 || optionIndex >= int(items.size()))
2534         return -1;
2535
2536     int listIndex = 0;
2537     int optionIndex2 = 0;
2538     for (;
2539          optionIndex2 < int(items.size()) && optionIndex2 <= optionIndex;
2540          listIndex++) { // not a typo!
2541         if (items[listIndex]->id() == ID_OPTION)
2542             optionIndex2++;
2543     }
2544     listIndex--;
2545     return listIndex;
2546 }
2547
2548 int HTMLSelectElementImpl::listToOptionIndex(int listIndex) const
2549 {
2550     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2551     if (listIndex < 0 || listIndex >= int(items.size()) ||
2552         items[listIndex]->id() != ID_OPTION)
2553         return -1;
2554
2555     int optionIndex = 0; // actual index of option not counting OPTGROUP entries that may be in list
2556     int i;
2557     for (i = 0; i < listIndex; i++)
2558         if (items[i]->id() == ID_OPTION)
2559             optionIndex++;
2560     return optionIndex;
2561 }
2562
2563 HTMLOptionsCollectionImpl *HTMLSelectElementImpl::options()
2564 {
2565     if (!m_options) {
2566         m_options = new HTMLOptionsCollectionImpl(this);
2567         m_options->ref();
2568     }
2569     return m_options;
2570 }
2571
2572 void HTMLSelectElementImpl::recalcListItems()
2573 {
2574     NodeImpl* current = firstChild();
2575     m_listItems.resize(0);
2576     HTMLOptionElementImpl* foundSelected = 0;
2577     while(current) {
2578         if (current->id() == ID_OPTGROUP && current->firstChild()) {
2579             // ### what if optgroup contains just comments? don't want one of no options in it...
2580             m_listItems.resize(m_listItems.size()+1);
2581             m_listItems[m_listItems.size()-1] = static_cast<HTMLGenericFormElementImpl*>(current);
2582             current = current->firstChild();
2583         }
2584         if (current->id() == ID_OPTION) {
2585             m_listItems.resize(m_listItems.size()+1);
2586             m_listItems[m_listItems.size()-1] = static_cast<HTMLGenericFormElementImpl*>(current);
2587             if (!foundSelected && !m_multiple && m_size <= 1) {
2588                 foundSelected = static_cast<HTMLOptionElementImpl*>(current);
2589                 foundSelected->m_selected = true;
2590             }
2591             else if (foundSelected && !m_multiple && static_cast<HTMLOptionElementImpl*>(current)->selected()) {
2592                 foundSelected->m_selected = false;
2593                 foundSelected = static_cast<HTMLOptionElementImpl*>(current);
2594             }
2595         }
2596         NodeImpl *parent = current->parentNode();
2597         current = current->nextSibling();
2598         if (!current) {
2599             if (parent != this)
2600                 current = parent->nextSibling();
2601         }
2602     }
2603     m_recalcListItems = false;
2604 }
2605
2606 void HTMLSelectElementImpl::childrenChanged()
2607 {
2608     setRecalcListItems();
2609
2610     HTMLGenericFormElementImpl::childrenChanged();
2611 }
2612
2613 void HTMLSelectElementImpl::setRecalcListItems()
2614 {
2615     m_recalcListItems = true;
2616     if (m_render)
2617         static_cast<khtml::RenderSelect*>(m_render)->setOptionsChanged(true);
2618     setChanged();
2619 }
2620
2621 void HTMLSelectElementImpl::reset()
2622 {
2623     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2624     uint i;
2625     for (i = 0; i < items.size(); i++) {
2626         if (items[i]->id() == ID_OPTION) {
2627             HTMLOptionElementImpl *option = static_cast<HTMLOptionElementImpl*>(items[i]);
2628             bool selected = (!option->getAttribute(ATTR_SELECTED).isNull());
2629             option->setSelected(selected);
2630         }
2631     }
2632     if ( m_render )
2633         static_cast<RenderSelect*>(m_render)->setSelectionChanged(true);
2634     setChanged( true );
2635 }
2636
2637 void HTMLSelectElementImpl::notifyOptionSelected(HTMLOptionElementImpl *selectedOption, bool selected)
2638 {
2639     if (selected && !m_multiple) {
2640         // deselect all other options
2641         QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2642         uint i;
2643         for (i = 0; i < items.size(); i++) {
2644             if (items[i]->id() == ID_OPTION)
2645                 static_cast<HTMLOptionElementImpl*>(items[i])->m_selected = (items[i] == selectedOption);
2646         }
2647     }
2648     if (m_render)
2649         static_cast<RenderSelect*>(m_render)->setSelectionChanged(true);
2650
2651     setChanged(true);
2652 }
2653
2654 #if APPLE_CHANGES
2655
2656 void HTMLSelectElementImpl::defaultEventHandler(EventImpl *evt)
2657 {
2658     // Use key press event here since sending simulated mouse events
2659     // on key down blocks the proper sending of the key press event.
2660     if (evt->id() == EventImpl::KEYPRESS_EVENT) {
2661     
2662         if (!m_form || !m_render || !evt->isKeyboardEvent())
2663             return;
2664         
2665         DOMString key = static_cast<KeyboardEventImpl *>(evt)->keyIdentifier();
2666         
2667         if (key == "Enter") {
2668             m_form->submitClick();
2669             evt->setDefaultHandled();
2670         }
2671     }
2672     HTMLGenericFormElementImpl::defaultEventHandler(evt);
2673 }
2674
2675 #endif // APPLE_CHANGES
2676
2677 void HTMLSelectElementImpl::accessKeyAction()
2678 {
2679     focus();
2680 }
2681
2682 // -------------------------------------------------------------------------
2683
2684 HTMLKeygenElementImpl::HTMLKeygenElementImpl(DocumentPtr* doc, HTMLFormElementImpl* f)
2685     : HTMLSelectElementImpl(doc, f)
2686 {
2687     QStringList keys = KSSLKeyGen::supportedKeySizes();
2688     for (QStringList::Iterator i = keys.begin(); i != keys.end(); ++i) {
2689         HTMLOptionElementImpl* o = new HTMLOptionElementImpl(doc, form());
2690         addChild(o);
2691         o->addChild(new TextImpl(doc, DOMString(*i)));
2692     }
2693 }
2694
2695 NodeImpl::Id HTMLKeygenElementImpl::id() const
2696 {
2697     return ID_KEYGEN;
2698 }
2699
2700 DOMString HTMLKeygenElementImpl::type() const
2701 {
2702     return "keygen";
2703 }
2704
2705 void HTMLKeygenElementImpl::parseHTMLAttribute(HTMLAttributeImpl* attr)
2706 {
2707     switch(attr->id())
2708     {
2709     case ATTR_CHALLENGE:
2710         m_challenge = attr->value();
2711         break;
2712     case ATTR_KEYTYPE:
2713         m_keyType = attr->value();
2714         break;
2715     default:
2716         // skip HTMLSelectElementImpl parsing!
2717         HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
2718     }
2719 }
2720
2721 bool HTMLKeygenElementImpl::appendFormData(FormDataList& encoded_values, bool)
2722 {
2723 #if APPLE_CHANGES
2724     // Only RSA is supported at this time.
2725     if (!m_keyType.isNull() && strcasecmp(m_keyType, "rsa")) {
2726         return false;
2727     }
2728     QString value = KSSLKeyGen::signedPublicKeyAndChallengeString(selectedIndex(), m_challenge.string(), getDocument()->part()->baseURL());
2729     if (value.isNull()) {
2730         return false;
2731     }
2732     encoded_values.appendData(name(), value.utf8());
2733     return true;
2734 #else
2735     bool successful = false;
2736
2737     // pop up the fancy certificate creation dialog here
2738     KSSLKeyGen *kg = new KSSLKeyGen(static_cast<RenderWidget *>(m_render)->widget(), "Key Generator", true);
2739
2740     kg->setKeySize(0);
2741     successful = (QDialog::Accepted == kg->exec());
2742
2743     delete kg;
2744
2745     encoded_values.appendData(name(), "deadbeef");
2746     
2747     return successful;
2748 #endif
2749 }
2750
2751 // -------------------------------------------------------------------------
2752
2753 HTMLOptGroupElementImpl::HTMLOptGroupElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
2754     : HTMLGenericFormElementImpl(doc, f)
2755 {
2756 }
2757
2758 HTMLOptGroupElementImpl::~HTMLOptGroupElementImpl()
2759 {
2760 }
2761
2762 bool HTMLOptGroupElementImpl::isFocusable() const
2763 {
2764     return false;
2765 }
2766
2767 NodeImpl::Id HTMLOptGroupElementImpl::id() const
2768 {
2769     return ID_OPTGROUP;
2770 }
2771
2772 DOMString HTMLOptGroupElementImpl::type() const
2773 {
2774     return "optgroup";
2775 }
2776
2777 NodeImpl *HTMLOptGroupElementImpl::insertBefore ( NodeImpl *newChild, NodeImpl *refChild, int &exceptioncode )
2778 {
2779     NodeImpl *result = HTMLGenericFormElementImpl::insertBefore(newChild,refChild, exceptioncode);
2780     if ( !exceptioncode )
2781         recalcSelectOptions();
2782     return result;
2783 }
2784
2785 NodeImpl *HTMLOptGroupElementImpl::replaceChild ( NodeImpl *newChild, NodeImpl *oldChild, int &exceptioncode )
2786 {
2787     NodeImpl *result = HTMLGenericFormElementImpl::replaceChild(newChild,oldChild, exceptioncode);
2788     if(!exceptioncode)
2789         recalcSelectOptions();
2790     return result;
2791 }
2792
2793 NodeImpl *HTMLOptGroupElementImpl::removeChild ( NodeImpl *oldChild, int &exceptioncode )
2794 {
2795     NodeImpl *result = HTMLGenericFormElementImpl::removeChild(oldChild, exceptioncode);
2796     if( !exceptioncode )
2797         recalcSelectOptions();
2798     return result;
2799 }
2800
2801 NodeImpl *HTMLOptGroupElementImpl::appendChild ( NodeImpl *newChild, int &exceptioncode )
2802 {
2803     NodeImpl *result = HTMLGenericFormElementImpl::appendChild(newChild, exceptioncode);
2804     if( !exceptioncode )
2805         recalcSelectOptions();
2806     return result;
2807 }
2808
2809 NodeImpl* HTMLOptGroupElementImpl::addChild(NodeImpl* newChild)
2810 {
2811     recalcSelectOptions();
2812
2813     return HTMLGenericFormElementImpl::addChild(newChild);
2814 }
2815
2816 void HTMLOptGroupElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
2817 {
2818     HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
2819     recalcSelectOptions();
2820 }
2821
2822 void HTMLOptGroupElementImpl::recalcSelectOptions()
2823 {
2824     NodeImpl *select = parentNode();
2825     while (select && select->id() != ID_SELECT)
2826         select = select->parentNode();
2827     if (select)
2828         static_cast<HTMLSelectElementImpl*>(select)->setRecalcListItems();
2829 }
2830
2831 // -------------------------------------------------------------------------
2832
2833 HTMLOptionElementImpl::HTMLOptionElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
2834     : HTMLGenericFormElementImpl(doc, f)
2835 {
2836     m_selected = false;
2837 }
2838
2839 bool HTMLOptionElementImpl::isFocusable() const
2840 {
2841     return false;
2842 }
2843
2844 NodeImpl::Id HTMLOptionElementImpl::id() const
2845 {
2846     return ID_OPTION;
2847 }
2848
2849 DOMString HTMLOptionElementImpl::type() const
2850 {
2851     return "option";
2852 }
2853
2854 DOMString HTMLOptionElementImpl::text() const
2855 {
2856     DOMString text;
2857
2858     // WinIE does not use the label attribute, so as a quirk, we ignore it.
2859     if (getDocument() && !getDocument()->inCompatMode()) {
2860         DOMString text = getAttribute(ATTR_LABEL);
2861         if (!text.isEmpty())
2862             return text;
2863     }
2864
2865     const NodeImpl *n = this;
2866     while ((n = n->traverseNextNode(this))) {
2867         if (n->nodeType() == Node::TEXT_NODE || n->nodeType() == Node::CDATA_SECTION_NODE)
2868             text += n->nodeValue();
2869     }
2870
2871     return text;
2872 }
2873
2874 long HTMLOptionElementImpl::index() const
2875 {
2876     // Let's do this dynamically. Might be a bit slow, but we're sure
2877     // we won't forget to update a member variable in some cases...
2878     QMemArray<HTMLGenericFormElementImpl*> items = getSelect()->listItems();
2879     int l = items.count();
2880     int optionIndex = 0;
2881     for(int i = 0; i < l; i++) {
2882         if(items[i]->id() == ID_OPTION)
2883         {
2884             if (static_cast<HTMLOptionElementImpl*>(items[i]) == this)
2885                 return optionIndex;
2886             optionIndex++;
2887         }
2888     }
2889     kdWarning() << "HTMLOptionElementImpl::index(): option not found!" << endl;
2890     return 0;
2891 }
2892
2893 void HTMLOptionElementImpl::setIndex( long  )
2894 {
2895     kdWarning() << "Unimplemented HTMLOptionElementImpl::setIndex(long) called" << endl;
2896     // ###
2897 }
2898
2899 void HTMLOptionElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
2900 {
2901     switch(attr->id())
2902     {
2903     case ATTR_SELECTED:
2904         m_selected = (!attr->isNull());
2905         break;
2906     case ATTR_VALUE:
2907         m_value = attr->value();
2908         break;
2909     default:
2910         HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
2911     }
2912 }
2913
2914 DOMString HTMLOptionElementImpl::value() const
2915 {
2916     if ( !m_value.isNull() )
2917         return m_value;
2918     // Use the text if the value wasn't set.
2919     return text().string().stripWhiteSpace();
2920 }
2921
2922 void HTMLOptionElementImpl::setValue(DOMStringImpl* value)
2923 {
2924     setAttribute(ATTR_VALUE, value);
2925 }
2926
2927 void HTMLOptionElementImpl::setSelected(bool _selected)
2928 {
2929     if(m_selected == _selected)
2930         return;
2931     m_selected = _selected;
2932     HTMLSelectElementImpl *select = getSelect();
2933     if (select)
2934         select->notifyOptionSelected(this,_selected);
2935 }
2936
2937 void HTMLOptionElementImpl::childrenChanged()
2938 {
2939    HTMLSelectElementImpl *select = getSelect();
2940    if (select)
2941        select->childrenChanged();
2942 }
2943
2944 HTMLSelectElementImpl *HTMLOptionElementImpl::getSelect() const
2945 {
2946     NodeImpl *select = parentNode();
2947     while (select && select->id() != ID_SELECT)
2948         select = select->parentNode();
2949     return static_cast<HTMLSelectElementImpl*>(select);
2950 }
2951
2952 // -------------------------------------------------------------------------
2953
2954 HTMLTextAreaElementImpl::HTMLTextAreaElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
2955     : HTMLGenericFormElementImpl(doc, f), m_valueIsValid(false), m_valueMatchesRenderer(false)
2956 {
2957     // DTD requires rows & cols be specified, but we will provide reasonable defaults
2958     m_rows = 2;
2959     m_cols = 20;
2960     m_wrap = ta_Virtual;
2961 }
2962
2963 HTMLTextAreaElementImpl::~HTMLTextAreaElementImpl()
2964 {
2965     if (getDocument()) getDocument()->deregisterMaintainsState(this);
2966 }
2967
2968 NodeImpl::Id HTMLTextAreaElementImpl::id() const
2969 {
2970     return ID_TEXTAREA;
2971 }
2972
2973 DOMString HTMLTextAreaElementImpl::type() const
2974 {
2975     return "textarea";
2976 }
2977
2978 QString HTMLTextAreaElementImpl::state( )
2979 {
2980     // Make sure the string is not empty!
2981     return HTMLGenericFormElementImpl::state() + value().string()+'.';
2982 }
2983
2984 void HTMLTextAreaElementImpl::restoreState(QStringList &states)
2985 {
2986     QString state = HTMLGenericFormElementImpl::findMatchingState(states);
2987     if (state.isNull()) return;
2988     setDefaultValue(state.left(state.length()-1));
2989     // the close() in the rendertree will take care of transferring defaultvalue to 'value'
2990 }
2991
2992 void HTMLTextAreaElementImpl::select(  )
2993 {
2994     if (m_render)
2995         static_cast<RenderTextArea*>(m_render)->select();
2996     onSelect();
2997 }
2998
2999 void HTMLTextAreaElementImpl::childrenChanged()
3000 {
3001     setValue(defaultValue());
3002 }
3003     
3004 void HTMLTextAreaElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
3005 {
3006     switch(attr->id())
3007     {
3008     case ATTR_ROWS:
3009         m_rows = !attr->isNull() ? attr->value().toInt() : 3;
3010         if (renderer())
3011             renderer()->setNeedsLayoutAndMinMaxRecalc();
3012         break;
3013     case ATTR_COLS:
3014         m_cols = !attr->isNull() ? attr->value().toInt() : 60;
3015         if (renderer())
3016             renderer()->setNeedsLayoutAndMinMaxRecalc();
3017         break;
3018     case ATTR_WRAP:
3019         // virtual / physical is Netscape extension of HTML 3.0, now deprecated
3020         // soft/ hard / off is recommendation for HTML 4 extension by IE and NS 4
3021         if ( strcasecmp( attr->value(), "virtual" ) == 0  || strcasecmp( attr->value(), "soft") == 0)
3022             m_wrap = ta_Virtual;
3023         else if ( strcasecmp ( attr->value(), "physical" ) == 0 || strcasecmp( attr->value(), "hard") == 0)
3024             m_wrap = ta_Physical;
3025         else if(strcasecmp( attr->value(), "on" ) == 0)
3026             m_wrap = ta_Physical;
3027         else if(strcasecmp( attr->value(), "off") == 0)
3028             m_wrap = ta_NoWrap;
3029         if (renderer())
3030             renderer()->setNeedsLayoutAndMinMaxRecalc();
3031         break;
3032     case ATTR_ACCESSKEY:
3033         // ignore for the moment
3034         break;
3035     case ATTR_ONFOCUS:
3036         setHTMLEventListener(EventImpl::FOCUS_EVENT,
3037             getDocument()->createHTMLEventListener(attr->value().string(), this));
3038         break;
3039     case ATTR_ONBLUR:
3040         setHTMLEventListener(EventImpl::BLUR_EVENT,
3041             getDocument()->createHTMLEventListener(attr->value().string(), this));
3042         break;
3043     case ATTR_ONSELECT:
3044         setHTMLEventListener(EventImpl::SELECT_EVENT,
3045             getDocument()->createHTMLEventListener(attr->value().string(), this));
3046         break;
3047     case ATTR_ONCHANGE:
3048         setHTMLEventListener(EventImpl::CHANGE_EVENT,
3049             getDocument()->createHTMLEventListener(attr->value().string(), this));
3050         break;
3051     default:
3052         HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
3053     }
3054 }
3055
3056 RenderObject *HTMLTextAreaElementImpl::createRenderer(RenderArena *arena, RenderStyle *style)
3057 {
3058     return new (arena) RenderTextArea(this);
3059 }
3060
3061 bool HTMLTextAreaElementImpl::appendFormData(FormDataList& encoding, bool)
3062 {
3063     if (name().isEmpty()) return false;
3064     encoding.appendData(name(), value());
3065     return true;
3066 }
3067
3068 void HTMLTextAreaElementImpl::reset()
3069 {
3070     setValue(defaultValue());
3071 }
3072
3073 void HTMLTextAreaElementImpl::updateValue()
3074 {
3075     if ( !m_valueIsValid ) {
3076         if ( m_render ) {
3077             m_value = static_cast<RenderTextArea*>( m_render )->text();
3078             m_valueMatchesRenderer = true;
3079         } else {
3080             m_value = defaultValue().string();
3081             m_valueMatchesRenderer = false;
3082         }
3083         m_valueIsValid = true;
3084     }
3085 }
3086
3087 DOMString HTMLTextAreaElementImpl::value()
3088 {
3089     updateValue();
3090     return m_value.isNull() ? DOMString("") : m_value;
3091 }
3092
3093 void HTMLTextAreaElementImpl::setValue(const DOMString &value)
3094 {
3095     m_value = value.string();
3096     m_valueIsValid = true;
3097     m_valueMatchesRenderer = false;
3098     setChanged(true);
3099 }
3100
3101
3102 DOMString HTMLTextAreaElementImpl::defaultValue()
3103 {
3104     DOMString val = "";
3105     // there may be comments - just grab the text nodes
3106     NodeImpl *n;
3107     for (n = firstChild(); n; n = n->nextSibling())
3108         if (n->isTextNode())
3109             val += static_cast<TextImpl*>(n)->data();
3110     if (val[0] == '\r' && val[1] == '\n') {
3111         val = val.copy();
3112         val.remove(0,2);
3113     }
3114     else if (val[0] == '\r' || val[0] == '\n') {
3115         val = val.copy();
3116         val.remove(0,1);
3117     }
3118
3119     return val;
3120 }
3121
3122 void HTMLTextAreaElementImpl::setDefaultValue(const DOMString &defaultValue)
3123 {
3124     // there may be comments - remove all the text nodes and replace them with one
3125     QPtrList<NodeImpl> toRemove;
3126     NodeImpl *n;
3127     for (n = firstChild(); n; n = n->nextSibling())
3128         if (n->isTextNode())
3129             toRemove.append(n);
3130     QPtrListIterator<NodeImpl> it(toRemove);
3131     int exceptioncode = 0;
3132     for (; it.current(); ++it) {
3133         removeChild(it.current(), exceptioncode);
3134     }
3135     insertBefore(getDocument()->createTextNode(defaultValue),firstChild(), exceptioncode);
3136     setValue(defaultValue);
3137 }
3138
3139 void HTMLTextAreaElementImpl::blur()
3140 {
3141     if(getDocument()->focusNode() == this)
3142         getDocument()->setFocusNode(0);
3143 }
3144
3145 void HTMLTextAreaElementImpl::focus()
3146 {
3147     getDocument()->setFocusNode(this);
3148 }
3149
3150 bool HTMLTextAreaElementImpl::isEditable()
3151 {
3152     return true;
3153 }
3154
3155 void HTMLTextAreaElementImpl::accessKeyAction()
3156 {
3157     focus();
3158 }
3159
3160 void HTMLTextAreaElementImpl::detach()
3161 {
3162     HTMLGenericFormElementImpl::detach();
3163     m_valueMatchesRenderer = false;
3164 }
3165
3166 // -------------------------------------------------------------------------
3167
3168 HTMLIsIndexElementImpl::HTMLIsIndexElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
3169     : HTMLInputElementImpl(doc, f)
3170 {
3171     m_type = TEXT;
3172     setName("isindex");
3173 }
3174
3175 NodeImpl::Id HTMLIsIndexElementImpl::id() const
3176 {
3177     return ID_ISINDEX;
3178 }
3179
3180 void HTMLIsIndexElementImpl::parseHTMLAttribute(HTMLAttributeImpl* attr)
3181 {
3182     switch(attr->id())
3183     {
3184     case ATTR_PROMPT:
3185         setValue(attr->value());
3186     default:
3187         // don't call HTMLInputElement::parseHTMLAttribute here, as it would
3188         // accept attributes this element does not support
3189         HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
3190     }
3191 }
3192
3193 // -------------------------------------------------------------------------
3194
3195 unsigned long HTMLOptionsCollectionImpl::length() const
3196 {
3197     // Not yet implemented.
3198     return 0;
3199 }
3200
3201 void HTMLOptionsCollectionImpl::setLength(unsigned long length)
3202 {
3203     // Not yet implemented.
3204 }
3205
3206 NodeImpl *HTMLOptionsCollectionImpl::item(unsigned long index) const
3207 {
3208     // Not yet implemented.
3209     return 0;
3210 }
3211
3212 NodeImpl *HTMLOptionsCollectionImpl::namedItem(const DOMString &name) const
3213 {
3214     // Not yet implemented.
3215     return 0;
3216 }
3217
3218 // -------------------------------------------------------------------------
3219
3220 FormDataList::FormDataList(QTextCodec *c)
3221     : m_codec(c)
3222 {
3223 }
3224
3225 void FormDataList::appendString(const QCString &s)
3226 {
3227     m_list.append(s);
3228 }
3229
3230 void FormDataList::appendString(const QString &s)
3231 {
3232     QCString cstr = fixLineBreaks(m_codec->fromUnicode(s));
3233     cstr.truncate(cstr.length());
3234     m_list.append(cstr);
3235 }
3236
3237 void FormDataList::appendFile(const DOMString &key, const DOMString &filename)
3238 {
3239     appendString(key.string());
3240     m_list.append(filename.string());
3241 }
3242
3243 } // namespace