/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * 
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: filtnav.cxx,v $
 * $Revision: 1.48.216.1 $
 *
 * 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"
#ifndef _SVX_FMRESIDS_HRC
#include "fmresids.hrc"
#endif
#include "fmctrler.hxx"
#include "filtnav.hxx"
#include <com/sun/star/util/XNumberFormatter.hpp>
#include <com/sun/star/form/XFormController.hpp>
#include <fmexch.hxx>
#include "fmitems.hxx"

#ifndef _SVX_SVXIDS_HRC
#include <svx/svxids.hrc>
#endif

#ifndef _SVX_FMPROP_HRC
#include "fmprop.hrc"
#endif

#ifndef _SVX_FMHELP_HRC
#include "fmhelp.hrc"
#endif
#include <svx/dialmgr.hxx>
#include <sfx2/dispatch.hxx>
#include <sfx2/objsh.hxx>
#include <sfx2/objitem.hxx>
#include <sfx2/request.hxx>
#include <tools/shl.hxx>

#ifndef _WRKWIN_HXX //autogen
#include <vcl/wrkwin.hxx>
#endif
#include <svx/fmshell.hxx>
#include <fmshimp.hxx>
#include <fmservs.hxx>
#include <fmtools.hxx>
#include <cppuhelper/implbase1.hxx>
#include <comphelper/property.hxx>
#include <comphelper/uno3.hxx>
#include <connectivity/dbtools.hxx>
#include <comphelper/processfactory.hxx>
#include <com/sun/star/lang/XUnoTunnel.hpp>
#include <comphelper/sequence.hxx>
#include "gridcell.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 ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::sdbc;
using namespace ::com::sun::star::sdb;
using namespace ::com::sun::star::beans;
using namespace ::svxform;
using namespace ::connectivity::simple;
using namespace ::connectivity;


//........................................................................
namespace svxform
{
//........................................................................

//========================================================================
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_aChilds.begin();
		 i != m_aChilds.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 Reference< ::com::sun::star::awt::XTextComponent > & _xText) const
{
	for (::std::vector<FmFilterData*>::const_iterator i = m_aChilds.begin();
		 i != m_aChilds.end(); ++i)
	{
		FmFilterItem* pCond = PTR_CAST(FmFilterItem, *i);
		DBG_ASSERT(pCond, "Wrong element in container");
		if (_xText == pCond->GetTextComponent())
			return pCond;
	}
	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< ::com::sun::star::lang::XMultiServiceFactory >& _rxFactory,
						   FmFilterItems* pParent,
					 const ::rtl::OUString& aFieldName,
					 const ::rtl::OUString& aText,
					 const Reference< ::com::sun::star::awt::XTextComponent > & _xText)
		  :FmFilterData(_rxFactory,pParent, aText)
		  ,m_aFieldName(aFieldName)
		  ,m_xText(_xText)
{
}

