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