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