//------------------------------------------------------------------------
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 FmFilterReplacedHint : public FmFilterHint
{
public:
	TYPEINFO();
	FmFilterReplacedHint(FmFilterData* pData)
		:FmFilterHint(pData){}

};
TYPEINIT1( FmFilterReplacedHint, 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< ::com::sun::star::awt::XTextListener >
{
	FmFilterControls		m_aFilterControls;
	FmFilterModel*			m_pModel;

public:
	FmFilterAdapter(FmFilterModel* pModel, const Reference< ::com::sun::star::container::XIndexAccess >& xControllers);

// ::com::sun::star::lang::XEventListener
	virtual void SAL_CALL disposing(const ::com::sun::star::lang::EventObject& Source) throw( RuntimeException );

// ::com::sun::star::awt::XTextListener
	virtual void SAL_CALL textChanged(const ::com::sun::star::awt::TextEvent& e) throw( ::com::sun::star::uno::RuntimeException );

// helpers
	void dispose() throw( RuntimeException );

	void InsertElements(const Reference< ::com::sun::star::container::XIndexAccess >& xControllers);
	void RemoveElement(const Reference< ::com::sun::star::awt::XTextComponent > & xText);

	Reference< ::com::sun::star::beans::XPropertySet > getField(const Reference< ::com::sun::star::awt::XTextComponent > & xText) const;
	void setText(sal_Int32 nPos,
		const FmFilterItem* pFilterItem,
		const ::rtl::OUString& rText);
	void DeleteItemsByText(::std::vector<FmFilterData*>& rItems, const Reference< ::com::sun::star::awt::XTextComponent > & xText);
	Reference< ::com::sun::star::form::XForm > findForm(const Reference< ::com::sun::star::container::XChild >& xChild);
};

//------------------------------------------------------------------------
FmFilterAdapter::FmFilterAdapter(FmFilterModel* pModel, const Reference< ::com::sun::star::container::XIndexAccess >& xControllers)
				 :m_pModel(pModel)
{
	InsertElements(xControllers);

	// listen on all controls as text listener
	for (FmFilterControls::const_iterator iter = m_aFilterControls.begin();
		iter != m_aFilterControls.end(); iter++)
		(*iter).first->addTextListener(this);
}

//------------------------------------------------------------------------
void FmFilterAdapter::dispose() throw( RuntimeException )
{
	// clear the filter control map
	for (FmFilterControls::const_iterator iter = m_aFilterControls.begin();
		 iter != m_aFilterControls.end(); iter++)
		 (*iter).first->removeTextListener(this);

	m_aFilterControls.clear();
}

//------------------------------------------------------------------------------
// delete all items relate to the control
void FmFilterAdapter::DeleteItemsByText(::std::vector<FmFilterData*>& _rItems,
										const Reference< ::com::sun::star::awt::XTextComponent > & xText)
{
	for (::std::vector<FmFilterData*>::reverse_iterator i = _rItems.rbegin();
		// link problems with operator ==
		i.base() != _rItems.rend().base(); i++)
	{
		FmFilterItems* pFilterItems = PTR_CAST(FmFilterItems, *i);
		if (pFilterItems)
		{
			FmFilterItem* pFilterItem = pFilterItems->Find(xText);
			if (pFilterItem)
			{
				// remove the condition
				::std::vector<FmFilterData*>& rItems = pFilterItems->GetChilds();
				::std::vector<FmFilterData*>::iterator j = ::std::find(rItems.begin(), rItems.end(), pFilterItem);
				if (j != rItems.end())
					m_pModel->Remove(j, pFilterItem);
			}
			continue;
		}
		FmFormItem* pFormItem = PTR_CAST(FmFormItem, *i);
		if (pFormItem)
			DeleteItemsByText(pFormItem->GetChilds(), xText);
	}
}

//------------------------------------------------------------------------
void FmFilterAdapter::InsertElements(const Reference< ::com::sun::star::container::XIndexAccess >& xControllers)
{
	for (sal_Int32 i = 0, nLen = xControllers->getCount(); i < nLen; ++i)
	{
		Reference< ::com::sun::star::container::XIndexAccess > xElement;
		xControllers->getByIndex(i) >>= xElement;

		// Insert the Elements of the controller
		InsertElements(xElement);

		// store the filter controls
		FmXFormController* pController = FmXFormController::getImplementation( xElement.get() );
        DBG_ASSERT( pController, "FmFilterAdapter::InsertElements: no controller!" );

		const FmFilterControls& rControls = pController->getFilterControls();
		for (FmFilterControls::const_iterator iter = rControls.begin(); iter != rControls.end(); ++iter )
			m_aFilterControls.insert(*iter);
	}
}

//------------------------------------------------------------------------------
void FmFilterAdapter::RemoveElement(const Reference< ::com::sun::star::awt::XTextComponent > & xText)
{
	if (xText.is())
	{
		// alle Level durchlaufen und eintraege entfernen
		if (m_pModel)
			DeleteItemsByText(m_pModel->GetChilds(), xText);

		FmFilterControls::iterator iter = m_aFilterControls.find(xText);
		if (iter != m_aFilterControls.end())
			m_aFilterControls.erase(iter);
	}
}

//------------------------------------------------------------------------
Reference< ::com::sun::star::beans::XPropertySet >	FmFilterAdapter::getField(const Reference< ::com::sun::star::awt::XTextComponent > & xText) const
{
	Reference< ::com::sun::star::beans::XPropertySet >	xField;
	FmFilterControls::const_iterator i = m_aFilterControls.find(xText);
	if (i != m_aFilterControls.end())
		xField = (*i).second;

	return xField;
}

//------------------------------------------------------------------------
void FmFilterAdapter::setText(sal_Int32 nRowPos,
							  const FmFilterItem* pFilterItem,
							  const ::rtl::OUString& rText)
{
	// set the text for the text component
	Reference< ::com::sun::star::awt::XTextComponent > xText(pFilterItem->GetTextComponent());
	xText->setText(rText);

	// get the controller of the text component and its filter rows
	FmFormItem* pFormItem = PTR_CAST(FmFormItem,pFilterItem->GetParent()->GetParent());
	FmXFormController* pController = FmXFormController::getImplementation( pFormItem->GetController().get() );
    DBG_ASSERT( pController, "FmFilterAdapter::setText: no controller!" );
	FmFilterRows& rRows = pController->getFilterRows();

	DBG_ASSERT(nRowPos < (sal_Int32)rRows.size(), "wrong row pos");
	// Suchen der aktuellen Row
	FmFilterRow& rRow = rRows[nRowPos];

	// do we have a new filter
	if (rText.getLength())
		rRow[xText] = rText;
	else
	{
		// do we have the control in the row
		FmFilterRow::iterator iter = rRow.find(xText);
		// erase the entry out of the row
		if (iter != rRow.end())
			rRow.erase(iter);
	}
}


// ::com::sun::star::lang::XEventListener
//------------------------------------------------------------------------
void SAL_CALL FmFilterAdapter::disposing(const ::com::sun::star::lang::EventObject& e) throw( RuntimeException )
{
	Reference< ::com::sun::star::awt::XTextComponent >	xText(e.Source,UNO_QUERY);
	if (xText.is())
		RemoveElement(xText);
}

// XTextListener
//------------------------------------------------------------------------
Reference< ::com::sun::star::form::XForm > FmFilterAdapter::findForm(const Reference< ::com::sun::star::container::XChild >& xChild)
{
	Reference< ::com::sun::star::form::XForm > xForm;
	if (xChild.is())
	{
		xForm = Reference< ::com::sun::star::form::XForm >(xChild->getParent(), UNO_QUERY);
		if (!xForm.is())
			xForm = findForm(Reference< ::com::sun::star::container::XChild >(xChild->getParent(), UNO_QUERY));
	}
	return xForm;
}

// XTextListener
//------------------------------------------------------------------------
void FmFilterAdapter::textChanged(const ::com::sun::star::awt::TextEvent& e) throw( ::com::sun::star::uno::RuntimeException )
{
	// Find the according formitem in the
	Reference< ::com::sun::star::awt::XControl > xControl(e.Source, UNO_QUERY);
	if (!m_pModel || !xControl.is())
		return;

	Reference< ::com::sun::star::form::XForm > xForm(findForm(Reference< ::com::sun::star::container::XChild >(xControl->getModel(), UNO_QUERY)));
	if (!xForm.is())
		return;

	FmFormItem* pFormItem = m_pModel->Find(m_pModel->m_aChilds, xForm);
	if (pFormItem)
	{
		Reference< ::com::sun::star::awt::XTextComponent > xText(e.Source, UNO_QUERY);
		FmFilterItems* pFilter = PTR_CAST(FmFilterItems, pFormItem->GetChilds()[pFormItem->GetCurrentPosition()]);
		FmFilterItem* pFilterItem = pFilter->Find(xText);
		if (pFilterItem)
		{
			if (xText->getText().getLength())
			{
				pFilterItem->SetText(xText->getText());
				// 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 = getLabelName(Reference< ::com::sun::star::beans::XPropertySet > (Reference< ::com::sun::star::awt::XControl > (xText, UNO_QUERY)->getModel(),UNO_QUERY));

			pFilterItem = new FmFilterItem(m_pModel->getORB(),pFilter, aFieldName, xText->getText(), xText);
			m_pModel->Insert(pFilter->GetChilds().end(), pFilterItem);
		}
		m_pModel->CheckIntegrity(pFormItem);
	}
}

//========================================================================
// class FmFilterModel
//========================================================================
TYPEINIT1(FmFilterModel, FmParentData);
//------------------------------------------------------------------------
FmFilterModel::FmFilterModel(const Reference< ::com::sun::star::lang::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_aChilds.begin();
		 i != m_aChilds.end(); i++)
		delete (*i);

	m_aChilds.clear();
}

//------------------------------------------------------------------------
void FmFilterModel::Update(const Reference< ::com::sun::star::container::XIndexAccess > & xControllers, const Reference< ::com::sun::star::form::XFormController > & xCurrent)
{
	if ((::com::sun::star::form::XFormController*) xCurrent.get() == (::com::sun::star::form::XFormController*) m_xController.get())
		return;

	if (!xControllers.is())
	{
		Clear();
		return;
	}

	// there is only a new current controller
	if ((::com::sun::star::container::XIndexAccess*)m_xControllers.get() != (::com::sun::star::container::XIndexAccess*)xControllers.get())
	{
		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);
		CheckIntegrity(this);
	}
	else
		SetCurrentController(xCurrent);
}

