/************************************************************************* * * 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 $ * * 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 * * 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 #include #include #include "fmitems.hxx" #ifndef _SVX_SVXIDS_HRC #include #endif #ifndef _SVX_FMPROP_HRC #include "fmprop.hrc" #endif #ifndef _SVX_FMHELP_HRC #include "fmhelp.hrc" #endif #include #include #include #include #include #include #ifndef _WRKWIN_HXX //autogen #include #endif #include #include #include #include #include #include #include #include #include #include #include #include "gridcell.hxx" #include #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::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::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& 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& _rItems, const Reference< ::com::sun::star::awt::XTextComponent > & xText) { for (::std::vector::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& rItems = pFilterItems->GetChilds(); ::std::vector::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::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& rItems, const Reference< ::com::sun::star::form::XFormController > & xController) const { for (::std::vector::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& rItems, const Reference< ::com::sun::star::form::XForm >& xForm) const { for (::std::vector::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::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::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::iterator& rPos, FmFilterData* pData) { ::std::vector& 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& rItems = pParent->GetChilds(); // erase the item from the model ::std::vector::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& rChilds = ((FmFilterItems*)pData)->GetChilds(); while (!rChilds.empty()) { ::std::vector::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::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& rParentParentItems = pData->GetParent()->GetParent()->GetChilds(); ::std::vector::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::iterator& rPos, FmFilterData* pData) { ::std::vector& 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& rItems = pItem->GetParent()->GetParent()->GetChilds(); ::std::vector::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& rItems = pFormItem->GetChilds(); ::std::vector::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& rItems = pItem->GetChilds(); sal_Bool bAppendLevel = sal_False; for (::std::vector::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(_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(FmFilterData* pItem) { 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) { 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& _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& _rFilterList,FmFilterItems* _pTargetItems,sal_Bool _bCopy) { ::std::vector::const_iterator aEnd = _rFilterList.end(); for (::std::vector::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 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 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 aItemList; if ( getSelectedFilterItems(aItemList) ) { ::std::mem_fun1_t 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::const_iterator aEnd = aItemList.end(); sal_Bool bNextTargetItem = sal_True; while ( bNextTargetItem ) { ::std::vector::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 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::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 //........................................................................