+2006-07-11 Adele Peterson <adele@apple.com>
+
+ Reviewed by Hyatt.
+
+ - Fix for http://bugzilla.opendarwin.org/show_bug.cgi?id=9861
+ REGRESSION: Can't dynamically change list box to popup
+
+ and updated fix for http://bugzilla.opendarwin.org/show_bug.cgi?id=9859
+ REGRESSION: Can't dynamically change popup to list box
+
+ The original fix for 9859 was in the renderer, and I think we can catch the change
+ earlier in the element to detach and reattach.
+
+ I also did some cleanup to remove the PopupButton code path from DeprecatedRenderSelect
+
+ Test: fast/forms/select-change-listbox-to-popup.html
+
+ * html/HTMLSelectElement.cpp:
+ (WebCore::HTMLSelectElement::parseMappedAttribute): If the new attribute value is going to require us to change from listbox to popup or vice versa,
+ and we're already attached, then detach and reattach to create the correct renderer. If we're not attached, then we'll create the correct renderer
+ when we attach.
+ (WebCore::HTMLSelectElement::recalcStyle): Updated shouldUseMenuList since it no longer takes a RenderStyle.
+ (WebCore::HTMLSelectElement::isKeyboardFocusable): ditto.
+ (WebCore::HTMLSelectElement::isMouseFocusable): ditto.
+ (WebCore::HTMLSelectElement::createRenderer): ditto.
+ (WebCore::HTMLSelectElement::setRecalcListItems): ditto.
+ (WebCore::HTMLSelectElement::reset): ditto.
+ (WebCore::HTMLSelectElement::notifyOptionSelected): ditto.
+ (WebCore::HTMLSelectElement::defaultEventHandler): ditto.
+
+ * html/HTMLSelectElement.h: (WebCore::HTMLSelectElement::shouldUseMenuList):
+ This method no longer takes a RenderStyle. That was leftover from when we used to use the appearance
+ to determine whether or not to use the new menu list implementation.
+
+ * rendering/DeprecatedRenderSelect.h: Removed PopupButton code path.
+ * rendering/DeprecatedRenderSelect.cpp:
+ (WebCore::DeprecatedRenderSelect::DeprecatedRenderSelect):
+ (WebCore::DeprecatedRenderSelect::setWidgetWritingDirection):
+ (WebCore::DeprecatedRenderSelect::updateFromElement):
+ (WebCore::DeprecatedRenderSelect::baselinePosition):
+ (WebCore::DeprecatedRenderSelect::layout):
+ (WebCore::DeprecatedRenderSelect::updateSelection):
+
+ * rendering/RenderMenuList.cpp: (WebCore::RenderMenuList::updateFromElement):
+ Backed out previous fix since this is now done in HTMLSelectElement.
+
2006-07-11 Adele Peterson <adele@apple.com>
Reviewed by Hyatt.
void HTMLSelectElement::recalcStyle( StyleChange ch )
{
if (hasChangedChild() && renderer()) {
- if (shouldUseMenuList(renderer()->style()))
+ if (shouldUseMenuList())
static_cast<RenderMenuList*>(renderer())->setOptionsChanged(true);
else
static_cast<DeprecatedRenderSelect*>(renderer())->setOptionsChanged(true);
void HTMLSelectElement::parseMappedAttribute(MappedAttribute *attr)
{
+ bool oldShouldUseMenuList = shouldUseMenuList();
if (attr->name() == sizeAttr) {
m_size = max(attr->value().toInt(), 1);
+ if (oldShouldUseMenuList != shouldUseMenuList() && attached()) {
+ detach();
+ attach();
+ }
} else if (attr->name() == widthAttr) {
m_minwidth = max(attr->value().toInt(), 0);
} else if (attr->name() == multipleAttr) {
m_multiple = (!attr->isNull());
+ if (oldShouldUseMenuList != shouldUseMenuList() && attached()) {
+ detach();
+ attach();
+ }
} else if (attr->name() == accesskeyAttr) {
// FIXME: ignore for the moment
} else if (attr->name() == onfocusAttr) {
bool HTMLSelectElement::isKeyboardFocusable() const
{
- if (renderer() && shouldUseMenuList(renderer()->style()))
+ if (renderer() && shouldUseMenuList())
return isFocusable();
return HTMLGenericFormElement::isKeyboardFocusable();
}
bool HTMLSelectElement::isMouseFocusable() const
{
- if (renderer() && shouldUseMenuList(renderer()->style()))
+ if (renderer() && shouldUseMenuList())
return isFocusable();
return HTMLGenericFormElement::isMouseFocusable();
}
RenderObject *HTMLSelectElement::createRenderer(RenderArena *arena, RenderStyle *style)
{
- if (shouldUseMenuList(style))
+ if (shouldUseMenuList())
return new (arena) RenderMenuList(this);
return new (arena) DeprecatedRenderSelect(this);
}
{
m_recalcListItems = true;
if (renderer()) {
- if (shouldUseMenuList(renderer()->style()))
+ if (shouldUseMenuList())
static_cast<RenderMenuList*>(renderer())->setOptionsChanged(true);
else
static_cast<DeprecatedRenderSelect*>(renderer())->setOptionsChanged(true);
if (!optionSelected && firstOption)
firstOption->setSelected(true);
if (renderer()) {
- if (shouldUseMenuList(renderer()->style()))
+ if (shouldUseMenuList())
static_cast<RenderMenuList*>(renderer())->setSelectionChanged(true);
else
static_cast<DeprecatedRenderSelect*>(renderer())->setSelectionChanged(true);
}
}
if (renderer()) {
- if (shouldUseMenuList(renderer()->style()))
+ if (shouldUseMenuList())
static_cast<RenderMenuList*>(renderer())->setSelectionChanged(true);
else
static_cast<DeprecatedRenderSelect*>(renderer())->setSelectionChanged(true);
form()->submitClick();
evt->setDefaultHandled();
}
- if ((keyIdentifier == "Down" || keyIdentifier == "Up" || keyIdentifier == "U+000020") && renderer() && shouldUseMenuList(renderer()->style())) {
+ if ((keyIdentifier == "Down" || keyIdentifier == "Up" || keyIdentifier == "U+000020") && renderer() && shouldUseMenuList()) {
static_cast<RenderMenuList*>(renderer())->showPopup();
evt->setDefaultHandled();
}
}
- if (evt->type() == mousedownEvent && renderer() && shouldUseMenuList(renderer()->style())) {
+ if (evt->type() == mousedownEvent && renderer() && shouldUseMenuList()) {
static_cast<RenderMenuList*>(renderer())->showPopup();
evt->setDefaultHandled();
}
: RenderFormElement(element)
, m_size(element->size())
, m_multiple(element->multiple())
- , m_useListBox(m_multiple || m_size > 1)
, m_selectionChanged(true)
, m_ignoreSelectEvents(false)
, m_optionsChanged(true)
{
- if (m_useListBox)
- setWidget(createListBox());
- else
- setWidget(new PopUpButton);
+ setWidget(createListBox());
}
void DeprecatedRenderSelect::setWidgetWritingDirection()
{
TextDirection d = style()->direction() == RTL ? RTL : LTR;
- if (m_useListBox)
- static_cast<ListBox*>(m_widget)->setWritingDirection(d);
- else
- static_cast<PopUpButton*>(m_widget)->setWritingDirection(d);
+ static_cast<ListBox*>(m_widget)->setWritingDirection(d);
}
void DeprecatedRenderSelect::setStyle(RenderStyle* s)
// change widget type
bool oldMultiple = m_multiple;
- unsigned oldSize = m_size;
- bool oldListbox = m_useListBox;
-
m_multiple = static_cast<HTMLSelectElement*>(node())->multiple();
- m_size = static_cast<HTMLSelectElement*>(node())->size();
- m_useListBox = (m_multiple || m_size > 1);
-
- if (oldMultiple != m_multiple || oldSize != m_size) {
- if (m_useListBox != oldListbox) {
- // type of select has changed
- delete m_widget;
-
- if (m_useListBox)
- setWidget(createListBox());
- else
- setWidget(new PopUpButton);
- setWidgetWritingDirection();
- }
- if (m_useListBox && oldMultiple != m_multiple) {
- static_cast<ListBox*>(m_widget)->setSelectionMode(m_multiple ? ListBox::Extended : ListBox::Single);
- }
+ if (oldMultiple != m_multiple) {
+ static_cast<ListBox*>(m_widget)->setSelectionMode(m_multiple ? ListBox::Extended : ListBox::Single);
m_selectionChanged = true;
m_optionsChanged = true;
}
Vector<HTMLElement*> listItems = static_cast<HTMLSelectElement*>(node())->listItems();
int listIndex;
- if (m_useListBox)
- static_cast<ListBox*>(m_widget)->clear();
- else
- static_cast<PopUpButton*>(m_widget)->clear();
-
+ static_cast<ListBox*>(m_widget)->clear();
+
bool groupEnabled = true;
for (listIndex = 0; listIndex < int(listItems.size()); listIndex++) {
if (listItems[listIndex]->hasTagName(optgroupTag)) {
groupEnabled = optgroupElement->isEnabled();
- if (m_useListBox)
- static_cast<ListBox*>(m_widget)->appendGroupLabel(label, groupEnabled);
- else
- static_cast<PopUpButton*>(m_widget)->appendGroupLabel(label);
+ static_cast<ListBox*>(m_widget)->appendGroupLabel(label, groupEnabled);
+
} else if (listItems[listIndex]->hasTagName(optionTag)) {
HTMLOptionElement* optionElement = static_cast<HTMLOptionElement*>(listItems[listIndex]);
DeprecatedString itemText = optionElement->text().deprecatedString();
if (listItems[listIndex]->parentNode()->hasTagName(optgroupTag))
itemText.prepend(" ");
- if (m_useListBox)
- static_cast<ListBox*>(m_widget)->appendItem(itemText, groupEnabled && optionElement->isEnabled());
- else
- static_cast<PopUpButton*>(m_widget)->appendItem(itemText, groupEnabled && optionElement->isEnabled());
- } else if (listItems[listIndex]->hasTagName(hrTag)) {
- if (!m_useListBox)
- static_cast<PopUpButton*>(m_widget)->appendSeparator();
+ static_cast<ListBox*>(m_widget)->appendItem(itemText, groupEnabled && optionElement->isEnabled());
} else
ASSERT(false);
m_selectionChanged = true;
}
- if (m_useListBox)
- static_cast<ListBox*>(m_widget)->doneAppendingItems();
+ static_cast<ListBox*>(m_widget)->doneAppendingItems();
setNeedsLayoutAndMinMaxRecalc();
m_optionsChanged = false;
}
short DeprecatedRenderSelect::baselinePosition(bool f, bool isRootLineBox) const
{
- if (m_useListBox) {
- // FIXME: Should get the hardcoded constant of 7 by calling a ListBox function,
- // as we do for other widget classes.
- return RenderWidget::baselinePosition(f, isRootLineBox) - 7;
- }
- return RenderFormElement::baselinePosition(f, isRootLineBox);
+ // FIXME: Should get the hardcoded constant of 7 by calling a ListBox function,
+ // as we do for other widget classes.
+ return RenderWidget::baselinePosition(f, isRootLineBox) - 7;
}
void DeprecatedRenderSelect::calcMinMaxWidth()
// first selected one)
// calculate size
- if (m_useListBox) {
- ListBox* w = static_cast<ListBox*>(m_widget);
-
-
- int size = m_size;
- // check if multiple and size was not given or invalid
- // Internet Exploder sets size to min(number of elements, 4)
- // Netscape seems to simply set it to "number of elements"
- // the average of that is IMHO min(number of elements, 10)
- // so I did that ;-)
- if (size < 1)
- size = min(static_cast<ListBox*>(m_widget)->count(), 10U);
-
- // Let the widget tell us how big it wants to be.
- IntSize s(w->sizeForNumberOfLines(size));
- setIntrinsicWidth(s.width());
- setIntrinsicHeight(s.height());
- } else {
- IntSize s(m_widget->sizeHint());
- setIntrinsicWidth(s.width());
- setIntrinsicHeight(s.height());
- }
+ ListBox* w = static_cast<ListBox*>(m_widget);
+
+
+ int size = m_size;
+ // check if multiple and size was not given or invalid
+ // Internet Exploder sets size to min(number of elements, 4)
+ // Netscape seems to simply set it to "number of elements"
+ // the average of that is IMHO min(number of elements, 10)
+ // so I did that ;-)
+ if (size < 1)
+ size = min(static_cast<ListBox*>(m_widget)->count(), 10U);
+
+ // Let the widget tell us how big it wants to be.
+ IntSize s(w->sizeForNumberOfLines(size));
+ setIntrinsicWidth(s.width());
+ setIntrinsicHeight(s.height());
RenderFormElement::layout();
m_widget->setEnabled(foundOption && ! static_cast<HTMLSelectElement*>(node())->disabled());
}
-void DeprecatedRenderSelect::valueChanged(Widget*)
-{
- if (m_ignoreSelectEvents)
- return;
-
- ASSERT(!m_useListBox);
-
- int index = static_cast<PopUpButton*>(m_widget)->currentItem();
-
- Vector<HTMLElement*> listItems = static_cast<HTMLSelectElement*>(node())->listItems();
- if (index >= 0 && index < (int)listItems.size()) {
- bool found = listItems[index]->hasTagName(optionTag);
- if (!found) {
- // this one is not selectable, we need to find an option element
- while ((unsigned) index < listItems.size()) {
- if (listItems[index]->hasTagName(optionTag)) {
- found = true;
- break;
- }
- ++index;
- }
-
- if (!found) {
- while (index >= 0) {
- if (listItems[index]->hasTagName(optionTag)) {
- found = true;
- break;
- }
- --index;
- }
- }
- }
-
- if (found) {
- if (index != static_cast<PopUpButton*>(m_widget)->currentItem())
- static_cast<PopUpButton*>(m_widget)->setCurrentItem(index);
-
- for (unsigned i = 0; i < listItems.size(); ++i)
- if (listItems[i]->hasTagName(optionTag) && i != (unsigned int) index)
- static_cast<HTMLOptionElement*>(listItems[i])->m_selected = false;
-
- static_cast<HTMLOptionElement*>(listItems[index])->m_selected = true;
- }
- }
-
- static_cast<HTMLSelectElement*>(node())->onChange();
-}
-
void DeprecatedRenderSelect::selectionChanged(Widget*)
{
if (m_ignoreSelectEvents)
{
Vector<HTMLElement*> listItems = static_cast<HTMLSelectElement*>(node())->listItems();
int i;
- if (m_useListBox) {
- // if multi-select, we select only the new selected index
- ListBox *listBox = static_cast<ListBox*>(m_widget);
- int j = 0;
- for (i = 0; i < int(listItems.size()); i++) {
- listBox->setSelected(j, listItems[i]->hasTagName(optionTag) &&
- static_cast<HTMLOptionElement*>(listItems[i])->selected());
- if (listItems[i]->hasTagName(optionTag) || listItems[i]->hasTagName(optgroupTag))
- ++j;
-
- }
- } else {
- bool found = false;
- unsigned firstOption = listItems.size();
- i = listItems.size();
- while (i--)
- if (listItems[i]->hasTagName(optionTag)) {
- if (found)
- static_cast<HTMLOptionElement*>(listItems[i])->m_selected = false;
- else if (static_cast<HTMLOptionElement*>(listItems[i])->selected()) {
- static_cast<PopUpButton*>(m_widget)->setCurrentItem(i);
- found = true;
- }
- firstOption = i;
- }
-
- ASSERT(firstOption == listItems.size() || found);
+ // if multi-select, we select only the new selected index
+ ListBox *listBox = static_cast<ListBox*>(m_widget);
+ int j = 0;
+ for (i = 0; i < int(listItems.size()); i++) {
+ listBox->setSelected(j, listItems[i]->hasTagName(optionTag) &&
+ static_cast<HTMLOptionElement*>(listItems[i])->selected());
+ if (listItems[i]->hasTagName(optionTag) || listItems[i]->hasTagName(optgroupTag))
+ ++j;
+
}
m_selectionChanged = false;