//------------------------------------------------------------------------
void FmFilterModel::Update(const Reference< ::com::sun::star::container::XIndexAccess > & xControllers, FmParentData* pParent)
{
	sal_Int32 nCount = xControllers->getCount();
	for (sal_Int32 i = 0; i < nCount; i++)
	{
		Reference< ::com::sun::star::form::XFormController >  xController;
		xControllers->getByIndex(i) >>= xController;
		Reference< ::com::sun::star::beans::XPropertySet >	xModelAsSet(xController->getModel(), UNO_QUERY);
		::rtl::OUString aName = ::comphelper::getString(xModelAsSet->getPropertyValue(FM_PROP_NAME));

		// Insert a new ::com::sun::star::form
		FmFormItem* pFormItem = new FmFormItem(m_xORB,pParent, xController, aName);
		Insert(pParent->GetChilds().end(), pFormItem);

		// And now insert the filters for the form
	    FmXFormController* pController = FmXFormController::getImplementation( pFormItem->GetController().get() );
        DBG_ASSERT( pController, "FmFilterAdapter::Update: no controller!" );

		INT32 nPos = pController->getCurrentFilterPosition();
		pFormItem->SetCurrentPosition(nPos);

		String aTitle(SVX_RES(RID_STR_FILTER_FILTER_FOR));
		const FmFilterRows& rRows = pController->getFilterRows();
		for (FmFilterRows::const_iterator iter = rRows.begin(); iter != rRows.end(); ++iter)
		{
			const FmFilterRow& rRow = *iter;
			// now add the filter rows
			// One Row always exists

			FmFilterItems* pFilterItems = new FmFilterItems(m_xORB,pFormItem, aTitle);
			Insert(pFormItem->GetChilds().end(), pFilterItems);
			for (FmFilterRow::const_iterator iter1 = rRow.begin(); iter1 != rRow.end(); ++iter1)
			{
				// insert new and conditons
				::rtl::OUString aFieldName = getLabelName(Reference< ::com::sun::star::beans::XPropertySet > (Reference< ::com::sun::star::awt::XControl > ((*iter1).first, UNO_QUERY)->getModel(),UNO_QUERY));
				FmFilterItem* pANDCondition = new FmFilterItem(m_xORB,pFilterItems, aFieldName, (*iter1).second, (*iter1).first);
				Insert(pFilterItems->GetChilds().end(), pANDCondition);
			}
			// title for the next conditions
			aTitle = SVX_RES(RID_STR_FILTER_FILTER_OR);
		}

		// now add dependent controllers
		Reference< ::com::sun::star::container::XIndexAccess >	xControllerAsIndex(xController, UNO_QUERY);
		Update(xControllerAsIndex, pFormItem);
	}
}

