diff options
author | Kurt Zenker <kz@openoffice.org> | 2008-03-06 10:48:47 +0000 |
---|---|---|
committer | Kurt Zenker <kz@openoffice.org> | 2008-03-06 10:48:47 +0000 |
commit | 672dde158f1a0b1d7e66d87fabc64cbf0a8b7182 (patch) | |
tree | 7818be7263bbe7ac29dcf70aa0137cda5496d4be /toolkit | |
parent | e17ddba9755523f757f624e58fdbc86fe3c07844 (diff) |
INTEGRATION: CWS layout_DEV300 (1.1.2); FILE ADDED
2008/02/08 18:44:44 jcn 1.1.2.1: Initial toolkit import from ee9a2fcc29d7e2f01cc80ef7c13bf7bc7d55ae7e.
layout/source/awt -> toolkit/source/awt
layout/source/core -> toolkit/source/layout
layout/source/wrapper -> toolkit/source/vclcompat
layout/inc/layout -> toolkit/inc/layout
layout/source/inc -> toolkit/inc/layout
layout/workben -> toolkit/workben/layout
That's ooo-build trunk r11539 @ ooh680-m5/src680-m245.
Diffstat (limited to 'toolkit')
-rw-r--r-- | toolkit/source/layout/flow.cxx | 176 | ||||
-rw-r--r-- | toolkit/source/layout/flow.hxx | 65 | ||||
-rw-r--r-- | toolkit/source/layout/import.cxx | 208 | ||||
-rw-r--r-- | toolkit/source/layout/import.hxx | 283 | ||||
-rw-r--r-- | toolkit/source/layout/proplist.hxx | 34 | ||||
-rw-r--r-- | toolkit/source/layout/root.cxx | 329 | ||||
-rw-r--r-- | toolkit/source/layout/root.hxx | 127 | ||||
-rw-r--r-- | toolkit/source/layout/table.cxx | 326 | ||||
-rw-r--r-- | toolkit/source/layout/table.hxx | 79 | ||||
-rw-r--r-- | toolkit/source/layout/timer.cxx | 121 | ||||
-rw-r--r-- | toolkit/source/layout/timer.hxx | 22 |
11 files changed, 1770 insertions, 0 deletions
diff --git a/toolkit/source/layout/flow.cxx b/toolkit/source/layout/flow.cxx new file mode 100644 index 000000000000..c8573c82a4fa --- /dev/null +++ b/toolkit/source/layout/flow.cxx @@ -0,0 +1,176 @@ +#include "flow.hxx" + +#include <sal/macros.h> + +namespace layoutimpl +{ + +using namespace css; + +bool Flow::ChildData::isVisible() +{ + return xChild.is(); +} + +Flow::Flow() + : Container() + , mnSpacing( 0 ) + , mbHomogeneous( false ) +{ + addProp( RTL_CONSTASCII_USTRINGPARAM( "Homogeneous" ), + ::getCppuType( static_cast< const sal_Bool* >( NULL ) ), + &mbHomogeneous ); + addProp( RTL_CONSTASCII_USTRINGPARAM( "Spacing" ), + ::getCppuType( static_cast< const sal_Int32* >( NULL ) ), + &mnSpacing ); +} + +void SAL_CALL +Flow::addChild( const uno::Reference< awt::XLayoutConstrains >& xChild ) + throw (uno::RuntimeException, css::awt::MaxChildrenException) +{ + if ( xChild.is() ) + { + ChildData *pData = new ChildData(); + pData->xChild = xChild; + maChildren.push_back( pData ); + + setChildParent( xChild ); + queueResize(); + } +} + +void SAL_CALL +Flow::removeChild( const css::uno::Reference< css::awt::XLayoutConstrains >& xChild ) + throw (css::uno::RuntimeException) +{ + for( std::list< ChildData * >::iterator it = maChildren.begin(); + it != maChildren.end(); it++ ) + { + if ( (*it)->xChild == xChild ) + { + delete *it; + maChildren.erase( it ); + + unsetChildParent( xChild ); + queueResize(); + break; + } + } +} + +css::uno::Sequence< css::uno::Reference < css::awt::XLayoutConstrains > > SAL_CALL +Flow::getChildren() + throw (css::uno::RuntimeException) +{ + uno::Sequence< uno::Reference< awt::XLayoutConstrains > > children( maChildren.size() ); + unsigned int i = 0; + for( std::list< ChildData * >::iterator it = maChildren.begin(); + it != maChildren.end(); it++, i++ ) + children[i] = (*it)->xChild; + + return children; +} + +uno::Reference< beans::XPropertySet > SAL_CALL +Flow::getChildProperties( const uno::Reference< awt::XLayoutConstrains >& /*xChild*/ ) + throw (uno::RuntimeException) +{ + return uno::Reference< beans::XPropertySet >(); +} + +css::awt::Size +Flow::calculateSize( long nMaxWidth ) +{ + long nNeedHeight = 0; + + std::list<ChildData *>::const_iterator it; + mnEachWidth = 0; + // first pass, for homogeneous property + for (it = maChildren.begin(); it != maChildren.end(); it++) + { + if ( !(*it)->isVisible() ) + continue; + (*it)->aRequisition = (*it)->xChild->getMinimumSize(); + if ( mbHomogeneous ) + mnEachWidth = SAL_MAX( mnEachWidth, (*it)->aRequisition.Width ); + } + + long nRowWidth = 0, nRowHeight = 0; + for (it = maChildren.begin(); it != maChildren.end(); it++) + { + if ( !(*it)->isVisible() ) + continue; + + awt::Size aChildSize = (*it)->aRequisition; + if ( mbHomogeneous ) + aChildSize.Width = mnEachWidth; + + if ( nMaxWidth && nRowWidth > 0 && nRowWidth + aChildSize.Width > nMaxWidth ) + { + nRowWidth = 0; + nNeedHeight += nRowHeight; + nRowHeight = 0; + } + nRowHeight = SAL_MAX( nRowHeight, aChildSize.Height ); + nRowWidth += aChildSize.Width; + } + nNeedHeight += nRowHeight; + + return awt::Size( nRowWidth, nNeedHeight ); +} + +awt::Size SAL_CALL +Flow::getMinimumSize() throw(uno::RuntimeException) +{ + return maRequisition = calculateSize( 0 ); +} + +sal_Bool SAL_CALL +Flow::hasHeightForWidth() + throw(css::uno::RuntimeException) +{ + return true; +} + +sal_Int32 SAL_CALL +Flow::getHeightForWidth( sal_Int32 nWidth ) + throw(css::uno::RuntimeException) +{ + return calculateSize( nWidth ).Height; +} + +void SAL_CALL +Flow::allocateArea( const css::awt::Rectangle &rArea ) + throw (css::uno::RuntimeException) +{ + maAllocation = rArea; + + std::list<ChildData *>::const_iterator it; + long nX = 0, nY = 0, nRowHeight = 0; + for (it = maChildren.begin(); it != maChildren.end(); it++) + { + ChildData *child = *it; + if ( !child->isVisible() ) + continue; + + awt::Size aChildSize( child->aRequisition ); + if ( mbHomogeneous ) + aChildSize.Width = mnEachWidth; + + if ( nX > 0 && nX + aChildSize.Width > rArea.Width ) + { + nX = 0; + nY += nRowHeight; + nRowHeight = 0; + } + nRowHeight = SAL_MAX( nRowHeight, aChildSize.Height ); + + allocateChildAt( child->xChild, + awt::Rectangle( rArea.X + nX, rArea.Y + nY, aChildSize.Width, aChildSize.Height ) ); + + nX += aChildSize.Width; + } +} + +} // namespace layoutimpl diff --git a/toolkit/source/layout/flow.hxx b/toolkit/source/layout/flow.hxx new file mode 100644 index 000000000000..8e21e8659fea --- /dev/null +++ b/toolkit/source/layout/flow.hxx @@ -0,0 +1,65 @@ +#ifndef CORE_FLOW_HXX +#define CORE_FLOW_HXX + +#include "container.hxx" + +#include <list> + +namespace layoutimpl +{ + +class Flow : public Container +{ +protected: + // Box properties (i.e. affect all children) + sal_Int32 mnSpacing; + sal_Bool mbHomogeneous; + + // Children properties + struct ChildData + { + css::awt::Size aRequisition; + css::uno::Reference< css::awt::XLayoutConstrains > xChild; + css::uno::Reference< css::beans::XPropertySet > xProps; + bool isVisible(); + }; + std::list< ChildData * > maChildren; + long mnEachWidth; // on homogeneous, the width of every child + +public: + Flow(); + + // css::awt::XLayoutContainer + virtual void SAL_CALL addChild( const css::uno::Reference< css::awt::XLayoutConstrains >& Child ) + throw (css::uno::RuntimeException, css::awt::MaxChildrenException); + virtual void SAL_CALL removeChild( const css::uno::Reference< css::awt::XLayoutConstrains >& Child ) + throw (css::uno::RuntimeException); + + virtual css::uno::Sequence< css::uno::Reference + < css::awt::XLayoutConstrains > > SAL_CALL getChildren() + throw (css::uno::RuntimeException); + + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL getChildProperties( + const css::uno::Reference< css::awt::XLayoutConstrains >& Child ) + throw (css::uno::RuntimeException); + + virtual void SAL_CALL allocateArea( const css::awt::Rectangle &rArea ) + throw (css::uno::RuntimeException); + + virtual css::awt::Size SAL_CALL getMinimumSize() + throw(css::uno::RuntimeException); + virtual sal_Bool SAL_CALL hasHeightForWidth() + throw(css::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getHeightForWidth( sal_Int32 nWidth ) + throw(css::uno::RuntimeException); + +PROPHELPER_SET_INFO + +private: + // shared between getMinimumSize() and getHeightForWidth() + css::awt::Size calculateSize( long nMaxWidth ); +}; + +} // namespace layoutimpl + +#endif /*FLOW_CORE_HXX*/ diff --git a/toolkit/source/layout/import.cxx b/toolkit/source/layout/import.cxx new file mode 100644 index 000000000000..ec0814babeb6 --- /dev/null +++ b/toolkit/source/layout/import.cxx @@ -0,0 +1,208 @@ +#include "import.hxx" + +#include <com/sun/star/awt/XButton.hpp> +#include <com/sun/star/awt/XDialog2.hpp> +#include <tools/debug.hxx> + +#include "root.hxx" +#include "helper.hxx" +#include "dialogbuttonhbox.hxx" + + +#define XMLNS_LAYOUT_URI "http://openoffice.org/2007/layout" +#define XMLNS_CONTAINER_URI "http://openoffice.org/2007/layout/container" + +namespace layoutimpl +{ +using namespace css; + +using ::rtl::OUString; + +ElementBase::~ElementBase() +SAL_THROW( () ) +{ + //delete mpImport; + //mpImport = 0; +} + +//** parser +WidgetElement::WidgetElement ( sal_Int32 nUid, const OUString &rName, + uno::Reference <xml::input::XAttributes> const &attributes, + ElementBase *pParent, + ImportContext *pImport) +SAL_THROW (()) +: ElementBase( nUid, rName, attributes, pParent, pImport ) +{ + OUString name = rName.toAsciiLowerCase(); + + PropList aProps; + propsFromAttributes( attributes, aProps, pImport->XMLNS_LAYOUT_UID ); + + OUString aId; + findAndRemove( "id", aProps, aId ); + OUString aLang; + findAndRemove( "xml-lang", aProps, aLang ); + + { +//DEBUG + uno::Reference< awt::XLayoutConstrains > xParent; + if ( pParent ) + xParent = ((WidgetElement *) pParent)->mpWidget->getPeer(); + + + mpWidget = pImport->mrRoot.create( aId, name, + getAttributeProps( aProps ), uno::Reference< awt::XLayoutContainer >( xParent, uno::UNO_QUERY ) ); + + } + + // TODO: handle with non-existing widgets + + mpWidget->setProperties( aProps ); + + uno::Reference< awt::XDialog2 > xDialog( mpWidget->getPeer(), uno::UNO_QUERY ); + if ( xDialog.is() ) + { + OUString aTitle; + if ( findAndRemove( "title", aProps, aTitle ) ) + xDialog->setTitle( aTitle ); + } // DEBUG: + else if ( pParent == NULL ) + { + DBG_ERROR( "Fatal error: top node isn't a dialog" ); + } + + bool bOrdering; + OUString aOrdering; + bOrdering = findAndRemove( "ordering", aProps, aOrdering ); + if ( DialogButtonHBox *b = dynamic_cast<DialogButtonHBox *> ( mpWidget->getPeer().get() ) ) + { + if ( bOrdering ) + b->setOrdering ( aOrdering ); + } + +#ifdef IMPORT_RADIOGROUP + bool bSetRadioGroup, bSetTitle; + OUString aRadioGroup, aTitle; + bSetRadioGroup = findAndRemove( "radiogroup", aProps, aRadioGroup ); + bSetTitle = findAndRemove( "title", aProps, aTitle ); + + setProperties( mxPeer, aProps ); + + // we need to add radio buttons to the group after their properties are + // set, so we can check if they should be the one selected by default or not. + // And the state changed event isn't fired when changing properties. + if ( bSetRadioGroup ) + { + static int i = 0; + i++; + uno::Reference< awt::XRadioButton > xRadio( mxPeer, uno::UNO_QUERY ); + if ( xRadio.is() ) + pImport->mxRadioGroups.addItem( aRadioGroup, xRadio ); + } + if ( bSetTitle ) + { + uno::Reference< awt::XDialog2 > xDialog( mxPeer, uno::UNO_QUERY ); + if ( xDialog.is() ) + xDialog->setTitle( aTitle ); + } +#endif +} + +WidgetElement::~WidgetElement() +{ + //delete mpWidget; + //mpWidget = 0; +} + +uno::Reference <xml::input::XElement> +WidgetElement::startChildElement ( sal_Int32 nUid, OUString const &name, + uno::Reference <xml::input::XAttributes> const &attributes ) + throw( xml::sax::SAXException, uno::RuntimeException ) +{ + // Adding a child to the widget + WidgetElement *pChild = new WidgetElement ( nUid, name, attributes, this, mpImport ); + + if ( !mpWidget->addChild( pChild->mpWidget ) ) + { + DBG_ERROR2( "ERROR: cannot add %s to container %s, container full", OUSTRING_CSTR( name ), OUSTRING_CSTR( getLocalName() ) ); + throw xml::sax::SAXException(); + } + + PropList aProps; + propsFromAttributes( attributes, aProps, mpImport->XMLNS_CONTAINER_UID ); + mpWidget->setChildProperties( pChild->mpWidget, aProps ); + + return pChild; +} + +// Support Ivo Hinkelmann's move label/text/title attribute to CONTENT +// transex3 hack. +void SAL_CALL +WidgetElement::characters( OUString const& rChars ) + throw (css::xml::sax::SAXException, css::uno::RuntimeException) +{ + if ( mpWidget && rChars.trim().getLength() ) + { + uno::Reference< awt::XDialog2 > xDialog( mpWidget->getPeer(), uno::UNO_QUERY ); + uno::Reference< awt::XButton > xButton( mpWidget->getPeer(), uno::UNO_QUERY ); + if ( xDialog.is() ) + xDialog->setTitle( rChars ); + else if ( xButton.is() ) + mpWidget->setProperty( OUString::createFromAscii( "label" ), rChars ); + else + mpWidget->setProperty( OUString::createFromAscii( "text" ), rChars ); + } +} +// ---- ElementBase ---- + +ElementBase::ElementBase( sal_Int32 nUid, OUString const & rLocalName, + uno::Reference< xml::input::XAttributes > const & xAttributes, + ElementBase* pParent, + ImportContext* pImport ) +SAL_THROW(()) +: mpImport( pImport ) + , mpParent( pParent ) + , mnUid( nUid ) + , maLocalName( rLocalName ) + , mxAttributes( xAttributes ) +{ +} + +// ---- ImportContext ---- + +void ImportContext::startDocument( + uno::Reference< xml::input::XNamespaceMapping > const & xNamespaceMapping ) + throw (xml::sax::SAXException, uno::RuntimeException) +{ + XMLNS_LAYOUT_UID = xNamespaceMapping->getUidByUri( + OUString( RTL_CONSTASCII_USTRINGPARAM( XMLNS_LAYOUT_URI ) ) ); + XMLNS_CONTAINER_UID = xNamespaceMapping->getUidByUri( + OUString( RTL_CONSTASCII_USTRINGPARAM( XMLNS_CONTAINER_URI ) ) ); +} + +ToplevelElement::ToplevelElement (OUString const &rName, + uno::Reference <xml::input::XAttributes> const &xAttributes, + ImportContext *pImport) +SAL_THROW(()) +: WidgetElement( 0, rName, xAttributes, NULL, pImport ) +{ +} + +ToplevelElement::~ToplevelElement() +{ +} + +uno::Reference< xml::input::XElement > ImportContext::startRootElement( + sal_Int32 nUid, OUString const & rLocalName, + uno::Reference< xml::input::XAttributes > const & xAttributes ) + throw (xml::sax::SAXException, uno::RuntimeException) +{ + if (XMLNS_LAYOUT_UID != nUid) + throw xml::sax::SAXException( + OUString( RTL_CONSTASCII_USTRINGPARAM( "invalid namespace!" ) ), + uno::Reference< uno::XInterface >(), uno::Any() ); + else + return new ToplevelElement( rLocalName, xAttributes, this ); +} + +} // namespace layoutimpl diff --git a/toolkit/source/layout/import.hxx b/toolkit/source/layout/import.hxx new file mode 100644 index 000000000000..e4b43ab78df3 --- /dev/null +++ b/toolkit/source/layout/import.hxx @@ -0,0 +1,283 @@ +#ifndef IMPORT_HXX +#define IMPORT_HXX + +#include <map> +#include <list> +#include <hash_map> + +#include <com/sun/star/xml/input/XRoot.hpp> +#include <cppuhelper/implbase1.hxx> + +namespace layoutimpl +{ +class LayoutRoot; +class LayoutWidget; +namespace css = ::com::sun::star; + +/* blocks under IMPORT_RADIOGROUP are marked for deletion. + The use of it is to synchronize radio buttons into groups. + But toolkit doesn't fire toggle events when toggled from the code. + Another approach is to implement our own XRadioButton from our + internal toolkit. We could have some singleton where they would + register... We would need to add another attribute... +*/ + +#ifdef IMPORT_RADIOGROUP +#include <com/sun/star/awt/XRadioButton.hpp> +class RadioGroups +{ +public: + RadioGroups() + { + } + + void addItem( rtl::OUString id, css::uno::Reference< css::awt::XRadioButton > xRadio ) + throw (css::uno::RuntimeException) + { + if ( ! xRadio.is() ) + throw css::uno::RuntimeException(); + + css::uno::Reference< RadioGroup > group; + RadioGroupsMap::iterator it = mxRadioGroups.find( id ); + if ( it == mxRadioGroups.end() ) + { + group = css::uno::Reference< RadioGroup > ( new RadioGroup() ); + mxRadioGroups [id] = group; + } + else + group = it->second; + group->addItem( xRadio ); + } + +private: + class RadioGroup : public ::cppu::WeakImplHelper1< css::awt::XItemListener > + { + public: + RadioGroup() + { + } + + void addItem( css::uno::Reference< css::awt::XRadioButton > xRadio ) + { + if ( ! mxSelectedRadio.is() ) + { + xRadio->setState( true ); + mxSelectedRadio = xRadio; + } + else if ( xRadio->getState() ) + { + mxSelectedRadio->setState( false ); + mxSelectedRadio = xRadio; + } + + xRadio->addItemListener( this ); + mxRadios.push_back (xRadio); + } + + private: + typedef std::list< css::uno::Reference< css::awt::XRadioButton > > RadioButtonsList; + RadioButtonsList mxRadios; + css::uno::Reference< css::awt::XRadioButton > mxSelectedRadio; + + // awt::XItemListener + void itemStateChanged( const com::sun::star::awt::ItemEvent& e) + throw (css::uno::RuntimeException) + { + if ( e.Selected ) + { + mxSelectedRadio->setState( false ); + // the only radio button selected would be the one that fired the event + for( RadioButtonsList::iterator it = mxRadios.begin(); it != mxRadios.end(); it++ ) + if ( (*it)->getState() ) + { + mxSelectedRadio = *it; + break; + } + } + } + + // lang::XEventListener + void SAL_CALL disposing( const css::lang::EventObject& ) + throw (css::uno::RuntimeException) + { + } + }; + + // each RadioGroup will stay alive after RadioGroups die with the ImportContext + // because they are referenced by every XRadioButton through the listener + typedef std::map< rtl::OUString, css::uno::Reference< RadioGroup > > RadioGroupsMap; + RadioGroupsMap mxRadioGroups; +}; +#endif + +#if 0 +// generator +class Widget +{ +public: + Widget( css::uno::Reference< css::awt::XToolkit > xToolkit, + css::uno::Reference< css::awt::XWindow > xToplevel, + rtl::OUString unoName, long attrbs ); + virtual ~Widget(); + + virtual void setProperties( const PropList &rProps ); + + virtual bool addChild( Widget *pChild ); + virtual void setChildProperties( Widget *pChild, const PropList &rProps ); + + inline css::uno::Reference< css::awt::XLayoutConstrains > getPeer() + { return mxWidget; } + + inline css::uno::Reference< css::awt::XLayoutConstrains > getContainer() + { return mxContainer; } + +protected: + css::uno::Reference< css::awt::XLayoutConstrains > mxWidget; + css::uno::Reference< css::awt::XLayoutContainer > mxContainer; +}; + +class Root +{ +public: + Root( css::uno::Reference< css::awt::XToolkit > xToolkit ) + : mxToolkit( xToolkit ) {} + ~Root(); + + virtual Widget *create( rtl::OUString id, const rtl::OUString unoName, long attrbs ); + + css::uno::Reference< css::awt::XLayoutConstrains > getById( rtl::OUString id ); + inline css::uno::Reference< css::awt::XLayoutConstrains > getToplevel(); + +protected: + css::uno::Reference< css::awt::XToolkit > mxToolkit; + Widget *mpToplevel; + + typedef std::hash_map< rtl::OUString, css::uno::Reference< css::awt::XLayoutConstrains >, + rtl::OUStringHash > ItemHash; + ItemHash maItems; +}; +#endif + +// parser +class ImportContext : public ::cppu::WeakImplHelper1< css::xml::input::XRoot > +{ +public: + sal_Int32 XMLNS_LAYOUT_UID, XMLNS_CONTAINER_UID; + LayoutRoot &mrRoot; // switch to XNameContainer ref ? +#ifdef IMPORT_RADIOGROUP + RadioGroups mxRadioGroups; +#endif + + inline ImportContext( LayoutRoot &rRoot ) SAL_THROW( () ) + : mrRoot( rRoot ) {} + virtual ~ImportContext() {} + + // XRoot + virtual void SAL_CALL startDocument( + css::uno::Reference< css::xml::input::XNamespaceMapping > + const & xNamespaceMapping ) + throw (css::xml::sax::SAXException, css::uno::RuntimeException); + virtual void SAL_CALL endDocument() + throw (css::xml::sax::SAXException, css::uno::RuntimeException) + { /* ignore */ } + virtual void SAL_CALL processingInstruction( + ::rtl::OUString const & /* rTarget */, ::rtl::OUString const & /* rData */ ) + throw (css::xml::sax::SAXException, css::uno::RuntimeException) + { /* ignore */ } + virtual void SAL_CALL setDocumentLocator( + css::uno::Reference< css::xml::sax::XLocator > const & /* xLocator */ ) + throw (css::xml::sax::SAXException, css::uno::RuntimeException) + { /* ignore */ } + virtual css::uno::Reference< css::xml::input::XElement > + SAL_CALL startRootElement( + sal_Int32 nUid, ::rtl::OUString const & rLocalName, + css::uno::Reference<css::xml::input::XAttributes > const & xAttributes ) + throw (css::xml::sax::SAXException, css::uno::RuntimeException); +}; + +class ElementBase : public ::cppu::WeakImplHelper1< css::xml::input::XElement > +{ +protected: + ImportContext *mpImport; +/* TODO: check if all this memebers are needed. */ + ElementBase *mpParent; + sal_Int32 mnUid; + + ::rtl::OUString maLocalName; + css::uno::Reference< css::xml::input::XAttributes > mxAttributes; +public: + ElementBase( + sal_Int32 nUid, ::rtl::OUString const & rLocalName, + css::uno::Reference< css::xml::input::XAttributes > const & xAttributes, + ElementBase * pParent, ImportContext * pImport ) + SAL_THROW( () ); + virtual ~ElementBase() SAL_THROW(()); + + // XElement + virtual css::uno::Reference<css::xml::input::XElement> SAL_CALL getParent() + throw (css::uno::RuntimeException) + { return static_cast< css::xml::input::XElement * >( mpParent ); } + virtual ::rtl::OUString SAL_CALL getLocalName() throw (css::uno::RuntimeException) + { return maLocalName; } + virtual sal_Int32 SAL_CALL getUid() throw (css::uno::RuntimeException) + { return mnUid; } + virtual css::uno::Reference< css::xml::input::XAttributes > + SAL_CALL getAttributes() throw (css::uno::RuntimeException) + { return mxAttributes; } + + virtual void SAL_CALL ignorableWhitespace( + ::rtl::OUString const & /* rWhitespaces */ ) + throw (css::xml::sax::SAXException, css::uno::RuntimeException) + { /* ignore */ } + virtual void SAL_CALL characters( ::rtl::OUString const & /* rChars */ ) + throw (css::xml::sax::SAXException, css::uno::RuntimeException) + { /* ignore */ } + virtual void SAL_CALL processingInstruction( + ::rtl::OUString const & /* Target */, ::rtl::OUString const & /* Data */ ) + throw (css::xml::sax::SAXException, css::uno::RuntimeException) + { /* ignore */ } + + virtual css::uno::Reference< css::xml::input::XElement > + SAL_CALL startChildElement( + sal_Int32 nUid, ::rtl::OUString const & rLocalName, + css::uno::Reference<css::xml::input::XAttributes > const & xAttributes ) + throw (css::xml::sax::SAXException, css::uno::RuntimeException) = 0; + virtual void SAL_CALL endElement() + throw (css::xml::sax::SAXException, css::uno::RuntimeException) + { /* ignore */ } +}; + +class WidgetElement : public ElementBase +{ +protected: + LayoutWidget *mpWidget; + +public: + WidgetElement( sal_Int32 nUid, rtl::OUString const &name, + css::uno::Reference< css::xml::input::XAttributes > const &attributes, + ElementBase *parent, ImportContext *import ) SAL_THROW (()); + + ~WidgetElement(); + + + virtual css::uno::Reference< css::xml::input::XElement> SAL_CALL + startChildElement (sal_Int32 id, rtl::OUString const &name, + css::uno::Reference< css::xml::input::XAttributes > const &attributes) + throw( css::xml::sax::SAXException, css::uno::RuntimeException ); + virtual void SAL_CALL characters( ::rtl::OUString const & /* rChars */ ) + throw (css::xml::sax::SAXException, css::uno::RuntimeException); +}; + +class ToplevelElement : public WidgetElement +{ +public: + ToplevelElement( rtl::OUString const &name, + css::uno::Reference< css::xml::input::XAttributes > const &attributes, + ImportContext *import ) SAL_THROW (()); + ~ToplevelElement(); +}; + + +} // namespace layoutimpl + +#endif /* IMPORT_HXX */ diff --git a/toolkit/source/layout/proplist.hxx b/toolkit/source/layout/proplist.hxx new file mode 100644 index 000000000000..551072181fbc --- /dev/null +++ b/toolkit/source/layout/proplist.hxx @@ -0,0 +1,34 @@ +#ifndef CORE_PROPLIST_HXX +#define CORE_PROPLIST_HXX + +#include <list> +#include <com/sun/star/xml/input/XAttributes.hpp> + +#include <rtl/ustring.hxx> + +namespace layoutimpl +{ + +namespace css = ::com::sun::star; + +typedef std::list< std::pair< rtl::OUString, rtl::OUString > > PropList; + +void propsFromAttributes( const css::uno::Reference<css::xml::input::XAttributes> & xAttributes, + PropList &rProps, sal_Int32 nNamespace ); + +void setProperties( css::uno::Reference< css::uno::XInterface > const& xPeer, + PropList const& rProps); + +void setProperty( css::uno::Reference< css::uno::XInterface > const& xPeer, + rtl::OUString const& attr, rtl::OUString const& value ); + +long getAttributeProps( PropList &rProps ); +bool findAndRemove( const char *pAttr, PropList &rProps, rtl::OUString &rValue); + +} + +// Convert a rtl::OUString to a byte string. +#define OUSTRING_CSTR( str ) \ + rtl::OUStringToOString( str, RTL_TEXTENCODING_ASCII_US ).getStr() + +#endif // CORE_PROPLIST_HXX diff --git a/toolkit/source/layout/root.cxx b/toolkit/source/layout/root.cxx new file mode 100644 index 000000000000..47488a0213e8 --- /dev/null +++ b/toolkit/source/layout/root.cxx @@ -0,0 +1,329 @@ +#include "root.hxx" + +#include <assert.h> +#include <com/sun/star/xml/sax/XParser.hpp> + +#include "helper.hxx" +#include "import.hxx" +#include "timer.hxx" +#include "translate.hxx" + +namespace layoutimpl +{ + +using namespace css; +using ::rtl::OUString; + +LayoutRoot::LayoutRoot( const uno::Reference< lang::XMultiServiceFactory >& xFactory ) + : mbDisposed( sal_False ) + , mxFactory( xFactory ) + , mpListeners( NULL ) + , mpToplevel( NULL ) +{ + if ( !xFactory.is() ) + throw uno::RuntimeException(); + mxLayoutUnit = uno::Reference< awt::XLayoutUnit >( new LayoutUnit() ); +} + +LayoutRoot::~LayoutRoot() +{ +// TODO: we want to delete the top level LayoutWidget... + ::osl::MutexGuard aGuard( maMutex ); + if ( !mbDisposed ) + { + try + { + m_refCount++; // inhibit multiple destruction + dispose(); + } + catch( uno::Exception& ) + { + } + } +} + +// XInitialization +void SAL_CALL LayoutRoot::initialize( const uno::Sequence< uno::Any >& aArguments ) + throw ( uno::Exception, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + if ( mbDisposed ) + throw lang::DisposedException(); + + if ( mxContainer.is() ) // only 1 init ... + throw uno::Exception(); + + if ( !aArguments.getLength() ) + throw lang::IllegalArgumentException(); + + OSL_ENSURE( aArguments.getLength() == 1, "Wrong arg count\n" ); + + OUString aXMLName; + if ( !( aArguments[0] >>= aXMLName ) ) + throw lang::IllegalArgumentException(); + + uno::Reference< xml::sax::XParser > xParser + ( mxFactory->createInstance( + OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.xml.sax.Parser" ) ) ), + uno::UNO_QUERY ); + OSL_ASSERT( xParser.is() ); + if (! xParser.is()) + { + throw uno::RuntimeException( + OUString( RTL_CONSTASCII_USTRINGPARAM( "cannot create sax-parser component" ) ), + uno::Reference< uno::XInterface >() ); + } + + OUString aXMLFile = readRightTranslation( aXMLName ); + + uno::Reference< io::XInputStream > xStream = getFileAsStream( mxFactory, + aXMLFile ); + + // error handler, entity resolver omitted + + // FIXME: quite possibly we want to pass this in ... + uno::Reference< awt::XToolkit > xToolkit; + + mxToolkit = uno::Reference< awt::XToolkit >( + mxFactory->createInstance( + OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.awt.Toolkit" ) ) ), + uno::UNO_QUERY ); + + if ( !mxToolkit.is() ) + throw uno::RuntimeException( + OUString( RTL_CONSTASCII_USTRINGPARAM( "failed to create toolkit!" ) ), + uno::Reference< uno::XInterface >() ); + + ImportContext *pCtx = new ImportContext( *this ); + + uno::Reference< xml::input::XRoot > xRoot( pCtx ); + uno::Sequence < uno::Any > aArgs( 1 ); + aArgs[0] <<= xRoot; + uno::Reference< xml::sax::XDocumentHandler > xDocHandler + (mxFactory->createInstanceWithArguments + ( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.xml.input.SaxDocumentHandler" ) ), + aArgs ), uno::UNO_QUERY ); + + xParser->setDocumentHandler( xDocHandler ); + + xml::sax::InputSource source; + source.aInputStream = xStream; + source.sSystemId = OUString( RTL_CONSTASCII_USTRINGPARAM( "virtual file" ) ); + + xParser->parseStream( source ); +} + +// XLayoutContainer +uno::Reference< awt::XLayoutContainer > LayoutRoot::getLayoutContainer() throw (uno::RuntimeException) +{ + return uno::Reference< awt::XLayoutContainer >(); +} + +// local helper ... +void LayoutRoot::addItem( const OUString &rName, + const uno::Reference< awt::XLayoutConstrains > &xRef ) +{ + maItems[ rName ] = xRef; +} + +// XNameAccess +uno::Any SAL_CALL LayoutRoot::getByName( const OUString &rName ) + throw ( container::NoSuchElementException, + lang::WrappedTargetException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + if ( mbDisposed ) + throw lang::DisposedException(); + + uno::Reference< awt::XLayoutConstrains > xItem; + ItemHash::iterator i = maItems.find( rName ); + if ( i != maItems.end() ) + xItem = i->second; + return uno::makeAny( xItem ); +} + +sal_Bool SAL_CALL LayoutRoot::hasByName( const OUString &rName ) + throw (uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( maMutex ); + if ( mbDisposed ) throw lang::DisposedException(); + + ItemHash::iterator i = maItems.find( rName ); + return i != maItems.end(); +} + +uno::Sequence< OUString > SAL_CALL LayoutRoot::getElementNames() + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + if ( mbDisposed ) throw lang::DisposedException(); + + uno::Sequence< OUString > aNames( maItems.size() ); + sal_Int32 nPos = 0; + + for( ItemHash::const_iterator i = maItems.begin(); + i != maItems.end(); i++ ) + aNames[ nPos++ ] = i->first; + + return aNames; +} + +uno::Type SAL_CALL LayoutRoot::getElementType() + throw ( uno::RuntimeException ) +{ + return getCppuType( ( const uno::Reference< awt::XLayoutConstrains >* )NULL ); +} + +sal_Bool SAL_CALL LayoutRoot::hasElements() + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + if ( mbDisposed ) throw lang::DisposedException(); + + return maItems.size() > 0; +} + +// XComponent +void SAL_CALL LayoutRoot::dispose() + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + if ( mbDisposed ) throw lang::DisposedException(); + + if ( mpListeners ) + { + + lang::EventObject aSource( static_cast< ::cppu::OWeakObject* >(this) ); + mpListeners->disposeAndClear( aSource ); + delete mpListeners; + mpListeners = NULL; + } + + maItems.clear(); + mbDisposed = sal_True; +} + +void SAL_CALL LayoutRoot::addEventListener( const uno::Reference< lang::XEventListener >& xListener ) + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + if ( mbDisposed ) throw lang::DisposedException(); + + if ( !mpListeners ) + mpListeners = new ::cppu::OInterfaceContainerHelper( maMutex ); + mpListeners->addInterface( xListener ); +} + +void SAL_CALL LayoutRoot::removeEventListener( const uno::Reference< lang::XEventListener >& xListener ) + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + if ( mbDisposed ) throw lang::DisposedException(); + + if ( mpListeners ) + mpListeners->removeInterface( xListener ); +} + +// builder + +LayoutWidget *LayoutRoot::create( OUString id, const OUString unoName, long attrbs,uno::Reference< awt::XLayoutContainer > xParent ) +{ + LayoutWidget *pWidget = new LayoutWidget( mxToolkit, xParent, unoName, attrbs ); + if ( !mpToplevel ) + { + mpToplevel = pWidget; + mxWindow = uno::Reference< awt::XWindow >( pWidget->getPeer(), uno::UNO_QUERY ); + mxContainer = pWidget->mxContainer; + } + if ( pWidget->mxContainer.is() ) + pWidget->mxContainer->setLayoutUnit( mxLayoutUnit ); + if ( id.getLength() ) + maItems[ id ] = pWidget->getPeer(); + return pWidget; +} + +/* + uno::Reference< awt::XLayoutConstrains > LayoutRoot::getToplevel() + { + if ( mpToplevel ) + return mpToplevel->getPeer(); + return uno::Reference< awt::XLayoutConstrains > (); + } + + uno::Reference< awt::XLayoutConstrains > LayoutRoot::getById( OUString id ) + { + uno::Reference< awt::XLayoutConstrains > rRef = 0; + ItemHash::iterator i = maItems.find( id ); + if ( i != maItems.end() ) + rRef = i->second; + return rRef; + } +*/ + +LayoutWidget::LayoutWidget( uno::Reference< awt::XToolkit > xToolkit, + uno::Reference< awt::XLayoutContainer > xParent, + OUString unoName, long attrbs ) +{ + while ( xParent.is() && !uno::Reference< awt::XWindow >( xParent, uno::UNO_QUERY ).is() ) + { + uno::Reference< awt::XLayoutContainer > xContainer( xParent, uno::UNO_QUERY ); + assert( xContainer.is() ); + xParent = uno::Reference< awt::XLayoutContainer >( xContainer->getParent(), uno::UNO_QUERY ); + } + + mxWidget = createWidget( xToolkit, xParent, unoName, attrbs ); + assert( mxWidget.is() ); + mxContainer = uno::Reference< awt::XLayoutContainer >( mxWidget, uno::UNO_QUERY ); +} + +LayoutWidget::~LayoutWidget() +{ + /* should we dispose of the references...? */ + // at least of its children... Or should root? +} + +bool LayoutWidget::addChild( LayoutWidget *pChild ) +{ + if ( !mxContainer.is() ) + return false; + + try + { + mxContainer->addChild( pChild->mxWidget ); + } + catch( awt::MaxChildrenException ex ) + { + return false; + } + return true; +} + +void LayoutWidget::setProperties( PropList const& rProps ) +{ + ::layoutimpl::setProperties( mxWidget, rProps ); +} + +void LayoutWidget::setProperty( OUString const& attr, OUString const& value ) +{ + ::layoutimpl::setProperty( mxWidget, attr, value ); +} + +void LayoutWidget::setChildProperties( LayoutWidget *pChild, + PropList const& rProps ) +{ + uno::Reference< beans::XPropertySet > xChildPeer; + xChildPeer = mxContainer->getChildProperties( pChild->mxWidget ); + + if ( xChildPeer.is() ) + ::layoutimpl::setProperties( xChildPeer, rProps ); +} + +} // namespace layoutimpl + diff --git a/toolkit/source/layout/root.hxx b/toolkit/source/layout/root.hxx new file mode 100644 index 000000000000..e87c880e4635 --- /dev/null +++ b/toolkit/source/layout/root.hxx @@ -0,0 +1,127 @@ +#ifndef CORE_ROOT_HXX +#define CORE_ROOT_HXX + +#include <hash_map> + +#include <com/sun/star/awt/XLayoutRoot.hpp> +#include <com/sun/star/awt/XToolkit.hpp> +#include <com/sun/star/awt/XWindow.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <cppuhelper/implbase3.hxx> +#include <cppuhelper/interfacecontainer.h> + +#include "proplist.hxx" + +namespace layoutimpl +{ + +namespace css = ::com::sun::star; + +css::uno::Reference< css::io::XInputStream > +getFileAsStream( const css::uno::Reference< css::lang::XMultiServiceFactory > &xFactory, + const rtl::OUString &rName ); + +/* Interface generation code -- to hook to a parser. */ + +/* + TODO: (ricardo) I think we should cut on LayoutRoot, stripping out its widget + proxy interface (just make it return the root widget). Would even make it easier + if there was interest to support multiple toplevel widgets in the same file. + + We also need to make sure the code gets diposed well... There is no need to keep + these objects around after initialization... +*/ + + +class LayoutWidget; + +class LayoutRoot : public ::cppu::WeakImplHelper3< + css::awt::XLayoutRoot, + css::lang::XInitialization, + css::lang::XComponent> +{ +protected: + ::osl::Mutex maMutex; + + typedef std::hash_map< rtl::OUString, + css::uno::Reference< css::awt::XLayoutConstrains >, + ::rtl::OUStringHash > ItemHash; + ItemHash maItems; + + sal_Bool mbDisposed; + css::uno::Reference< css::lang::XMultiServiceFactory > mxFactory; + ::cppu::OInterfaceContainerHelper *mpListeners; + + css::uno::Reference< css::awt::XWindow > mxWindow; + css::uno::Reference< css::awt::XLayoutContainer > mxContainer; + + css::uno::Reference< css::awt::XToolkit > mxToolkit; + LayoutWidget *mpToplevel; + css::uno::Reference< css::awt::XLayoutUnit > mxLayoutUnit; + +public: + LayoutRoot( const css::uno::Reference< css::lang::XMultiServiceFactory >& xFactory ); + virtual ~LayoutRoot(); + + void addItem( const rtl::OUString &rName, + const css::uno::Reference< css::awt::XLayoutConstrains > &xRef ); + + void setWindow( css::uno::Reference< css::awt::XLayoutConstrains > xPeer ) + { + mxWindow = css::uno::Reference< css::awt::XWindow >( xPeer, css::uno::UNO_QUERY ); + } + + // get XLayoutContainer + virtual css::uno::Reference< css::awt::XLayoutContainer > getLayoutContainer() throw (css::uno::RuntimeException); + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) throw (css::uno::Exception, css::uno::RuntimeException); + + // XNameAccess + virtual css::uno::Any SAL_CALL getByName( const ::rtl::OUString& aName ) throw (css::container::NoSuchElementException, css::lang::WrappedTargetException, css::uno::RuntimeException); + virtual css::uno::Sequence< ::rtl::OUString > SAL_CALL getElementNames() throw (css::uno::RuntimeException); + virtual sal_Bool SAL_CALL hasByName( const ::rtl::OUString& aName ) throw (css::uno::RuntimeException); + virtual css::uno::Type SAL_CALL getElementType() throw (css::uno::RuntimeException); + virtual sal_Bool SAL_CALL hasElements() throw (css::uno::RuntimeException); + + // XComponent + virtual void SAL_CALL dispose() throw (css::uno::RuntimeException); + virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) throw (css::uno::RuntimeException); + virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) throw (css::uno::RuntimeException); + + // generator + virtual LayoutWidget *create( rtl::OUString id, const rtl::OUString unoName, long attrbs, css::uno::Reference< css::awt::XLayoutContainer > xParent ); +}; + +class LayoutWidget +{ + friend class LayoutRoot; + +public: + LayoutWidget() {} + LayoutWidget( css::uno::Reference< css::awt::XToolkit > xToolkit, + css::uno::Reference< css::awt::XLayoutContainer > xToplevel, + rtl::OUString unoName, long attrbs ); + virtual ~LayoutWidget(); + + virtual void setProperties( const PropList &rProps ); + virtual void setProperty( rtl::OUString const& attr, rtl::OUString const& value ); + + virtual bool addChild( LayoutWidget *pChild ); + virtual void setChildProperties( LayoutWidget *pChild, const PropList &rProps ); + + inline css::uno::Reference< css::awt::XLayoutConstrains > getPeer() + { return mxWidget; } + inline css::uno::Reference< css::awt::XLayoutContainer > getContainer() + { return mxContainer; } + +protected: + css::uno::Reference< css::awt::XLayoutConstrains > mxWidget; + css::uno::Reference< css::awt::XLayoutContainer > mxContainer; +}; + +} // namespace layoutimpl + +#endif // CORE_ROOT_HXX diff --git a/toolkit/source/layout/table.cxx b/toolkit/source/layout/table.cxx new file mode 100644 index 000000000000..2cffbb8af399 --- /dev/null +++ b/toolkit/source/layout/table.cxx @@ -0,0 +1,326 @@ +#include <table.hxx> + +#include <sal/macros.h> +#include <osl/mutex.hxx> +#include <cppuhelper/propshlp.hxx> +#include <cppuhelper/interfacecontainer.h> +#include <com/sun/star/awt/PosSize.hpp> +#include <tools/debug.hxx> + +// fixed point precision for distributing error +#define FIXED_PT 16 + +namespace layoutimpl +{ + +using namespace com::sun::star; + +class TableChildProps : public PropHelper +{ +public: + TableChildProps( Table::ChildData *pData ) + { + addProp( RTL_CONSTASCII_USTRINGPARAM( "XExpand" ), + ::getCppuType( static_cast< const sal_Bool* >( NULL ) ), + &( pData->bExpand[ 0 ] ) ); + addProp( RTL_CONSTASCII_USTRINGPARAM( "YExpand" ), + ::getCppuType( static_cast< const sal_Bool* >( NULL ) ), + &( pData->bExpand[ 1 ] ) ); + addProp( RTL_CONSTASCII_USTRINGPARAM( "ColSpan" ), + ::getCppuType( static_cast< const sal_Int32* >( NULL ) ), + &( pData->nColSpan ) ); + addProp( RTL_CONSTASCII_USTRINGPARAM( "RowSpan" ), + ::getCppuType( static_cast< const sal_Int32* >( NULL ) ), + &( pData->nRowSpan ) ); + } + PROPHELPER_SET_INFO +}; + +bool Table::ChildData::isVisible() +{ + if ( !xChild.is() || nColSpan < 1 || nRowSpan < 1 ) + return false; + return xChild.is(); +} + +Table::Table() + : Container() +{ + // another default value could be 0xffff for infinite columns( = 1 row ) + mnColsLen = 1; + addProp( RTL_CONSTASCII_USTRINGPARAM( "Columns" ), + ::getCppuType( static_cast< const sal_Int32* >( NULL ) ), + &mnColsLen ); +} + +void SAL_CALL +Table::addChild( const uno::Reference< awt::XLayoutConstrains >& xChild ) + throw( uno::RuntimeException, awt::MaxChildrenException ) +{ + if ( xChild.is() ) + { + ChildData *pData = new ChildData(); + pData->bExpand[ 0 ] = pData->bExpand[ 1 ] = true; + pData->nColSpan = pData->nRowSpan = 1; + pData->xChild = xChild; + maChildren.push_back( pData ); + + setChildParent( xChild ); + queueResize(); + + // cause of flicker + allocateChildAt( xChild, awt::Rectangle( 0,0,0,0 ) ); + } +} + +void SAL_CALL +Table::removeChild( const uno::Reference< awt::XLayoutConstrains >& xChild ) + throw( uno::RuntimeException ) +{ + for( std::list< ChildData * >::iterator it = maChildren.begin(); + it != maChildren.end(); it++ ) + { + if ( ( *it )->xChild == xChild ) + { + delete *it; + maChildren.erase( it ); + + unsetChildParent( xChild ); + queueResize(); + break; + } + } + DBG_ERROR( "Table error: trying to remove child that doesn't exist" ); +} + +uno::Sequence< uno::Reference < awt::XLayoutConstrains > > SAL_CALL +Table::getChildren() + throw( uno::RuntimeException ) +{ + uno::Sequence< uno::Reference< awt::XLayoutConstrains > > children( maChildren.size() ); + unsigned int i = 0; + for( std::list< ChildData * >::iterator it = maChildren.begin(); + it != maChildren.end(); it++, i++ ) + children[i] =( *it )->xChild; + + return children; +} + +uno::Reference< beans::XPropertySet > SAL_CALL +Table::getChildProperties( const uno::Reference< awt::XLayoutConstrains >& xChild ) + throw( uno::RuntimeException ) +{ + std::list< ChildData * >::iterator iter; + for( iter = maChildren.begin(); iter != maChildren.end(); iter++ ) + { + if ( ( *iter )->xChild == xChild ) + { + if ( !( *iter )->xProps.is() ) + { + // FIXME: make me safe ! + PropHelper *pProps = new TableChildProps( *iter ); + pProps->setChangeListener( this ); +( *iter )->xProps = pProps; + } + return( *iter )->xProps; + } + } + return uno::Reference< beans::XPropertySet >(); +} + +awt::Size SAL_CALL +Table::getMinimumSize() throw( uno::RuntimeException ) +{ + int nRowsLen = 0; + + // 1. layout the table -- adjust to cope with row-spans... + { + // temporary 1D representation of the table + std::vector< ChildData *> aTable; + + int col = 0, row = 0; + for( std::list<ChildData *>::iterator it = maChildren.begin(); + it != maChildren.end(); it++ ) + { + ChildData *child = *it; + if ( !child->isVisible() ) + continue; + + while ( col + SAL_MIN( child->nColSpan, mnColsLen ) > mnColsLen ) + { + col = 0; + row++; + + unsigned int i = col +( row*mnColsLen ); + while ( aTable.size() > i && !aTable[ i ] ) + i++; + + col = i % mnColsLen; + row = i / mnColsLen; + } + + child->nLeftCol = col; + child->nRightCol = SAL_MIN( col + child->nColSpan, mnColsLen ); + child->nTopRow = row; + child->nBottomRow = row + child->nRowSpan; + + col += child->nColSpan; + + unsigned int start = child->nLeftCol +( child->nTopRow*mnColsLen ); + unsigned int end =( child->nRightCol-1 ) +( ( child->nBottomRow-1 )*mnColsLen ); + if ( aTable.size() < end+1 ) + aTable.resize( end+1, NULL ); + for( unsigned int i = start; i < end; i++ ) + aTable[ i ] = child; + + nRowsLen = SAL_MAX( nRowsLen, child->nBottomRow ); + } + } + + // 2. calculate columns/rows sizes + for( int g = 0; g < 2; g++ ) + { + std::vector< GroupData > &aGroup = g == 0 ? maCols : maRows; + + aGroup.clear(); + aGroup.resize( g == 0 ? mnColsLen : nRowsLen ); + + // 2.1 base sizes on one-column/row children + for( std::list<ChildData *>::iterator it = maChildren.begin(); + it != maChildren.end(); it++ ) + { + ChildData *child = *it; + if ( !child->isVisible() ) + continue; + const int nFirstAttach = g == 0 ? child->nLeftCol : child->nTopRow; + const int nLastAttach = g == 0 ? child->nRightCol : child->nBottomRow; + + if ( nFirstAttach == nLastAttach-1 ) + { + child->aRequisition = child->xChild->getMinimumSize(); + int attach = nFirstAttach; + int child_size = g == 0 ? child->aRequisition.Width + : child->aRequisition.Height; + aGroup[ attach ].nSize = SAL_MAX( aGroup[ attach ].nSize, child_size ); + if ( child->bExpand[ g ] ) + aGroup[ attach ].bExpand = true; + } + } + + // 2.2 make sure multiple-columns/rows children fit + for( std::list<ChildData *>::iterator it = maChildren.begin(); + it != maChildren.end(); it++ ) + { + ChildData *child = *it; + if ( !child->isVisible() ) + continue; + const int nFirstAttach = g == 0 ? child->nLeftCol : child->nTopRow; + const int nLastAttach = g == 0 ? child->nRightCol : child->nBottomRow; + + if ( nFirstAttach != nLastAttach-1 ) + { + child->aRequisition = child->xChild->getMinimumSize(); + int size = 0; + int expandables = 0; + for( int i = nFirstAttach; i < nLastAttach; i++ ) + { + size += aGroup[ i ].nSize; + if ( aGroup[ i ].bExpand ) + expandables++; + } + + int child_size = g == 0 ? child->aRequisition.Width + : child->aRequisition.Height; + int extra = child_size - size; + if ( extra > 0 ) + { + if ( expandables ) + extra /= expandables; + else + extra /= nLastAttach - nFirstAttach; + + for( int i = nFirstAttach; i < nLastAttach; i++ ) + if ( expandables == 0 || aGroup[ i ].bExpand ) + aGroup[ i ].nSize += extra; + } + } + } + } + + // 3. Sum everything up + mnColExpandables =( mnRowExpandables = 0 ); + maRequisition.Width =( maRequisition.Height = 0 ); + for( std::vector<GroupData>::iterator it = maCols.begin(); + it != maCols.end(); it++ ) + { + maRequisition.Width += it->nSize; + if ( it->bExpand ) + mnColExpandables++; + } + for( std::vector<GroupData>::iterator it = maRows.begin(); + it != maRows.end(); it++ ) + { + maRequisition.Height += it->nSize; + if ( it->bExpand ) + mnRowExpandables++; + } + + return maRequisition; +} + +void SAL_CALL +Table::allocateArea( const awt::Rectangle &rArea ) + throw( uno::RuntimeException ) +{ + maAllocation = rArea; + if ( maCols.size() == 0 || maRows.size() == 0 ) + return; + + int nExtraSize[ 2 ] = { SAL_MAX( rArea.Width - maRequisition.Width, 0 ), + SAL_MAX( rArea.Height - maRequisition.Height, 0 ) }; + // split it + nExtraSize[ 0 ] /= mnColExpandables ? mnColExpandables : mnColsLen; + nExtraSize[ 1 ] /= mnRowExpandables ? mnRowExpandables : maRows.size(); + + for( std::list<ChildData *>::const_iterator it = maChildren.begin(); + it != maChildren.end(); it++ ) + { + ChildData *child = *it; + if ( !child->isVisible() ) + continue; + + awt::Rectangle rChildArea( rArea.X, rArea.Y, 0, 0 ); + + for( int g = 0; g < 2; g++ ) + { + std::vector< GroupData > &aGroup = g == 0 ? maCols : maRows; + const int nFirstAttach = g == 0 ? child->nLeftCol : child->nTopRow; + const int nLastAttach = g == 0 ? child->nRightCol : child->nBottomRow; + + for( int i = 0; i < nFirstAttach; i++ ) + { + int gSize = aGroup[ i ].nSize; + if ( aGroup[ i ].bExpand ) + gSize += nExtraSize[ g ]; + if ( g == 0 ) + rChildArea.X += gSize; + else + rChildArea.Y += gSize; + } + for( int i = nFirstAttach; i < nLastAttach; i++ ) + { + int gSize = aGroup[ i ].nSize; + if ( aGroup[ i ].bExpand ) + gSize += nExtraSize[ g ]; + if ( g == 0 ) + rChildArea.Width += gSize; + else + rChildArea.Height += gSize; + } + } + + allocateChildAt( child->xChild, rChildArea ); + } +} + +} // namespace layoutimpl diff --git a/toolkit/source/layout/table.hxx b/toolkit/source/layout/table.hxx new file mode 100644 index 000000000000..1374de2d61e3 --- /dev/null +++ b/toolkit/source/layout/table.hxx @@ -0,0 +1,79 @@ +#ifndef TABLE_HXX +#define TABLE_HXX + +#include "container.hxx" + +#include <list> + +namespace layoutimpl +{ + +class Table : public Container +{ + friend class TableChildProps; +protected: + // Table properties + sal_Int32 mnColsLen; + + // Children properties + struct ChildData + { + sal_Bool bExpand[ 2 ]; + sal_Int32 nColSpan, nRowSpan; + css::awt::Size aRequisition; + css::uno::Reference< css::awt::XLayoutConstrains > xChild; + css::uno::Reference< css::beans::XPropertySet > xProps; + bool isVisible(); + + // automatically calculated + int nLeftCol, nRightCol, nTopRow, nBottomRow; + }; + std::list< ChildData * > maChildren; + + // a group of children; either a column or a row + struct GroupData + { + sal_Bool bExpand; + int nSize; // request size (width or height) + GroupData() : bExpand( false ), nSize( 0 ) {} + }; + std::vector< GroupData > maCols, maRows; + int mnColExpandables, mnRowExpandables; + +public: + Table(); + + // css::awt::XLayoutContainer + virtual void SAL_CALL addChild( const css::uno::Reference< css::awt::XLayoutConstrains >& Child ) + throw (css::uno::RuntimeException, css::awt::MaxChildrenException); + virtual void SAL_CALL removeChild( const css::uno::Reference< css::awt::XLayoutConstrains >& Child ) + throw (css::uno::RuntimeException); + + virtual css::uno::Sequence< css::uno::Reference + < css::awt::XLayoutConstrains > > SAL_CALL getChildren() + throw (css::uno::RuntimeException); + + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL getChildProperties( + const css::uno::Reference< css::awt::XLayoutConstrains >& Child ) + throw (css::uno::RuntimeException); + + virtual void SAL_CALL allocateArea( const css::awt::Rectangle &rArea ) + throw (css::uno::RuntimeException); + + virtual css::awt::Size SAL_CALL getMinimumSize() + throw(css::uno::RuntimeException); + + // unimplemented: + virtual sal_Bool SAL_CALL hasHeightForWidth() + throw(css::uno::RuntimeException) + { return false; } + virtual sal_Int32 SAL_CALL getHeightForWidth( sal_Int32 /*nWidth*/ ) + throw(css::uno::RuntimeException) + { return maRequisition.Height; } + + PROPHELPER_SET_INFO +}; + +} // namespace layoutimpl + +#endif /*TABLE_HXX*/ diff --git a/toolkit/source/layout/timer.cxx b/toolkit/source/layout/timer.cxx new file mode 100644 index 000000000000..496d206b900e --- /dev/null +++ b/toolkit/source/layout/timer.cxx @@ -0,0 +1,121 @@ +#include "timer.hxx" + +#include <vector> +#include <list> +#include <vcl/timer.hxx> +#include <com/sun/star/awt/XLayoutContainer.hpp> + +namespace layoutimpl +{ +using namespace ::com::sun::star; + +class AllocateTimer : public Timer +{ + typedef std::list< uno::Reference< awt::XLayoutContainer > > ContainerList; + ContainerList mxContainers; + uno::Reference< awt::XLayoutContainer > mxLastAdded; + +public: + AllocateTimer() + { + // timer set to 0 -- just process it as soon as it gets idle + SetTimeout( 0 ); + } + + static inline bool isParentOf( uno::Reference< awt::XLayoutContainer > xParent, + uno::Reference< awt::XLayoutContainer > xWidget ) + { + while ( xWidget.is() ) + { + if ( xWidget == xParent ) + return true; + xWidget = uno::Reference< awt::XLayoutContainer >( xWidget->getParent(), uno::UNO_QUERY ); + } + return false; + } + + static inline void eraseChildren( ContainerList::iterator &it, ContainerList &list ) + { + ContainerList::iterator jt = list.begin(); + while ( jt != list.end() ) + { + if ( it != jt && isParentOf( *it, *jt ) ) + jt = list.erase( jt ); + else + jt++; + } + } + + static inline bool isContainerDamaged( uno::Reference< awt::XLayoutContainer > xContainer ) + { + uno::Reference< awt::XLayoutConstrains > xConstrains( xContainer, uno::UNO_QUERY ); + awt::Size lastReq( xContainer->getRequestedSize() ); + awt::Size curReq( xConstrains->getMinimumSize() ); + return lastReq.Width != curReq.Width || lastReq.Height != curReq.Height; + } + + void add( const uno::Reference< awt::XLayoutContainer > &xContainer ) + { + // small optimization + if ( mxLastAdded == xContainer ) + return; + mxLastAdded = xContainer; + + mxContainers.push_back( xContainer ); + } + + virtual void Timeout() + { + mxLastAdded = uno::Reference< awt::XLayoutContainer >(); + + // 1. remove duplications and children + for( ContainerList::iterator it = mxContainers.begin(); + it != mxContainers.end(); it++ ) + eraseChildren( it, mxContainers ); + + // 2. check damage extent + for( ContainerList::iterator it = mxContainers.begin(); + it != mxContainers.end(); it++ ) + { + uno::Reference< awt::XLayoutContainer > xContainer = *it; + while ( xContainer->getParent().is() && isContainerDamaged( xContainer ) ) + { + xContainer = uno::Reference< awt::XLayoutContainer >( + xContainer->getParent(), uno::UNO_QUERY ); + } + + if ( *it != xContainer ) + { + // 2.2 replace it with parent + *it = xContainer; + + // 2.3 remove children of new parent + eraseChildren( it, mxContainers ); + } + } + + // 3. force re-calculations + for( ContainerList::iterator it = mxContainers.begin(); + it != mxContainers.end(); it++ ) + (*it)->allocateArea( (*it)->getAllocatedArea() ); + } +}; + +static void AddResizeTimeout( const uno::Reference< awt::XLayoutContainer > &xCont ) +{ + static AllocateTimer timer; + timer.add( xCont ); + timer.Start(); +} + +LayoutUnit::LayoutUnit() : LayoutUnit_Base() +{ +} + +void SAL_CALL LayoutUnit::queueResize( const uno::Reference< awt::XLayoutContainer > &xContainer ) + throw( uno::RuntimeException ) +{ + AddResizeTimeout( xContainer ); +} + +} diff --git a/toolkit/source/layout/timer.hxx b/toolkit/source/layout/timer.hxx new file mode 100644 index 000000000000..d87528cbdcf3 --- /dev/null +++ b/toolkit/source/layout/timer.hxx @@ -0,0 +1,22 @@ +#ifndef CORE_TIMER_HXX +#define CORE_TIMER_HXX + +#include <com/sun/star/awt/XLayoutUnit.hpp> +#include <cppuhelper/implbase1.hxx> + +namespace layoutimpl +{ + +typedef ::cppu::WeakImplHelper1< com::sun::star::awt::XLayoutUnit > LayoutUnit_Base; + +class LayoutUnit : public LayoutUnit_Base +{ +public: + LayoutUnit(); + void SAL_CALL queueResize( const com::sun::star::uno::Reference< com::sun::star::awt::XLayoutContainer > &xContainer ) + throw( com::sun::star::uno::RuntimeException ); +}; + +} + +#endif /*CORE_TIMER_HXX*/ |