khtml Library API Documentation

render_replaced.cpp

00001 
00024 #include "render_replaced.h"
00025 #include "render_root.h"
00026 
00027 #include <assert.h>
00028 #include <qwidget.h>
00029 #include <qpainter.h>
00030 #include <qevent.h>
00031 #include <qapplication.h>
00032 #include <kglobalsettings.h>
00033 
00034 #include "khtml_ext.h"
00035 #include "khtmlview.h"
00036 #include "xml/dom2_eventsimpl.h"
00037 #include "khtml_part.h"
00038 #include "xml/dom_docimpl.h" // ### remove dependency
00039 #include <kdebug.h>
00040 
00041 using namespace khtml;
00042 using namespace DOM;
00043 
00044 
00045 RenderReplaced::RenderReplaced(DOM::NodeImpl* node)
00046     : RenderBox(node)
00047 {
00048     // init RenderObject attributes
00049     setReplaced(true);
00050 
00051     m_intrinsicWidth = 200;
00052     m_intrinsicHeight = 150;
00053 }
00054 
00055 void RenderReplaced::paint( QPainter *p, int _x, int _y, int _w, int _h,
00056                             int _tx, int _ty)
00057 {
00058     // not visible or nont even once layouted?
00059     if (style()->visibility() != VISIBLE || m_y <=  -500000)  return;
00060 
00061     _tx += m_x;
00062     _ty += m_y;
00063 
00064     if((_ty > _y + _h) || (_ty + m_height < _y)) return;
00065 
00066     // overflow: hidden
00067     bool clipped = false;
00068     if (style()->overflow()==OHIDDEN || (style()->position() == ABSOLUTE && style()->clipSpecified()) ) {
00069         calcClip(p, _tx, _ty);
00070     clipped = true;
00071     }
00072 
00073     if(hasSpecialObjects()) paintBoxDecorations(p, _x, _y, _w, _h, _tx, _ty);
00074 
00075     paintObject(p, _x, _y, _w, _h, _tx, _ty);
00076 
00077     // overflow: hidden
00078     // restore clip region
00079     if ( clipped ) {
00080     p->restore();
00081     }
00082 }
00083 
00084 void RenderReplaced::calcMinMaxWidth()
00085 {
00086     KHTMLAssert( !minMaxKnown());
00087 
00088 #ifdef DEBUG_LAYOUT
00089     kdDebug( 6040 ) << "RenderReplaced::calcMinMaxWidth() known=" << minMaxKnown() << endl;
00090 #endif
00091 
00092     int width = calcReplacedWidth();
00093 
00094     if (!isWidget())
00095         width += paddingLeft() + paddingRight() + borderLeft() + borderRight();
00096 
00097     if ( style()->width().isPercent() || style()->height().isPercent() ) {
00098         m_minWidth = 0;
00099         m_maxWidth = width;
00100     }
00101     else
00102         m_minWidth = m_maxWidth = width;
00103 
00104     setMinMaxKnown();
00105 }
00106 
00107 short RenderReplaced::lineHeight( bool ) const
00108 {
00109     return height()+marginTop()+marginBottom();
00110 }
00111 
00112 short RenderReplaced::baselinePosition( bool ) const
00113 {
00114     return height()+marginTop()+marginBottom();
00115 }
00116 
00117 void RenderReplaced::position(int x, int y, int, int, int, bool, bool, int)
00118 {
00119     m_x = x + marginLeft();
00120     m_y = y + marginTop();
00121 }
00122 
00123 // -----------------------------------------------------------------------------
00124 
00125 RenderWidget::RenderWidget(DOM::NodeImpl* node)
00126         : RenderReplaced(node)
00127 {
00128     m_widget = 0;
00129     // a replaced element doesn't support being anonymous
00130     assert(node);
00131     m_view = node->getDocument()->view();
00132 
00133     // this is no real reference counting, its just there
00134     // to make sure that we're not deleted while we're recursed
00135     // in an eventFilter of the widget
00136     ref();
00137 }
00138 
00139 void RenderWidget::detach()
00140 {
00141     remove();
00142 
00143     if ( m_widget ) {
00144         if ( m_view ) {
00145             m_view->setWidgetVisible(this, false);
00146             m_view->removeChild( m_widget );
00147             m_view = 0;
00148         }
00149 
00150         m_widget->removeEventFilter( this );
00151         m_widget->setMouseTracking( false );
00152     }
00153     deref();
00154 }
00155 
00156 RenderWidget::~RenderWidget()
00157 {
00158     KHTMLAssert( refCount() <= 0 );
00159 
00160     if(m_widget) {
00161         m_widget->hide();
00162         m_widget->deleteLater();
00163     }
00164 }
00165 
00166 class QWidgetResizeEvent : public QEvent
00167 {
00168 public:
00169     enum { Type = 0xfeedabee };
00170     QWidgetResizeEvent( int _w,  int _h ) :
00171     QEvent( (QEvent::Type)Type ),  w( _w ), h( _h ) {}
00172     int w;
00173     int h;
00174 };
00175 
00176 void  RenderWidget::resizeWidget( int w, int h )
00177 {
00178     // ugly hack to limit the maximum size of the widget (as X11 has problems i
00179     h = QMIN( h, 3072 );
00180     w = QMIN( w, 2000 );
00181 
00182     if (m_widget->width() != w || m_widget->height() != h) {
00183         ref();
00184         element()->ref();
00185     QApplication::postEvent( this, new QWidgetResizeEvent( w, h ) );
00186         element()->deref();
00187         deref();
00188     }
00189 }
00190 
00191 bool RenderWidget::event( QEvent *e )
00192 {
00193     if ( m_widget && (e->type() == (int)QWidgetResizeEvent::Type) ) {
00194     QWidgetResizeEvent *re = static_cast<QWidgetResizeEvent *>(e);
00195     m_widget->resize( re->w,  re->h );
00196     }
00197     return true;
00198 }
00199 
00200 
00201 void RenderWidget::setQWidget(QWidget *widget)
00202 {
00203     if (widget != m_widget)
00204     {
00205         if (m_widget) {
00206             m_widget->removeEventFilter(this);
00207             disconnect( m_widget, SIGNAL( destroyed()), this, SLOT( slotWidgetDestructed()));
00208             delete m_widget;
00209             m_widget = 0;
00210         }
00211         m_widget = widget;
00212         if (m_widget) {
00213             connect( m_widget, SIGNAL( destroyed()), this, SLOT( slotWidgetDestructed()));
00214             m_widget->installEventFilter(this);
00215             if (m_widget->focusPolicy() > QWidget::StrongFocus)
00216                 m_widget->setFocusPolicy(QWidget::StrongFocus);
00217             // if we're already layouted, apply the calculated space to the
00218             // widget immediately
00219             if (layouted()) {
00220         // ugly hack to limit the maximum size of the widget (as X11 has problems if it's bigger)
00221         resizeWidget( m_width-borderLeft()-borderRight()-paddingLeft()-paddingRight(),
00222                   m_height-borderTop()-borderBottom()-paddingTop()-paddingBottom() );
00223             }
00224             else
00225                 setPos(xPos(), -500000);
00226         }
00227         m_view->setWidgetVisible(this, false);
00228     m_view->addChild( m_widget, 0, -500000);
00229     }
00230 }
00231 
00232 void RenderWidget::layout( )
00233 {
00234     KHTMLAssert( !layouted() );
00235     KHTMLAssert( minMaxKnown() );
00236     if ( m_widget ) {
00237     resizeWidget( m_width-borderLeft()-borderRight()-paddingLeft()-paddingRight(),
00238               m_height-borderTop()-borderBottom()-paddingTop()-paddingBottom() );
00239     }
00240 
00241     setLayouted();
00242 }
00243 
00244 void RenderWidget::updateFromElement()
00245 {
00246     if (m_widget) {
00247         QColor color = style()->color();
00248         QColor backgroundColor = style()->backgroundColor();
00249 
00250         if ( color.isValid() || backgroundColor.isValid() ) {
00251             QPalette pal(QApplication::palette(m_widget));
00252 
00253             int contrast_ = KGlobalSettings::contrast();
00254             int highlightVal = 100 + (2*contrast_+4)*16/10;
00255             int lowlightVal = 100 + (2*contrast_+4)*10;
00256 
00257             if (backgroundColor.isValid()) {
00258                 for ( int i = 0; i < QPalette::NColorGroups; i++ ) {
00259                     pal.setColor( (QPalette::ColorGroup)i, QColorGroup::Background, backgroundColor );
00260                     pal.setColor( (QPalette::ColorGroup)i, QColorGroup::Light, backgroundColor.light(highlightVal) );
00261                     pal.setColor( (QPalette::ColorGroup)i, QColorGroup::Dark, backgroundColor.dark(lowlightVal) );
00262                     pal.setColor( (QPalette::ColorGroup)i, QColorGroup::Mid, backgroundColor.dark(120) );
00263                     pal.setColor( (QPalette::ColorGroup)i, QColorGroup::Midlight, backgroundColor.light(110) );
00264                     pal.setColor( (QPalette::ColorGroup)i, QColorGroup::Button, backgroundColor );
00265                     pal.setColor( (QPalette::ColorGroup)i, QColorGroup::Base, backgroundColor );
00266         }
00267             }
00268             if ( color.isValid() ) {
00269                 struct ColorSet {
00270                     QPalette::ColorGroup cg;
00271                     QColorGroup::ColorRole cr;
00272                 };
00273                 const struct ColorSet toSet [] = {
00274                     { QPalette::Active, QColorGroup::Foreground },
00275                     { QPalette::Active, QColorGroup::ButtonText },
00276                     { QPalette::Active, QColorGroup::Text },
00277                     { QPalette::Inactive, QColorGroup::Foreground },
00278                     { QPalette::Inactive, QColorGroup::ButtonText },
00279                     { QPalette::Inactive, QColorGroup::Text },
00280                     { QPalette::Disabled,QColorGroup::ButtonText },
00281                     { QPalette::NColorGroups, QColorGroup::NColorRoles },
00282                 };
00283                 const ColorSet *set = toSet;
00284                 while( set->cg != QPalette::NColorGroups ) {
00285                     pal.setColor( set->cg, set->cr, color );
00286                     ++set;
00287                 }
00288 
00289                 QColor disfg = color;
00290                 int h, s, v;
00291                 disfg.hsv( &h, &s, &v );
00292                 if (v > 128)
00293                     // dark bg, light fg - need a darker disabled fg
00294                     disfg = disfg.dark(lowlightVal);
00295                 else if (disfg != Qt::black)
00296                     // light bg, dark fg - need a lighter disabled fg - but only if !black
00297                     disfg = disfg.light(highlightVal);
00298                 else
00299                     // black fg - use darkgrey disabled fg
00300                     disfg = Qt::darkGray;
00301                 pal.setColor(QPalette::Disabled,QColorGroup::Foreground,disfg);
00302             }
00303 
00304             m_widget->setPalette(pal);
00305         }
00306         else
00307             m_widget->unsetPalette();
00308     }
00309 
00310     RenderReplaced::updateFromElement();
00311 }
00312 
00313 void RenderWidget::slotWidgetDestructed()
00314 {
00315     m_widget = 0;
00316 }
00317 
00318 void RenderWidget::setStyle(RenderStyle *_style)
00319 {
00320     RenderReplaced::setStyle(_style);
00321     if(m_widget)
00322     {
00323         m_widget->setFont(style()->font());
00324         if (style()->visibility() != VISIBLE) {
00325             m_widget->hide();
00326         }
00327     }
00328 
00329     // do not paint background or borders for widgets
00330     setSpecialObjects(false);
00331 }
00332 
00333 void RenderWidget::paintObject(QPainter* /*p*/, int, int, int, int, int _tx, int _ty)
00334 {
00335     if (!m_widget || !m_view)
00336     return;
00337 
00338     if (style()->visibility() != VISIBLE) {
00339     m_widget->hide();
00340     return;
00341     }
00342 
00343     // add offset for relative positioning
00344     if(isRelPositioned())
00345     relativePositionOffset(_tx, _ty);
00346 
00347     int xPos = _tx+borderLeft()+paddingLeft();
00348     int yPos = _ty+borderTop()+paddingTop();
00349 
00350     int childw = m_widget->width();
00351     int childh = m_widget->height();
00352     if ( (childw == 2000 || childh == 3072) && m_widget->inherits( "KHTMLView" ) ) {
00353     KHTMLView *vw = static_cast<KHTMLView *>(m_widget);
00354     int cy = m_view->contentsY();
00355     int ch = m_view->visibleHeight();
00356 
00357 
00358     int childx = m_view->childX( m_widget );
00359     int childy = m_view->childY( m_widget );
00360 
00361     int xNew = xPos;
00362     int yNew = childy;
00363 
00364     //  qDebug("cy=%d, ch=%d, childy=%d, childh=%d", cy, ch, childy, childh );
00365     if ( childh == 3072 ) {
00366         if ( cy + ch > childy + childh ) {
00367         yNew = cy + ( ch - childh )/2;
00368         } else if ( cy < childy ) {
00369         yNew = cy + ( ch - childh )/2;
00370         }
00371 //      qDebug("calculated yNew=%d", yNew);
00372     }
00373     yNew = QMIN( yNew, yPos + m_height - childh );
00374     yNew = QMAX( yNew, yPos );
00375     if ( yNew != childy || xNew != childx ) {
00376         if ( vw->contentsHeight() < yNew - yPos + childh )
00377         vw->resizeContents( vw->contentsWidth(), yNew - yPos + childh );
00378         vw->setContentsPos( xNew - xPos, yNew - yPos );
00379     }
00380     xPos = xNew;
00381     yPos = yNew;
00382     }
00383     m_view->setWidgetVisible(this, true);
00384     m_view->addChild(m_widget, xPos, yPos );
00385     m_widget->show();
00386 }
00387 
00388 bool RenderWidget::eventFilter(QObject* /*o*/, QEvent* e)
00389 {
00390     if ( !element() ) return true;
00391 
00392     ref();
00393     element()->ref();
00394 
00395     bool filtered = false;
00396 
00397     //kdDebug() << "RenderWidget::eventFilter type=" << e->type() << endl;
00398     switch(e->type()) {
00399     case QEvent::FocusOut:
00400         // Don't count popup as a valid reason for losing the focus
00401         // (example: opening the options of a select combobox shouldn't emit onblur)
00402         if ( QFocusEvent::reason() != QFocusEvent::Popup )
00403             handleFocusOut();
00404         break;
00405     case QEvent::FocusIn:
00406         //kdDebug(6000) << "RenderWidget::eventFilter captures FocusIn" << endl;
00407         element()->getDocument()->setFocusNode(element());
00408 //         if ( isEditable() ) {
00409 //             KHTMLPartBrowserExtension *ext = static_cast<KHTMLPartBrowserExtension *>( element()->view->part()->browserExtension() );
00410 //             if ( ext )  ext->editableWidgetFocused( m_widget );
00411 //         }
00412         break;
00413     case QEvent::MouseButtonPress:
00414     case QEvent::MouseButtonRelease:
00415     break;
00416     case QEvent::MouseButtonDblClick:
00417     break;
00418     case QEvent::MouseMove:
00419 //     {
00420 //         int absX, absY;
00421 //         absolutePosition(absX,absY);
00422 //         QMouseEvent* _e = static_cast<QMouseEvent*>(e);
00423 //         QMouseEvent e2(e->type(),QPoint(absX,absY)+_e->pos(),_e->button(),_e->state());
00424 //         element()->dispatchMouseEvent(&e2);
00425 //         // ### change cursor like in KHTMLView?
00426 //     }
00427     break;
00428     case QEvent::Wheel:
00429         // don't allow the widget to react to wheel event unless its
00430         // currently focused. this avoids accidentally changing a select box
00431         // or something while wheeling a webpage.
00432         if (qApp->focusWidget() != m_widget &&
00433             m_widget->focusPolicy() <= QWidget::StrongFocus)  {
00434             static_cast<QWheelEvent*>(e)->ignore();
00435             QApplication::sendEvent(m_view, e);
00436             filtered = true;
00437         }
00438     break;
00439     case QEvent::KeyPress:
00440     case QEvent::KeyRelease:
00441         if (!element()->dispatchKeyEvent(static_cast<QKeyEvent*>(e)))
00442             filtered = true;
00443         break;
00444     default: break;
00445     };
00446 
00447     element()->deref();
00448 
00449     // stop processing if the widget gets deleted, but continue in all other cases
00450     if (hasOneRef())
00451         filtered = true;
00452     deref();
00453 
00454     return filtered;
00455 }
00456 
00457 
00458 #include "render_replaced.moc"
00459 
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.0.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Oct 8 12:22:43 2003 by doxygen 1.2.18 written by Dimitri van Heesch, © 1997-2001