//------------------------------------------------------------------------
FmFormItem* FmFilterModel::Find(const ::std::vector<FmFilterData*>& rItems, const Reference< ::com::sun::star::form::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 ((::com::sun::star::form::XFormController*)xController.get() == (::com::sun::star::form::XFormController*)pForm->GetController().get())
				return pForm;
			else
			{
				pForm = Find(pForm->GetChilds(), xController);
				if (pForm)
					return pForm;
			}
		}
	}
	return NULL;
}

//------------------------------------------------------------------------
FmFormItem* FmFilterModel::Find(const ::std::vector<FmFilterData*>& rItems, const Reference< ::com::sun::star::form::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->GetChilds(), xForm);
				if (pForm)
					return pForm;
			}
		}
	}
	return NULL;
}

//------------------------------------------------------------------------
void FmFilterModel::SetCurrentController(const Reference< ::com::sun::star::form::XFormController > & xCurrent)
{
	if ((::com::sun::star::form::XFormController*) xCurrent.get() == (::com::sun::star::form::XFormController*) m_xController.get())
		return;

	m_xController = xCurrent;

	FmFormItem* pItem = Find(m_aChilds, xCurrent);
	if (pItem)
	{
		if ( (USHORT)pItem->GetChilds().size() > pItem->GetCurrentPosition() )
			SetCurrentItems( static_cast< FmFilterItems* >( pItem->GetChilds()[ pItem->GetCurrentPosition() ] ) );
	}
}

