1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "filtnav.hxx"
23 #include "fmitems.hxx"
25 #include "svx/fmresids.hrc"
27 #include <com/sun/star/awt/XControlModel.hpp>
28 #include <com/sun/star/awt/XControl.hpp>
29 #include <com/sun/star/awt/XTextComponent.hpp>
30 #include <com/sun/star/form/runtime/XFormController.hpp>
31 #include <com/sun/star/lang/XUnoTunnel.hpp>
32 #include <com/sun/star/util/NumberFormatter.hpp>
33 #include <com/sun/star/beans/XFastPropertySet.hpp>
35 #include <comphelper/processfactory.hxx>
36 #include <comphelper/property.hxx>
37 #include <comphelper/sequence.hxx>
38 #include <comphelper/string.hxx>
39 #include <comphelper/uno3.hxx>
40 #include <connectivity/dbtools.hxx>
41 #include <connectivity/sqlnode.hxx>
42 #include <cppuhelper/implbase1.hxx>
43 #include <fmservs.hxx>
44 #include <fmshimp.hxx>
45 #include <sfx2/dispatch.hxx>
46 #include <sfx2/objitem.hxx>
47 #include <sfx2/objsh.hxx>
48 #include <sfx2/request.hxx>
49 #include <svx/dialmgr.hxx>
50 #include <svx/fmshell.hxx>
51 #include <svx/fmtools.hxx>
52 #include <svx/svxids.hrc>
53 #include <vcl/wrkwin.hxx>
54 #include <vcl/settings.hxx>
55 #include <tools/diagnose_ex.h>
56 #include <svtools/svlbitm.hxx>
57 #include "svtools/treelistentry.hxx"
58 #include "svtools/viewdataentry.hxx"
62 #define DROP_ACTION_TIMER_INITIAL_TICKS 10
63 // solange dauert es, bis das Scrollen anspringt
64 #define DROP_ACTION_TIMER_SCROLL_TICKS 3
65 // in diesen Intervallen wird jeweils eine Zeile gescrollt
66 #define DROP_ACTION_TIMER_TICK_BASE 10
67 // das ist die Basis, mit der beide Angaben multipliziert werden (in ms)
69 using namespace ::svxform
;
70 using namespace ::connectivity
;
71 using namespace ::dbtools
;
78 using ::com::sun::star::uno::Reference
;
79 using ::com::sun::star::lang::XMultiServiceFactory
;
80 using ::com::sun::star::awt::TextEvent
;
81 using ::com::sun::star::container::XIndexAccess
;
82 using ::com::sun::star::uno::UNO_QUERY
;
83 using ::com::sun::star::beans::XPropertySet
;
84 using ::com::sun::star::form::runtime::XFormController
;
85 using ::com::sun::star::form::runtime::XFilterController
;
86 using ::com::sun::star::form::runtime::XFilterControllerListener
;
87 using ::com::sun::star::form::runtime::FilterEvent
;
88 using ::com::sun::star::lang::EventObject
;
89 using ::com::sun::star::uno::RuntimeException
;
90 using ::com::sun::star::form::XForm
;
91 using ::com::sun::star::container::XChild
;
92 using ::com::sun::star::awt::XControl
;
93 using ::com::sun::star::sdbc::XConnection
;
94 using ::com::sun::star::util::XNumberFormatsSupplier
;
95 using ::com::sun::star::util::XNumberFormatter
;
96 using ::com::sun::star::util::XNumberFormatter2
;
97 using ::com::sun::star::util::NumberFormatter
;
98 using ::com::sun::star::sdbc::XRowSet
;
99 using ::com::sun::star::lang::Locale
;
100 using ::com::sun::star::sdb::SQLContext
;
101 using ::com::sun::star::uno::XInterface
;
102 using ::com::sun::star::uno::UNO_QUERY_THROW
;
103 using ::com::sun::star::uno::UNO_SET_THROW
;
104 using ::com::sun::star::uno::Exception
;
105 using ::com::sun::star::awt::XTextComponent
;
106 using ::com::sun::star::uno::Sequence
;
109 OFilterItemExchange::OFilterItemExchange()
114 void OFilterItemExchange::AddSupportedFormats()
116 AddFormat(getFormatId());
120 SotClipboardFormatId
OFilterItemExchange::getFormatId()
122 static SotClipboardFormatId s_nFormat
= static_cast<SotClipboardFormatId
>(-1);
123 if (static_cast<SotClipboardFormatId
>(-1) == s_nFormat
)
125 s_nFormat
= SotExchange::RegisterFormatName(OUString("application/x-openoffice;windows_formatname=\"form.FilterControlExchange\""));
126 DBG_ASSERT(static_cast<SotClipboardFormatId
>(-1) != s_nFormat
, "OFilterExchangeHelper::getFormatId: bad exchange id!");
132 OLocalExchange
* OFilterExchangeHelper::createExchange() const
134 return new OFilterItemExchange
;
138 TYPEINIT0(FmFilterData
);
139 Image
FmFilterData::GetImage() const
145 TYPEINIT1(FmParentData
, FmFilterData
);
147 FmParentData::~FmParentData()
149 for (::std::vector
<FmFilterData
*>::const_iterator i
= m_aChildren
.begin();
150 i
!= m_aChildren
.end(); ++i
)
155 TYPEINIT1(FmFormItem
, FmParentData
);
157 Image
FmFormItem::GetImage() const
163 ImageList
aNavigatorImages( SVX_RES( RID_SVXIMGLIST_FMEXPL
) );
164 aImage
= aNavigatorImages
.GetImage( RID_SVXIMG_FORM
);
170 TYPEINIT1(FmFilterItems
, FmParentData
);
172 FmFilterItem
* FmFilterItems::Find( const ::sal_Int32 _nFilterComponentIndex
) const
174 for ( ::std::vector
< FmFilterData
* >::const_iterator i
= m_aChildren
.begin();
175 i
!= m_aChildren
.end();
179 FmFilterItem
* pCondition
= PTR_CAST( FmFilterItem
, *i
);
180 DBG_ASSERT( pCondition
, "FmFilterItems::Find: Wrong element in container!" );
181 if ( _nFilterComponentIndex
== pCondition
->GetComponentIndex() )
188 Image
FmFilterItems::GetImage() const
194 ImageList
aNavigatorImages( SVX_RES( RID_SVXIMGLIST_FMEXPL
) );
195 aImage
= aNavigatorImages
.GetImage( RID_SVXIMG_FILTER
);
201 TYPEINIT1(FmFilterItem
, FmFilterData
);
203 FmFilterItem::FmFilterItem( FmFilterItems
* pParent
,
204 const OUString
& aFieldName
,
205 const OUString
& aText
,
206 const sal_Int32 _nComponentIndex
)
207 :FmFilterData(pParent
, aText
)
208 ,m_aFieldName(aFieldName
)
209 ,m_nComponentIndex( _nComponentIndex
)
214 Image
FmFilterItem::GetImage() const
220 ImageList
aNavigatorImages( SVX_RES( RID_SVXIMGLIST_FMEXPL
) );
221 aImage
= aNavigatorImages
.GetImage( RID_SVXIMG_FIELD
);
227 // Hints for communicatition between model and view
229 class FmFilterHint
: public SfxHint
231 FmFilterData
* m_pData
;
234 FmFilterHint(FmFilterData
* pData
):m_pData(pData
){}
235 FmFilterData
* GetData() const { return m_pData
; }
239 class FmFilterInsertedHint
: public FmFilterHint
241 sal_uLong m_nPos
; // Position relative to the parent of the data
244 FmFilterInsertedHint(FmFilterData
* pData
, sal_uLong nRelPos
)
248 sal_uLong
GetPos() const { return m_nPos
; }
252 class FmFilterRemovedHint
: public FmFilterHint
255 FmFilterRemovedHint(FmFilterData
* pData
)
256 :FmFilterHint(pData
){}
260 class FmFilterTextChangedHint
: public FmFilterHint
263 FmFilterTextChangedHint(FmFilterData
* pData
)
264 :FmFilterHint(pData
){}
268 class FilterClearingHint
: public SfxHint
271 FilterClearingHint(){}
275 class FmFilterCurrentChangedHint
: public SfxHint
278 FmFilterCurrentChangedHint(){}
282 // class FmFilterAdapter, Listener an den FilterControls
284 class FmFilterAdapter
: public ::cppu::WeakImplHelper1
< XFilterControllerListener
>
286 FmFilterModel
* m_pModel
;
287 Reference
< XIndexAccess
> m_xControllers
;
290 FmFilterAdapter(FmFilterModel
* pModel
, const Reference
< XIndexAccess
>& xControllers
);
293 virtual void SAL_CALL
disposing(const EventObject
& Source
) throw( RuntimeException
, std::exception
) SAL_OVERRIDE
;
295 // XFilterControllerListener
296 virtual void SAL_CALL
predicateExpressionChanged( const FilterEvent
& _Event
) throw (RuntimeException
, std::exception
) SAL_OVERRIDE
;
297 virtual void SAL_CALL
disjunctiveTermRemoved( const FilterEvent
& _Event
) throw (RuntimeException
, std::exception
) SAL_OVERRIDE
;
298 virtual void SAL_CALL
disjunctiveTermAdded( const FilterEvent
& _Event
) throw (RuntimeException
, std::exception
) SAL_OVERRIDE
;
301 void dispose() throw( RuntimeException
);
303 void AddOrRemoveListener( const Reference
< XIndexAccess
>& _rxControllers
, const bool _bAdd
);
305 static void setText(sal_Int32 nPos
,
306 const FmFilterItem
* pFilterItem
,
307 const OUString
& rText
);
311 FmFilterAdapter::FmFilterAdapter(FmFilterModel
* pModel
, const Reference
< XIndexAccess
>& xControllers
)
313 ,m_xControllers( xControllers
)
315 AddOrRemoveListener( m_xControllers
, true );
319 void FmFilterAdapter::dispose() throw( RuntimeException
)
321 AddOrRemoveListener( m_xControllers
, false );
325 void FmFilterAdapter::AddOrRemoveListener( const Reference
< XIndexAccess
>& _rxControllers
, const bool _bAdd
)
327 for (sal_Int32 i
= 0, nLen
= _rxControllers
->getCount(); i
< nLen
; ++i
)
329 Reference
< XIndexAccess
> xElement( _rxControllers
->getByIndex(i
), UNO_QUERY
);
332 AddOrRemoveListener( xElement
, _bAdd
);
334 // handle this particular controller
335 Reference
< XFilterController
> xController( xElement
, UNO_QUERY
);
336 OSL_ENSURE( xController
.is(), "FmFilterAdapter::InsertElements: no XFilterController, cannot sync data!" );
337 if ( xController
.is() )
340 xController
->addFilterControllerListener( this );
342 xController
->removeFilterControllerListener( this );
348 void FmFilterAdapter::setText(sal_Int32 nRowPos
,
349 const FmFilterItem
* pFilterItem
,
350 const OUString
& rText
)
352 FmFormItem
* pFormItem
= PTR_CAST( FmFormItem
, pFilterItem
->GetParent()->GetParent() );
356 Reference
< XFilterController
> xController( pFormItem
->GetController(), UNO_QUERY_THROW
);
357 xController
->setPredicateExpression( pFilterItem
->GetComponentIndex(), nRowPos
, rText
);
359 catch( const Exception
& )
361 DBG_UNHANDLED_EXCEPTION();
368 void SAL_CALL
FmFilterAdapter::disposing(const EventObject
& /*e*/) throw( RuntimeException
, std::exception
)
375 OUString
lcl_getLabelName_nothrow( const Reference
< XControl
>& _rxControl
)
380 Reference
< XPropertySet
> xModel( _rxControl
->getModel(), UNO_QUERY_THROW
);
381 sLabelName
= getLabelName( xModel
);
383 catch( const Exception
& )
385 DBG_UNHANDLED_EXCEPTION();
390 Reference
< XPropertySet
> lcl_getBoundField_nothrow( const Reference
< XControl
>& _rxControl
)
392 Reference
< XPropertySet
> xField
;
395 Reference
< XPropertySet
> xModelProps( _rxControl
->getModel(), UNO_QUERY_THROW
);
396 xField
.set( xModelProps
->getPropertyValue( FM_PROP_BOUNDFIELD
), UNO_QUERY_THROW
);
398 catch( const Exception
& )
400 DBG_UNHANDLED_EXCEPTION();
406 // XFilterControllerListener
408 void FmFilterAdapter::predicateExpressionChanged( const FilterEvent
& _Event
) throw( RuntimeException
, std::exception
)
410 SolarMutexGuard aGuard
;
415 // the controller which sent the event
416 Reference
< XFormController
> xController( _Event
.Source
, UNO_QUERY_THROW
);
417 Reference
< XFilterController
> xFilterController( _Event
.Source
, UNO_QUERY_THROW
);
418 Reference
< XForm
> xForm( xController
->getModel(), UNO_QUERY_THROW
);
420 FmFormItem
* pFormItem
= m_pModel
->Find( m_pModel
->m_aChildren
, xForm
);
421 OSL_ENSURE( pFormItem
, "FmFilterAdapter::predicateExpressionChanged: don't know this form!" );
425 const sal_Int32
nActiveTerm( xFilterController
->getActiveTerm() );
427 FmFilterItems
* pFilter
= PTR_CAST( FmFilterItems
, pFormItem
->GetChildren()[ nActiveTerm
] );
428 FmFilterItem
* pFilterItem
= pFilter
->Find( _Event
.FilterComponent
);
431 if ( !_Event
.PredicateExpression
.isEmpty())
433 pFilterItem
->SetText( _Event
.PredicateExpression
);
434 // UI benachrichtigen
435 FmFilterTextChangedHint
aChangeHint(pFilterItem
);
436 m_pModel
->Broadcast( aChangeHint
);
440 // no text anymore so remove the condition
441 m_pModel
->Remove(pFilterItem
);
446 // searching the component by field name
447 OUString
aFieldName( lcl_getLabelName_nothrow( xFilterController
->getFilterComponent( _Event
.FilterComponent
) ) );
449 pFilterItem
= new FmFilterItem( pFilter
, aFieldName
, _Event
.PredicateExpression
, _Event
.FilterComponent
);
450 m_pModel
->Insert(pFilter
->GetChildren().end(), pFilterItem
);
453 // ensure there's one empty term in the filter, just in case the active term was previously empty
454 m_pModel
->EnsureEmptyFilterRows( *pFormItem
);
458 void SAL_CALL
FmFilterAdapter::disjunctiveTermRemoved( const FilterEvent
& _Event
) throw (RuntimeException
, std::exception
)
460 SolarMutexGuard aGuard
;
462 Reference
< XFormController
> xController( _Event
.Source
, UNO_QUERY_THROW
);
463 Reference
< XFilterController
> xFilterController( _Event
.Source
, UNO_QUERY_THROW
);
464 Reference
< XForm
> xForm( xController
->getModel(), UNO_QUERY_THROW
);
466 FmFormItem
* pFormItem
= m_pModel
->Find( m_pModel
->m_aChildren
, xForm
);
467 OSL_ENSURE( pFormItem
, "FmFilterAdapter::disjunctiveTermRemoved: don't know this form!" );
471 ::std::vector
< FmFilterData
* >& rTermItems
= pFormItem
->GetChildren();
472 const bool bValidIndex
= ( _Event
.DisjunctiveTerm
>= 0 ) && ( (size_t)_Event
.DisjunctiveTerm
< rTermItems
.size() );
473 OSL_ENSURE( bValidIndex
, "FmFilterAdapter::disjunctiveTermRemoved: invalid term index!" );
477 // if the first term was removed, then the to-be first term needs its text updated
478 if ( _Event
.DisjunctiveTerm
== 0 )
480 rTermItems
[1]->SetText( SVX_RESSTR(RID_STR_FILTER_FILTER_FOR
));
481 FmFilterTextChangedHint
aChangeHint( rTermItems
[1] );
482 m_pModel
->Broadcast( aChangeHint
);
485 // finally remove the entry from the model
486 m_pModel
->Remove( rTermItems
.begin() + _Event
.DisjunctiveTerm
);
488 // ensure there's one empty term in the filter, just in case the currently removed one was the last empty one
489 m_pModel
->EnsureEmptyFilterRows( *pFormItem
);
493 void SAL_CALL
FmFilterAdapter::disjunctiveTermAdded( const FilterEvent
& _Event
) throw (RuntimeException
, std::exception
)
495 SolarMutexGuard aGuard
;
497 Reference
< XFormController
> xController( _Event
.Source
, UNO_QUERY_THROW
);
498 Reference
< XFilterController
> xFilterController( _Event
.Source
, UNO_QUERY_THROW
);
499 Reference
< XForm
> xForm( xController
->getModel(), UNO_QUERY_THROW
);
501 FmFormItem
* pFormItem
= m_pModel
->Find( m_pModel
->m_aChildren
, xForm
);
502 OSL_ENSURE( pFormItem
, "FmFilterAdapter::disjunctiveTermAdded: don't know this form!" );
506 const sal_Int32 nInsertPos
= _Event
.DisjunctiveTerm
;
507 bool bValidIndex
= ( nInsertPos
>= 0 ) && ( (size_t)nInsertPos
<= pFormItem
->GetChildren().size() );
510 OSL_FAIL( "FmFilterAdapter::disjunctiveTermAdded: invalid index!" );
514 const ::std::vector
< FmFilterData
* >::iterator insertPos
= pFormItem
->GetChildren().begin() + nInsertPos
;
516 FmFilterItems
* pFilterItems
= new FmFilterItems(pFormItem
, SVX_RESSTR(RID_STR_FILTER_FILTER_OR
));
517 m_pModel
->Insert( insertPos
, pFilterItems
);
520 TYPEINIT1(FmFilterModel
, FmParentData
);
522 FmFilterModel::FmFilterModel()
523 :FmParentData(NULL
, OUString())
524 ,OSQLParserClient(comphelper::getProcessComponentContext())
526 ,m_pCurrentItems(NULL
)
531 FmFilterModel::~FmFilterModel()
537 void FmFilterModel::Clear()
540 FilterClearingHint aClearedHint
;
541 Broadcast( aClearedHint
);
546 m_pAdapter
->dispose();
547 m_pAdapter
->release();
551 m_pCurrentItems
= NULL
;
552 m_xController
= NULL
;
553 m_xControllers
= NULL
;
555 for (::std::vector
<FmFilterData
*>::const_iterator i
= m_aChildren
.begin();
556 i
!= m_aChildren
.end(); ++i
)
563 void FmFilterModel::Update(const Reference
< XIndexAccess
> & xControllers
, const Reference
< XFormController
> & xCurrent
)
565 if ( xCurrent
== m_xController
)
568 if (!xControllers
.is())
574 // there is only a new current controller
575 if ( m_xControllers
!= xControllers
)
579 m_xControllers
= xControllers
;
580 Update(m_xControllers
, this);
582 DBG_ASSERT(xCurrent
.is(), "FmFilterModel::Update(...) no current controller");
584 // Listening for TextChanges
585 m_pAdapter
= new FmFilterAdapter(this, xControllers
);
586 m_pAdapter
->acquire();
588 SetCurrentController(xCurrent
);
589 EnsureEmptyFilterRows( *this );
592 SetCurrentController(xCurrent
);
596 void FmFilterModel::Update(const Reference
< XIndexAccess
> & xControllers
, FmParentData
* pParent
)
600 sal_Int32 nCount
= xControllers
->getCount();
601 for ( sal_Int32 i
= 0; i
< nCount
; ++i
)
603 Reference
< XFormController
> xController( xControllers
->getByIndex(i
), UNO_QUERY_THROW
);
605 Reference
< XPropertySet
> xFormProperties( xController
->getModel(), UNO_QUERY_THROW
);
607 OSL_VERIFY( xFormProperties
->getPropertyValue( FM_PROP_NAME
) >>= aName
);
609 // Insert a new item for the form
610 FmFormItem
* pFormItem
= new FmFormItem( pParent
, xController
, aName
);
611 Insert( pParent
->GetChildren().end(), pFormItem
);
613 Reference
< XFilterController
> xFilterController( pFormItem
->GetFilterController(), UNO_SET_THROW
);
615 // insert the existing filters for the form
616 OUString
aTitle(SVX_RESSTR(RID_STR_FILTER_FILTER_FOR
));
618 Sequence
< Sequence
< OUString
> > aExpressions
= xFilterController
->getPredicateExpressions();
619 for ( const Sequence
< OUString
>* pConjunctionTerm
= aExpressions
.getConstArray();
620 pConjunctionTerm
!= aExpressions
.getConstArray() + aExpressions
.getLength();
624 // we always display one row, even if there's no term to be displayed
625 FmFilterItems
* pFilterItems
= new FmFilterItems( pFormItem
, aTitle
);
626 Insert( pFormItem
->GetChildren().end(), pFilterItems
);
628 const Sequence
< OUString
>& rDisjunction( *pConjunctionTerm
);
629 for ( const OUString
* pDisjunctiveTerm
= rDisjunction
.getConstArray();
630 pDisjunctiveTerm
!= rDisjunction
.getConstArray() + rDisjunction
.getLength();
634 if ( pDisjunctiveTerm
->isEmpty() )
635 // no condition for this particular component in this particular conjunction term
638 const sal_Int32 nComponentIndex
= pDisjunctiveTerm
- rDisjunction
.getConstArray();
640 // determine the display name of the control
641 const Reference
< XControl
> xFilterControl( xFilterController
->getFilterComponent( nComponentIndex
) );
642 const OUString
sDisplayName( lcl_getLabelName_nothrow( xFilterControl
) );
644 // insert a new entry
645 FmFilterItem
* pANDCondition
= new FmFilterItem( pFilterItems
, sDisplayName
, *pDisjunctiveTerm
, nComponentIndex
);
646 Insert( pFilterItems
->GetChildren().end(), pANDCondition
);
649 // title for the next conditions
650 aTitle
= SVX_RESSTR( RID_STR_FILTER_FILTER_OR
);
653 // now add dependent controllers
654 Update( xController
, pFormItem
);
657 catch( const Exception
& )
659 DBG_UNHANDLED_EXCEPTION();
664 FmFormItem
* FmFilterModel::Find(const ::std::vector
<FmFilterData
*>& rItems
, const Reference
< XFormController
> & xController
) const
666 for (::std::vector
<FmFilterData
*>::const_iterator i
= rItems
.begin();
667 i
!= rItems
.end(); ++i
)
669 FmFormItem
* pForm
= PTR_CAST(FmFormItem
,*i
);
672 if ( xController
== pForm
->GetController() )
676 pForm
= Find(pForm
->GetChildren(), xController
);
686 FmFormItem
* FmFilterModel::Find(const ::std::vector
<FmFilterData
*>& rItems
, const Reference
< XForm
>& xForm
) const
688 for (::std::vector
<FmFilterData
*>::const_iterator i
= rItems
.begin();
689 i
!= rItems
.end(); ++i
)
691 FmFormItem
* pForm
= PTR_CAST(FmFormItem
,*i
);
694 if (xForm
== pForm
->GetController()->getModel())
698 pForm
= Find(pForm
->GetChildren(), xForm
);
708 void FmFilterModel::SetCurrentController(const Reference
< XFormController
> & xCurrent
)
710 if ( xCurrent
== m_xController
)
713 m_xController
= xCurrent
;
715 FmFormItem
* pItem
= Find( m_aChildren
, xCurrent
);
721 Reference
< XFilterController
> xFilterController( m_xController
, UNO_QUERY_THROW
);
722 const sal_Int32
nActiveTerm( xFilterController
->getActiveTerm() );
723 if ( pItem
->GetChildren().size() > (size_t)nActiveTerm
)
725 SetCurrentItems( static_cast< FmFilterItems
* >( pItem
->GetChildren()[ nActiveTerm
] ) );
728 catch( const Exception
& )
730 DBG_UNHANDLED_EXCEPTION();
735 void FmFilterModel::AppendFilterItems( FmFormItem
& _rFormItem
)
737 // insert the condition behind the last filter items
738 ::std::vector
<FmFilterData
*>::reverse_iterator iter
;
739 for ( iter
= _rFormItem
.GetChildren().rbegin();
740 iter
!= _rFormItem
.GetChildren().rend();
744 if ((*iter
)->ISA(FmFilterItems
))
748 sal_Int32 nInsertPos
= iter
.base() - _rFormItem
.GetChildren().begin();
749 // delegate this to the FilterController, it will notify us, which will let us update our model
752 Reference
< XFilterController
> xFilterController( _rFormItem
.GetFilterController(), UNO_SET_THROW
);
753 if ( nInsertPos
>= xFilterController
->getDisjunctiveTerms() )
754 xFilterController
->appendEmptyDisjunctiveTerm();
756 catch( const Exception
& )
758 DBG_UNHANDLED_EXCEPTION();
763 void FmFilterModel::Insert(const ::std::vector
<FmFilterData
*>::iterator
& rPos
, FmFilterData
* pData
)
765 ::std::vector
<FmFilterData
*>& rItems
= pData
->GetParent()->GetChildren();
766 sal_uLong nPos
= rPos
== rItems
.end() ? CONTAINER_APPEND
: rPos
- rItems
.begin();
767 if (nPos
== CONTAINER_APPEND
)
769 rItems
.push_back(pData
);
770 nPos
= rItems
.size() - 1;
774 rItems
.insert(rPos
, pData
);
777 // UI benachrichtigen
778 FmFilterInsertedHint
aInsertedHint(pData
, nPos
);
779 Broadcast( aInsertedHint
);
783 void FmFilterModel::Remove(FmFilterData
* pData
)
785 FmParentData
* pParent
= pData
->GetParent();
786 ::std::vector
<FmFilterData
*>& rItems
= pParent
->GetChildren();
788 // erase the item from the model
789 ::std::vector
<FmFilterData
*>::iterator i
= ::std::find(rItems
.begin(), rItems
.end(), pData
);
790 DBG_ASSERT(i
!= rItems
.end(), "FmFilterModel::Remove(): unknown Item");
791 // position within the parent
792 sal_Int32 nPos
= i
- rItems
.begin();
793 if (pData
->ISA(FmFilterItems
))
795 FmFormItem
* pFormItem
= static_cast<FmFormItem
*>(pParent
);
799 Reference
< XFilterController
> xFilterController( pFormItem
->GetFilterController(), UNO_SET_THROW
);
801 bool bEmptyLastTerm
= ( ( nPos
== 0 ) && xFilterController
->getDisjunctiveTerms() == 1 );
802 if ( bEmptyLastTerm
)
804 // remove all children (by setting an empty predicate expression)
805 ::std::vector
< FmFilterData
* >& rChildren
= static_cast<FmFilterItems
*>(pData
)->GetChildren();
806 while ( !rChildren
.empty() )
808 ::std::vector
< FmFilterData
* >::iterator removePos
= rChildren
.end() - 1;
809 FmFilterItem
* pFilterItem
= PTR_CAST( FmFilterItem
, *removePos
);
810 FmFilterAdapter::setText( nPos
, pFilterItem
, OUString() );
816 xFilterController
->removeDisjunctiveTerm( nPos
);
819 catch( const Exception
& )
821 DBG_UNHANDLED_EXCEPTION();
824 else // FormItems can not be deleted
826 FmFilterItem
* pFilterItem
= PTR_CAST(FmFilterItem
, pData
);
828 // if its the last condition remove the parent
829 if (rItems
.size() == 1)
830 Remove(pFilterItem
->GetParent());
833 // find the position of the father within his father
834 ::std::vector
<FmFilterData
*>& rParentParentItems
= pData
->GetParent()->GetParent()->GetChildren();
835 ::std::vector
<FmFilterData
*>::iterator j
= ::std::find(rParentParentItems
.begin(), rParentParentItems
.end(), pFilterItem
->GetParent());
836 DBG_ASSERT(j
!= rParentParentItems
.end(), "FmFilterModel::Remove(): unknown Item");
837 sal_Int32 nParentPos
= j
- rParentParentItems
.begin();
839 // EmptyText removes the filter
840 FmFilterAdapter::setText(nParentPos
, pFilterItem
, OUString());
847 void FmFilterModel::Remove( const ::std::vector
<FmFilterData
*>::iterator
& rPos
)
849 // remove from parent's child list
850 FmFilterData
* pData
= *rPos
;
851 pData
->GetParent()->GetChildren().erase( rPos
);
853 // notify the view, this will remove the actual SvTreeListEntry
854 FmFilterRemovedHint
aRemoveHint( pData
);
855 Broadcast( aRemoveHint
);
861 bool FmFilterModel::ValidateText(FmFilterItem
* pItem
, OUString
& rText
, OUString
& rErrorMsg
) const
863 FmFormItem
* pFormItem
= PTR_CAST( FmFormItem
, pItem
->GetParent()->GetParent() );
866 Reference
< XFormController
> xFormController( pFormItem
->GetController() );
867 // obtain the connection of the form belonging to the controller
868 Reference
< XRowSet
> xRowSet( xFormController
->getModel(), UNO_QUERY_THROW
);
869 Reference
< XConnection
> xConnection( getConnection( xRowSet
) );
871 // obtain a number formatter for this connection
872 // TODO: shouldn't this be cached?
873 Reference
< XNumberFormatsSupplier
> xFormatSupplier
= getNumberFormats( xConnection
, true );
874 Reference
< XNumberFormatter
> xFormatter( NumberFormatter::create( comphelper::getProcessComponentContext() ), UNO_QUERY_THROW
);
875 xFormatter
->attachNumberFormatsSupplier( xFormatSupplier
);
877 // get the field (database column) which the item is responsible for
878 Reference
< XFilterController
> xFilterController( xFormController
, UNO_QUERY_THROW
);
879 Reference
< XPropertySet
> xField( lcl_getBoundField_nothrow( xFilterController
->getFilterComponent( pItem
->GetComponentIndex() ) ), UNO_SET_THROW
);
881 // parse the given text as filter predicate
882 OUString aErr
, aTxt( rText
);
883 std::shared_ptr
< OSQLParseNode
> pParseNode
= predicateTree( aErr
, aTxt
, xFormatter
, xField
);
886 if ( pParseNode
!= nullptr )
888 OUString aPreparedText
;
889 Locale aAppLocale
= Application::GetSettings().GetUILanguageTag().getLocale();
890 pParseNode
->parseNodeToPredicateStr(
891 aPreparedText
, xConnection
, xFormatter
, xField
, OUString(), aAppLocale
, '.', getParseContext() );
892 rText
= aPreparedText
;
896 catch( const Exception
& )
898 DBG_UNHANDLED_EXCEPTION();
905 void FmFilterModel::Append(FmFilterItems
* pItems
, FmFilterItem
* pFilterItem
)
907 Insert(pItems
->GetChildren().end(), pFilterItem
);
911 void FmFilterModel::SetTextForItem(FmFilterItem
* pItem
, const OUString
& rText
)
913 ::std::vector
<FmFilterData
*>& rItems
= pItem
->GetParent()->GetParent()->GetChildren();
914 ::std::vector
<FmFilterData
*>::iterator i
= ::std::find(rItems
.begin(), rItems
.end(), pItem
->GetParent());
915 sal_Int32 nParentPos
= i
- rItems
.begin();
917 FmFilterAdapter::setText(nParentPos
, pItem
, rText
);
924 pItem
->SetText(rText
);
925 FmFilterTextChangedHint
aChangeHint(pItem
);
926 Broadcast( aChangeHint
);
931 void FmFilterModel::SetCurrentItems(FmFilterItems
* pCurrent
)
933 if (m_pCurrentItems
== pCurrent
)
936 // search for the condition
939 FmFormItem
* pFormItem
= static_cast<FmFormItem
*>(pCurrent
->GetParent());
940 ::std::vector
<FmFilterData
*>& rItems
= pFormItem
->GetChildren();
941 ::std::vector
<FmFilterData
*>::const_iterator i
= ::std::find(rItems
.begin(), rItems
.end(), pCurrent
);
943 if (i
!= rItems
.end())
945 // determine the filter position
946 sal_Int32 nPos
= i
- rItems
.begin();
949 Reference
< XFilterController
> xFilterController( pFormItem
->GetFilterController(), UNO_SET_THROW
);
950 xFilterController
->setActiveTerm( nPos
);
952 catch( const Exception
& )
954 DBG_UNHANDLED_EXCEPTION();
957 if ( m_xController
!= pFormItem
->GetController() )
958 // calls SetCurrentItems again
959 SetCurrentController( pFormItem
->GetController() );
961 m_pCurrentItems
= pCurrent
;
964 m_pCurrentItems
= NULL
;
967 m_pCurrentItems
= NULL
;
970 // UI benachrichtigen
971 FmFilterCurrentChangedHint aHint
;
976 void FmFilterModel::EnsureEmptyFilterRows( FmParentData
& _rItem
)
978 // checks whether for each form there's one free level for input
979 ::std::vector
< FmFilterData
* >& rChildren
= _rItem
.GetChildren();
980 bool bAppendLevel
= _rItem
.ISA( FmFormItem
);
982 for ( ::std::vector
<FmFilterData
*>::iterator i
= rChildren
.begin();
983 i
!= rChildren
.end();
987 FmFilterItems
* pItems
= PTR_CAST(FmFilterItems
, *i
);
988 if ( pItems
&& pItems
->GetChildren().empty() )
990 bAppendLevel
= false;
994 FmFormItem
* pFormItem
= PTR_CAST(FmFormItem
, *i
);
997 EnsureEmptyFilterRows( *pFormItem
);
1004 FmFormItem
* pFormItem
= PTR_CAST( FmFormItem
, &_rItem
);
1005 OSL_ENSURE( pFormItem
, "FmFilterModel::EnsureEmptyFilterRows: no FmFormItem, but a FmFilterItems child?" );
1007 AppendFilterItems( *pFormItem
);
1011 class FmFilterItemsString
: public SvLBoxString
1014 FmFilterItemsString( SvTreeListEntry
* pEntry
, sal_uInt16 nFlags
, const OUString
& rStr
)
1015 :SvLBoxString(pEntry
,nFlags
,rStr
){}
1017 virtual void Paint(const Point
& rPos
, SvTreeListBox
& rDev
, vcl::RenderContext
& rRenderContext
,
1018 const SvViewDataEntry
* pView
, const SvTreeListEntry
* pEntry
) SAL_OVERRIDE
;
1019 virtual void InitViewData( SvTreeListBox
* pView
,SvTreeListEntry
* pEntry
, SvViewDataItem
* pViewData
) SAL_OVERRIDE
;
1022 const int nxDBmp
= 12;
1024 void FmFilterItemsString::Paint(const Point
& rPos
, SvTreeListBox
& rDev
, vcl::RenderContext
& rRenderContext
,
1025 const SvViewDataEntry
* /*pView*/, const SvTreeListEntry
* pEntry
)
1027 FmFilterItems
* pRow
= static_cast<FmFilterItems
*>(pEntry
->GetUserData());
1028 FmFormItem
* pForm
= static_cast<FmFormItem
*>(pRow
->GetParent());
1030 // current filter is significant painted
1031 const bool bIsCurrentFilter
= pForm
->GetChildren()[ pForm
->GetFilterController()->getActiveTerm() ] == pRow
;
1032 if (bIsCurrentFilter
)
1034 rRenderContext
.Push(PushFlags::LINECOLOR
);
1035 rRenderContext
.SetLineColor(rRenderContext
.GetTextColor());
1037 Rectangle
aRect(rPos
, GetSize(&rDev
, pEntry
));
1038 Point
aFirst(rPos
.X(), aRect
.Bottom() - 6);
1039 Point
aSecond(aFirst
.X() + 2, aFirst
.Y() + 3);
1041 rRenderContext
.DrawLine(aFirst
, aSecond
);
1048 rRenderContext
.DrawLine(aFirst
, aSecond
);
1049 rRenderContext
.Pop();
1052 rRenderContext
.DrawText(Point(rPos
.X() + nxDBmp
, rPos
.Y()), GetText());
1056 void FmFilterItemsString::InitViewData( SvTreeListBox
* pView
,SvTreeListEntry
* pEntry
, SvViewDataItem
* pViewData
)
1059 pViewData
= pView
->GetViewDataItem( pEntry
, this );
1061 Size
aSize(pView
->GetTextWidth(GetText()), pView
->GetTextHeight());
1062 aSize
.Width() += nxDBmp
;
1063 pViewData
->maSize
= aSize
;
1066 class FmFilterString
: public SvLBoxString
1071 FmFilterString( SvTreeListEntry
* pEntry
, sal_uInt16 nFlags
, const OUString
& rStr
, const OUString
& aName
)
1072 : SvLBoxString(pEntry
,nFlags
,rStr
)
1078 virtual void Paint(const Point
& rPos
, SvTreeListBox
& rDev
, vcl::RenderContext
& rRenderContext
,
1079 const SvViewDataEntry
* pView
, const SvTreeListEntry
* pEntry
) SAL_OVERRIDE
;
1080 virtual void InitViewData( SvTreeListBox
* pView
,SvTreeListEntry
* pEntry
, SvViewDataItem
* pViewData
) SAL_OVERRIDE
;
1086 void FmFilterString::InitViewData( SvTreeListBox
* pView
,SvTreeListEntry
* pEntry
, SvViewDataItem
* pViewData
)
1089 pViewData
= pView
->GetViewDataItem( pEntry
, this );
1091 vcl::Font
aOldFont( pView
->GetFont());
1092 vcl::Font
aFont( aOldFont
);
1093 aFont
.SetWeight(WEIGHT_BOLD
);
1094 pView
->Control::SetFont( aFont
);
1096 Size
aSize(pView
->GetTextWidth(m_aName
), pView
->GetTextHeight());
1097 pView
->Control::SetFont( aOldFont
);
1098 aSize
.Width() += pView
->GetTextWidth(GetText()) + nxD
;
1099 pViewData
->maSize
= aSize
;
1103 void FmFilterString::Paint(const Point
& rPos
, SvTreeListBox
& rDev
, vcl::RenderContext
& rRenderContext
,
1104 const SvViewDataEntry
* /*pView*/, const SvTreeListEntry
* /*pEntry*/)
1106 rRenderContext
.Push(PushFlags::FONT
);
1107 vcl::Font
aFont(rRenderContext
.GetFont());
1108 aFont
.SetWeight(WEIGHT_BOLD
);
1109 rRenderContext
.SetFont(aFont
);
1112 rRenderContext
.DrawText(aPos
, m_aName
);
1114 // position for the second text
1115 aPos
.X() += rDev
.GetTextWidth(m_aName
) + nxD
;
1116 rRenderContext
.Pop();
1117 rDev
.DrawText(aPos
, GetText());
1120 FmFilterNavigator::FmFilterNavigator( vcl::Window
* pParent
)
1121 :SvTreeListBox( pParent
, WB_HASBUTTONS
|WB_HASLINES
|WB_BORDER
|WB_HASBUTTONSATROOT
)
1123 ,m_pEditingCurrently( NULL
)
1124 ,m_aControlExchange( this )
1125 ,m_aTimerCounter( 0 )
1126 ,m_aDropActionType( DA_SCROLLUP
)
1128 SetHelpId( HID_FILTER_NAVIGATOR
);
1131 ImageList
aNavigatorImages( SVX_RES( RID_SVXIMGLIST_FMEXPL
) );
1133 aNavigatorImages
.GetImage( RID_SVXIMG_COLLAPSEDNODE
),
1134 aNavigatorImages
.GetImage( RID_SVXIMG_EXPANDEDNODE
)
1138 m_pModel
= new FmFilterModel();
1139 StartListening( *m_pModel
);
1141 EnableInplaceEditing( true );
1142 SetSelectionMode(MULTIPLE_SELECTION
);
1144 SetDragDropMode(DragDropMode::ALL
);
1146 m_aDropActionTimer
.SetTimeoutHdl(LINK(this, FmFilterNavigator
, OnDropActionTimer
));
1150 FmFilterNavigator::~FmFilterNavigator()
1155 void FmFilterNavigator::dispose()
1157 EndListening( *m_pModel
);
1159 SvTreeListBox::dispose();
1163 void FmFilterNavigator::UpdateContent(const Reference
< XIndexAccess
> & xControllers
, const Reference
< XFormController
> & xCurrent
)
1165 if (xCurrent
== m_pModel
->GetCurrentController())
1168 m_pModel
->Update(xControllers
, xCurrent
);
1170 // expand the filters for the current controller
1171 SvTreeListEntry
* pEntry
= FindEntry(m_pModel
->GetCurrentForm());
1172 if (pEntry
&& !IsExpanded(pEntry
))
1176 if (!IsExpanded(pEntry
))
1179 pEntry
= FindEntry(m_pModel
->GetCurrentItems());
1182 if (!IsExpanded(pEntry
))
1184 Select(pEntry
, true);
1190 bool FmFilterNavigator::EditingEntry( SvTreeListEntry
* pEntry
, Selection
& rSelection
)
1192 m_pEditingCurrently
= pEntry
;
1193 if (!SvTreeListBox::EditingEntry( pEntry
, rSelection
))
1196 return pEntry
&& static_cast<FmFilterData
*>(pEntry
->GetUserData())->ISA(FmFilterItem
);
1200 bool FmFilterNavigator::EditedEntry( SvTreeListEntry
* pEntry
, const OUString
& rNewText
)
1202 DBG_ASSERT(pEntry
== m_pEditingCurrently
, "FmFilterNavigator::EditedEntry: suspicious entry!");
1203 m_pEditingCurrently
= NULL
;
1205 if (EditingCanceled())
1208 DBG_ASSERT(static_cast<FmFilterData
*>(pEntry
->GetUserData())->ISA(FmFilterItem
),
1209 "FmFilterNavigator::EditedEntry() wrong entry");
1211 OUString
aText(comphelper::string::strip(rNewText
, ' '));
1212 if (aText
.isEmpty())
1214 // deleting the entry asynchron
1215 PostUserEvent(LINK(this, FmFilterNavigator
, OnRemove
), pEntry
, true);
1221 if (m_pModel
->ValidateText(static_cast<FmFilterItem
*>(pEntry
->GetUserData()), aText
, aErrorMsg
))
1224 // this will set the text at the FmFilterItem, as well as update any filter controls
1225 // which are connected to this particular entry
1226 m_pModel
->SetTextForItem( static_cast< FmFilterItem
* >( pEntry
->GetUserData() ), aText
);
1228 SetCursor( pEntry
, true );
1229 SetEntryText( pEntry
, aText
);
1233 // display the error and return sal_False
1235 aError
.Message
= SVX_RESSTR(RID_STR_SYNTAXERROR
);
1236 aError
.Details
= aErrorMsg
;
1237 displayException(aError
, this);
1246 IMPL_LINK( FmFilterNavigator
, OnRemove
, SvTreeListEntry
*, pEntry
)
1248 // now remove the entry
1249 m_pModel
->Remove(static_cast<FmFilterData
*>(pEntry
->GetUserData()));
1254 IMPL_LINK_NOARG_TYPED(FmFilterNavigator
, OnDropActionTimer
, Timer
*, void)
1256 if (--m_aTimerCounter
> 0)
1259 switch (m_aDropActionType
)
1262 ScrollOutputArea(1);
1263 m_aTimerCounter
= DROP_ACTION_TIMER_SCROLL_TICKS
;
1265 case DA_SCROLLDOWN
:
1266 ScrollOutputArea(-1);
1267 m_aTimerCounter
= DROP_ACTION_TIMER_SCROLL_TICKS
;
1271 SvTreeListEntry
* pToExpand
= GetEntry(m_aTimerTriggered
);
1272 if (pToExpand
&& (GetChildCount(pToExpand
) > 0) && !IsExpanded(pToExpand
))
1274 m_aDropActionTimer
.Stop();
1282 sal_Int8
FmFilterNavigator::AcceptDrop( const AcceptDropEvent
& rEvt
)
1284 Point aDropPos
= rEvt
.maPosPixel
;
1286 // possible DropActions scroll and expand
1289 if (m_aDropActionTimer
.IsActive())
1290 m_aDropActionTimer
.Stop();
1294 bool bNeedTrigger
= false;
1296 if ((aDropPos
.Y() >= 0) && (aDropPos
.Y() < GetEntryHeight()))
1298 m_aDropActionType
= DA_SCROLLUP
;
1299 bNeedTrigger
= true;
1303 if ((aDropPos
.Y() < GetSizePixel().Height()) && (aDropPos
.Y() >= GetSizePixel().Height() - GetEntryHeight()))
1305 m_aDropActionType
= DA_SCROLLDOWN
;
1306 bNeedTrigger
= true;
1309 { // is it an entry with children, and not yet expanded?
1310 SvTreeListEntry
* pDropppedOn
= GetEntry(aDropPos
);
1311 if (pDropppedOn
&& (GetChildCount(pDropppedOn
) > 0) && !IsExpanded(pDropppedOn
))
1314 m_aDropActionType
= DA_EXPANDNODE
;
1315 bNeedTrigger
= true;
1319 if (bNeedTrigger
&& (m_aTimerTriggered
!= aDropPos
))
1321 m_aTimerCounter
= DROP_ACTION_TIMER_INITIAL_TICKS
;
1322 // remember DropPos because there are QueryDrops even though the mouse was not moved
1323 m_aTimerTriggered
= aDropPos
;
1324 if (!m_aDropActionTimer
.IsActive())
1326 m_aDropActionTimer
.SetTimeout(DROP_ACTION_TIMER_TICK_BASE
);
1327 m_aDropActionTimer
.Start();
1330 else if (!bNeedTrigger
)
1331 m_aDropActionTimer
.Stop();
1334 if (!m_aControlExchange
.isDragSource())
1335 return DND_ACTION_NONE
;
1337 if (!OFilterItemExchange::hasFormat(GetDataFlavorExVector()))
1338 return DND_ACTION_NONE
;
1340 // do we conain the formitem?
1341 if (!FindEntry(m_aControlExchange
->getFormItem()))
1342 return DND_ACTION_NONE
;
1344 SvTreeListEntry
* pDropTarget
= GetEntry(aDropPos
);
1346 return DND_ACTION_NONE
;
1348 FmFilterData
* pData
= static_cast<FmFilterData
*>(pDropTarget
->GetUserData());
1349 FmFormItem
* pForm
= NULL
;
1350 if (pData
->ISA(FmFilterItem
))
1352 pForm
= PTR_CAST(FmFormItem
,pData
->GetParent()->GetParent());
1353 if (pForm
!= m_aControlExchange
->getFormItem())
1354 return DND_ACTION_NONE
;
1356 else if (pData
->ISA(FmFilterItems
))
1358 pForm
= PTR_CAST(FmFormItem
,pData
->GetParent());
1359 if (pForm
!= m_aControlExchange
->getFormItem())
1360 return DND_ACTION_NONE
;
1363 return DND_ACTION_NONE
;
1365 return rEvt
.mnAction
;
1370 FmFilterItems
* getTargetItems(SvTreeListEntry
* _pTarget
)
1372 FmFilterData
* pData
= static_cast<FmFilterData
*>(_pTarget
->GetUserData());
1373 FmFilterItems
* pTargetItems
= dynamic_cast<FmFilterItems
*>(pData
);
1375 pTargetItems
= dynamic_cast<FmFilterItems
*>(pData
->GetParent());
1376 return pTargetItems
;
1380 sal_Int8
FmFilterNavigator::ExecuteDrop( const ExecuteDropEvent
& rEvt
)
1382 // you can't scroll after dropping...
1383 if (m_aDropActionTimer
.IsActive())
1384 m_aDropActionTimer
.Stop();
1386 if (!m_aControlExchange
.isDragSource())
1387 return DND_ACTION_NONE
;
1389 Point aDropPos
= rEvt
.maPosPixel
;
1390 SvTreeListEntry
* pDropTarget
= GetEntry( aDropPos
);
1392 return DND_ACTION_NONE
;
1394 // search the container where to add the items
1395 FmFilterItems
* pTargetItems
= getTargetItems(pDropTarget
);
1397 SvTreeListEntry
* pEntry
= FindEntry(pTargetItems
);
1398 Select(pEntry
, true);
1399 SetCurEntry(pEntry
);
1401 insertFilterItem(m_aControlExchange
->getDraggedEntries(),pTargetItems
,DND_ACTION_COPY
== rEvt
.mnAction
);
1403 return DND_ACTION_COPY
;
1407 void FmFilterNavigator::InitEntry(SvTreeListEntry
* pEntry
,
1408 const OUString
& rStr
,
1411 SvLBoxButtonKind eButtonKind
)
1413 SvTreeListBox::InitEntry( pEntry
, rStr
, rImg1
, rImg2
, eButtonKind
);
1414 SvLBoxString
* pString
= NULL
;
1416 if (static_cast<FmFilterData
*>(pEntry
->GetUserData())->ISA(FmFilterItem
))
1417 pString
= new FmFilterString(pEntry
, 0, rStr
, static_cast<FmFilterItem
*>(pEntry
->GetUserData())->GetFieldName());
1418 else if (static_cast<FmFilterData
*>(pEntry
->GetUserData())->ISA(FmFilterItems
))
1419 pString
= new FmFilterItemsString(pEntry
, 0, rStr
);
1422 pEntry
->ReplaceItem( pString
, 1 );
1426 bool FmFilterNavigator::Select( SvTreeListEntry
* pEntry
, bool bSelect
)
1428 if (bSelect
== IsSelected(pEntry
)) // das passiert manchmal, ich glaube, die Basisklasse geht zu sehr auf Nummer sicher ;)
1431 if (SvTreeListBox::Select(pEntry
, bSelect
))
1435 FmFormItem
* pFormItem
= NULL
;
1436 if (static_cast<FmFilterData
*>(pEntry
->GetUserData())->ISA(FmFilterItem
))
1437 pFormItem
= static_cast<FmFormItem
*>(static_cast<FmFilterItem
*>(pEntry
->GetUserData())->GetParent()->GetParent());
1438 else if (static_cast<FmFilterData
*>(pEntry
->GetUserData())->ISA(FmFilterItems
))
1439 pFormItem
= static_cast<FmFormItem
*>(static_cast<FmFilterItem
*>(pEntry
->GetUserData())->GetParent()->GetParent());
1440 else if (static_cast<FmFilterData
*>(pEntry
->GetUserData())->ISA(FmFormItem
))
1441 pFormItem
= static_cast<FmFormItem
*>(pEntry
->GetUserData());
1445 // will the controller be exchanged?
1446 if (static_cast<FmFilterData
*>(pEntry
->GetUserData())->ISA(FmFilterItem
))
1447 m_pModel
->SetCurrentItems(static_cast<FmFilterItems
*>(static_cast<FmFilterItem
*>(pEntry
->GetUserData())->GetParent()));
1448 else if (static_cast<FmFilterData
*>(pEntry
->GetUserData())->ISA(FmFilterItems
))
1449 m_pModel
->SetCurrentItems(static_cast<FmFilterItems
*>(pEntry
->GetUserData()));
1450 else if (static_cast<FmFilterData
*>(pEntry
->GetUserData())->ISA(FmFormItem
))
1451 m_pModel
->SetCurrentController(static_cast<FmFormItem
*>(pEntry
->GetUserData())->GetController());
1460 void FmFilterNavigator::Notify( SfxBroadcaster
& /*rBC*/, const SfxHint
& rHint
)
1462 if (const FmFilterInsertedHint
* pInsertHint
= dynamic_cast<const FmFilterInsertedHint
*>(&rHint
))
1464 Insert(pInsertHint
->GetData(), pInsertHint
->GetPos());
1466 else if( dynamic_cast<const FilterClearingHint
*>(&rHint
) )
1468 SvTreeListBox::Clear();
1470 else if (const FmFilterRemovedHint
* pRemoveHint
= dynamic_cast<const FmFilterRemovedHint
*>(&rHint
))
1472 Remove(pRemoveHint
->GetData());
1474 else if (const FmFilterTextChangedHint
*pChangeHint
= dynamic_cast<const FmFilterTextChangedHint
*>(&rHint
))
1476 SvTreeListEntry
* pEntry
= FindEntry(pChangeHint
->GetData());
1478 SetEntryText( pEntry
, pChangeHint
->GetData()->GetText());
1480 else if( dynamic_cast<const FmFilterCurrentChangedHint
*>(&rHint
) )
1482 // invalidate the entries
1483 for (SvTreeListEntry
* pEntry
= First(); pEntry
!= NULL
;
1484 pEntry
= Next(pEntry
))
1485 GetModel()->InvalidateEntry( pEntry
);
1489 SvTreeListEntry
* FmFilterNavigator::FindEntry(const FmFilterData
* pItem
) const
1491 SvTreeListEntry
* pEntry
= NULL
;
1494 for (pEntry
= First(); pEntry
!= NULL
; pEntry
= Next( pEntry
))
1496 FmFilterData
* pEntryItem
= static_cast<FmFilterData
*>(pEntry
->GetUserData());
1497 if (pEntryItem
== pItem
)
1505 void FmFilterNavigator::Insert(FmFilterData
* pItem
, sal_uLong nPos
)
1507 const FmParentData
* pParent
= pItem
->GetParent() ? pItem
->GetParent() : GetFilterModel();
1510 SvTreeListEntry
* pParentEntry
= FindEntry( pParent
);
1511 InsertEntry( pItem
->GetText(), pItem
->GetImage(), pItem
->GetImage(), pParentEntry
, false, nPos
, pItem
);
1513 Expand( pParentEntry
);
1517 void FmFilterNavigator::Remove(FmFilterData
* pItem
)
1519 // der Entry zu den Daten
1520 SvTreeListEntry
* pEntry
= FindEntry(pItem
);
1522 if (pEntry
== m_pEditingCurrently
)
1527 GetModel()->Remove( pEntry
);
1530 FmFormItem
* FmFilterNavigator::getSelectedFilterItems(::std::vector
<FmFilterItem
*>& _rItemList
)
1532 // be sure that the data is only used within only one form!
1533 FmFormItem
* pFirstItem
= NULL
;
1535 bool bHandled
= true;
1536 bool bFoundSomething
= false;
1537 for (SvTreeListEntry
* pEntry
= FirstSelected();
1538 bHandled
&& pEntry
!= NULL
;
1539 pEntry
= NextSelected(pEntry
))
1541 FmFilterItem
* pFilter
= PTR_CAST(FmFilterItem
, static_cast<FmFilterData
*>(pEntry
->GetUserData()));
1544 FmFormItem
* pForm
= PTR_CAST(FmFormItem
,pFilter
->GetParent()->GetParent());
1547 else if (!pFirstItem
)
1549 else if (pFirstItem
!= pForm
)
1554 _rItemList
.push_back(pFilter
);
1555 bFoundSomething
= true;
1559 if ( !bHandled
|| !bFoundSomething
)
1564 void FmFilterNavigator::insertFilterItem(const ::std::vector
<FmFilterItem
*>& _rFilterList
,FmFilterItems
* _pTargetItems
,bool _bCopy
)
1566 ::std::vector
<FmFilterItem
*>::const_iterator aEnd
= _rFilterList
.end();
1567 for ( ::std::vector
< FmFilterItem
* >::const_iterator i
= _rFilterList
.begin();
1572 FmFilterItem
* pLookupItem( *i
);
1573 if ( pLookupItem
->GetParent() == _pTargetItems
)
1576 FmFilterItem
* pFilterItem
= _pTargetItems
->Find( pLookupItem
->GetComponentIndex() );
1577 OUString aText
= pLookupItem
->GetText();
1580 pFilterItem
= new FmFilterItem( _pTargetItems
, pLookupItem
->GetFieldName(), aText
, pLookupItem
->GetComponentIndex() );
1581 m_pModel
->Append( _pTargetItems
, pFilterItem
);
1585 m_pModel
->Remove( pLookupItem
);
1587 // now set the text for the new dragged item
1588 m_pModel
->SetTextForItem( pFilterItem
, aText
);
1591 m_pModel
->EnsureEmptyFilterRows( *_pTargetItems
->GetParent() );
1595 void FmFilterNavigator::StartDrag( sal_Int8
/*_nAction*/, const Point
& /*_rPosPixel*/ )
1599 // be sure that the data is only used within a only one form!
1600 m_aControlExchange
.prepareDrag();
1602 ::std::vector
<FmFilterItem
*> aItemList
;
1603 if ( FmFormItem
* pFirstItem
= getSelectedFilterItems(aItemList
) )
1605 m_aControlExchange
->setDraggedEntries(aItemList
);
1606 m_aControlExchange
->setFormItem(pFirstItem
);
1607 m_aControlExchange
.startDrag( DND_ACTION_COPYMOVE
);
1612 void FmFilterNavigator::Command( const CommandEvent
& rEvt
)
1614 bool bHandled
= false;
1615 switch (rEvt
.GetCommand())
1617 case CommandEventId::ContextMenu
:
1619 // die Stelle, an der geklickt wurde
1621 SvTreeListEntry
* pClicked
= NULL
;
1622 if (rEvt
.IsMouseEvent())
1624 aWhere
= rEvt
.GetMousePosPixel();
1625 pClicked
= GetEntry(aWhere
);
1626 if (pClicked
== NULL
)
1629 if (!IsSelected(pClicked
))
1632 Select(pClicked
, true);
1633 SetCurEntry(pClicked
);
1638 pClicked
= GetCurEntry();
1641 aWhere
= GetEntryPosition( pClicked
);
1644 ::std::vector
<FmFilterData
*> aSelectList
;
1645 for (SvTreeListEntry
* pEntry
= FirstSelected();
1647 pEntry
= NextSelected(pEntry
))
1649 // don't delete forms
1650 FmFormItem
* pForm
= PTR_CAST(FmFormItem
, static_cast<FmFilterData
*>(pEntry
->GetUserData()));
1652 aSelectList
.push_back(static_cast<FmFilterData
*>(pEntry
->GetUserData()));
1654 if (aSelectList
.size() == 1)
1656 // don't delete the only empty row of a form
1657 FmFilterItems
* pFilterItems
= PTR_CAST(FmFilterItems
, aSelectList
[0]);
1658 if (pFilterItems
&& pFilterItems
->GetChildren().empty()
1659 && pFilterItems
->GetParent()->GetChildren().size() == 1)
1660 aSelectList
.clear();
1663 PopupMenu
aContextMenu(SVX_RES(RID_FM_FILTER_MENU
));
1665 // every condition could be deleted except the first one if its the only one
1666 aContextMenu
.EnableItem( SID_FM_DELETE
, !aSelectList
.empty() );
1669 bool bEdit
= PTR_CAST(FmFilterItem
, static_cast<FmFilterData
*>(pClicked
->GetUserData())) != NULL
&&
1670 IsSelected(pClicked
) && GetSelectionCount() == 1;
1672 aContextMenu
.EnableItem( SID_FM_FILTER_EDIT
,
1674 aContextMenu
.EnableItem( SID_FM_FILTER_IS_NULL
,
1676 aContextMenu
.EnableItem( SID_FM_FILTER_IS_NOT_NULL
,
1679 aContextMenu
.RemoveDisabledEntries(true, true);
1680 sal_uInt16 nSlotId
= aContextMenu
.Execute( this, aWhere
);
1683 case SID_FM_FILTER_EDIT
:
1685 EditEntry( pClicked
);
1687 case SID_FM_FILTER_IS_NULL
:
1688 case SID_FM_FILTER_IS_NOT_NULL
:
1692 if (nSlotId
== SID_FM_FILTER_IS_NULL
)
1695 aText
= "IS NOT NULL";
1697 m_pModel
->ValidateText(static_cast<FmFilterItem
*>(pClicked
->GetUserData()),
1699 m_pModel
->SetTextForItem(static_cast<FmFilterItem
*>(pClicked
->GetUserData()), aText
);
1713 SvTreeListBox::Command( rEvt
);
1716 SvTreeListEntry
* FmFilterNavigator::getNextEntry(SvTreeListEntry
* _pStartWith
)
1718 SvTreeListEntry
* pEntry
= _pStartWith
? _pStartWith
: LastSelected();
1719 pEntry
= Next(pEntry
);
1720 // we need the next filter entry
1721 while( pEntry
&& GetChildCount( pEntry
) == 0 && pEntry
!= Last() )
1722 pEntry
= Next(pEntry
);
1726 SvTreeListEntry
* FmFilterNavigator::getPrevEntry(SvTreeListEntry
* _pStartWith
)
1728 SvTreeListEntry
* pEntry
= _pStartWith
? _pStartWith
: FirstSelected();
1729 pEntry
= Prev(pEntry
);
1730 // check if the previous entry is a filter, if so get the next prev
1731 if ( pEntry
&& GetChildCount( pEntry
) != 0 )
1733 pEntry
= Prev(pEntry
);
1734 // if the entry is still no leaf return
1735 if ( pEntry
&& GetChildCount( pEntry
) != 0 )
1741 void FmFilterNavigator::KeyInput(const KeyEvent
& rKEvt
)
1743 const vcl::KeyCode
& rKeyCode
= rKEvt
.GetKeyCode();
1745 switch ( rKeyCode
.GetCode() )
1750 if ( !rKeyCode
.IsMod1() || !rKeyCode
.IsMod2() || rKeyCode
.IsShift() )
1753 ::std::vector
<FmFilterItem
*> aItemList
;
1754 if ( !getSelectedFilterItems( aItemList
) )
1757 ::std::mem_fun1_t
<SvTreeListEntry
*,FmFilterNavigator
,SvTreeListEntry
*> getter
= ::std::mem_fun(&FmFilterNavigator::getNextEntry
);
1758 if ( rKeyCode
.GetCode() == KEY_UP
)
1759 getter
= ::std::mem_fun(&FmFilterNavigator::getPrevEntry
);
1761 SvTreeListEntry
* pTarget
= getter( this, NULL
);
1765 FmFilterItems
* pTargetItems
= getTargetItems( pTarget
);
1766 if ( !pTargetItems
)
1769 ::std::vector
<FmFilterItem
*>::const_iterator aEnd
= aItemList
.end();
1770 bool bNextTargetItem
= true;
1771 while ( bNextTargetItem
)
1773 ::std::vector
<FmFilterItem
*>::const_iterator i
= aItemList
.begin();
1774 for (; i
!= aEnd
; ++i
)
1776 if ( (*i
)->GetParent() == pTargetItems
)
1778 pTarget
= getter(this,pTarget
);
1781 pTargetItems
= getTargetItems( pTarget
);
1786 FmFilterItem
* pFilterItem
= pTargetItems
->Find( (*i
)->GetComponentIndex() );
1787 // we found the text component so jump above
1790 pTarget
= getter( this, pTarget
);
1794 pTargetItems
= getTargetItems( pTarget
);
1799 bNextTargetItem
= i
!= aEnd
&& pTargetItems
;
1804 insertFilterItem( aItemList
, pTargetItems
);
1812 if ( rKeyCode
.GetModifier() )
1815 if ( !IsSelected( First() ) || GetEntryCount() > 1 )
1821 SvTreeListBox::KeyInput(rKEvt
);
1825 void FmFilterNavigator::DeleteSelection()
1827 // to avoid the deletion of an entry twice (e.g. deletion of a parent and afterward
1828 // the deletion of its child, i have to shrink the selecton list
1829 ::std::vector
<SvTreeListEntry
*> aEntryList
;
1830 for (SvTreeListEntry
* pEntry
= FirstSelected();
1832 pEntry
= NextSelected(pEntry
))
1834 FmFilterItem
* pFilterItem
= PTR_CAST(FmFilterItem
, static_cast<FmFilterData
*>(pEntry
->GetUserData()));
1835 if (pFilterItem
&& IsSelected(GetParent(pEntry
)))
1838 FmFormItem
* pForm
= PTR_CAST(FmFormItem
, static_cast<FmFilterData
*>(pEntry
->GetUserData()));
1840 aEntryList
.push_back(pEntry
);
1843 // Remove the selection
1846 for (::std::vector
<SvTreeListEntry
*>::reverse_iterator i
= aEntryList
.rbegin();
1847 // link problems with operator ==
1848 i
.base() != aEntryList
.rend().base(); ++i
)
1850 m_pModel
->Remove(static_cast<FmFilterData
*>((*i
)->GetUserData()));
1854 FmFilterNavigatorWin::FmFilterNavigatorWin( SfxBindings
* _pBindings
, SfxChildWindow
* _pMgr
,
1855 vcl::Window
* _pParent
)
1856 :SfxDockingWindow( _pBindings
, _pMgr
, _pParent
, WinBits(WB_STDMODELESS
|WB_SIZEABLE
|WB_ROLLABLE
|WB_3DLOOK
|WB_DOCKABLE
) )
1857 ,SfxControllerItem( SID_FM_FILTER_NAVIGATOR_CONTROL
, *_pBindings
)
1859 SetHelpId( HID_FILTER_NAVIGATOR_WIN
);
1861 m_pNavigator
= VclPtr
<FmFilterNavigator
>::Create( this );
1862 m_pNavigator
->Show();
1863 SetText( SVX_RES(RID_STR_FILTER_NAVIGATOR
) );
1864 SfxDockingWindow::SetFloatingSize( Size(200,200) );
1868 FmFilterNavigatorWin::~FmFilterNavigatorWin()
1873 void FmFilterNavigatorWin::dispose()
1875 m_pNavigator
.disposeAndClear();
1876 SfxDockingWindow::dispose();
1880 void FmFilterNavigatorWin::UpdateContent(FmFormShell
* pFormShell
)
1886 m_pNavigator
->UpdateContent( NULL
, NULL
);
1889 Reference
< XFormController
> xController(pFormShell
->GetImpl()->getActiveInternalController());
1890 Reference
< XIndexAccess
> xContainer
;
1891 if (xController
.is())
1893 Reference
< XChild
> xChild(xController
, UNO_QUERY
);
1894 for (Reference
< XInterface
> xParent(xChild
->getParent());
1896 xParent
= xChild
.is() ? xChild
->getParent() : Reference
< XInterface
> ())
1898 xContainer
= Reference
< XIndexAccess
> (xParent
, UNO_QUERY
);
1899 xChild
= Reference
< XChild
> (xParent
, UNO_QUERY
);
1902 m_pNavigator
->UpdateContent(xContainer
, xController
);
1907 void FmFilterNavigatorWin::StateChanged( sal_uInt16 nSID
, SfxItemState eState
, const SfxPoolItem
* pState
)
1909 if( !pState
|| SID_FM_FILTER_NAVIGATOR_CONTROL
!= nSID
)
1912 if( eState
>= SfxItemState::DEFAULT
)
1914 FmFormShell
* pShell
= PTR_CAST( FmFormShell
, static_cast<const SfxObjectItem
*>(pState
)->GetShell() );
1915 UpdateContent( pShell
);
1918 UpdateContent( NULL
);
1922 bool FmFilterNavigatorWin::Close()
1924 if ( m_pNavigator
&& m_pNavigator
->IsEditingActive() )
1925 m_pNavigator
->EndEditing();
1927 if ( m_pNavigator
&& m_pNavigator
->IsEditingActive() )
1928 // the EndEditing was vetoed (perhaps of an syntax error or such)
1931 UpdateContent( NULL
);
1932 return SfxDockingWindow::Close();
1936 void FmFilterNavigatorWin::FillInfo( SfxChildWinInfo
& rInfo
) const
1938 SfxDockingWindow::FillInfo( rInfo
);
1939 rInfo
.bVisible
= false;
1943 Size
FmFilterNavigatorWin::CalcDockingSize( SfxChildAlignment eAlign
)
1945 if ( ( eAlign
== SfxChildAlignment::TOP
) || ( eAlign
== SfxChildAlignment::BOTTOM
) )
1948 return SfxDockingWindow::CalcDockingSize( eAlign
);
1952 SfxChildAlignment
FmFilterNavigatorWin::CheckAlignment( SfxChildAlignment eActAlign
, SfxChildAlignment eAlign
)
1956 case SfxChildAlignment::LEFT
:
1957 case SfxChildAlignment::RIGHT
:
1958 case SfxChildAlignment::NOALIGNMENT
:
1968 void FmFilterNavigatorWin::Resize()
1970 SfxDockingWindow::Resize();
1972 Size aLogOutputSize
= PixelToLogic( GetOutputSizePixel(), MAP_APPFONT
);
1973 Size aLogExplSize
= aLogOutputSize
;
1974 aLogExplSize
.Width() -= 6;
1975 aLogExplSize
.Height() -= 6;
1977 Point aExplPos
= LogicToPixel( Point(3,3), MAP_APPFONT
);
1978 Size aExplSize
= LogicToPixel( aLogExplSize
, MAP_APPFONT
);
1980 m_pNavigator
->SetPosSizePixel( aExplPos
, aExplSize
);
1983 void FmFilterNavigatorWin::GetFocus()
1987 m_pNavigator
->GrabFocus();
1990 SFX_IMPL_DOCKINGWINDOW( FmFilterNavigatorWinMgr
, SID_FM_FILTER_NAVIGATOR
)
1993 FmFilterNavigatorWinMgr::FmFilterNavigatorWinMgr( vcl::Window
*_pParent
, sal_uInt16 _nId
,
1994 SfxBindings
*_pBindings
, SfxChildWinInfo
* _pInfo
)
1995 :SfxChildWindow( _pParent
, _nId
)
1997 pWindow
= VclPtr
<FmFilterNavigatorWin
>::Create( _pBindings
, this, _pParent
);
1998 eChildAlignment
= SfxChildAlignment::NOALIGNMENT
;
1999 static_cast<SfxDockingWindow
*>(pWindow
.get())->Initialize( _pInfo
);
2006 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */