diff options
Diffstat (limited to 'svx/source/form/filtnav.cxx')
-rw-r--r-- | svx/source/form/filtnav.cxx | 2085 |
1 files changed, 2085 insertions, 0 deletions
diff --git a/svx/source/form/filtnav.cxx b/svx/source/form/filtnav.cxx new file mode 100644 index 000000000000..9d1b65208fdf --- /dev/null +++ b/svx/source/form/filtnav.cxx @@ -0,0 +1,2085 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" + + +#include "filtnav.hxx" +#include "fmexch.hxx" +#include "fmhelp.hrc" +#include "fmitems.hxx" +#include "fmprop.hrc" +#include "fmresids.hrc" +#include "gridcell.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/form/runtime/XFormController.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/util/XNumberFormatter.hpp> +/** === end UNO includes === **/ + +#include <comphelper/processfactory.hxx> +#include <svx/fmtools.hxx> +#include <comphelper/property.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/uno3.hxx> +#include <connectivity/dbtools.hxx> +#include <cppuhelper/implbase1.hxx> +#include <fmservs.hxx> +#include <fmshimp.hxx> +#include <rtl/logfile.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/objitem.hxx> +#include <sfx2/objsh.hxx> +#include <sfx2/request.hxx> +#include <svx/dialmgr.hxx> +#include <svx/fmshell.hxx> +#include <svx/svxids.hrc> +#include <tools/shl.hxx> +#include <vcl/wrkwin.hxx> + +#include <functional> + +#define SYNC_DELAY 200 +#define DROP_ACTION_TIMER_INITIAL_TICKS 10 + // solange dauert es, bis das Scrollen anspringt +#define DROP_ACTION_TIMER_SCROLL_TICKS 3 + // in diesen Intervallen wird jeweils eine Zeile gescrollt +#define DROP_ACTION_TIMER_TICK_BASE 10 + // das ist die Basis, mit der beide Angaben multipliziert werden (in ms) + +using namespace ::svxform; +using namespace ::connectivity::simple; +using namespace ::connectivity; + + +//........................................................................ +namespace svxform +{ +//........................................................................ + + /** === begin UNO using === **/ + using ::com::sun::star::uno::Reference; + using ::com::sun::star::lang::XMultiServiceFactory; + using ::com::sun::star::awt::TextEvent; + using ::com::sun::star::container::XIndexAccess; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::beans::XPropertySet; + using ::com::sun::star::form::runtime::XFormController; + using ::com::sun::star::form::runtime::XFilterController; + using ::com::sun::star::form::runtime::XFilterControllerListener; + using ::com::sun::star::form::runtime::FilterEvent; + using ::com::sun::star::lang::EventObject; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::form::XForm; + using ::com::sun::star::container::XChild; + using ::com::sun::star::awt::XControl; + using ::com::sun::star::sdbc::XConnection; + using ::com::sun::star::util::XNumberFormatsSupplier; + using ::com::sun::star::beans::XPropertySet; + using ::com::sun::star::util::XNumberFormatter; + using ::com::sun::star::sdbc::XRowSet; + using ::com::sun::star::lang::Locale; + using ::com::sun::star::sdb::SQLContext; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::UNO_SET_THROW; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::awt::XTextComponent; + using ::com::sun::star::uno::Sequence; + /** === end UNO using === **/ + +//======================================================================== +OFilterItemExchange::OFilterItemExchange() +{ +} + +//------------------------------------------------------------------------ +void OFilterItemExchange::AddSupportedFormats() +{ + AddFormat(getFormatId()); +} + +//------------------------------------------------------------------------ +sal_uInt32 OFilterItemExchange::getFormatId() +{ + static sal_uInt32 s_nFormat = (sal_uInt32)-1; + if ((sal_uInt32)-1 == s_nFormat) + { + s_nFormat = SotExchange::RegisterFormatName(String::CreateFromAscii("application/x-openoffice;windows_formatname=\"form.FilterControlExchange\"")); + DBG_ASSERT((sal_uInt32)-1 != s_nFormat, "OFilterExchangeHelper::getFormatId: bad exchange id!"); + } + return s_nFormat; +} + +//------------------------------------------------------------------------ +OLocalExchange* OFilterExchangeHelper::createExchange() const +{ + return new OFilterItemExchange; +} + +//======================================================================== +TYPEINIT0(FmFilterData); +Image FmFilterData::GetImage( BmpColorMode /*_eMode*/ ) const +{ + return Image(); +} + +//======================================================================== +TYPEINIT1(FmParentData, FmFilterData); +//------------------------------------------------------------------------ +FmParentData::~FmParentData() +{ + for (::std::vector<FmFilterData*>::const_iterator i = m_aChildren.begin(); + i != m_aChildren.end(); i++) + delete (*i); +} + +//======================================================================== +TYPEINIT1(FmFormItem, FmParentData); +//------------------------------------------------------------------------ +Image FmFormItem::GetImage( BmpColorMode _eMode ) const +{ + static Image aImage; + static Image aImage_HC; + + if (!aImage) + { + ImageList aNavigatorImages( SVX_RES( RID_SVXIMGLIST_FMEXPL ) ); + ImageList aNavigatorImages_HC( SVX_RES( RID_SVXIMGLIST_FMEXPL_HC ) ); + + aImage = aNavigatorImages.GetImage( RID_SVXIMG_FORM ); + aImage_HC = aNavigatorImages_HC.GetImage( RID_SVXIMG_FORM ); + } + return ( BMP_COLOR_HIGHCONTRAST == _eMode ) ? aImage_HC : aImage; +} + +//======================================================================== +TYPEINIT1(FmFilterItems, FmParentData); +//------------------------------------------------------------------------ +FmFilterItem* FmFilterItems::Find( const ::sal_Int32 _nFilterComponentIndex ) const +{ + for ( ::std::vector< FmFilterData* >::const_iterator i = m_aChildren.begin(); + i != m_aChildren.end(); + ++i + ) + { + FmFilterItem* pCondition = PTR_CAST( FmFilterItem, *i ); + DBG_ASSERT( pCondition, "FmFilterItems::Find: Wrong element in container!" ); + if ( _nFilterComponentIndex == pCondition->GetComponentIndex() ) + return pCondition; + } + return NULL; +} + +//------------------------------------------------------------------------ +Image FmFilterItems::GetImage( BmpColorMode _eMode ) const +{ + static Image aImage; + static Image aImage_HC; + + if (!aImage) + { + ImageList aNavigatorImages( SVX_RES( RID_SVXIMGLIST_FMEXPL ) ); + ImageList aNavigatorImages_HC( SVX_RES( RID_SVXIMGLIST_FMEXPL_HC ) ); + + aImage = aNavigatorImages.GetImage( RID_SVXIMG_FILTER ); + aImage_HC = aNavigatorImages_HC.GetImage( RID_SVXIMG_FILTER ); + } + return ( BMP_COLOR_HIGHCONTRAST == _eMode ) ? aImage_HC : aImage; +} + +//======================================================================== +TYPEINIT1(FmFilterItem, FmFilterData); +//------------------------------------------------------------------------ +FmFilterItem::FmFilterItem( const Reference< XMultiServiceFactory >& _rxFactory, + FmFilterItems* pParent, + const ::rtl::OUString& aFieldName, + const ::rtl::OUString& aText, + const sal_Int32 _nComponentIndex ) + :FmFilterData(_rxFactory,pParent, aText) + ,m_aFieldName(aFieldName) + ,m_nComponentIndex( _nComponentIndex ) +{ +} + +//------------------------------------------------------------------------ +Image FmFilterItem::GetImage( BmpColorMode _eMode ) const +{ + static Image aImage; + static Image aImage_HC; + + if (!aImage) + { + ImageList aNavigatorImages( SVX_RES( RID_SVXIMGLIST_FMEXPL ) ); + ImageList aNavigatorImages_HC( SVX_RES( RID_SVXIMGLIST_FMEXPL_HC ) ); + + aImage = aNavigatorImages.GetImage( RID_SVXIMG_FIELD ); + aImage_HC = aNavigatorImages_HC.GetImage( RID_SVXIMG_FIELD ); + } + return ( BMP_COLOR_HIGHCONTRAST == _eMode ) ? aImage_HC : aImage; +} + +//======================================================================== +// Hints for communicatition between model and view +//======================================================================== +class FmFilterHint : public SfxHint +{ + FmFilterData* m_pData; + +public: + TYPEINFO(); + FmFilterHint(FmFilterData* pData):m_pData(pData){} + FmFilterData* GetData() const { return m_pData; } +}; +TYPEINIT1( FmFilterHint, SfxHint ); + +//======================================================================== +class FmFilterInsertedHint : public FmFilterHint +{ + sal_Int32 m_nPos; // Position relative to the parent of the data + +public: + TYPEINFO(); + FmFilterInsertedHint(FmFilterData* pData, sal_Int32 nRelPos) + :FmFilterHint(pData) + ,m_nPos(nRelPos){} + + sal_Int32 GetPos() const { return m_nPos; } +}; +TYPEINIT1( FmFilterInsertedHint, FmFilterHint ); + +//======================================================================== +class FmFilterRemovedHint : public FmFilterHint +{ +public: + TYPEINFO(); + FmFilterRemovedHint(FmFilterData* pData) + :FmFilterHint(pData){} + +}; +TYPEINIT1( FmFilterRemovedHint, FmFilterHint ); + +//======================================================================== +class FmFilterTextChangedHint : public FmFilterHint +{ +public: + TYPEINFO(); + FmFilterTextChangedHint(FmFilterData* pData) + :FmFilterHint(pData){} + +}; +TYPEINIT1( FmFilterTextChangedHint, FmFilterHint ); + +//======================================================================== +class FilterClearingHint : public SfxHint +{ +public: + TYPEINFO(); + FilterClearingHint(){} +}; +TYPEINIT1( FilterClearingHint, SfxHint ); + +//======================================================================== +class FmFilterCurrentChangedHint : public SfxHint +{ +public: + TYPEINFO(); + FmFilterCurrentChangedHint(){} +}; +TYPEINIT1( FmFilterCurrentChangedHint, SfxHint ); + +//======================================================================== +// class FmFilterAdapter, Listener an den FilterControls +//======================================================================== +class FmFilterAdapter : public ::cppu::WeakImplHelper1< XFilterControllerListener > +{ + FmFilterModel* m_pModel; + Reference< XIndexAccess > m_xControllers; + +public: + FmFilterAdapter(FmFilterModel* pModel, const Reference< XIndexAccess >& xControllers); + +// XEventListener + virtual void SAL_CALL disposing(const EventObject& Source) throw( RuntimeException ); + +// XFilterControllerListener + virtual void SAL_CALL predicateExpressionChanged( const FilterEvent& _Event ) throw (RuntimeException); + virtual void SAL_CALL disjunctiveTermRemoved( const FilterEvent& _Event ) throw (RuntimeException); + virtual void SAL_CALL disjunctiveTermAdded( const FilterEvent& _Event ) throw (RuntimeException); + +// helpers + void dispose() throw( RuntimeException ); + + void AddOrRemoveListener( const Reference< XIndexAccess >& _rxControllers, const bool _bAdd ); + + void setText(sal_Int32 nPos, + const FmFilterItem* pFilterItem, + const ::rtl::OUString& rText); +}; + +//------------------------------------------------------------------------ +FmFilterAdapter::FmFilterAdapter(FmFilterModel* pModel, const Reference< XIndexAccess >& xControllers) + :m_pModel( pModel ) + ,m_xControllers( xControllers ) +{ + AddOrRemoveListener( m_xControllers, true ); +} + +//------------------------------------------------------------------------ +void FmFilterAdapter::dispose() throw( RuntimeException ) +{ + AddOrRemoveListener( m_xControllers, false ); +} + +//------------------------------------------------------------------------ +void FmFilterAdapter::AddOrRemoveListener( const Reference< XIndexAccess >& _rxControllers, const bool _bAdd ) +{ + for (sal_Int32 i = 0, nLen = _rxControllers->getCount(); i < nLen; ++i) + { + Reference< XIndexAccess > xElement( _rxControllers->getByIndex(i), UNO_QUERY ); + + // step down + AddOrRemoveListener( xElement, _bAdd ); + + // handle this particular controller + Reference< XFilterController > xController( xElement, UNO_QUERY ); + OSL_ENSURE( xController.is(), "FmFilterAdapter::InsertElements: no XFilterController, cannot sync data!" ); + if ( xController.is() ) + { + if ( _bAdd ) + xController->addFilterControllerListener( this ); + else + xController->removeFilterControllerListener( this ); + } + } +} + +//------------------------------------------------------------------------ +void FmFilterAdapter::setText(sal_Int32 nRowPos, + const FmFilterItem* pFilterItem, + const ::rtl::OUString& rText) +{ + FmFormItem* pFormItem = PTR_CAST( FmFormItem, pFilterItem->GetParent()->GetParent() ); + + try + { + Reference< XFilterController > xController( pFormItem->GetController(), UNO_QUERY_THROW ); + xController->setPredicateExpression( pFilterItem->GetComponentIndex(), nRowPos, rText ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + + +// XEventListener +//------------------------------------------------------------------------ +void SAL_CALL FmFilterAdapter::disposing(const EventObject& /*e*/) throw( RuntimeException ) +{ +} + +//------------------------------------------------------------------------ +namespace +{ + ::rtl::OUString lcl_getLabelName_nothrow( const Reference< XControl >& _rxControl ) + { + ::rtl::OUString sLabelName; + try + { + Reference< XControl > xControl( _rxControl, UNO_SET_THROW ); + Reference< XPropertySet > xModel( xControl->getModel(), UNO_QUERY_THROW ); + sLabelName = getLabelName( xModel ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + return sLabelName; + } + + Reference< XPropertySet > lcl_getBoundField_nothrow( const Reference< XControl >& _rxControl ) + { + Reference< XPropertySet > xField; + try + { + Reference< XControl > xControl( _rxControl, UNO_SET_THROW ); + Reference< XPropertySet > xModelProps( xControl->getModel(), UNO_QUERY_THROW ); + xField.set( xModelProps->getPropertyValue( FM_PROP_BOUNDFIELD ), UNO_QUERY_THROW ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + return xField; + } +} + +// XFilterControllerListener +//------------------------------------------------------------------------ +void FmFilterAdapter::predicateExpressionChanged( const FilterEvent& _Event ) throw( RuntimeException ) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + if ( !m_pModel ) + return; + + // the controller which sent the event + Reference< XFormController > xController( _Event.Source, UNO_QUERY_THROW ); + Reference< XFilterController > xFilterController( _Event.Source, UNO_QUERY_THROW ); + Reference< XForm > xForm( xController->getModel(), UNO_QUERY_THROW ); + + FmFormItem* pFormItem = m_pModel->Find( m_pModel->m_aChildren, xForm ); + OSL_ENSURE( pFormItem, "FmFilterAdapter::predicateExpressionChanged: don't know this form!" ); + if ( !pFormItem ) + return; + + const sal_Int32 nActiveTerm( xFilterController->getActiveTerm() ); + + FmFilterItems* pFilter = PTR_CAST( FmFilterItems, pFormItem->GetChildren()[ nActiveTerm ] ); + FmFilterItem* pFilterItem = pFilter->Find( _Event.FilterComponent ); + if ( pFilterItem ) + { + if ( _Event.PredicateExpression.getLength()) + { + pFilterItem->SetText( _Event.PredicateExpression ); + // UI benachrichtigen + FmFilterTextChangedHint aChangeHint(pFilterItem); + m_pModel->Broadcast( aChangeHint ); + } + else + { + // no text anymore so remove the condition + m_pModel->Remove(pFilterItem); + } + } + else + { + // searching the component by field name + ::rtl::OUString aFieldName( lcl_getLabelName_nothrow( xFilterController->getFilterComponent( _Event.FilterComponent ) ) ); + + pFilterItem = new FmFilterItem( m_pModel->getORB(), pFilter, aFieldName, _Event.PredicateExpression, _Event.FilterComponent ); + m_pModel->Insert(pFilter->GetChildren().end(), pFilterItem); + } + + // ensure there's one empty term in the filter, just in case the active term was previously empty + m_pModel->EnsureEmptyFilterRows( *pFormItem ); +} + +//------------------------------------------------------------------------ +void SAL_CALL FmFilterAdapter::disjunctiveTermRemoved( const FilterEvent& _Event ) throw (RuntimeException) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + Reference< XFormController > xController( _Event.Source, UNO_QUERY_THROW ); + Reference< XFilterController > xFilterController( _Event.Source, UNO_QUERY_THROW ); + Reference< XForm > xForm( xController->getModel(), UNO_QUERY_THROW ); + + FmFormItem* pFormItem = m_pModel->Find( m_pModel->m_aChildren, xForm ); + OSL_ENSURE( pFormItem, "FmFilterAdapter::disjunctiveTermRemoved: don't know this form!" ); + if ( !pFormItem ) + return; + + ::std::vector< FmFilterData* >& rTermItems = pFormItem->GetChildren(); + const bool bValidIndex = ( _Event.DisjunctiveTerm >= 0 ) && ( (size_t)_Event.DisjunctiveTerm < rTermItems.size() ); + OSL_ENSURE( bValidIndex, "FmFilterAdapter::disjunctiveTermRemoved: invalid term index!" ); + if ( !bValidIndex ) + return; + + // if the first term was removed, then the to-be first term needs its text updated + if ( _Event.DisjunctiveTerm == 0 ) + { + rTermItems[1]->SetText( String( SVX_RES( RID_STR_FILTER_FILTER_FOR ) ) ); + FmFilterTextChangedHint aChangeHint( rTermItems[1] ); + m_pModel->Broadcast( aChangeHint ); + } + + // finally remove the entry from the model + m_pModel->Remove( rTermItems.begin() + _Event.DisjunctiveTerm ); + + // ensure there's one empty term in the filter, just in case the currently removed one was the last empty one + m_pModel->EnsureEmptyFilterRows( *pFormItem ); +} + +//------------------------------------------------------------------------ +void SAL_CALL FmFilterAdapter::disjunctiveTermAdded( const FilterEvent& _Event ) throw (RuntimeException) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + Reference< XFormController > xController( _Event.Source, UNO_QUERY_THROW ); + Reference< XFilterController > xFilterController( _Event.Source, UNO_QUERY_THROW ); + Reference< XForm > xForm( xController->getModel(), UNO_QUERY_THROW ); + + FmFormItem* pFormItem = m_pModel->Find( m_pModel->m_aChildren, xForm ); + OSL_ENSURE( pFormItem, "FmFilterAdapter::disjunctiveTermAdded: don't know this form!" ); + if ( !pFormItem ) + return; + + const sal_Int32 nInsertPos = _Event.DisjunctiveTerm; + bool bValidIndex = ( nInsertPos >= 0 ) && ( (size_t)nInsertPos <= pFormItem->GetChildren().size() ); + if ( !bValidIndex ) + { + OSL_ENSURE( false, "FmFilterAdapter::disjunctiveTermAdded: invalid index!" ); + return; + } + + const ::std::vector< FmFilterData* >::iterator insertPos = pFormItem->GetChildren().begin() + nInsertPos; + + FmFilterItems* pFilterItems = new FmFilterItems( m_pModel->getORB(), pFormItem, String( SVX_RES( RID_STR_FILTER_FILTER_OR ) ) ); + m_pModel->Insert( insertPos, pFilterItems ); +} + +//======================================================================== +// class FmFilterModel +//======================================================================== +TYPEINIT1(FmFilterModel, FmParentData); +//------------------------------------------------------------------------ +FmFilterModel::FmFilterModel(const Reference< XMultiServiceFactory >& _rxFactory) + :FmParentData(_rxFactory,NULL, ::rtl::OUString()) + ,OSQLParserClient(_rxFactory) + ,m_xORB(_rxFactory) + ,m_pAdapter(NULL) + ,m_pCurrentItems(NULL) +{ +} + +//------------------------------------------------------------------------ +FmFilterModel::~FmFilterModel() +{ + Clear(); +} + +//------------------------------------------------------------------------ +void FmFilterModel::Clear() +{ + // notify + FilterClearingHint aClearedHint; + Broadcast( aClearedHint ); + + // loose endings + if (m_pAdapter) + { + m_pAdapter->dispose(); + m_pAdapter->release(); + m_pAdapter= NULL; + } + + m_pCurrentItems = NULL; + m_xController = NULL; + m_xControllers = NULL; + + for (::std::vector<FmFilterData*>::const_iterator i = m_aChildren.begin(); + i != m_aChildren.end(); i++) + delete (*i); + + m_aChildren.clear(); +} + +//------------------------------------------------------------------------ +void FmFilterModel::Update(const Reference< XIndexAccess > & xControllers, const Reference< XFormController > & xCurrent) +{ + if ( xCurrent == m_xController ) + return; + + if (!xControllers.is()) + { + Clear(); + return; + } + + // there is only a new current controller + if ( m_xControllers != xControllers ) + { + Clear(); + + m_xControllers = xControllers; + Update(m_xControllers, this); + + DBG_ASSERT(xCurrent.is(), "FmFilterModel::Update(...) no current controller"); + + // Listening for TextChanges + m_pAdapter = new FmFilterAdapter(this, xControllers); + m_pAdapter->acquire(); + + SetCurrentController(xCurrent); + EnsureEmptyFilterRows( *this ); + } + else + SetCurrentController(xCurrent); +} + +//------------------------------------------------------------------------ +void FmFilterModel::Update(const Reference< XIndexAccess > & xControllers, FmParentData* pParent) +{ + try + { + sal_Int32 nCount = xControllers->getCount(); + for ( sal_Int32 i = 0; i < nCount; ++i ) + { + Reference< XFormController > xController( xControllers->getByIndex(i), UNO_QUERY_THROW ); + + Reference< XPropertySet > xFormProperties( xController->getModel(), UNO_QUERY_THROW ); + ::rtl::OUString aName; + OSL_VERIFY( xFormProperties->getPropertyValue( FM_PROP_NAME ) >>= aName ); + + // Insert a new item for the form + FmFormItem* pFormItem = new FmFormItem( m_xORB, pParent, xController, aName ); + Insert( pParent->GetChildren().end(), pFormItem ); + + Reference< XFilterController > xFilterController( pFormItem->GetFilterController(), UNO_SET_THROW ); + + // insert the existing filters for the form + String aTitle( SVX_RES( RID_STR_FILTER_FILTER_FOR ) ); + + Sequence< Sequence< ::rtl::OUString > > aExpressions = xFilterController->getPredicateExpressions(); + for ( const Sequence< ::rtl::OUString >* pConjunctionTerm = aExpressions.getConstArray(); + pConjunctionTerm != aExpressions.getConstArray() + aExpressions.getLength(); + ++pConjunctionTerm + ) + { + // we always display one row, even if there's no term to be displayed + FmFilterItems* pFilterItems = new FmFilterItems( m_xORB, pFormItem, aTitle ); + Insert( pFormItem->GetChildren().end(), pFilterItems ); + + const Sequence< ::rtl::OUString >& rDisjunction( *pConjunctionTerm ); + for ( const ::rtl::OUString* pDisjunctiveTerm = rDisjunction.getConstArray(); + pDisjunctiveTerm != rDisjunction.getConstArray() + rDisjunction.getLength(); + ++pDisjunctiveTerm + ) + { + if ( pDisjunctiveTerm->getLength() == 0 ) + // no condition for this particular component in this particular conjunction term + continue; + + const sal_Int32 nComponentIndex = pDisjunctiveTerm - rDisjunction.getConstArray(); + + // determine the display name of the control + const Reference< XControl > xFilterControl( xFilterController->getFilterComponent( nComponentIndex ) ); + const ::rtl::OUString sDisplayName( lcl_getLabelName_nothrow( xFilterControl ) ); + + // insert a new entry + FmFilterItem* pANDCondition = new FmFilterItem( m_xORB, pFilterItems, sDisplayName, *pDisjunctiveTerm, nComponentIndex ); + Insert( pFilterItems->GetChildren().end(), pANDCondition ); + } + + // title for the next conditions + aTitle = SVX_RES( RID_STR_FILTER_FILTER_OR ); + } + + // now add dependent controllers + Reference< XIndexAccess > xControllerAsIndex( xController, UNO_QUERY ); + Update( xControllerAsIndex, pFormItem ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + +//------------------------------------------------------------------------ +FmFormItem* FmFilterModel::Find(const ::std::vector<FmFilterData*>& rItems, const Reference< XFormController > & xController) const +{ + for (::std::vector<FmFilterData*>::const_iterator i = rItems.begin(); + i != rItems.end(); i++) + { + FmFormItem* pForm = PTR_CAST(FmFormItem,*i); + if (pForm) + { + if ( xController == pForm->GetController() ) + return pForm; + else + { + pForm = Find(pForm->GetChildren(), xController); + if (pForm) + return pForm; + } + } + } + return NULL; +} + +//------------------------------------------------------------------------ +FmFormItem* FmFilterModel::Find(const ::std::vector<FmFilterData*>& rItems, const Reference< XForm >& xForm) const +{ + for (::std::vector<FmFilterData*>::const_iterator i = rItems.begin(); + i != rItems.end(); i++) + { + FmFormItem* pForm = PTR_CAST(FmFormItem,*i); + if (pForm) + { + if (xForm == pForm->GetController()->getModel()) + return pForm; + else + { + pForm = Find(pForm->GetChildren(), xForm); + if (pForm) + return pForm; + } + } + } + return NULL; +} + +//------------------------------------------------------------------------ +void FmFilterModel::SetCurrentController(const Reference< XFormController > & xCurrent) +{ + if ( xCurrent == m_xController ) + return; + + m_xController = xCurrent; + + FmFormItem* pItem = Find( m_aChildren, xCurrent ); + if ( !pItem ) + return; + + try + { + Reference< XFilterController > xFilterController( m_xController, UNO_QUERY_THROW ); + const sal_Int32 nActiveTerm( xFilterController->getActiveTerm() ); + if ( pItem->GetChildren().size() > (size_t)nActiveTerm ) + { + SetCurrentItems( static_cast< FmFilterItems* >( pItem->GetChildren()[ nActiveTerm ] ) ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + +//------------------------------------------------------------------------ +void FmFilterModel::AppendFilterItems( FmFormItem& _rFormItem ) +{ + // insert the condition behind the last filter items + ::std::vector<FmFilterData*>::reverse_iterator iter; + for ( iter = _rFormItem.GetChildren().rbegin(); + iter != _rFormItem.GetChildren().rend(); + ++iter + ) + { + if ((*iter)->ISA(FmFilterItems)) + break; + } + + sal_Int32 nInsertPos = iter.base() - _rFormItem.GetChildren().begin(); + // delegate this to the FilterController, it will notify us, which will let us update our model + try + { + Reference< XFilterController > xFilterController( _rFormItem.GetFilterController(), UNO_SET_THROW ); + if ( nInsertPos >= xFilterController->getDisjunctiveTerms() ) + xFilterController->appendEmptyDisjunctiveTerm(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + +//------------------------------------------------------------------------ +void FmFilterModel::Insert(const ::std::vector<FmFilterData*>::iterator& rPos, FmFilterData* pData) +{ + ::std::vector<FmFilterData*>& rItems = pData->GetParent()->GetChildren(); + sal_Int32 nPos = rPos == rItems.end() ? LIST_APPEND : rPos - rItems.begin(); + rItems.insert(rPos, pData); + + // UI benachrichtigen + FmFilterInsertedHint aInsertedHint(pData, nPos); + Broadcast( aInsertedHint ); +} + +//------------------------------------------------------------------------ +void FmFilterModel::Remove(FmFilterData* pData) +{ + FmParentData* pParent = pData->GetParent(); + ::std::vector<FmFilterData*>& rItems = pParent->GetChildren(); + + // erase the item from the model + ::std::vector<FmFilterData*>::iterator i = ::std::find(rItems.begin(), rItems.end(), pData); + DBG_ASSERT(i != rItems.end(), "FmFilterModel::Remove(): unknown Item"); + // position within the parent + sal_Int32 nPos = i - rItems.begin(); + if (pData->ISA(FmFilterItems)) + { + FmFormItem* pFormItem = (FmFormItem*)pParent; + + try + { + Reference< XFilterController > xFilterController( pFormItem->GetFilterController(), UNO_SET_THROW ); + + bool bEmptyLastTerm = ( ( nPos == 0 ) && xFilterController->getDisjunctiveTerms() == 1 ); + if ( bEmptyLastTerm ) + { + // remove all children (by setting an empty predicate expression) + ::std::vector< FmFilterData* >& rChildren = ((FmFilterItems*)pData)->GetChildren(); + while ( !rChildren.empty() ) + { + ::std::vector< FmFilterData* >::iterator removePos = rChildren.end() - 1; + FmFilterItem* pFilterItem = PTR_CAST( FmFilterItem, *removePos ); + m_pAdapter->setText( nPos, pFilterItem, ::rtl::OUString() ); + Remove( removePos ); + } + } + else + { + xFilterController->removeDisjunctiveTerm( nPos ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + else // FormItems can not be deleted + { + FmFilterItem* pFilterItem = PTR_CAST(FmFilterItem, pData); + + // if its the last condition remove the parent + if (rItems.size() == 1) + Remove(pFilterItem->GetParent()); + else + { + // find the position of the father within his father + ::std::vector<FmFilterData*>& rParentParentItems = pData->GetParent()->GetParent()->GetChildren(); + ::std::vector<FmFilterData*>::iterator j = ::std::find(rParentParentItems.begin(), rParentParentItems.end(), pFilterItem->GetParent()); + DBG_ASSERT(j != rParentParentItems.end(), "FmFilterModel::Remove(): unknown Item"); + sal_Int32 nParentPos = j - rParentParentItems.begin(); + + // EmptyText removes the filter + m_pAdapter->setText(nParentPos, pFilterItem, ::rtl::OUString()); + Remove( i ); + } + } +} + +//------------------------------------------------------------------------ +void FmFilterModel::Remove( const ::std::vector<FmFilterData*>::iterator& rPos ) +{ + // remove from parent's child list + FmFilterData* pData = *rPos; + pData->GetParent()->GetChildren().erase( rPos ); + + // notify the view, this will remove the actual SvLBoxEntry + FmFilterRemovedHint aRemoveHint( pData ); + Broadcast( aRemoveHint ); + + delete pData; +} + +//------------------------------------------------------------------------ +sal_Bool FmFilterModel::ValidateText(FmFilterItem* pItem, UniString& rText, UniString& rErrorMsg) const +{ + FmFormItem* pFormItem = PTR_CAST( FmFormItem, pItem->GetParent()->GetParent() ); + try + { + Reference< XFormController > xFormController( pFormItem->GetController() ); + // obtain the connection of the form belonging to the controller + OStaticDataAccessTools aStaticTools; + Reference< XRowSet > xRowSet( xFormController->getModel(), UNO_QUERY_THROW ); + Reference< XConnection > xConnection( aStaticTools.getRowSetConnection( xRowSet ) ); + + // obtain a number formatter for this connection + // TODO: shouldn't this be cached? + Reference< XNumberFormatsSupplier > xFormatSupplier = aStaticTools.getNumberFormats( xConnection, sal_True ); + Reference< XNumberFormatter > xFormatter( m_xORB->createInstance( FM_NUMBER_FORMATTER ), UNO_QUERY ); + xFormatter->attachNumberFormatsSupplier( xFormatSupplier ); + + // get the field (database column) which the item is responsible for + Reference< XFilterController > xFilterController( xFormController, UNO_QUERY_THROW ); + Reference< XPropertySet > xField( lcl_getBoundField_nothrow( xFilterController->getFilterComponent( pItem->GetComponentIndex() ) ), UNO_SET_THROW ); + + // parse the given text as filter predicate + ::rtl::OUString aErr, aTxt( rText ); + ::rtl::Reference< ISQLParseNode > xParseNode = predicateTree( aErr, aTxt, xFormatter, xField ); + rErrorMsg = aErr; + rText = aTxt; + if ( xParseNode.is() ) + { + ::rtl::OUString aPreparedText; + Locale aAppLocale = Application::GetSettings().GetUILocale(); + xParseNode->parseNodeToPredicateStr( + aPreparedText, xConnection, xFormatter, xField, aAppLocale, '.', getParseContext() ); + rText = aPreparedText; + return sal_True; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + return sal_False; +} + +//------------------------------------------------------------------------ +void FmFilterModel::Append(FmFilterItems* pItems, FmFilterItem* pFilterItem) +{ + Insert(pItems->GetChildren().end(), pFilterItem); +} + +//------------------------------------------------------------------------ +void FmFilterModel::SetTextForItem(FmFilterItem* pItem, const ::rtl::OUString& rText) +{ + ::std::vector<FmFilterData*>& rItems = pItem->GetParent()->GetParent()->GetChildren(); + ::std::vector<FmFilterData*>::iterator i = ::std::find(rItems.begin(), rItems.end(), pItem->GetParent()); + sal_Int32 nParentPos = i - rItems.begin(); + + m_pAdapter->setText(nParentPos, pItem, rText); + + if (!rText) + Remove(pItem); + else + { + // Change the text + pItem->SetText(rText); + FmFilterTextChangedHint aChangeHint(pItem); + Broadcast( aChangeHint ); + } +} + +//------------------------------------------------------------------------ +void FmFilterModel::SetCurrentItems(FmFilterItems* pCurrent) +{ + if (m_pCurrentItems == pCurrent) + return; + + // search for the condition + if (pCurrent) + { + FmFormItem* pFormItem = (FmFormItem*)pCurrent->GetParent(); + ::std::vector<FmFilterData*>& rItems = pFormItem->GetChildren(); + ::std::vector<FmFilterData*>::const_iterator i = ::std::find(rItems.begin(), rItems.end(), pCurrent); + + if (i != rItems.end()) + { + // determine the filter position + sal_Int32 nPos = i - rItems.begin(); + try + { + Reference< XFilterController > xFilterController( pFormItem->GetFilterController(), UNO_SET_THROW ); + xFilterController->setActiveTerm( nPos ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + if ( m_xController != pFormItem->GetController() ) + // calls SetCurrentItems again + SetCurrentController( pFormItem->GetController() ); + else + m_pCurrentItems = pCurrent; + } + else + m_pCurrentItems = NULL; + } + else + m_pCurrentItems = NULL; + + + // UI benachrichtigen + FmFilterCurrentChangedHint aHint; + Broadcast( aHint ); +} + +//------------------------------------------------------------------------ +void FmFilterModel::EnsureEmptyFilterRows( FmParentData& _rItem ) +{ + // checks whether for each form there's one free level for input + ::std::vector< FmFilterData* >& rChildren = _rItem.GetChildren(); + sal_Bool bAppendLevel = _rItem.ISA( FmFormItem ); + + for ( ::std::vector<FmFilterData*>::iterator i = rChildren.begin(); + i != rChildren.end(); + ++i + ) + { + FmFilterItems* pItems = PTR_CAST(FmFilterItems, *i); + if ( pItems && pItems->GetChildren().empty() ) + { + bAppendLevel = sal_False; + break; + } + + FmFormItem* pFormItem = PTR_CAST(FmFormItem, *i); + if (pFormItem) + { + EnsureEmptyFilterRows( *pFormItem ); + continue; + } + } + + if ( bAppendLevel ) + { + FmFormItem* pFormItem = PTR_CAST( FmFormItem, &_rItem ); + OSL_ENSURE( pFormItem, "FmFilterModel::EnsureEmptyFilterRows: no FmFormItem, but a FmFilterItems child?" ); + if ( pFormItem ) + AppendFilterItems( *pFormItem ); + } +} + +//======================================================================== +// class FmFilterItemsString +//======================================================================== +class FmFilterItemsString : public SvLBoxString +{ +public: + FmFilterItemsString( SvLBoxEntry* pEntry, sal_uInt16 nFlags, const XubString& rStr ) + :SvLBoxString(pEntry,nFlags,rStr){} + + virtual void Paint(const Point& rPos, SvLBox& rDev, sal_uInt16 nFlags, SvLBoxEntry* pEntry); + virtual void InitViewData( SvLBox* pView,SvLBoxEntry* pEntry, SvViewDataItem* pViewData); +}; + +const int nxDBmp = 12; +//------------------------------------------------------------------------ +void FmFilterItemsString::Paint(const Point& rPos, SvLBox& rDev, sal_uInt16 /*nFlags*/, SvLBoxEntry* pEntry ) +{ + FmFilterItems* pRow = (FmFilterItems*)pEntry->GetUserData(); + FmFormItem* pForm = (FmFormItem*)pRow->GetParent(); + + // current filter is significant painted + const bool bIsCurrentFilter = pForm->GetChildren()[ pForm->GetFilterController()->getActiveTerm() ] == pRow; + if ( bIsCurrentFilter ) + { + rDev.Push( PUSH_LINECOLOR ); + + rDev.SetLineColor( rDev.GetTextColor() ); + + Rectangle aRect( rPos, GetSize( &rDev, pEntry ) ); + Point aFirst( rPos.X(), aRect.Bottom() - 6 ); + Point aSecond(aFirst .X() + 2, aFirst.Y() + 3 ); + + rDev.DrawLine( aFirst, aSecond ); + + aFirst = aSecond; + aFirst.X() += 1; + aSecond.X() += 6; + aSecond.Y() -= 5; + + rDev.DrawLine( aFirst, aSecond ); + + rDev.Pop(); + } + + rDev.DrawText( Point(rPos.X() + nxDBmp, rPos.Y()), GetText() ); +} + +//------------------------------------------------------------------------ +void FmFilterItemsString::InitViewData( SvLBox* pView,SvLBoxEntry* pEntry, SvViewDataItem* pViewData) +{ + if( !pViewData ) + pViewData = pView->GetViewDataItem( pEntry, this ); + + Size aSize(pView->GetTextWidth(GetText()), pView->GetTextHeight()); + aSize.Width() += nxDBmp; + pViewData->aSize = aSize; +} + +//======================================================================== +// class FmFilterString +//======================================================================== +class FmFilterString : public SvLBoxString +{ + UniString m_aName; + +public: + FmFilterString( SvLBoxEntry* pEntry, sal_uInt16 nFlags, const XubString& rStr, const UniString& aName) + :SvLBoxString(pEntry,nFlags,rStr) + ,m_aName(aName) + { + m_aName.AppendAscii(": "); + } + + virtual void Paint(const Point& rPos, SvLBox& rDev, sal_uInt16 nFlags, SvLBoxEntry* pEntry); + virtual void InitViewData( SvLBox* pView,SvLBoxEntry* pEntry, SvViewDataItem* pViewData); +}; + +const int nxD = 4; + +//------------------------------------------------------------------------ +void FmFilterString::InitViewData( SvLBox* pView,SvLBoxEntry* pEntry, SvViewDataItem* pViewData) +{ + if( !pViewData ) + pViewData = pView->GetViewDataItem( pEntry, this ); + + Font aOldFont( pView->GetFont()); + Font aFont( aOldFont ); + aFont.SetWeight(WEIGHT_BOLD); + pView->SetFont( aFont ); + + Size aSize(pView->GetTextWidth(m_aName), pView->GetTextHeight()); + pView->SetFont( aOldFont ); + aSize.Width() += pView->GetTextWidth(GetText()) + nxD; + pViewData->aSize = aSize; +} + +//------------------------------------------------------------------------ +void FmFilterString::Paint(const Point& rPos, SvLBox& rDev, sal_uInt16 /*nFlags*/, SvLBoxEntry* /*pEntry*/ ) +{ + Font aOldFont( rDev.GetFont()); + Font aFont( aOldFont ); + aFont.SetWeight(WEIGHT_BOLD); + rDev.SetFont( aFont ); + + Point aPos(rPos); + rDev.DrawText( aPos, m_aName ); + + // position for the second text + aPos.X() += rDev.GetTextWidth(m_aName) + nxD; + rDev.SetFont( aOldFont ); + rDev.DrawText( aPos, GetText() ); +} + +//======================================================================== +// class FmFilterNavigator +//======================================================================== +FmFilterNavigator::FmFilterNavigator( Window* pParent ) + :SvTreeListBox( pParent, WB_HASBUTTONS|WB_HASLINES|WB_BORDER|WB_HASBUTTONSATROOT ) + ,m_pModel( NULL ) + ,m_pEditingCurrently( NULL ) + ,m_aControlExchange( this ) + ,m_aTimerCounter( 0 ) + ,m_aDropActionType( DA_SCROLLUP ) +{ + SetHelpId( HID_FILTER_NAVIGATOR ); + + { + { + ImageList aNavigatorImages( SVX_RES( RID_SVXIMGLIST_FMEXPL ) ); + SetNodeBitmaps( + aNavigatorImages.GetImage( RID_SVXIMG_COLLAPSEDNODE ), + aNavigatorImages.GetImage( RID_SVXIMG_EXPANDEDNODE ), + BMP_COLOR_NORMAL + ); + } + { + ImageList aNavigatorImages( SVX_RES( RID_SVXIMGLIST_FMEXPL_HC ) ); + SetNodeBitmaps( + aNavigatorImages.GetImage( RID_SVXIMG_COLLAPSEDNODE ), + aNavigatorImages.GetImage( RID_SVXIMG_EXPANDEDNODE ), + BMP_COLOR_HIGHCONTRAST + ); + } + } + + m_pModel = new FmFilterModel(comphelper::getProcessServiceFactory()); + StartListening( *m_pModel ); + + EnableInplaceEditing( sal_True ); + SetSelectionMode(MULTIPLE_SELECTION); + + SetDragDropMode(0xFFFF); + + m_aDropActionTimer.SetTimeoutHdl(LINK(this, FmFilterNavigator, OnDropActionTimer)); +} + +//------------------------------------------------------------------------ +FmFilterNavigator::~FmFilterNavigator() +{ + EndListening( *m_pModel ); + delete m_pModel; +} + +//------------------------------------------------------------------------ +void FmFilterNavigator::Clear() +{ + m_pModel->Clear(); +} + +//------------------------------------------------------------------------ +void FmFilterNavigator::UpdateContent(const Reference< XIndexAccess > & xControllers, const Reference< XFormController > & xCurrent) +{ + if (xCurrent == m_pModel->GetCurrentController()) + return; + + m_pModel->Update(xControllers, xCurrent); + + // expand the filters for the current controller + SvLBoxEntry* pEntry = FindEntry(m_pModel->GetCurrentForm()); + if (pEntry && !IsExpanded(pEntry)) + { + SelectAll(sal_False); + + if (!IsExpanded(pEntry)) + Expand(pEntry); + + pEntry = FindEntry(m_pModel->GetCurrentItems()); + if (pEntry) + { + if (!IsExpanded(pEntry)) + Expand(pEntry); + Select(pEntry, sal_True); + } + } +} + +//------------------------------------------------------------------------ +sal_Bool FmFilterNavigator::EditingEntry( SvLBoxEntry* pEntry, Selection& rSelection ) +{ + m_pEditingCurrently = pEntry; + if (!SvTreeListBox::EditingEntry( pEntry, rSelection )) + return sal_False; + + return pEntry && ((FmFilterData*)pEntry->GetUserData())->ISA(FmFilterItem); +} + +//------------------------------------------------------------------------ +sal_Bool FmFilterNavigator::EditedEntry( SvLBoxEntry* pEntry, const XubString& rNewText ) +{ + DBG_ASSERT(pEntry == m_pEditingCurrently, "FmFilterNavigator::EditedEntry: suspicious entry!"); + m_pEditingCurrently = NULL; + + if (EditingCanceled()) + return sal_True; + + DBG_ASSERT(((FmFilterData*)pEntry->GetUserData())->ISA(FmFilterItem), + "FmFilterNavigator::EditedEntry() wrong entry"); + + UniString aText(rNewText); + aText.EraseTrailingChars(); + aText.EraseLeadingChars(); + if (aText.Len() == 0) + { + // deleting the entry asynchron + ULONG nEvent; + PostUserEvent(nEvent, LINK(this, FmFilterNavigator, OnRemove), pEntry); + } + else + { + UniString aErrorMsg; + + if (m_pModel->ValidateText((FmFilterItem*)pEntry->GetUserData(), aText, aErrorMsg)) + { + GrabFocus(); + // this will set the text at the FmFilterItem, as well as update any filter controls + // which are connected to this particular entry + m_pModel->SetTextForItem( static_cast< FmFilterItem* >( pEntry->GetUserData() ), aText ); + + SetCursor( pEntry, sal_True ); + SetEntryText( pEntry, aText ); + } + else + { + // display the error and return sal_False + SQLContext aError; + aError.Message = String(SVX_RES(RID_STR_SYNTAXERROR)); + aError.Details = aErrorMsg; + displayException(aError, this); + + return sal_False; + } + } + return sal_True; +} + +//------------------------------------------------------------------------ +IMPL_LINK( FmFilterNavigator, OnRemove, SvLBoxEntry*, pEntry ) +{ + // now remove the entry + m_pModel->Remove((FmFilterData*) pEntry->GetUserData()); + return 0L; +} + +//------------------------------------------------------------------------ +IMPL_LINK( FmFilterNavigator, OnDropActionTimer, void*, EMPTYARG ) +{ + if (--m_aTimerCounter > 0) + return 0L; + + switch (m_aDropActionType) + { + case DA_SCROLLUP : + ScrollOutputArea(1); + m_aTimerCounter = DROP_ACTION_TIMER_SCROLL_TICKS; + break; + case DA_SCROLLDOWN : + ScrollOutputArea(-1); + m_aTimerCounter = DROP_ACTION_TIMER_SCROLL_TICKS; + break; + case DA_EXPANDNODE: + { + SvLBoxEntry* pToExpand = GetEntry(m_aTimerTriggered); + if (pToExpand && (GetChildCount(pToExpand) > 0) && !IsExpanded(pToExpand)) + // tja, eigentlich muesste ich noch testen, ob die Node nicht schon expandiert ist, aber ich + // habe dazu weder in den Basisklassen noch im Model eine Methode gefunden ... + // aber ich denke, die BK sollte es auch so vertragen + Expand(pToExpand); + + // nach dem Expand habe ich im Gegensatz zum Scrollen natuerlich nix mehr zu tun + m_aDropActionTimer.Stop(); + } + break; + } + return 0L; +} + + +//------------------------------------------------------------------------ +sal_Int8 FmFilterNavigator::AcceptDrop( const AcceptDropEvent& rEvt ) +{ + Point aDropPos = rEvt.maPosPixel; + + // kuemmern wir uns erst mal um moeglich DropActions (Scrollen und Aufklappen) + if (rEvt.mbLeaving) + { + if (m_aDropActionTimer.IsActive()) + m_aDropActionTimer.Stop(); + } + else + { + sal_Bool bNeedTrigger = sal_False; + // auf dem ersten Eintrag ? + if ((aDropPos.Y() >= 0) && (aDropPos.Y() < GetEntryHeight())) + { + m_aDropActionType = DA_SCROLLUP; + bNeedTrigger = sal_True; + } + else + { + // auf dem letzten (bzw. in dem Bereich, den ein Eintrag einnehmen wuerde, wenn er unten genau buendig + // abschliessen wuerde) ? + if ((aDropPos.Y() < GetSizePixel().Height()) && (aDropPos.Y() >= GetSizePixel().Height() - GetEntryHeight())) + { + m_aDropActionType = DA_SCROLLDOWN; + bNeedTrigger = sal_True; + } + else + { // is it an entry whith children, and not yet expanded? + SvLBoxEntry* pDropppedOn = GetEntry(aDropPos); + if (pDropppedOn && (GetChildCount(pDropppedOn) > 0) && !IsExpanded(pDropppedOn)) + { + // -> aufklappen + m_aDropActionType = DA_EXPANDNODE; + bNeedTrigger = sal_True; + } + } + } + if (bNeedTrigger && (m_aTimerTriggered != aDropPos)) + { + // neu anfangen zu zaehlen + m_aTimerCounter = DROP_ACTION_TIMER_INITIAL_TICKS; + // die Pos merken, da ich auch QueryDrops bekomme, wenn sich die Maus gar nicht bewegt hat + m_aTimerTriggered = aDropPos; + // und den Timer los + if (!m_aDropActionTimer.IsActive()) // gibt es den Timer schon ? + { + m_aDropActionTimer.SetTimeout(DROP_ACTION_TIMER_TICK_BASE); + m_aDropActionTimer.Start(); + } + } + else if (!bNeedTrigger) + m_aDropActionTimer.Stop(); + } + + + // Hat das Object das richtige Format? + if (!m_aControlExchange.isDragSource()) + return DND_ACTION_NONE; + + if (!m_aControlExchange->hasFormat(GetDataFlavorExVector())) + return DND_ACTION_NONE; + + // do we conain the formitem? + if (!FindEntry(m_aControlExchange->getFormItem())) + return DND_ACTION_NONE; + + SvLBoxEntry* pDropTarget = GetEntry(aDropPos); + if (!pDropTarget) + return DND_ACTION_NONE; + + FmFilterData* pData = (FmFilterData*)pDropTarget->GetUserData(); + FmFormItem* pForm = NULL; + if (pData->ISA(FmFilterItem)) + { + pForm = PTR_CAST(FmFormItem,pData->GetParent()->GetParent()); + if (pForm != m_aControlExchange->getFormItem()) + return DND_ACTION_NONE; + } + else if (pData->ISA(FmFilterItems)) + { + pForm = PTR_CAST(FmFormItem,pData->GetParent()); + if (pForm != m_aControlExchange->getFormItem()) + return DND_ACTION_NONE; + } + else + return DND_ACTION_NONE; + + return rEvt.mnAction; +} +// ----------------------------------------------------------------------------- +namespace +{ + FmFilterItems* getTargetItems(SvLBoxEntry* _pTarget) + { + FmFilterData* pData = static_cast<FmFilterData*>(_pTarget->GetUserData()); + FmFilterItems* pTargetItems = pData->ISA(FmFilterItems) + ? + PTR_CAST(FmFilterItems,pData) + : + PTR_CAST(FmFilterItems,pData->GetParent()); + return pTargetItems; + } +} +//------------------------------------------------------------------------ +sal_Int8 FmFilterNavigator::ExecuteDrop( const ExecuteDropEvent& rEvt ) +{ + // ware schlecht, wenn nach dem Droppen noch gescrollt wird ... + if (m_aDropActionTimer.IsActive()) + m_aDropActionTimer.Stop(); + + // Format-Ueberpruefung + if (!m_aControlExchange.isDragSource()) + return DND_ACTION_NONE; + + // das Ziel des Drop sowie einige Daten darueber + Point aDropPos = rEvt.maPosPixel; + SvLBoxEntry* pDropTarget = GetEntry( aDropPos ); + if (!pDropTarget) + return DND_ACTION_NONE; + + // search the container where to add the items + FmFilterItems* pTargetItems = getTargetItems(pDropTarget); + SelectAll(sal_False); + SvLBoxEntry* pEntry = FindEntry(pTargetItems); + Select(pEntry, sal_True); + SetCurEntry(pEntry); + + insertFilterItem(m_aControlExchange->getDraggedEntries(),pTargetItems,DND_ACTION_COPY == rEvt.mnAction); + + return sal_True; +} + +//------------------------------------------------------------------------ +void FmFilterNavigator::InitEntry(SvLBoxEntry* pEntry, + const XubString& rStr, + const Image& rImg1, + const Image& rImg2, + SvLBoxButtonKind eButtonKind) +{ + SvTreeListBox::InitEntry( pEntry, rStr, rImg1, rImg2, eButtonKind ); + SvLBoxString* pString = NULL; + + if (((FmFilterData*)pEntry->GetUserData())->ISA(FmFilterItem)) + pString = new FmFilterString(pEntry, 0, rStr, ((FmFilterItem*)pEntry->GetUserData())->GetFieldName()); + else if (((FmFilterData*)pEntry->GetUserData())->ISA(FmFilterItems)) + pString = new FmFilterItemsString(pEntry, 0, rStr ); + + if (pString) + pEntry->ReplaceItem( pString, 1 ); +} + +//------------------------------------------------------------------------ +sal_Bool FmFilterNavigator::Select( SvLBoxEntry* pEntry, sal_Bool bSelect ) +{ + if (bSelect == IsSelected(pEntry)) // das passiert manchmal, ich glaube, die Basisklasse geht zu sehr auf Nummer sicher ;) + return sal_True; + + if (SvTreeListBox::Select(pEntry, bSelect)) + { + if (bSelect) + { + FmFormItem* pFormItem = NULL; + if (((FmFilterData*)pEntry->GetUserData())->ISA(FmFilterItem)) + pFormItem = (FmFormItem*)((FmFilterItem*)pEntry->GetUserData())->GetParent()->GetParent(); + else if (((FmFilterData*)pEntry->GetUserData())->ISA(FmFilterItems)) + pFormItem = (FmFormItem*)((FmFilterItem*)pEntry->GetUserData())->GetParent()->GetParent(); + else if (((FmFilterData*)pEntry->GetUserData())->ISA(FmFormItem)) + pFormItem = (FmFormItem*)pEntry->GetUserData(); + + if (pFormItem) + { + // will the controller be exchanged? + if (((FmFilterData*)pEntry->GetUserData())->ISA(FmFilterItem)) + m_pModel->SetCurrentItems((FmFilterItems*)((FmFilterItem*)pEntry->GetUserData())->GetParent()); + else if (((FmFilterData*)pEntry->GetUserData())->ISA(FmFilterItems)) + m_pModel->SetCurrentItems((FmFilterItems*)pEntry->GetUserData()); + else if (((FmFilterData*)pEntry->GetUserData())->ISA(FmFormItem)) + m_pModel->SetCurrentController(((FmFormItem*)pEntry->GetUserData())->GetController()); + } + } + return sal_True; + } + else + return sal_False; +} + +//------------------------------------------------------------------------ +void FmFilterNavigator::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint ) +{ + if (rHint.ISA(FmFilterInsertedHint)) + { + FmFilterInsertedHint* pHint = (FmFilterInsertedHint*)&rHint; + Insert(pHint->GetData(), pHint->GetPos()); + } + else if( rHint.ISA(FilterClearingHint) ) + { + SvTreeListBox::Clear(); + } + else if( rHint.ISA(FmFilterRemovedHint) ) + { + FmFilterRemovedHint* pHint = (FmFilterRemovedHint*)&rHint; + Remove(pHint->GetData()); + } + else if( rHint.ISA(FmFilterTextChangedHint) ) + { + FmFilterTextChangedHint* pHint = (FmFilterTextChangedHint*)&rHint; + SvLBoxEntry* pEntry = FindEntry(pHint->GetData()); + if (pEntry) + SetEntryText( pEntry, pHint->GetData()->GetText()); + } + else if( rHint.ISA(FmFilterCurrentChangedHint) ) + { + // invalidate the entries + for (SvLBoxEntry* pEntry = First(); pEntry != NULL; + pEntry = Next(pEntry)) + GetModel()->InvalidateEntry( pEntry ); + } +} + +//------------------------------------------------------------------------ +SvLBoxEntry* FmFilterNavigator::FindEntry(const FmFilterData* pItem) const +{ + SvLBoxEntry* pEntry = NULL; + if (pItem) + { + for (pEntry = First(); pEntry != NULL; pEntry = Next( pEntry )) + { + FmFilterData* pEntryItem = (FmFilterData*)pEntry->GetUserData(); + if (pEntryItem == pItem) + break; + } + } + return pEntry; +} + +//------------------------------------------------------------------------ +void FmFilterNavigator::Insert(FmFilterData* pItem, sal_Int32 nPos) +{ + const FmParentData* pParent = pItem->GetParent() ? pItem->GetParent() : GetFilterModel(); + + // insert the item + SvLBoxEntry* pParentEntry = FindEntry( pParent ); + SvLBoxEntry* pNewEntry = InsertEntry(pItem->GetText(), pItem->GetImage(), pItem->GetImage(), pParentEntry, sal_False, nPos, pItem ); + if ( pNewEntry ) + { + SetExpandedEntryBmp( pNewEntry, pItem->GetImage( BMP_COLOR_HIGHCONTRAST ), BMP_COLOR_HIGHCONTRAST ); + SetCollapsedEntryBmp( pNewEntry, pItem->GetImage( BMP_COLOR_HIGHCONTRAST ), BMP_COLOR_HIGHCONTRAST ); + } + if ( pParentEntry ) + Expand( pParentEntry ); +} + +//------------------------------------------------------------------------ +void FmFilterNavigator::Remove(FmFilterData* pItem) +{ + // der Entry zu den Daten + SvLBoxEntry* pEntry = FindEntry(pItem); + + if (pEntry == m_pEditingCurrently) + // cancel editing + EndEditing(sal_True); + + if (pEntry) + GetModel()->Remove( pEntry ); +} +// ----------------------------------------------------------------------------- +FmFormItem* FmFilterNavigator::getSelectedFilterItems(::std::vector<FmFilterItem*>& _rItemList) +{ + // be sure that the data is only used within only one form! + FmFormItem* pFirstItem = NULL; + + sal_Bool bHandled = sal_True; + sal_Bool bFoundSomething = sal_False; + for (SvLBoxEntry* pEntry = FirstSelected(); + bHandled && pEntry != NULL; + pEntry = NextSelected(pEntry)) + { + FmFilterItem* pFilter = PTR_CAST(FmFilterItem, (FmFilterData*)pEntry->GetUserData()); + if (pFilter) + { + FmFormItem* pForm = PTR_CAST(FmFormItem,pFilter->GetParent()->GetParent()); + if (!pForm) + bHandled = sal_False; + else if (!pFirstItem) + pFirstItem = pForm; + else if (pFirstItem != pForm) + bHandled = sal_False; + + if (bHandled) + { + _rItemList.push_back(pFilter); + bFoundSomething = sal_True; + } + } + } + if ( !bHandled || !bFoundSomething ) + pFirstItem = NULL; + return pFirstItem; +} +// ----------------------------------------------------------------------------- +void FmFilterNavigator::insertFilterItem(const ::std::vector<FmFilterItem*>& _rFilterList,FmFilterItems* _pTargetItems,sal_Bool _bCopy) +{ + ::std::vector<FmFilterItem*>::const_iterator aEnd = _rFilterList.end(); + for ( ::std::vector< FmFilterItem* >::const_iterator i = _rFilterList.begin(); + i != aEnd; + ++i + ) + { + FmFilterItem* pLookupItem( *i ); + if ( pLookupItem->GetParent() == _pTargetItems ) + continue; + + FmFilterItem* pFilterItem = _pTargetItems->Find( pLookupItem->GetComponentIndex() ); + String aText = pLookupItem->GetText(); + if ( !pFilterItem ) + { + pFilterItem = new FmFilterItem( m_pModel->getORB(), _pTargetItems, pLookupItem->GetFieldName(), aText, pLookupItem->GetComponentIndex() ); + m_pModel->Append( _pTargetItems, pFilterItem ); + } + + if ( !_bCopy ) + m_pModel->Remove( pLookupItem ); + + // now set the text for the new dragged item + m_pModel->SetTextForItem( pFilterItem, aText ); + } + + m_pModel->EnsureEmptyFilterRows( *_pTargetItems->GetParent() ); +} + +//------------------------------------------------------------------------------ +void FmFilterNavigator::StartDrag( sal_Int8 /*_nAction*/, const Point& /*_rPosPixel*/ ) +{ + EndSelection(); + + // be sure that the data is only used within a only one form! + m_aControlExchange.prepareDrag(); + + ::std::vector<FmFilterItem*> aItemList; + if ( FmFormItem* pFirstItem = getSelectedFilterItems(aItemList) ) + { + m_aControlExchange->setDraggedEntries(aItemList); + m_aControlExchange->setFormItem(pFirstItem); + m_aControlExchange.startDrag( DND_ACTION_COPYMOVE ); + } +} + +//------------------------------------------------------------------------------ +void FmFilterNavigator::Command( const CommandEvent& rEvt ) +{ + sal_Bool bHandled = sal_False; + switch (rEvt.GetCommand()) + { + case COMMAND_CONTEXTMENU: + { + // die Stelle, an der geklickt wurde + Point aWhere; + SvLBoxEntry* pClicked = NULL; + if (rEvt.IsMouseEvent()) + { + aWhere = rEvt.GetMousePosPixel(); + pClicked = GetEntry(aWhere); + if (pClicked == NULL) + break; + + if (!IsSelected(pClicked)) + { + SelectAll(sal_False); + Select(pClicked, sal_True); + SetCurEntry(pClicked); + } + } + else + { + pClicked = GetCurEntry(); + if (!pClicked) + break; + aWhere = GetEntryPosition( pClicked ); + } + + ::std::vector<FmFilterData*> aSelectList; + for (SvLBoxEntry* pEntry = FirstSelected(); + pEntry != NULL; + pEntry = NextSelected(pEntry)) + { + // don't delete forms + FmFormItem* pForm = PTR_CAST(FmFormItem, (FmFilterData*)pEntry->GetUserData()); + if (!pForm) + aSelectList.push_back((FmFilterData*)pEntry->GetUserData()); + } + if (aSelectList.size() == 1) + { + // don't delete the only empty row of a form + FmFilterItems* pFilterItems = PTR_CAST(FmFilterItems, aSelectList[0]); + if (pFilterItems && pFilterItems->GetChildren().empty() + && pFilterItems->GetParent()->GetChildren().size() == 1) + aSelectList.clear(); + } + + PopupMenu aContextMenu(SVX_RES(RID_FM_FILTER_MENU)); + + // every condition could be deleted except the first one if its the only one + aContextMenu.EnableItem( SID_FM_DELETE, !aSelectList.empty() ); + + // + sal_Bool bEdit = PTR_CAST(FmFilterItem, (FmFilterData*)pClicked->GetUserData()) != NULL && + IsSelected(pClicked) && GetSelectionCount() == 1; + + aContextMenu.EnableItem( SID_FM_FILTER_EDIT, + bEdit ); + aContextMenu.EnableItem( SID_FM_FILTER_IS_NULL, + bEdit ); + aContextMenu.EnableItem( SID_FM_FILTER_IS_NOT_NULL, + bEdit ); + + aContextMenu.RemoveDisabledEntries(sal_True, sal_True); + sal_uInt16 nSlotId = aContextMenu.Execute( this, aWhere ); + switch( nSlotId ) + { + case SID_FM_FILTER_EDIT: + { + EditEntry( pClicked ); + } break; + case SID_FM_FILTER_IS_NULL: + case SID_FM_FILTER_IS_NOT_NULL: + { + UniString aErrorMsg; + UniString aText; + if (nSlotId == SID_FM_FILTER_IS_NULL) + aText.AssignAscii("IS NULL"); + else + aText.AssignAscii("IS NOT NULL"); + + m_pModel->ValidateText((FmFilterItem*)pClicked->GetUserData(), + aText, aErrorMsg); + m_pModel->SetTextForItem((FmFilterItem*)pClicked->GetUserData(), aText); + } break; + case SID_FM_DELETE: + { + DeleteSelection(); + } break; + } + bHandled = sal_True; + } break; + } + + if (!bHandled) + SvTreeListBox::Command( rEvt ); +} +// ----------------------------------------------------------------------------- +SvLBoxEntry* FmFilterNavigator::getNextEntry(SvLBoxEntry* _pStartWith) +{ + SvLBoxEntry* pEntry = _pStartWith ? _pStartWith : LastSelected(); + pEntry = Next(pEntry); + // we need the next filter entry + while( pEntry && GetChildCount( pEntry ) == 0 && pEntry != Last() ) + pEntry = Next(pEntry); + return pEntry; +} +// ----------------------------------------------------------------------------- +SvLBoxEntry* FmFilterNavigator::getPrevEntry(SvLBoxEntry* _pStartWith) +{ + SvLBoxEntry* pEntry = _pStartWith ? _pStartWith : FirstSelected(); + pEntry = Prev(pEntry); + // check if the previous entry is a filter, if so get the next prev + if ( pEntry && GetChildCount( pEntry ) != 0 ) + { + pEntry = Prev(pEntry); + // if the entry is still no leaf return + if ( pEntry && GetChildCount( pEntry ) != 0 ) + pEntry = NULL; + } + return pEntry; +} +//------------------------------------------------------------------------ +void FmFilterNavigator::KeyInput(const KeyEvent& rKEvt) +{ + const KeyCode& rKeyCode = rKEvt.GetKeyCode(); + + switch ( rKeyCode.GetCode() ) + { + case KEY_UP: + case KEY_DOWN: + { + if ( !rKeyCode.IsMod1() || !rKeyCode.IsMod2() || rKeyCode.IsShift() ) + break; + + ::std::vector<FmFilterItem*> aItemList; + if ( !getSelectedFilterItems( aItemList ) ) + break; + + ::std::mem_fun1_t<SvLBoxEntry*,FmFilterNavigator,SvLBoxEntry*> getter = ::std::mem_fun(&FmFilterNavigator::getNextEntry); + if ( rKeyCode.GetCode() == KEY_UP ) + getter = ::std::mem_fun(&FmFilterNavigator::getPrevEntry); + + SvLBoxEntry* pTarget = getter( this, NULL ); + if ( !pTarget ) + break; + + FmFilterItems* pTargetItems = getTargetItems( pTarget ); + if ( !pTargetItems ) + break; + + ::std::vector<FmFilterItem*>::const_iterator aEnd = aItemList.end(); + sal_Bool bNextTargetItem = sal_True; + while ( bNextTargetItem ) + { + ::std::vector<FmFilterItem*>::const_iterator i = aItemList.begin(); + for (; i != aEnd; ++i) + { + if ( (*i)->GetParent() == pTargetItems ) + { + pTarget = getter(this,pTarget); + if ( !pTarget ) + return; + pTargetItems = getTargetItems( pTarget ); + break; + } + else + { + FmFilterItem* pFilterItem = pTargetItems->Find( (*i)->GetComponentIndex() ); + // we found the text component so jump above + if ( pFilterItem ) + { + pTarget = getter( this, pTarget ); + if ( !pTarget ) + return; + + pTargetItems = getTargetItems( pTarget ); + break; + } + } + } + bNextTargetItem = i != aEnd && pTargetItems; + } + + if ( pTargetItems ) + { + insertFilterItem( aItemList, pTargetItems ); + return; + } + } + break; + + case KEY_DELETE: + { + if ( rKeyCode.GetModifier() ) + break; + + if ( !IsSelected( First() ) || GetEntryCount() > 1 ) + DeleteSelection(); + return; + } + } + + SvTreeListBox::KeyInput(rKEvt); +} + +//------------------------------------------------------------------------------ +void FmFilterNavigator::DeleteSelection() +{ + // to avoid the deletion of an entry twice (e.g. deletion of a parent and afterward + // the deletion of it's child, i have to shrink the selecton list + ::std::vector<SvLBoxEntry*> aEntryList; + for (SvLBoxEntry* pEntry = FirstSelected(); + pEntry != NULL; + pEntry = NextSelected(pEntry)) + { + FmFilterItem* pFilterItem = PTR_CAST(FmFilterItem, (FmFilterData*)pEntry->GetUserData()); + if (pFilterItem && IsSelected(GetParent(pEntry))) + continue; + + FmFormItem* pForm = PTR_CAST(FmFormItem, (FmFilterData*)pEntry->GetUserData()); + if (!pForm) + aEntryList.push_back(pEntry); + } + + // Remove the selection + SelectAll(FALSE); + + for (::std::vector<SvLBoxEntry*>::reverse_iterator i = aEntryList.rbegin(); + // link problems with operator == + i.base() != aEntryList.rend().base(); i++) + { + m_pModel->Remove((FmFilterData*)(*i)->GetUserData()); + } +} +// ----------------------------------------------------------------------------- + +//======================================================================== +// class FmFilterNavigatorWin +//======================================================================== +FmFilterNavigatorWin::FmFilterNavigatorWin( SfxBindings* _pBindings, SfxChildWindow* _pMgr, + Window* _pParent ) + :SfxDockingWindow( _pBindings, _pMgr, _pParent, WinBits(WB_STDMODELESS|WB_SIZEABLE|WB_ROLLABLE|WB_3DLOOK|WB_DOCKABLE) ) + ,SfxControllerItem( SID_FM_FILTER_NAVIGATOR_CONTROL, *_pBindings ) +{ + SetHelpId( HID_FILTER_NAVIGATOR_WIN ); + + m_pNavigator = new FmFilterNavigator( this ); + m_pNavigator->Show(); + SetText( SVX_RES(RID_STR_FILTER_NAVIGATOR) ); + SfxDockingWindow::SetFloatingSize( Size(200,200) ); +} + +//------------------------------------------------------------------------ +FmFilterNavigatorWin::~FmFilterNavigatorWin() +{ + delete m_pNavigator; +} + +//----------------------------------------------------------------------- +void FmFilterNavigatorWin::UpdateContent(FmFormShell* pFormShell) +{ + if (!pFormShell) + m_pNavigator->UpdateContent( NULL, NULL ); + else + { + Reference< XFormController > xController(pFormShell->GetImpl()->getActiveInternalController()); + Reference< XIndexAccess > xContainer; + if (xController.is()) + { + Reference< XChild > xChild(xController, UNO_QUERY); + for (Reference< XInterface > xParent(xChild->getParent()); + xParent.is(); + xParent = xChild.is() ? xChild->getParent() : Reference< XInterface > ()) + { + xContainer = Reference< XIndexAccess > (xParent, UNO_QUERY); + xChild = Reference< XChild > (xParent, UNO_QUERY); + } + } + m_pNavigator->UpdateContent(xContainer, xController); + } +} + +//----------------------------------------------------------------------- +void FmFilterNavigatorWin::StateChanged( sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState ) +{ + if( !pState || SID_FM_FILTER_NAVIGATOR_CONTROL != nSID ) + return; + + if( eState >= SFX_ITEM_AVAILABLE ) + { + FmFormShell* pShell = PTR_CAST( FmFormShell,((SfxObjectItem*)pState)->GetShell() ); + UpdateContent( pShell ); + } + else + UpdateContent( NULL ); +} + +//----------------------------------------------------------------------- +sal_Bool FmFilterNavigatorWin::Close() +{ + if ( m_pNavigator && m_pNavigator->IsEditingActive() ) + m_pNavigator->EndEditing(); + + if ( m_pNavigator && m_pNavigator->IsEditingActive() ) + // the EndEditing was vetoed (perhaps of an syntax error or such) + return sal_False; + + UpdateContent( NULL ); + return SfxDockingWindow::Close(); +} + +//----------------------------------------------------------------------- +void FmFilterNavigatorWin::FillInfo( SfxChildWinInfo& rInfo ) const +{ + SfxDockingWindow::FillInfo( rInfo ); + rInfo.bVisible = sal_False; +} + +//----------------------------------------------------------------------- +Size FmFilterNavigatorWin::CalcDockingSize( SfxChildAlignment eAlign ) +{ + if ( ( eAlign == SFX_ALIGN_TOP ) || ( eAlign == SFX_ALIGN_BOTTOM ) ) + return Size(); + + return SfxDockingWindow::CalcDockingSize( eAlign ); +} + +//----------------------------------------------------------------------- +SfxChildAlignment FmFilterNavigatorWin::CheckAlignment( SfxChildAlignment eActAlign, SfxChildAlignment eAlign ) +{ + switch (eAlign) + { + case SFX_ALIGN_LEFT: + case SFX_ALIGN_RIGHT: + case SFX_ALIGN_NOALIGNMENT: + return (eAlign); + default: + break; + } + + return (eActAlign); +} + +//------------------------------------------------------------------------ +void FmFilterNavigatorWin::Resize() +{ + SfxDockingWindow::Resize(); + + Size aLogOutputSize = PixelToLogic( GetOutputSizePixel(), MAP_APPFONT ); + Size aLogExplSize = aLogOutputSize; + aLogExplSize.Width() -= 6; + aLogExplSize.Height() -= 6; + + Point aExplPos = LogicToPixel( Point(3,3), MAP_APPFONT ); + Size aExplSize = LogicToPixel( aLogExplSize, MAP_APPFONT ); + + m_pNavigator->SetPosSizePixel( aExplPos, aExplSize ); +} +// ----------------------------------------------------------------------------- +void FmFilterNavigatorWin::GetFocus() +{ + // oj #97405# + if ( m_pNavigator ) + m_pNavigator->GrabFocus(); +} +// ----------------------------------------------------------------------------- + + +//======================================================================== +// class FmFilterNavigatorWinMgr +//======================================================================== +SFX_IMPL_DOCKINGWINDOW( FmFilterNavigatorWinMgr, SID_FM_FILTER_NAVIGATOR ) + +//----------------------------------------------------------------------- +FmFilterNavigatorWinMgr::FmFilterNavigatorWinMgr( Window *_pParent, sal_uInt16 _nId, + SfxBindings *_pBindings, SfxChildWinInfo* _pInfo ) + :SfxChildWindow( _pParent, _nId ) +{ + pWindow = new FmFilterNavigatorWin( _pBindings, this, _pParent ); + eChildAlignment = SFX_ALIGN_NOALIGNMENT; + ((SfxDockingWindow*)pWindow)->Initialize( _pInfo ); +} + +//........................................................................ +} // namespace svxform +//........................................................................ |