//------------------------------------------------------------------------
void FmFilterModel::AppendFilterItems(FmFormItem* pFormItem)
{
	DBG_ASSERT(pFormItem, "AppendFilterItems(): no form item present");

	FmFilterItems* pFilterItems = new FmFilterItems(m_xORB,pFormItem, ::rtl::OUString(String(SVX_RES(RID_STR_FILTER_FILTER_OR))));
	// insert the condition behind the last filter items
	::std::vector<FmFilterData*>::reverse_iterator iter;
	for (iter = pFormItem->GetChilds().rbegin();
		// link problems with operator ==
		iter.base() != pFormItem->GetChilds().rend().base(); iter++)
	{
		if ((*iter)->ISA(FmFilterItems))
			break;
	}
	sal_Int32 nInsertPos = iter.base() - pFormItem->GetChilds().rend().base();
	::std::vector<FmFilterData*>::iterator i = pFormItem->GetChilds().begin() + nInsertPos;

	Insert(i, pFilterItems);

	// do we need a new row
	FmXFormController* pController = FmXFormController::getImplementation( pFormItem->GetController().get() );
    DBG_ASSERT( pController, "FmFilterAdapter::AppendFilterItems: no controller!" );
	FmFilterRows& rRows = pController->getFilterRows();

	// determine the filter position
	if (nInsertPos >= (sal_Int32)rRows.size())
		rRows.push_back(FmFilterRow());
}

//------------------------------------------------------------------------
void FmFilterModel::Insert(const ::std::vector<FmFilterData*>::iterator& rPos, FmFilterData* pData)
{
	::std::vector<FmFilterData*>& rItems = pData->GetParent()->GetChilds();
	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->GetChilds();

	// 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;
	    FmXFormController* pController = FmXFormController::getImplementation( pFormItem->GetController().get() );
        DBG_ASSERT( pController, "FmFilterAdapter::Remove: no controller!" );
		FmFilterRows& rRows = pController->getFilterRows();

		// how many entries do we have
		// it's the last row than we just empty it
		if (nPos == (sal_Int32)(rRows.size() - 1))
		{
			// remove all childs and stay current
			::std::vector<FmFilterData*>& rChilds = ((FmFilterItems*)pData)->GetChilds();
			while (!rChilds.empty())
			{
				::std::vector<FmFilterData*>::iterator j = rChilds.end();
				j--;

				// we stay on the level so delete each item explizit to clean the controls
				sal_Int32 nParentPos = j - rChilds.begin();
				// EmptyText removes the filter
				FmFilterItem* pFilterItem = PTR_CAST(FmFilterItem, *j);
				m_pAdapter->setText(nParentPos, pFilterItem, ::rtl::OUString());
				Remove(j, pFilterItem);
			}
		}
		else // delete the row
		{
			// if the row is on the current position we have to away from that position.
			// than we can delete it
			if (nPos == pFormItem->GetCurrentPosition())
			{
				::std::vector<FmFilterData*>::iterator j = i;

				// give a new current postion
				if (nPos < (sal_Int32)(rRows.size() - 1))
					// set it to the next row
					++j;
				else
					// set it to the previous row
					--j;

				// if necessary we have the formItem for the current controller
				// than we have to adjust the data displayed in the form
				pFormItem->SetCurrentPosition(j - rItems.begin());
				pController->setCurrentFilterPosition(j - rItems.begin());

				// Keep the view consistent and force and new painting
				FmFilterTextChangedHint aChangeHint(*j);
				Broadcast( aChangeHint );
			}

			// now delete the entry
			// before deleting we have to shift the current position of the form if necessary
			if (nPos < pFormItem->GetCurrentPosition())
			{
				pFormItem->SetCurrentPosition(pFormItem->GetCurrentPosition() - 1);
				pController->decrementCurrentFilterPosition();

				// is it the first row, than the nex row has to recieve a different name
				if (nPos == 0)
				{
					// ensure that the text labels are consistent
					rItems[1]->SetText(String(SVX_RES(RID_STR_FILTER_FILTER_FOR)));
					FmFilterTextChangedHint aChangeHint(rItems[1]);
					Broadcast( aChangeHint );
				}
			}

			// delete it
			rRows.erase(rRows.begin() + nPos);

			// and keep the controller consistent
			DBG_ASSERT(rRows.size() != 0, "wrong row size");

			// and remove it from the model
			Remove(i, pData);
		}
	}
	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()->GetChilds();
			::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, pData);
		}
	}
}

