Reviewed by Vicki.
[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 DOMString HTMLInputElementImpl::altText() const
1731 {
1732     // http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#altgen
1733     // also heavily discussed by Hixie on bugzilla
1734     // note this is intentionally different to HTMLImageElementImpl::altText()
1735     DOMString alt = getAttribute( ATTR_ALT );
1736     // fall back to title attribute
1737     if ( alt.isNull() )
1738         alt = getAttribute( ATTR_TITLE );
1739     if ( alt.isNull() )
1740         alt = getAttribute( ATTR_VALUE );
1741     if ( alt.isEmpty() )
1742 #if APPLE_CHANGES
1743         alt = inputElementAltText();
1744 #else
1745         alt = i18n( "Submit" );
1746 #endif
1747
1748     return alt;
1749 }
1750
1751 bool HTMLInputElementImpl::isSuccessfulSubmitButton() const
1752 {
1753     // HTML spec says that buttons must have names
1754     // to be considered successful. However, other browsers
1755     // do not impose this constraint. Therefore, we behave
1756     // differently and can use different buttons than the 
1757     // author intended. 
1758     // Was: (m_type == SUBMIT && !name().isEmpty())
1759     return !m_disabled && (m_type == IMAGE || m_type == SUBMIT);
1760 }
1761
1762 bool HTMLInputElementImpl::isActivatedSubmit() const
1763 {
1764     return m_activeSubmit;
1765 }
1766
1767 void HTMLInputElementImpl::setActivatedSubmit(bool flag)
1768 {
1769     m_activeSubmit = flag;
1770 }
1771
1772 bool HTMLInputElementImpl::appendFormData(FormDataList &encoding, bool multipart)
1773 {
1774     // image generates its own names
1775     if (name().isEmpty() && m_type != IMAGE) return false;
1776
1777     switch (m_type) {
1778         case HIDDEN:
1779         case TEXT:
1780 #if APPLE_CHANGES
1781         case SEARCH:
1782         case RANGE:
1783 #endif
1784         case PASSWORD:
1785             // always successful
1786             encoding.appendData(name(), value());
1787             return true;
1788
1789         case CHECKBOX:
1790         case RADIO:
1791             if (checked()) {
1792                 encoding.appendData(name(), value());
1793                 return true;
1794             }
1795             break;
1796
1797         case BUTTON:
1798         case RESET:
1799             // those buttons are never successful
1800             return false;
1801
1802         case IMAGE:
1803             if (m_activeSubmit)
1804             {
1805                 encoding.appendData(name().isEmpty() ? QString::fromLatin1("x") : (name().string() + ".x"), clickX());
1806                 encoding.appendData(name().isEmpty() ? QString::fromLatin1("y") : (name().string() + ".y"), clickY());
1807                 if (!name().isEmpty() && !value().isEmpty())
1808                     encoding.appendData(name(), value());
1809                 return true;
1810             }
1811             break;
1812
1813         case SUBMIT:
1814             if (m_activeSubmit)
1815             {
1816                 QString enc_str = valueWithDefault().string();
1817                 if (!enc_str.isEmpty()) {
1818                     encoding.appendData(name(), enc_str);
1819                     return true;
1820                 }
1821             }
1822             break;
1823
1824         case FILE:
1825         {
1826             // can't submit file on GET
1827             // don't submit if display: none or display: hidden
1828             if(!multipart || !renderer() || renderer()->style()->visibility() != khtml::VISIBLE)
1829                 return false;
1830
1831             // if no filename at all is entered, return successful, however empty
1832             // null would be more logical but netscape posts an empty file. argh.
1833             if (value().isEmpty()) {
1834                 encoding.appendData(name(), QString(""));
1835                 return true;
1836             }
1837
1838 #if APPLE_CHANGES
1839             encoding.appendFile(name(), value());
1840             return true;
1841 #else
1842             KURL fileurl("file:///");
1843             fileurl.setPath(value().string());
1844             KIO::UDSEntry filestat;
1845
1846             if (!KIO::NetAccess::stat(fileurl, filestat)) {
1847                 KMessageBox::sorry(0L, i18n("Error fetching file for submission:\n%1").arg(KIO::NetAccess::lastErrorString()));
1848                 return false;
1849             }
1850
1851             KFileItem fileitem(filestat, fileurl, true, false);
1852             if (fileitem.isDir()) {
1853                 return false;
1854             }
1855
1856             QString local;
1857             if ( KIO::NetAccess::download(fileurl, local) )
1858             {
1859                 QFile file(local);
1860                 if (file.open(IO_ReadOnly))
1861                 {
1862                     QCString filearray(file.size()+1);
1863                     int readbytes = file.readBlock( filearray.data(), file.size());
1864                     if ( readbytes >= 0 )
1865                         filearray[readbytes] = '\0';
1866                     file.close();
1867
1868                     encoding.appendData(name(), filearray);
1869                     KIO::NetAccess::removeTempFile( local );
1870
1871                     return true;
1872                 }
1873                 return false;
1874             }
1875             else {
1876                 KMessageBox::sorry(0L, i18n("Error fetching file for submission:\n%1").arg(KIO::NetAccess::lastErrorString()));
1877                 return false;
1878             }
1879             break;
1880 #endif
1881         }
1882         case ISINDEX:
1883             encoding.appendData(name(), value());
1884             return true;
1885     }
1886     return false;
1887 }
1888
1889 void HTMLInputElementImpl::reset()
1890 {
1891     if (storesValueSeparateFromAttribute())
1892         setValue(DOMString());
1893     setChecked(m_defaultChecked);
1894     m_useDefaultChecked = true;
1895 }
1896
1897 void HTMLInputElementImpl::setChecked(bool _checked)
1898 {
1899     if (checked() == _checked) return;
1900
1901     if (m_form && m_type == RADIO && _checked && !name().isEmpty())
1902         m_form->radioClicked(this);
1903
1904     m_useDefaultChecked = false;
1905     m_checked = _checked;
1906     setChanged();
1907 }
1908
1909
1910 DOMString HTMLInputElementImpl::value() const
1911 {
1912     DOMString value = m_value;
1913
1914     // It's important *not* to fall back to the value attribute for file inputs,
1915     // because that would allow a malicious web page to upload files by setting the
1916     // value attribute in markup.
1917     if (value.isNull() && m_type != FILE)
1918         value = getAttribute(ATTR_VALUE);
1919
1920     // If no attribute exists, then just use "on" or "" based off the checked() state of the control.
1921     if (value.isNull() && (m_type == CHECKBOX || m_type == RADIO))
1922         return DOMString(checked() ? "on" : "");
1923
1924     return value;
1925 }
1926
1927 DOMString HTMLInputElementImpl::valueWithDefault() const
1928 {
1929     DOMString v = value();
1930     if (v.isEmpty()) {
1931         switch (m_type) {
1932             case RESET:
1933 #if APPLE_CHANGES
1934                 v = resetButtonDefaultLabel();
1935 #else
1936                 v = i18n("Reset");
1937 #endif
1938                 break;
1939
1940             case SUBMIT:
1941 #if APPLE_CHANGES
1942                 v = submitButtonDefaultLabel();
1943 #else
1944                 v = i18n("Submit");
1945 #endif
1946                 break;
1947
1948             case BUTTON:
1949             case CHECKBOX:
1950             case FILE:
1951             case HIDDEN:
1952             case IMAGE:
1953             case ISINDEX:
1954             case PASSWORD:
1955             case RADIO:
1956         #if APPLE_CHANGES
1957             case RANGE:
1958             case SEARCH:
1959         #endif
1960             case TEXT:
1961                 break;
1962         }
1963     }
1964     return v;
1965 }
1966
1967 void HTMLInputElementImpl::setValue(const DOMString &value)
1968 {
1969     if (m_type == FILE) return;
1970
1971     if (storesValueSeparateFromAttribute()) {
1972         m_value = value;
1973         setChanged();
1974     } else {
1975         setAttribute(ATTR_VALUE, value);
1976     }
1977     m_valueMatchesRenderer = false;
1978 }
1979
1980 void HTMLInputElementImpl::setValueFromRenderer(const DOMString &value)
1981 {
1982     m_value = value;
1983     m_valueMatchesRenderer = true;
1984     
1985     // Fire the "input" DOM event.
1986     dispatchHTMLEvent(EventImpl::INPUT_EVENT, true, false);
1987 }
1988
1989 bool HTMLInputElementImpl::storesValueSeparateFromAttribute() const
1990 {
1991     switch (m_type) {
1992         case BUTTON:
1993         case CHECKBOX:
1994         case FILE:
1995         case HIDDEN:
1996         case IMAGE:
1997         case RADIO:
1998 #if APPLE_CHANGES
1999         case RANGE:
2000 #endif
2001         case RESET:
2002         case SUBMIT:
2003             return false;
2004         case ISINDEX:
2005         case PASSWORD:
2006 #if APPLE_CHANGES
2007         case SEARCH:
2008 #endif
2009         case TEXT:
2010             return true;
2011     }
2012     return false;
2013 }
2014
2015 void HTMLInputElementImpl::blur()
2016 {
2017     if(getDocument()->focusNode() == this)
2018         getDocument()->setFocusNode(0);
2019 }
2020
2021 void HTMLInputElementImpl::focus()
2022 {
2023     getDocument()->setFocusNode(this);
2024 }
2025
2026 void HTMLInputElementImpl::defaultEventHandler(EventImpl *evt)
2027 {
2028     if (evt->isMouseEvent() &&
2029         ( evt->id() == EventImpl::KHTML_CLICK_EVENT || evt->id() == EventImpl::KHTML_DBLCLICK_EVENT ) &&
2030         m_type == IMAGE
2031         && m_render) {
2032         // record the mouse position for when we get the DOMActivate event
2033         MouseEventImpl *me = static_cast<MouseEventImpl*>(evt);
2034         int offsetX, offsetY;
2035         m_render->absolutePosition(offsetX,offsetY);
2036         xPos = me->clientX()-offsetX;
2037         yPos = me->clientY()-offsetY;
2038
2039         me->setDefaultHandled();
2040     }
2041
2042     // DOMActivate events cause the input to be "activated" - in the case of image and submit inputs, this means
2043     // actually submitting the form. For reset inputs, the form is reset. These events are sent when the user clicks
2044     // on the element, or presses enter while it is the active element. Javacsript code wishing to activate the element
2045     // must dispatch a DOMActivate event - a click event will not do the job.
2046     if ((evt->id() == EventImpl::DOMACTIVATE_EVENT) &&
2047         (m_type == IMAGE || m_type == SUBMIT || m_type == RESET)){
2048
2049         if (!m_form)
2050             return;
2051
2052         if (m_type == RESET) {
2053             m_form->reset();
2054         }
2055         else {
2056             m_activeSubmit = true;
2057             if (!m_form->prepareSubmit()) {
2058                 xPos = 0;
2059                 yPos = 0;
2060             }
2061             m_activeSubmit = false;
2062         }
2063     }
2064
2065 #if APPLE_CHANGES
2066     // Use key press event here since sending simulated mouse events
2067     // on key down blocks the proper sending of the key press event.
2068     if (evt->id() == EventImpl::KEYPRESS_EVENT && evt->isKeyboardEvent()) {
2069         DOMString key = static_cast<KeyboardEventImpl *>(evt)->keyIdentifier();
2070         switch (m_type) {
2071             case BUTTON:
2072             case CHECKBOX:
2073             case FILE:
2074             case IMAGE:
2075             case RADIO:
2076             case RESET:
2077             case SUBMIT:
2078                 // Simulate mouse click for enter or spacebar for these types of elements.
2079                 // The AppKit already does this for spacebar for some, but not all, of them.
2080                 if (key == "U+000020" || key == "Enter") {
2081                     click();
2082                     evt->setDefaultHandled();
2083                 }
2084                 break;
2085             case HIDDEN:
2086             case ISINDEX:
2087             case PASSWORD:
2088             case RANGE:
2089             case SEARCH:
2090             case TEXT:
2091                 // Simulate mouse click on the default form button for enter for these types of elements.
2092                 if (key == "Enter" && m_form) {
2093                     m_form->submitClick();
2094                     evt->setDefaultHandled();
2095                 }
2096                 break;
2097         }
2098     }
2099 #endif
2100
2101     HTMLGenericFormElementImpl::defaultEventHandler(evt);
2102 }
2103
2104 bool HTMLInputElementImpl::isEditable()
2105 {
2106     return ((m_type == TEXT) || (m_type == PASSWORD) ||
2107             (m_type == SEARCH) || (m_type == ISINDEX) || (m_type == FILE));
2108 }
2109
2110 bool HTMLInputElementImpl::isURLAttribute(AttributeImpl *attr) const
2111 {
2112     return (attr->id() == ATTR_SRC);
2113 }
2114
2115 // -------------------------------------------------------------------------
2116
2117 HTMLLabelElementImpl::HTMLLabelElementImpl(DocumentPtr *doc)
2118     : HTMLElementImpl(doc)
2119 {
2120 }
2121
2122 HTMLLabelElementImpl::~HTMLLabelElementImpl()
2123 {
2124 }
2125
2126 bool HTMLLabelElementImpl::isFocusable() const
2127 {
2128     return false;
2129 }
2130
2131 NodeImpl::Id HTMLLabelElementImpl::id() const
2132 {
2133     return ID_LABEL;
2134 }
2135
2136 void HTMLLabelElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
2137 {
2138     switch(attr->id())
2139     {
2140     case ATTR_ONFOCUS:
2141         setHTMLEventListener(EventImpl::FOCUS_EVENT,
2142             getDocument()->createHTMLEventListener(attr->value().string(), this));
2143         break;
2144     case ATTR_ONBLUR:
2145         setHTMLEventListener(EventImpl::BLUR_EVENT,
2146             getDocument()->createHTMLEventListener(attr->value().string(), this));
2147         break;
2148     default:
2149         HTMLElementImpl::parseHTMLAttribute(attr);
2150     }
2151 }
2152
2153 ElementImpl *HTMLLabelElementImpl::formElement()
2154 {
2155     DOMString formElementId = getAttribute(ATTR_FOR);
2156     if (formElementId.isNull()) {
2157         // Search children of the label element for a form element.
2158         NodeImpl *node = this;
2159         while ((node = node->traverseNextNode(this))) {
2160             if (node->isHTMLElement()) {
2161                 HTMLElementImpl *element = static_cast<HTMLElementImpl *>(node);
2162                 if (element->isGenericFormElement()) {
2163                     return element;
2164                 }
2165             }
2166         }
2167         return 0;
2168     }
2169     if (formElementId.isEmpty())
2170         return 0;
2171     return getDocument()->getElementById(formElementId);
2172 }
2173
2174 void HTMLLabelElementImpl::accessKeyAction()
2175 {
2176     ElementImpl *element = formElement();
2177     if (element)
2178         element->accessKeyAction();
2179 }
2180
2181 // -------------------------------------------------------------------------
2182
2183 HTMLLegendElementImpl::HTMLLegendElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
2184 : HTMLGenericFormElementImpl(doc, f)
2185 {
2186 }
2187
2188 HTMLLegendElementImpl::~HTMLLegendElementImpl()
2189 {
2190 }
2191
2192 bool HTMLLegendElementImpl::isFocusable() const
2193 {
2194     return false;
2195 }
2196
2197 NodeImpl::Id HTMLLegendElementImpl::id() const
2198 {
2199     return ID_LEGEND;
2200 }
2201
2202 RenderObject* HTMLLegendElementImpl::createRenderer(RenderArena* arena, RenderStyle* style)
2203 {
2204     return new (arena) RenderLegend(this);
2205 }
2206
2207 DOMString HTMLLegendElementImpl::type() const
2208 {
2209     return "legend";
2210 }
2211
2212 // -------------------------------------------------------------------------
2213
2214 HTMLSelectElementImpl::HTMLSelectElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
2215     : HTMLGenericFormElementImpl(doc, f), m_options(0)
2216 {
2217     m_multiple = false;
2218     m_recalcListItems = false;
2219     // 0 means invalid (i.e. not set)
2220     m_size = 0;
2221     m_minwidth = 0;
2222 }
2223
2224 HTMLSelectElementImpl::~HTMLSelectElementImpl()
2225 {
2226     if (getDocument()) getDocument()->deregisterMaintainsState(this);
2227     if (m_options) {
2228         m_options->detach();
2229         m_options->deref();
2230     }
2231 }
2232
2233 NodeImpl::Id HTMLSelectElementImpl::id() const
2234 {
2235     return ID_SELECT;
2236 }
2237
2238 void HTMLSelectElementImpl::recalcStyle( StyleChange ch )
2239 {
2240     if (hasChangedChild() && m_render) {
2241         static_cast<khtml::RenderSelect*>(m_render)->setOptionsChanged(true);
2242     }
2243
2244     HTMLGenericFormElementImpl::recalcStyle( ch );
2245 }
2246
2247
2248 DOMString HTMLSelectElementImpl::type() const
2249 {
2250     return (m_multiple ? "select-multiple" : "select-one");
2251 }
2252
2253 long HTMLSelectElementImpl::selectedIndex() const
2254 {
2255     // return the number of the first option selected
2256     uint o = 0;
2257     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2258     for (unsigned int i = 0; i < items.size(); i++) {
2259         if (items[i]->id() == ID_OPTION) {
2260             if (static_cast<HTMLOptionElementImpl*>(items[i])->selected())
2261                 return o;
2262             o++;
2263         }
2264     }
2265     Q_ASSERT(m_multiple);
2266     return -1;
2267 }
2268
2269 void HTMLSelectElementImpl::setSelectedIndex( long  index )
2270 {
2271     // deselect all other options and select only the new one
2272     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2273     int listIndex;
2274     for (listIndex = 0; listIndex < int(items.size()); listIndex++) {
2275         if (items[listIndex]->id() == ID_OPTION)
2276             static_cast<HTMLOptionElementImpl*>(items[listIndex])->setSelected(false);
2277     }
2278     listIndex = optionToListIndex(index);
2279     if (listIndex >= 0)
2280         static_cast<HTMLOptionElementImpl*>(items[listIndex])->setSelected(true);
2281
2282     setChanged(true);
2283 }
2284
2285 long HTMLSelectElementImpl::length() const
2286 {
2287     int len = 0;
2288     uint i;
2289     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2290     for (i = 0; i < items.size(); i++) {
2291         if (items[i]->id() == ID_OPTION)
2292             len++;
2293     }
2294     return len;
2295 }
2296
2297 void HTMLSelectElementImpl::add( HTMLElementImpl *element, HTMLElementImpl *before )
2298 {
2299     if (!element || element->id() != ID_OPTION)
2300         return;
2301
2302     int exceptioncode = 0;
2303     insertBefore(element, before, exceptioncode);
2304     if (!exceptioncode)
2305         setRecalcListItems();
2306 }
2307
2308 void HTMLSelectElementImpl::remove( long index )
2309 {
2310     int exceptioncode = 0;
2311     int listIndex = optionToListIndex(index);
2312
2313     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2314     if(listIndex < 0 || index >= int(items.size()))
2315         return; // ### what should we do ? remove the last item?
2316
2317     removeChild(items[listIndex], exceptioncode);
2318     if( !exceptioncode )
2319         setRecalcListItems();
2320 }
2321
2322 void HTMLSelectElementImpl::blur()
2323 {
2324     if(getDocument()->focusNode() == this)
2325         getDocument()->setFocusNode(0);
2326 }
2327
2328 void HTMLSelectElementImpl::focus()
2329 {
2330     getDocument()->setFocusNode(this);
2331 }
2332
2333 DOMString HTMLSelectElementImpl::value( )
2334 {
2335     uint i;
2336     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2337     for (i = 0; i < items.size(); i++) {
2338         if ( items[i]->id() == ID_OPTION
2339             && static_cast<HTMLOptionElementImpl*>(items[i])->selected())
2340             return static_cast<HTMLOptionElementImpl*>(items[i])->value();
2341     }
2342     return DOMString("");
2343 }
2344
2345 void HTMLSelectElementImpl::setValue(DOMStringImpl* value)
2346 {
2347     // find the option with value() matching the given parameter
2348     // and make it the current selection.
2349     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2350     for (unsigned i = 0; i < items.size(); i++)
2351         if (items[i]->id() == ID_OPTION && static_cast<HTMLOptionElementImpl*>(items[i])->value() == value) {
2352             static_cast<HTMLOptionElementImpl*>(items[i])->setSelected(true);
2353             return;
2354         }
2355 }
2356
2357 QString HTMLSelectElementImpl::state( )
2358 {
2359 #if !APPLE_CHANGES
2360     QString state;
2361 #endif
2362     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2363
2364     int l = items.count();
2365
2366 #if APPLE_CHANGES
2367     QChar stateChars[l];
2368     
2369     for(int i = 0; i < l; i++)
2370         if(items[i]->id() == ID_OPTION && static_cast<HTMLOptionElementImpl*>(items[i])->selected())
2371             stateChars[i] = 'X';
2372         else
2373             stateChars[i] = '.';
2374     QString state(stateChars, l);
2375 #else /* APPLE_CHANGES not defined */
2376     state.fill('.', l);
2377     for(int i = 0; i < l; i++)
2378         if(items[i]->id() == ID_OPTION && static_cast<HTMLOptionElementImpl*>(items[i])->selected())
2379             state[i] = 'X';
2380 #endif /* APPLE_CHANGES not defined */
2381
2382     return HTMLGenericFormElementImpl::state() + state;
2383 }
2384
2385 void HTMLSelectElementImpl::restoreState(QStringList &_states)
2386 {
2387     QString _state = HTMLGenericFormElementImpl::findMatchingState(_states);
2388     if (_state.isNull()) return;
2389
2390     recalcListItems();
2391
2392     QString state = _state;
2393     if(!state.isEmpty() && !state.contains('X') && !m_multiple) {
2394         qWarning("should not happen in restoreState!");
2395 #if APPLE_CHANGES
2396         // KWQString doesn't support this operation. Should never get here anyway.
2397         //state[0] = 'X';
2398 #else
2399         state[0] = 'X';
2400 #endif
2401     }
2402
2403     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2404
2405     int l = items.count();
2406     for(int i = 0; i < l; i++) {
2407         if(items[i]->id() == ID_OPTION) {
2408             HTMLOptionElementImpl* oe = static_cast<HTMLOptionElementImpl*>(items[i]);
2409             oe->setSelected(state[i] == 'X');
2410         }
2411     }
2412     setChanged(true);
2413 }
2414
2415 NodeImpl *HTMLSelectElementImpl::insertBefore ( NodeImpl *newChild, NodeImpl *refChild, int &exceptioncode )
2416 {
2417     NodeImpl *result = HTMLGenericFormElementImpl::insertBefore(newChild,refChild, exceptioncode );
2418     if (!exceptioncode)
2419         setRecalcListItems();
2420     return result;
2421 }
2422
2423 NodeImpl *HTMLSelectElementImpl::replaceChild ( NodeImpl *newChild, NodeImpl *oldChild, int &exceptioncode )
2424 {
2425     NodeImpl *result = HTMLGenericFormElementImpl::replaceChild(newChild,oldChild, exceptioncode);
2426     if( !exceptioncode )
2427         setRecalcListItems();
2428     return result;
2429 }
2430
2431 NodeImpl *HTMLSelectElementImpl::removeChild ( NodeImpl *oldChild, int &exceptioncode )
2432 {
2433     NodeImpl *result = HTMLGenericFormElementImpl::removeChild(oldChild, exceptioncode);
2434     if( !exceptioncode )
2435         setRecalcListItems();
2436     return result;
2437 }
2438
2439 NodeImpl *HTMLSelectElementImpl::appendChild ( NodeImpl *newChild, int &exceptioncode )
2440 {
2441     NodeImpl *result = HTMLGenericFormElementImpl::appendChild(newChild, exceptioncode);
2442     if( !exceptioncode )
2443         setRecalcListItems();
2444     setChanged(true);
2445     return result;
2446 }
2447
2448 NodeImpl* HTMLSelectElementImpl::addChild(NodeImpl* newChild)
2449 {
2450     setRecalcListItems();
2451     return HTMLGenericFormElementImpl::addChild(newChild);
2452 }
2453
2454 void HTMLSelectElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
2455 {
2456     switch(attr->id())
2457     {
2458     case ATTR_SIZE:
2459         m_size = QMAX( attr->value().toInt(), 1 );
2460         break;
2461     case ATTR_WIDTH:
2462         m_minwidth = QMAX( attr->value().toInt(), 0 );
2463         break;
2464     case ATTR_MULTIPLE:
2465         m_multiple = (!attr->isNull());
2466         break;
2467     case ATTR_ACCESSKEY:
2468         // ### ignore for the moment
2469         break;
2470     case ATTR_ONFOCUS:
2471         setHTMLEventListener(EventImpl::FOCUS_EVENT,
2472             getDocument()->createHTMLEventListener(attr->value().string(), this));
2473         break;
2474     case ATTR_ONBLUR:
2475         setHTMLEventListener(EventImpl::BLUR_EVENT,
2476             getDocument()->createHTMLEventListener(attr->value().string(), this));
2477         break;
2478     case ATTR_ONCHANGE:
2479         setHTMLEventListener(EventImpl::CHANGE_EVENT,
2480             getDocument()->createHTMLEventListener(attr->value().string(), this));
2481         break;
2482     default:
2483         HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
2484     }
2485 }
2486
2487 RenderObject *HTMLSelectElementImpl::createRenderer(RenderArena *arena, RenderStyle *style)
2488 {
2489     return new (arena) RenderSelect(this);
2490 }
2491
2492 bool HTMLSelectElementImpl::appendFormData(FormDataList& encoded_values, bool)
2493 {
2494     bool successful = false;
2495     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2496
2497     uint i;
2498     for (i = 0; i < items.size(); i++) {
2499         if (items[i]->id() == ID_OPTION) {
2500             HTMLOptionElementImpl *option = static_cast<HTMLOptionElementImpl*>(items[i]);
2501             if (option->selected()) {
2502                 encoded_values.appendData(name(), option->value());
2503                 successful = true;
2504             }
2505         }
2506     }
2507
2508     // ### this case should not happen. make sure that we select the first option
2509     // in any case. otherwise we have no consistency with the DOM interface. FIXME!
2510     // we return the first one if it was a combobox select
2511     if (!successful && !m_multiple && m_size <= 1 && items.size() &&
2512         (items[0]->id() == ID_OPTION) ) {
2513         HTMLOptionElementImpl *option = static_cast<HTMLOptionElementImpl*>(items[0]);
2514         if (option->value().isNull())
2515             encoded_values.appendData(name(), option->text().string().stripWhiteSpace());
2516         else
2517             encoded_values.appendData(name(), option->value());
2518         successful = true;
2519     }
2520
2521     return successful;
2522 }
2523
2524 int HTMLSelectElementImpl::optionToListIndex(int optionIndex) const
2525 {
2526     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2527     if (optionIndex < 0 || optionIndex >= int(items.size()))
2528         return -1;
2529
2530     int listIndex = 0;
2531     int optionIndex2 = 0;
2532     for (;
2533          optionIndex2 < int(items.size()) && optionIndex2 <= optionIndex;
2534          listIndex++) { // not a typo!
2535         if (items[listIndex]->id() == ID_OPTION)
2536             optionIndex2++;
2537     }
2538     listIndex--;
2539     return listIndex;
2540 }
2541
2542 int HTMLSelectElementImpl::listToOptionIndex(int listIndex) const
2543 {
2544     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2545     if (listIndex < 0 || listIndex >= int(items.size()) ||
2546         items[listIndex]->id() != ID_OPTION)
2547         return -1;
2548
2549     int optionIndex = 0; // actual index of option not counting OPTGROUP entries that may be in list
2550     int i;
2551     for (i = 0; i < listIndex; i++)
2552         if (items[i]->id() == ID_OPTION)
2553             optionIndex++;
2554     return optionIndex;
2555 }
2556
2557 HTMLOptionsCollectionImpl *HTMLSelectElementImpl::options()
2558 {
2559     if (!m_options) {
2560         m_options = new HTMLOptionsCollectionImpl(this);
2561         m_options->ref();
2562     }
2563     return m_options;
2564 }
2565
2566 void HTMLSelectElementImpl::recalcListItems()
2567 {
2568     NodeImpl* current = firstChild();
2569     m_listItems.resize(0);
2570     HTMLOptionElementImpl* foundSelected = 0;
2571     while(current) {
2572         if (current->id() == ID_OPTGROUP && current->firstChild()) {
2573             // ### what if optgroup contains just comments? don't want one of no options in it...
2574             m_listItems.resize(m_listItems.size()+1);
2575             m_listItems[m_listItems.size()-1] = static_cast<HTMLGenericFormElementImpl*>(current);
2576             current = current->firstChild();
2577         }
2578         if (current->id() == ID_OPTION) {
2579             m_listItems.resize(m_listItems.size()+1);
2580             m_listItems[m_listItems.size()-1] = static_cast<HTMLGenericFormElementImpl*>(current);
2581             if (!foundSelected && !m_multiple && m_size <= 1) {
2582                 foundSelected = static_cast<HTMLOptionElementImpl*>(current);
2583                 foundSelected->m_selected = true;
2584             }
2585             else if (foundSelected && !m_multiple && static_cast<HTMLOptionElementImpl*>(current)->selected()) {
2586                 foundSelected->m_selected = false;
2587                 foundSelected = static_cast<HTMLOptionElementImpl*>(current);
2588             }
2589         }
2590         NodeImpl *parent = current->parentNode();
2591         current = current->nextSibling();
2592         if (!current) {
2593             if (parent != this)
2594                 current = parent->nextSibling();
2595         }
2596     }
2597     m_recalcListItems = false;
2598 }
2599
2600 void HTMLSelectElementImpl::childrenChanged()
2601 {
2602     setRecalcListItems();
2603
2604     HTMLGenericFormElementImpl::childrenChanged();
2605 }
2606
2607 void HTMLSelectElementImpl::setRecalcListItems()
2608 {
2609     m_recalcListItems = true;
2610     if (m_render)
2611         static_cast<khtml::RenderSelect*>(m_render)->setOptionsChanged(true);
2612     setChanged();
2613 }
2614
2615 void HTMLSelectElementImpl::reset()
2616 {
2617     QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2618     uint i;
2619     for (i = 0; i < items.size(); i++) {
2620         if (items[i]->id() == ID_OPTION) {
2621             HTMLOptionElementImpl *option = static_cast<HTMLOptionElementImpl*>(items[i]);
2622             bool selected = (!option->getAttribute(ATTR_SELECTED).isNull());
2623             option->setSelected(selected);
2624         }
2625     }
2626     if ( m_render )
2627         static_cast<RenderSelect*>(m_render)->setSelectionChanged(true);
2628     setChanged( true );
2629 }
2630
2631 void HTMLSelectElementImpl::notifyOptionSelected(HTMLOptionElementImpl *selectedOption, bool selected)
2632 {
2633     if (selected && !m_multiple) {
2634         // deselect all other options
2635         QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2636         uint i;
2637         for (i = 0; i < items.size(); i++) {
2638             if (items[i]->id() == ID_OPTION)
2639                 static_cast<HTMLOptionElementImpl*>(items[i])->m_selected = (items[i] == selectedOption);
2640         }
2641     }
2642     if (m_render)
2643         static_cast<RenderSelect*>(m_render)->setSelectionChanged(true);
2644
2645     setChanged(true);
2646 }
2647
2648 #if APPLE_CHANGES
2649
2650 void HTMLSelectElementImpl::defaultEventHandler(EventImpl *evt)
2651 {
2652     // Use key press event here since sending simulated mouse events
2653     // on key down blocks the proper sending of the key press event.
2654     if (evt->id() == EventImpl::KEYPRESS_EVENT) {
2655     
2656         if (!m_form || !m_render || !evt->isKeyboardEvent())
2657             return;
2658         
2659         DOMString key = static_cast<KeyboardEventImpl *>(evt)->keyIdentifier();
2660         
2661         if (key == "Enter") {
2662             m_form->submitClick();
2663             evt->setDefaultHandled();
2664         }
2665     }
2666     HTMLGenericFormElementImpl::defaultEventHandler(evt);
2667 }
2668
2669 #endif // APPLE_CHANGES
2670
2671 void HTMLSelectElementImpl::accessKeyAction()
2672 {
2673     focus();
2674 }
2675
2676 // -------------------------------------------------------------------------
2677
2678 HTMLKeygenElementImpl::HTMLKeygenElementImpl(DocumentPtr* doc, HTMLFormElementImpl* f)
2679     : HTMLSelectElementImpl(doc, f)
2680 {
2681     QStringList keys = KSSLKeyGen::supportedKeySizes();
2682     for (QStringList::Iterator i = keys.begin(); i != keys.end(); ++i) {
2683         HTMLOptionElementImpl* o = new HTMLOptionElementImpl(doc, form());
2684         addChild(o);
2685         o->addChild(new TextImpl(doc, DOMString(*i)));
2686     }
2687 }
2688
2689 NodeImpl::Id HTMLKeygenElementImpl::id() const
2690 {
2691     return ID_KEYGEN;
2692 }
2693
2694 DOMString HTMLKeygenElementImpl::type() const
2695 {
2696     return "keygen";
2697 }
2698
2699 void HTMLKeygenElementImpl::parseHTMLAttribute(HTMLAttributeImpl* attr)
2700 {
2701     switch(attr->id())
2702     {
2703     case ATTR_CHALLENGE:
2704         m_challenge = attr->value();
2705         break;
2706     case ATTR_KEYTYPE:
2707         m_keyType = attr->value();
2708         break;
2709     default:
2710         // skip HTMLSelectElementImpl parsing!
2711         HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
2712     }
2713 }
2714
2715 bool HTMLKeygenElementImpl::appendFormData(FormDataList& encoded_values, bool)
2716 {
2717 #if APPLE_CHANGES
2718     // Only RSA is supported at this time.
2719     if (!m_keyType.isNull() && strcasecmp(m_keyType, "rsa")) {
2720         return false;
2721     }
2722     QString value = KSSLKeyGen::signedPublicKeyAndChallengeString(selectedIndex(), m_challenge.string(), getDocument()->part()->baseURL());
2723     if (value.isNull()) {
2724         return false;
2725     }
2726     encoded_values.appendData(name(), value.utf8());
2727     return true;
2728 #else
2729     bool successful = false;
2730
2731     // pop up the fancy certificate creation dialog here
2732     KSSLKeyGen *kg = new KSSLKeyGen(static_cast<RenderWidget *>(m_render)->widget(), "Key Generator", true);
2733
2734     kg->setKeySize(0);
2735     successful = (QDialog::Accepted == kg->exec());
2736
2737     delete kg;
2738
2739     encoded_values.appendData(name(), "deadbeef");
2740     
2741     return successful;
2742 #endif
2743 }
2744
2745 // -------------------------------------------------------------------------
2746
2747 HTMLOptGroupElementImpl::HTMLOptGroupElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
2748     : HTMLGenericFormElementImpl(doc, f)
2749 {
2750 }
2751
2752 HTMLOptGroupElementImpl::~HTMLOptGroupElementImpl()
2753 {
2754 }
2755
2756 bool HTMLOptGroupElementImpl::isFocusable() const
2757 {
2758     return false;
2759 }
2760
2761 NodeImpl::Id HTMLOptGroupElementImpl::id() const
2762 {
2763     return ID_OPTGROUP;
2764 }
2765
2766 DOMString HTMLOptGroupElementImpl::type() const
2767 {
2768     return "optgroup";
2769 }
2770
2771 NodeImpl *HTMLOptGroupElementImpl::insertBefore ( NodeImpl *newChild, NodeImpl *refChild, int &exceptioncode )
2772 {
2773     NodeImpl *result = HTMLGenericFormElementImpl::insertBefore(newChild,refChild, exceptioncode);
2774     if ( !exceptioncode )
2775         recalcSelectOptions();
2776     return result;
2777 }
2778
2779 NodeImpl *HTMLOptGroupElementImpl::replaceChild ( NodeImpl *newChild, NodeImpl *oldChild, int &exceptioncode )
2780 {
2781     NodeImpl *result = HTMLGenericFormElementImpl::replaceChild(newChild,oldChild, exceptioncode);
2782     if(!exceptioncode)
2783         recalcSelectOptions();
2784     return result;
2785 }
2786
2787 NodeImpl *HTMLOptGroupElementImpl::removeChild ( NodeImpl *oldChild, int &exceptioncode )
2788 {
2789     NodeImpl *result = HTMLGenericFormElementImpl::removeChild(oldChild, exceptioncode);
2790     if( !exceptioncode )
2791         recalcSelectOptions();
2792     return result;
2793 }
2794
2795 NodeImpl *HTMLOptGroupElementImpl::appendChild ( NodeImpl *newChild, int &exceptioncode )
2796 {
2797     NodeImpl *result = HTMLGenericFormElementImpl::appendChild(newChild, exceptioncode);
2798     if( !exceptioncode )
2799         recalcSelectOptions();
2800     return result;
2801 }
2802
2803 NodeImpl* HTMLOptGroupElementImpl::addChild(NodeImpl* newChild)
2804 {
2805     recalcSelectOptions();
2806
2807     return HTMLGenericFormElementImpl::addChild(newChild);
2808 }
2809
2810 void HTMLOptGroupElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
2811 {
2812     HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
2813     recalcSelectOptions();
2814 }
2815
2816 void HTMLOptGroupElementImpl::recalcSelectOptions()
2817 {
2818     NodeImpl *select = parentNode();
2819     while (select && select->id() != ID_SELECT)
2820         select = select->parentNode();
2821     if (select)
2822         static_cast<HTMLSelectElementImpl*>(select)->setRecalcListItems();
2823 }
2824
2825 // -------------------------------------------------------------------------
2826
2827 HTMLOptionElementImpl::HTMLOptionElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
2828     : HTMLGenericFormElementImpl(doc, f)
2829 {
2830     m_selected = false;
2831 }
2832
2833 bool HTMLOptionElementImpl::isFocusable() const
2834 {
2835     return false;
2836 }
2837
2838 NodeImpl::Id HTMLOptionElementImpl::id() const
2839 {
2840     return ID_OPTION;
2841 }
2842
2843 DOMString HTMLOptionElementImpl::type() const
2844 {
2845     return "option";
2846 }
2847
2848 DOMString HTMLOptionElementImpl::text() const
2849 {
2850     DOMString text;
2851
2852     // WinIE does not use the label attribute, so as a quirk, we ignore it.
2853     if (getDocument() && !getDocument()->inCompatMode()) {
2854         DOMString text = getAttribute(ATTR_LABEL);
2855         if (!text.isEmpty())
2856             return text;
2857     }
2858
2859     const NodeImpl *n = this;
2860     while ((n = n->traverseNextNode(this))) {
2861         if (n->nodeType() == Node::TEXT_NODE || n->nodeType() == Node::CDATA_SECTION_NODE)
2862             text += n->nodeValue();
2863     }
2864
2865     return text;
2866 }
2867
2868 long HTMLOptionElementImpl::index() const
2869 {
2870     // Let's do this dynamically. Might be a bit slow, but we're sure
2871     // we won't forget to update a member variable in some cases...
2872     QMemArray<HTMLGenericFormElementImpl*> items = getSelect()->listItems();
2873     int l = items.count();
2874     int optionIndex = 0;
2875     for(int i = 0; i < l; i++) {
2876         if(items[i]->id() == ID_OPTION)
2877         {
2878             if (static_cast<HTMLOptionElementImpl*>(items[i]) == this)
2879                 return optionIndex;
2880             optionIndex++;
2881         }
2882     }
2883     kdWarning() << "HTMLOptionElementImpl::index(): option not found!" << endl;
2884     return 0;
2885 }
2886
2887 void HTMLOptionElementImpl::setIndex( long  )
2888 {
2889     kdWarning() << "Unimplemented HTMLOptionElementImpl::setIndex(long) called" << endl;
2890     // ###
2891 }
2892
2893 void HTMLOptionElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
2894 {
2895     switch(attr->id())
2896     {
2897     case ATTR_SELECTED:
2898         m_selected = (!attr->isNull());
2899         break;
2900     case ATTR_VALUE:
2901         m_value = attr->value();
2902         break;
2903     default:
2904         HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
2905     }
2906 }
2907
2908 DOMString HTMLOptionElementImpl::value() const
2909 {
2910     if ( !m_value.isNull() )
2911         return m_value;
2912     // Use the text if the value wasn't set.
2913     return text().string().stripWhiteSpace();
2914 }
2915
2916 void HTMLOptionElementImpl::setValue(DOMStringImpl* value)
2917 {
2918     setAttribute(ATTR_VALUE, value);
2919 }
2920
2921 void HTMLOptionElementImpl::setSelected(bool _selected)
2922 {
2923     if(m_selected == _selected)
2924         return;
2925     m_selected = _selected;
2926     HTMLSelectElementImpl *select = getSelect();
2927     if (select)
2928         select->notifyOptionSelected(this,_selected);
2929 }
2930
2931 void HTMLOptionElementImpl::childrenChanged()
2932 {
2933    HTMLSelectElementImpl *select = getSelect();
2934    if (select)
2935        select->childrenChanged();
2936 }
2937
2938 HTMLSelectElementImpl *HTMLOptionElementImpl::getSelect() const
2939 {
2940     NodeImpl *select = parentNode();
2941     while (select && select->id() != ID_SELECT)
2942         select = select->parentNode();
2943     return static_cast<HTMLSelectElementImpl*>(select);
2944 }
2945
2946 // -------------------------------------------------------------------------
2947
2948 HTMLTextAreaElementImpl::HTMLTextAreaElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
2949     : HTMLGenericFormElementImpl(doc, f), m_valueIsValid(false), m_valueMatchesRenderer(false)
2950 {
2951     // DTD requires rows & cols be specified, but we will provide reasonable defaults
2952     m_rows = 2;
2953     m_cols = 20;
2954     m_wrap = ta_Virtual;
2955 }
2956
2957 HTMLTextAreaElementImpl::~HTMLTextAreaElementImpl()
2958 {
2959     if (getDocument()) getDocument()->deregisterMaintainsState(this);
2960 }
2961
2962 NodeImpl::Id HTMLTextAreaElementImpl::id() const
2963 {
2964     return ID_TEXTAREA;
2965 }
2966
2967 DOMString HTMLTextAreaElementImpl::type() const
2968 {
2969     return "textarea";
2970 }
2971
2972 QString HTMLTextAreaElementImpl::state( )
2973 {
2974     // Make sure the string is not empty!
2975     return HTMLGenericFormElementImpl::state() + value().string()+'.';
2976 }
2977
2978 void HTMLTextAreaElementImpl::restoreState(QStringList &states)
2979 {
2980     QString state = HTMLGenericFormElementImpl::findMatchingState(states);
2981     if (state.isNull()) return;
2982     setDefaultValue(state.left(state.length()-1));
2983     // the close() in the rendertree will take care of transferring defaultvalue to 'value'
2984 }
2985
2986 void HTMLTextAreaElementImpl::select(  )
2987 {
2988     if (m_render)
2989         static_cast<RenderTextArea*>(m_render)->select();
2990     onSelect();
2991 }
2992
2993 void HTMLTextAreaElementImpl::childrenChanged()
2994 {
2995     setValue(defaultValue());
2996 }
2997     
2998 void HTMLTextAreaElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
2999 {
3000     switch(attr->id())
3001     {
3002     case ATTR_ROWS:
3003         m_rows = !attr->isNull() ? attr->value().toInt() : 3;
3004         if (renderer())
3005             renderer()->setNeedsLayoutAndMinMaxRecalc();
3006         break;
3007     case ATTR_COLS:
3008         m_cols = !attr->isNull() ? attr->value().toInt() : 60;
3009         if (renderer())
3010             renderer()->setNeedsLayoutAndMinMaxRecalc();
3011         break;
3012     case ATTR_WRAP:
3013         // virtual / physical is Netscape extension of HTML 3.0, now deprecated
3014         // soft/ hard / off is recommendation for HTML 4 extension by IE and NS 4
3015         if ( strcasecmp( attr->value(), "virtual" ) == 0  || strcasecmp( attr->value(), "soft") == 0)
3016             m_wrap = ta_Virtual;
3017         else if ( strcasecmp ( attr->value(), "physical" ) == 0 || strcasecmp( attr->value(), "hard") == 0)
3018             m_wrap = ta_Physical;
3019         else if(strcasecmp( attr->value(), "on" ) == 0)
3020             m_wrap = ta_Physical;
3021         else if(strcasecmp( attr->value(), "off") == 0)
3022             m_wrap = ta_NoWrap;
3023         if (renderer())
3024             renderer()->setNeedsLayoutAndMinMaxRecalc();
3025         break;
3026     case ATTR_ACCESSKEY:
3027         // ignore for the moment
3028         break;
3029     case ATTR_ONFOCUS:
3030         setHTMLEventListener(EventImpl::FOCUS_EVENT,
3031             getDocument()->createHTMLEventListener(attr->value().string(), this));
3032         break;
3033     case ATTR_ONBLUR:
3034         setHTMLEventListener(EventImpl::BLUR_EVENT,
3035             getDocument()->createHTMLEventListener(attr->value().string(), this));
3036         break;
3037     case ATTR_ONSELECT:
3038         setHTMLEventListener(EventImpl::SELECT_EVENT,
3039             getDocument()->createHTMLEventListener(attr->value().string(), this));
3040         break;
3041     case ATTR_ONCHANGE:
3042         setHTMLEventListener(EventImpl::CHANGE_EVENT,
3043             getDocument()->createHTMLEventListener(attr->value().string(), this));
3044         break;
3045     default:
3046         HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
3047     }
3048 }
3049
3050 RenderObject *HTMLTextAreaElementImpl::createRenderer(RenderArena *arena, RenderStyle *style)
3051 {
3052     return new (arena) RenderTextArea(this);
3053 }
3054
3055 bool HTMLTextAreaElementImpl::appendFormData(FormDataList& encoding, bool)
3056 {
3057     if (name().isEmpty()) return false;
3058     encoding.appendData(name(), value());
3059     return true;
3060 }
3061
3062 void HTMLTextAreaElementImpl::reset()
3063 {
3064     setValue(defaultValue());
3065 }
3066
3067 void HTMLTextAreaElementImpl::updateValue()
3068 {
3069     if ( !m_valueIsValid ) {
3070         if ( m_render ) {
3071             m_value = static_cast<RenderTextArea*>( m_render )->text();
3072             m_valueMatchesRenderer = true;
3073         } else {
3074             m_value = defaultValue().string();
3075             m_valueMatchesRenderer = false;
3076         }
3077         m_valueIsValid = true;
3078     }
3079 }
3080
3081 DOMString HTMLTextAreaElementImpl::value()
3082 {
3083     updateValue();
3084     return m_value.isNull() ? DOMString("") : m_value;
3085 }
3086
3087 void HTMLTextAreaElementImpl::setValue(const DOMString &value)
3088 {
3089     m_value = value.string();
3090     m_valueIsValid = true;
3091     m_valueMatchesRenderer = false;
3092     setChanged(true);
3093 }
3094
3095
3096 DOMString HTMLTextAreaElementImpl::defaultValue()
3097 {
3098     DOMString val = "";
3099     // there may be comments - just grab the text nodes
3100     NodeImpl *n;
3101     for (n = firstChild(); n; n = n->nextSibling())
3102         if (n->isTextNode())
3103             val += static_cast<TextImpl*>(n)->data();
3104     if (val[0] == '\r' && val[1] == '\n') {
3105         val = val.copy();
3106         val.remove(0,2);
3107     }
3108     else if (val[0] == '\r' || val[0] == '\n') {
3109         val = val.copy();
3110         val.remove(0,1);
3111     }
3112
3113     return val;
3114 }
3115
3116 void HTMLTextAreaElementImpl::setDefaultValue(const DOMString &defaultValue)
3117 {
3118     // there may be comments - remove all the text nodes and replace them with one
3119     QPtrList<NodeImpl> toRemove;
3120     NodeImpl *n;
3121     for (n = firstChild(); n; n = n->nextSibling())
3122         if (n->isTextNode())
3123             toRemove.append(n);
3124     QPtrListIterator<NodeImpl> it(toRemove);
3125     int exceptioncode = 0;
3126     for (; it.current(); ++it) {
3127         removeChild(it.current(), exceptioncode);
3128     }
3129     insertBefore(getDocument()->createTextNode(defaultValue),firstChild(), exceptioncode);
3130     setValue(defaultValue);
3131 }
3132
3133 void HTMLTextAreaElementImpl::blur()
3134 {
3135     if(getDocument()->focusNode() == this)
3136         getDocument()->setFocusNode(0);
3137 }
3138
3139 void HTMLTextAreaElementImpl::focus()
3140 {
3141     getDocument()->setFocusNode(this);
3142 }
3143
3144 bool HTMLTextAreaElementImpl::isEditable()
3145 {
3146     return true;
3147 }
3148
3149 void HTMLTextAreaElementImpl::accessKeyAction()
3150 {
3151     focus();
3152 }
3153
3154 // -------------------------------------------------------------------------
3155
3156 HTMLIsIndexElementImpl::HTMLIsIndexElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
3157     : HTMLInputElementImpl(doc, f)
3158 {
3159     m_type = TEXT;
3160     setName("isindex");
3161 }
3162
3163 NodeImpl::Id HTMLIsIndexElementImpl::id() const
3164 {
3165     return ID_ISINDEX;
3166 }
3167
3168 void HTMLIsIndexElementImpl::parseHTMLAttribute(HTMLAttributeImpl* attr)
3169 {
3170     switch(attr->id())
3171     {
3172     case ATTR_PROMPT:
3173         setValue(attr->value());
3174     default:
3175         // don't call HTMLInputElement::parseHTMLAttribute here, as it would
3176         // accept attributes this element does not support
3177         HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
3178     }
3179 }
3180
3181 // -------------------------------------------------------------------------
3182
3183 unsigned long HTMLOptionsCollectionImpl::length() const
3184 {
3185     // Not yet implemented.
3186     return 0;
3187 }
3188
3189 void HTMLOptionsCollectionImpl::setLength(unsigned long length)
3190 {
3191     // Not yet implemented.
3192 }
3193
3194 NodeImpl *HTMLOptionsCollectionImpl::item(unsigned long index) const
3195 {
3196     // Not yet implemented.
3197     return 0;
3198 }
3199
3200 NodeImpl *HTMLOptionsCollectionImpl::namedItem(const DOMString &name) const
3201 {
3202     // Not yet implemented.
3203     return 0;
3204 }
3205
3206 // -------------------------------------------------------------------------
3207
3208 FormDataList::FormDataList(QTextCodec *c)
3209     : m_codec(c)
3210 {
3211 }
3212
3213 void FormDataList::appendString(const QCString &s)
3214 {
3215     m_list.append(s);
3216 }
3217
3218 void FormDataList::appendString(const QString &s)
3219 {
3220     QCString cstr = fixLineBreaks(m_codec->fromUnicode(s));
3221     cstr.truncate(cstr.length());
3222     m_list.append(cstr);
3223 }
3224
3225 void FormDataList::appendFile(const DOMString &key, const DOMString &filename)
3226 {
3227     appendString(key.string());
3228     m_list.append(filename.string());
3229 }
3230
3231 } // namespace