/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the 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 "svx/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
		sal_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(sal_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
//........................................................................