//------------------------------------------------------------------------
void FmFilterModel::Remove(const ::std::vector<FmFilterData*>::iterator& rPos, FmFilterData* pData)
{
	::std::vector<FmFilterData*>& rItems = pData->GetParent()->GetChilds();
	rItems.erase(rPos);

	// UI benachrichtigen
	FmFilterRemovedHint aRemoveHint( pData );
	Broadcast( aRemoveHint );

	delete pData;
}

//------------------------------------------------------------------------
sal_Bool FmFilterModel::ValidateText(FmFilterItem* pItem, UniString& rText, UniString& rErrorMsg) const
{
	// check the input
	Reference< XPropertySet >	xField(m_pAdapter->getField(pItem->GetTextComponent()));

	OStaticDataAccessTools aStaticTools;
	Reference< XConnection > xConnection(aStaticTools.getRowSetConnection(Reference< XRowSet > (m_xController->getModel(), UNO_QUERY)));
	Reference< ::com::sun::star::util::XNumberFormatsSupplier >  xFormatSupplier = aStaticTools.getNumberFormats(xConnection, sal_True);

	Reference< ::com::sun::star::util::XNumberFormatter >  xFormatter(m_xORB->createInstance(FM_NUMBER_FORMATTER), UNO_QUERY);
	xFormatter->attachNumberFormatsSupplier(xFormatSupplier);

	::rtl::OUString aErr, aTxt(rText);
	::rtl::Reference< ISQLParseNode > xParseNode = predicateTree(aErr, aTxt, xFormatter, xField);
	rErrorMsg = aErr;
	rText = aTxt;
	if (xParseNode.is())
	{
		::rtl::OUString aPreparedText;
		::com::sun::star::lang::Locale aAppLocale = Application::GetSettings().GetUILocale();
		xParseNode->parseNodeToPredicateStr(
            aPreparedText, xConnection, xFormatter, xField, aAppLocale, '.', getParseContext() );
		rText = aPreparedText;
		return sal_True;
	}
	else
		return sal_False;
}

//------------------------------------------------------------------------
void FmFilterModel::Append(FmFilterItems* pItems, FmFilterItem* pFilterItem)
{
	Insert(pItems->GetChilds().end(), pFilterItem);
}

//------------------------------------------------------------------------
void FmFilterModel::SetTextForItem(FmFilterItem* pItem, const ::rtl::OUString& rText)
{
	::std::vector<FmFilterData*>& rItems = pItem->GetParent()->GetParent()->GetChilds();
	::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->GetChilds();
		::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();
	        FmXFormController* pController = FmXFormController::getImplementation( pFormItem->GetController().get() );
            DBG_ASSERT( pController, "FmFilterAdapter::SetCurrentItems: no controller!" );
			pController->setCurrentFilterPosition(nPos);
			pFormItem->SetCurrentPosition(nPos);

			if ((::com::sun::star::form::XFormController*)m_xController.get() != (::com::sun::star::form::XFormController*)pFormItem->GetController().get())
				// 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::CheckIntegrity(FmParentData* pItem)
{
	// checks whether for each form there's one free level for input

	::std::vector<FmFilterData*>& rItems = pItem->GetChilds();
	sal_Bool bAppendLevel = sal_False;

	for (::std::vector<FmFilterData*>::iterator i = rItems.begin();
		 i != rItems.end(); i++)
	{
		FmFilterItems* pItems = PTR_CAST(FmFilterItems, *i);
		if (pItems)
		{
			bAppendLevel = !pItems->GetChilds().empty();
			continue;
		}

		FmFormItem* pFormItem = PTR_CAST(FmFormItem, *i);
		if (pFormItem)
		{
			CheckIntegrity(pFormItem);
			continue;
		}
	}
	if (bAppendLevel)
		AppendFilterItems((FmFormItem*)pItem);
}

//========================================================================
// 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
	if (pForm->GetChilds()[pForm->GetCurrentPosition()] == pRow)
	{
		Color aLineColor(rDev.GetLineColor());
		Rectangle aRect(rPos, GetSize(&rDev, pEntry ));
		Point aFirst(rPos.X(), aRect.Bottom() - 6);
		Point aSecond(aFirst.X() + 2, aFirst.Y() + 3);

		rDev.SetLineColor(rDev.GetTextColor());
		rDev.DrawLine(aFirst, aSecond);

		aFirst = aSecond;
		aFirst.X() += 1;
		aSecond.X() += 6;
		aSecond.Y() -= 5;

		rDev.DrawLine(aFirst, aSecond);
		rDev.SetLineColor( aLineColor );
	}
	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< ::com::sun::star::container::XIndexAccess > & xControllers, const Reference< ::com::sun::star::form::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
			{	// auf einem Entry mit Childs, der nicht aufgeklappt ist ?
				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 );
	}
}

