?? render_form.cpp
字號:
/*
* This file is part of the DOM implementation for KDE.
*
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* (C) 1999 Antti Koivisto (koivisto@kde.org)
* (C) 2000 Dirk Mueller (mueller@kde.org)
* Copyright (C) 2004 Apple Computer, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include <kdebug.h>
#include <klocale.h>
#include <kfiledialog.h>
#include <kcompletionbox.h>
#include <kcursor.h>
#include <qstyle.h>
#include "misc/helper.h"
#include "xml/dom2_eventsimpl.h"
#include "html/html_formimpl.h"
#include "misc/htmlhashes.h"
#include "rendering/render_form.h"
#include "rendering/render_canvas.h"
#include <assert.h>
#include "khtmlview.h"
#include "khtml_ext.h"
#include "xml/dom_docimpl.h"
#include <kdebug.h>
#if APPLE_CHANGES
#include "KWQFileButton.h"
#include "KWQSlider.h"
#endif
using namespace khtml;
using namespace DOM;
RenderFormElement::RenderFormElement(HTMLGenericFormElementImpl *element)
: RenderWidget(element)
{
setInline(true);
}
RenderFormElement::~RenderFormElement()
{
}
short RenderFormElement::baselinePosition( bool f, bool isRootLineBox ) const
{
#if APPLE_CHANGES
return marginTop() + widget()->baselinePosition(m_height);
#else
return RenderWidget::baselinePosition( f, isRootLineBox ) - 2 - style()->fontMetrics().descent();
#endif
}
#ifdef NOKIA_CHANGES
int RenderFormElement::calcReplacedWidth() const
{
int zoom(canvas()->view()->scalingFactor());
int width = RenderBox::calcReplacedWidth();
int bidiWidth = canvas()->view()->maxBidiWidth();
Length w = style()->width();
if( w.type == Fixed) {
width = width*100/zoom;
}
// form should not exceed the view width
width = width>bidiWidth?bidiWidth:width;
return width;
}
#endif
void RenderFormElement::setStyle(RenderStyle* s)
{
#if APPLE_CHANGES
if (canHaveIntrinsicMargins())
addIntrinsicMarginsIfAllowed(s);
#endif
RenderWidget::setStyle(s);
#if APPLE_CHANGES && !NOKIA_CHANGES
// Do not paint a background or border for Aqua form elements
setShouldPaintBackgroundOrBorder(false);
#endif
m_widget->setFont(style()->font());
}
void RenderFormElement::updateFromElement()
{
m_widget->setEnabled(!element()->disabled());
#if APPLE_CHANGES
m_widget->setPalette(QPalette(style()->backgroundColor(), style()->color()));
#else
QColor color = style()->color();
QColor backgroundColor = style()->backgroundColor();
if ( color.isValid() || backgroundColor.isValid() ) {
QPalette pal(m_widget->palette());
int contrast_ = KGlobalSettings::contrast();
int highlightVal = 100 + (2*contrast_+4)*16/10;
int lowlightVal = 100 + (2*contrast_+4)*10;
if (backgroundColor.isValid()) {
for ( int i = 0; i < QPalette::NColorGroups; i++ ) {
pal.setColor( (QPalette::ColorGroup)i, QColorGroup::Background, backgroundColor );
pal.setColor( (QPalette::ColorGroup)i, QColorGroup::Light, backgroundColor.light(highlightVal) );
pal.setColor( (QPalette::ColorGroup)i, QColorGroup::Dark, backgroundColor.dark(lowlightVal) );
pal.setColor( (QPalette::ColorGroup)i, QColorGroup::Mid, backgroundColor.dark(120) );
pal.setColor( (QPalette::ColorGroup)i, QColorGroup::Midlight, backgroundColor.light(110) );
pal.setColor( (QPalette::ColorGroup)i, QColorGroup::Button, backgroundColor );
pal.setColor( (QPalette::ColorGroup)i, QColorGroup::Base, backgroundColor );
}
}
if ( color.isValid() ) {
struct ColorSet {
QPalette::ColorGroup cg;
QColorGroup::ColorRole cr;
};
const struct ColorSet toSet [] = {
{ QPalette::Active, QColorGroup::Foreground },
{ QPalette::Active, QColorGroup::ButtonText },
{ QPalette::Active, QColorGroup::Text },
{ QPalette::Inactive, QColorGroup::Foreground },
{ QPalette::Inactive, QColorGroup::ButtonText },
{ QPalette::Inactive, QColorGroup::Text },
{ QPalette::Disabled,QColorGroup::ButtonText },
{ QPalette::NColorGroups, QColorGroup::NColorRoles },
};
const ColorSet *set = toSet;
while( set->cg != QPalette::NColorGroups ) {
pal.setColor( set->cg, set->cr, color );
++set;
}
QColor disfg = color;
int h, s, v;
disfg.hsv( &h, &s, &v );
if (v > 128)
// dark bg, light fg - need a darker disabled fg
disfg = disfg.dark(lowlightVal);
else if (disfg != Qt::black)
// light bg, dark fg - need a lighter disabled fg - but only if !black
disfg = disfg.light(highlightVal);
else
// black fg - use darkgrey disabled fg
disfg = Qt::darkGray;
pal.setColor(QPalette::Disabled,QColorGroup::Foreground,disfg);
}
m_widget->setPalette(pal);
}
else
m_widget->unsetPalette();
#endif
}
void RenderFormElement::layout()
{
KHTMLAssert( needsLayout() );
KHTMLAssert( minMaxKnown() );
// minimum height
m_height = 0;
calcWidth();
calcHeight();
#if !APPLE_CHANGES
if ( m_widget )
resizeWidget(m_widget,
m_width-borderLeft()-borderRight()-paddingLeft()-paddingRight(),
m_height-borderLeft()-borderRight()-paddingLeft()-paddingRight());
#endif
setNeedsLayout(false);
}
void RenderFormElement::slotClicked()
{
// FIXME: Should share code with KHTMLView::dispatchMouseEvent, which does a lot of the same stuff.
RenderArena *arena = ref();
#if APPLE_CHANGES
QMouseEvent event(QEvent::MouseButtonRelease); // gets "current event"
element()->dispatchMouseEvent(&event, EventImpl::CLICK_EVENT, event.clickCount());
#else
// We also send the KHTML_CLICK or KHTML_DBLCLICK event for
// CLICK. This is not part of the DOM specs, but is used for
// compatibility with the traditional onclick="" and ondblclick=""
// attributes, as there is no way to tell the difference between
// single & double clicks using DOM (only the click count is
// stored, which is not necessarily the same)
QMouseEvent e2(QEvent::MouseButtonRelease, m_mousePos, m_button, m_state);
element()->dispatchMouseEvent(&e2, EventImpl::CLICK_EVENT, m_clickCount);
element()->dispatchMouseEvent(&e2, m_isDoubleClick ? EventImpl::KHTML_DBLCLICK_EVENT : EventImpl::KHTML_CLICK_EVENT, m_clickCount);
#endif
deref(arena);
}
Qt::AlignmentFlags RenderFormElement::textAlignment() const
{
switch (style()->textAlign()) {
case LEFT:
case KHTML_LEFT:
return AlignLeft;
case RIGHT:
case KHTML_RIGHT:
return AlignRight;
case CENTER:
case KHTML_CENTER:
return AlignHCenter;
case JUSTIFY:
// Just fall into the auto code for justify.
case TAAUTO:
return style()->direction() == RTL ? AlignRight : AlignLeft;
}
assert(false); // Should never be reached.
return AlignLeft;
}
#if APPLE_CHANGES
void RenderFormElement::addIntrinsicMarginsIfAllowed(RenderStyle* _style)
{
// Cut out the intrinsic margins completely if we end up using mini controls.
if (_style->font().pixelSize() < 11)
return;
int m = intrinsicMargin();
if (_style->width().isVariable()) {
if (_style->marginLeft().quirk)
_style->setMarginLeft(Length(m, Fixed));
if (_style->marginRight().quirk)
_style->setMarginRight(Length(m, Fixed));
}
if (_style->height().isVariable()) {
if (_style->marginTop().quirk)
_style->setMarginTop(Length(m, Fixed));
if (_style->marginBottom().quirk)
_style->setMarginBottom(Length(m, Fixed));
}
}
#endif
// -------------------------------------------------------------------------
RenderButton::RenderButton(HTMLGenericFormElementImpl *element)
: RenderFormElement(element)
{
}
short RenderButton::baselinePosition( bool f, bool isRootLineBox ) const
{
#if APPLE_CHANGES
return RenderFormElement::baselinePosition( f, isRootLineBox );
#else
return RenderWidget::baselinePosition( f, isRootLineBox ) - 2;
#endif
}
// -------------------------------------------------------------------------------
RenderCheckBox::RenderCheckBox(HTMLInputElementImpl *element)
: RenderButton(element)
{
QCheckBox* b = new QCheckBox(view()->viewport());
b->setAutoMask(true);
b->setMouseTracking(true);
setQWidget(b);
connect(b,SIGNAL(stateChanged(int)),this,SLOT(slotStateChanged(int)));
connect(b, SIGNAL(clicked()), this, SLOT(slotClicked()));
}
void RenderCheckBox::calcMinMaxWidth()
{
KHTMLAssert( !minMaxKnown() );
#if APPLE_CHANGES
// Let the widget tell us how big it wants to be.
QSize s(widget()->sizeHint());
#else
QCheckBox *cb = static_cast<QCheckBox *>( m_widget );
QSize s( cb->style().pixelMetric( QStyle::PM_IndicatorWidth ),
cb->style().pixelMetric( QStyle::PM_IndicatorHeight ) );
#endif
setIntrinsicWidth( s.width() );
setIntrinsicHeight( s.height() );
RenderButton::calcMinMaxWidth();
}
void RenderCheckBox::updateFromElement()
{
widget()->setChecked(element()->checked());
RenderButton::updateFromElement();
}
// From the Qt documentation:
// state is 2 if the button is on, 1 if it is in the "no change" state or 0 if the button is off.
void RenderCheckBox::slotStateChanged(int state)
{
element()->setChecked(state == 2);
element()->onChange();
}
// -------------------------------------------------------------------------------
RenderRadioButton::RenderRadioButton(HTMLInputElementImpl *element)
: RenderButton(element)
{
QRadioButton* b = new QRadioButton(view()->viewport());
b->setAutoMask(true);
b->setMouseTracking(true);
setQWidget(b);
connect(b, SIGNAL(clicked()), this, SLOT(slotClicked()));
}
void RenderRadioButton::updateFromElement()
{
widget()->setChecked(element()->checked());
RenderButton::updateFromElement();
}
void RenderRadioButton::slotClicked()
{
element()->setChecked(true);
// emit mouseClick event etc
RenderButton::slotClicked();
}
void RenderRadioButton::calcMinMaxWidth()
{
KHTMLAssert( !minMaxKnown() );
#if APPLE_CHANGES
// Let the widget tell us how big it wants to be.
QSize s(widget()->sizeHint());
#else
QRadioButton *rb = static_cast<QRadioButton *>( m_widget );
QSize s( rb->style().pixelMetric( QStyle::PM_ExclusiveIndicatorWidth ),
rb->style().pixelMetric( QStyle::PM_ExclusiveIndicatorHeight ) );
#endif
setIntrinsicWidth( s.width() );
setIntrinsicHeight( s.height() );
RenderButton::calcMinMaxWidth();
}
// -------------------------------------------------------------------------------
RenderSubmitButton::RenderSubmitButton(HTMLInputElementImpl *element)
: RenderButton(element)
{
QPushButton* p = new QPushButton(view()->viewport());
setQWidget(p);
p->setAutoMask(true);
p->setMouseTracking(true);
connect(p, SIGNAL(clicked()), this, SLOT(slotClicked()));
}
QString RenderSubmitButton::rawText()
{
QString value = element()->valueWithDefault().string();
value = value.stripWhiteSpace();
value.replace(QChar('\\'), backslashAsCurrencySymbol());
#if APPLE_CHANGES
return value;
#else
QString raw;
for(unsigned int i = 0; i < value.length(); i++) {
raw += value[i];
if(value[i] == '&')
raw += '&';
}
return raw;
#endif
}
void RenderSubmitButton::calcMinMaxWidth()
{
KHTMLAssert( !minMaxKnown() );
#if APPLE_CHANGES
// Let the widget tell us how big it wants to be.
QSize s(widget()->sizeHint());
setIntrinsicWidth(s.width());
setIntrinsicHeight(s.height());
#else
QString raw = rawText();
QPushButton* pb = static_cast<QPushButton*>(m_widget);
pb->setText(raw);
pb->setFont(style()->font());
bool empty = raw.isEmpty();
if ( empty )
raw = QString::fromLatin1("XXXX");
QFontMetrics fm = pb->fontMetrics();
int margin = pb->style().pixelMetric( QStyle::PM_ButtonMargin, pb);
QSize s(pb->style().sizeFromContents(
QStyle::CT_PushButton, pb, fm.size( ShowPrefix, raw))
.expandedTo(QApplication::globalStrut()));
setIntrinsicWidth( s.width() - margin / 2 );
setIntrinsicHeight( s.height() - margin / 2);
#endif
RenderButton::calcMinMaxWidth();
}
#if APPLE_CHANGES
void RenderSubmitButton::setStyle(RenderStyle *s)
{
RenderButton::setStyle(s);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -