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