//------------------------------------------------------------------------
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)
	{
		if ((*i)->GetParent() == _pTargetItems)
			continue;
		else
		{
			FmFilterItem* pFilterItem = _pTargetItems->Find((*i)->GetTextComponent());
			String aText = (*i)->GetText();
			if ( !pFilterItem )
			{
				pFilterItem = new FmFilterItem(m_pModel->getORB(),_pTargetItems, (*i)->GetFieldName(), aText, (*i)->GetTextComponent());
				m_pModel->Append(_pTargetItems, pFilterItem);
			}

			if ( !_bCopy )
				m_pModel->Remove(*i);

			// now set the text for the new dragged item
			m_pModel->SetTextForItem(pFilterItem, aText);
		}
	}
	m_pModel->CheckIntegrity((FmFormItem*)_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->GetChilds().empty()
					&& pFilterItems->GetParent()->GetChilds().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();
	if (	rKeyCode.IsMod1() 
		&&	rKeyCode.IsMod2()
		&& !rKeyCode.IsShift()
		&& ( rKeyCode.GetCode() == KEY_UP || rKeyCode.GetCode() == KEY_DOWN )
		)
	{
		::std::vector<FmFilterItem*> aItemList;
		if ( getSelectedFilterItems(aItemList) )
		{
			::std::mem_fun1_t<SvLBoxEntry*,FmFilterNavigator,SvLBoxEntry*> aGetEntry = ::std::mem_fun(&FmFilterNavigator::getNextEntry);
			if ( rKeyCode.GetCode() == KEY_UP )
				aGetEntry = ::std::mem_fun(&FmFilterNavigator::getPrevEntry);

			SvLBoxEntry* pTarget = aGetEntry(this,NULL);

			if ( pTarget )
			{
				FmFilterItems* pTargetItems = getTargetItems(pTarget);
				if ( pTargetItems )
				{
					::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 = aGetEntry(this,pTarget);
								if ( !pTarget )
									return;
								pTargetItems = getTargetItems(pTarget);
								break;
							}
							else
							{
								FmFilterItem* pFilterItem = pTargetItems->Find((*i)->GetTextComponent());
								// we found the text component so jump above
								if ( pFilterItem )
								{
									pTarget = aGetEntry(this,pTarget);
									if ( !pTarget )
										return;
									pTargetItems = getTargetItems(pTarget);
									break;
								}
							}
						}
						bNextTargetItem = i != aEnd && pTargetItems;
					}
					if ( pTargetItems )
					{
						insertFilterItem(aItemList,pTargetItems);
						return;
					}
				}
			}
		}
	}
	else if (rKeyCode.GetCode() == KEY_DELETE && !rKeyCode.GetModifier())
	{
		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());
	}

	// now check if we need to insert new items
	m_pModel->CheckIntegrity(m_pModel);
}
// -----------------------------------------------------------------------------

//========================================================================
// 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< ::com::sun::star::form::XFormController >  xController(pFormShell->GetImpl()->getActiveInternalController());
		Reference< ::com::sun::star::container::XIndexAccess >	xContainer;
		if (xController.is())
		{
			Reference< ::com::sun::star::container::XChild >  xChild(xController, UNO_QUERY);
			for (Reference< XInterface >  xParent(xChild->getParent());
				 xParent.is();
				 xParent = xChild.is() ? xChild->getParent() : Reference< XInterface > ())
			{
				xContainer = Reference< ::com::sun::star::container::XIndexAccess > (xParent, UNO_QUERY);
				xChild = Reference< ::com::sun::star::container::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
//........................................................................
