Version 4.3.0.0.beta1, tag libreoffice-4.3.0.0.beta1
[LibreOffice.git] / svx / source / form / filtnav.cxx
blob93f443966e92f173f3c29ab9901278118d607b70
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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"
21 #include "fmexch.hxx"
22 #include "fmhelp.hrc"
23 #include "fmitems.hxx"
24 #include "fmprop.hrc"
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 <cppuhelper/implbase1.hxx>
42 #include <fmservs.hxx>
43 #include <fmshimp.hxx>
44 #include <sfx2/dispatch.hxx>
45 #include <sfx2/objitem.hxx>
46 #include <sfx2/objsh.hxx>
47 #include <sfx2/request.hxx>
48 #include <svx/dialmgr.hxx>
49 #include <svx/fmshell.hxx>
50 #include <svx/fmtools.hxx>
51 #include <svx/svxids.hrc>
52 #include <tools/shl.hxx>
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"
60 #include <functional>
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::simple;
71 using namespace ::connectivity;
75 namespace svxform
79 using ::com::sun::star::uno::Reference;
80 using ::com::sun::star::lang::XMultiServiceFactory;
81 using ::com::sun::star::awt::TextEvent;
82 using ::com::sun::star::container::XIndexAccess;
83 using ::com::sun::star::uno::UNO_QUERY;
84 using ::com::sun::star::beans::XPropertySet;
85 using ::com::sun::star::form::runtime::XFormController;
86 using ::com::sun::star::form::runtime::XFilterController;
87 using ::com::sun::star::form::runtime::XFilterControllerListener;
88 using ::com::sun::star::form::runtime::FilterEvent;
89 using ::com::sun::star::lang::EventObject;
90 using ::com::sun::star::uno::RuntimeException;
91 using ::com::sun::star::form::XForm;
92 using ::com::sun::star::container::XChild;
93 using ::com::sun::star::awt::XControl;
94 using ::com::sun::star::sdbc::XConnection;
95 using ::com::sun::star::util::XNumberFormatsSupplier;
96 using ::com::sun::star::util::XNumberFormatter;
97 using ::com::sun::star::util::XNumberFormatter2;
98 using ::com::sun::star::util::NumberFormatter;
99 using ::com::sun::star::sdbc::XRowSet;
100 using ::com::sun::star::lang::Locale;
101 using ::com::sun::star::sdb::SQLContext;
102 using ::com::sun::star::uno::XInterface;
103 using ::com::sun::star::uno::UNO_QUERY_THROW;
104 using ::com::sun::star::uno::UNO_SET_THROW;
105 using ::com::sun::star::uno::Exception;
106 using ::com::sun::star::awt::XTextComponent;
107 using ::com::sun::star::uno::Sequence;
110 OFilterItemExchange::OFilterItemExchange()
111 : m_pFormItem(NULL)
115 void OFilterItemExchange::AddSupportedFormats()
117 AddFormat(getFormatId());
121 sal_uInt32 OFilterItemExchange::getFormatId()
123 static sal_uInt32 s_nFormat = (sal_uInt32)-1;
124 if ((sal_uInt32)-1 == s_nFormat)
126 s_nFormat = SotExchange::RegisterFormatName(OUString("application/x-openoffice;windows_formatname=\"form.FilterControlExchange\""));
127 DBG_ASSERT((sal_uInt32)-1 != s_nFormat, "OFilterExchangeHelper::getFormatId: bad exchange id!");
129 return s_nFormat;
133 OLocalExchange* OFilterExchangeHelper::createExchange() const
135 return new OFilterItemExchange;
139 TYPEINIT0(FmFilterData);
140 Image FmFilterData::GetImage() const
142 return Image();
146 TYPEINIT1(FmParentData, FmFilterData);
148 FmParentData::~FmParentData()
150 for (::std::vector<FmFilterData*>::const_iterator i = m_aChildren.begin();
151 i != m_aChildren.end(); ++i)
152 delete (*i);
156 TYPEINIT1(FmFormItem, FmParentData);
158 Image FmFormItem::GetImage() const
160 static Image aImage;
162 if (!aImage)
164 ImageList aNavigatorImages( SVX_RES( RID_SVXIMGLIST_FMEXPL ) );
165 aImage = aNavigatorImages.GetImage( RID_SVXIMG_FORM );
167 return aImage;
171 TYPEINIT1(FmFilterItems, FmParentData);
173 FmFilterItem* FmFilterItems::Find( const ::sal_Int32 _nFilterComponentIndex ) const
175 for ( ::std::vector< FmFilterData* >::const_iterator i = m_aChildren.begin();
176 i != m_aChildren.end();
180 FmFilterItem* pCondition = PTR_CAST( FmFilterItem, *i );
181 DBG_ASSERT( pCondition, "FmFilterItems::Find: Wrong element in container!" );
182 if ( _nFilterComponentIndex == pCondition->GetComponentIndex() )
183 return pCondition;
185 return NULL;
189 Image FmFilterItems::GetImage() const
191 static Image aImage;
193 if (!aImage)
195 ImageList aNavigatorImages( SVX_RES( RID_SVXIMGLIST_FMEXPL ) );
196 aImage = aNavigatorImages.GetImage( RID_SVXIMG_FILTER );
198 return aImage;
202 TYPEINIT1(FmFilterItem, FmFilterData);
204 FmFilterItem::FmFilterItem( FmFilterItems* pParent,
205 const OUString& aFieldName,
206 const OUString& aText,
207 const sal_Int32 _nComponentIndex )
208 :FmFilterData(pParent, aText)
209 ,m_aFieldName(aFieldName)
210 ,m_nComponentIndex( _nComponentIndex )
215 Image FmFilterItem::GetImage() const
217 static Image aImage;
219 if (!aImage)
221 ImageList aNavigatorImages( SVX_RES( RID_SVXIMGLIST_FMEXPL ) );
222 aImage = aNavigatorImages.GetImage( RID_SVXIMG_FIELD );
224 return aImage;
228 // Hints for communicatition between model and view
230 class FmFilterHint : public SfxHint
232 FmFilterData* m_pData;
234 public:
235 TYPEINFO_OVERRIDE();
236 FmFilterHint(FmFilterData* pData):m_pData(pData){}
237 FmFilterData* GetData() const { return m_pData; }
239 TYPEINIT1( FmFilterHint, SfxHint );
242 class FmFilterInsertedHint : public FmFilterHint
244 sal_uLong m_nPos; // Position relative to the parent of the data
246 public:
247 TYPEINFO_OVERRIDE();
248 FmFilterInsertedHint(FmFilterData* pData, sal_uLong nRelPos)
249 :FmFilterHint(pData)
250 ,m_nPos(nRelPos){}
252 sal_uLong GetPos() const { return m_nPos; }
254 TYPEINIT1( FmFilterInsertedHint, FmFilterHint );
257 class FmFilterRemovedHint : public FmFilterHint
259 public:
260 TYPEINFO_OVERRIDE();
261 FmFilterRemovedHint(FmFilterData* pData)
262 :FmFilterHint(pData){}
265 TYPEINIT1( FmFilterRemovedHint, FmFilterHint );
268 class FmFilterTextChangedHint : public FmFilterHint
270 public:
271 TYPEINFO_OVERRIDE();
272 FmFilterTextChangedHint(FmFilterData* pData)
273 :FmFilterHint(pData){}
276 TYPEINIT1( FmFilterTextChangedHint, FmFilterHint );
279 class FilterClearingHint : public SfxHint
281 public:
282 TYPEINFO_OVERRIDE();
283 FilterClearingHint(){}
285 TYPEINIT1( FilterClearingHint, SfxHint );
288 class FmFilterCurrentChangedHint : public SfxHint
290 public:
291 TYPEINFO_OVERRIDE();
292 FmFilterCurrentChangedHint(){}
294 TYPEINIT1( FmFilterCurrentChangedHint, SfxHint );
297 // class FmFilterAdapter, Listener an den FilterControls
299 class FmFilterAdapter : public ::cppu::WeakImplHelper1< XFilterControllerListener >
301 FmFilterModel* m_pModel;
302 Reference< XIndexAccess > m_xControllers;
304 public:
305 FmFilterAdapter(FmFilterModel* pModel, const Reference< XIndexAccess >& xControllers);
307 // XEventListener
308 virtual void SAL_CALL disposing(const EventObject& Source) throw( RuntimeException, std::exception ) SAL_OVERRIDE;
310 // XFilterControllerListener
311 virtual void SAL_CALL predicateExpressionChanged( const FilterEvent& _Event ) throw (RuntimeException, std::exception) SAL_OVERRIDE;
312 virtual void SAL_CALL disjunctiveTermRemoved( const FilterEvent& _Event ) throw (RuntimeException, std::exception) SAL_OVERRIDE;
313 virtual void SAL_CALL disjunctiveTermAdded( const FilterEvent& _Event ) throw (RuntimeException, std::exception) SAL_OVERRIDE;
315 // helpers
316 void dispose() throw( RuntimeException );
318 void AddOrRemoveListener( const Reference< XIndexAccess >& _rxControllers, const bool _bAdd );
320 void setText(sal_Int32 nPos,
321 const FmFilterItem* pFilterItem,
322 const OUString& rText);
326 FmFilterAdapter::FmFilterAdapter(FmFilterModel* pModel, const Reference< XIndexAccess >& xControllers)
327 :m_pModel( pModel )
328 ,m_xControllers( xControllers )
330 AddOrRemoveListener( m_xControllers, true );
334 void FmFilterAdapter::dispose() throw( RuntimeException )
336 AddOrRemoveListener( m_xControllers, false );
340 void FmFilterAdapter::AddOrRemoveListener( const Reference< XIndexAccess >& _rxControllers, const bool _bAdd )
342 for (sal_Int32 i = 0, nLen = _rxControllers->getCount(); i < nLen; ++i)
344 Reference< XIndexAccess > xElement( _rxControllers->getByIndex(i), UNO_QUERY );
346 // step down
347 AddOrRemoveListener( xElement, _bAdd );
349 // handle this particular controller
350 Reference< XFilterController > xController( xElement, UNO_QUERY );
351 OSL_ENSURE( xController.is(), "FmFilterAdapter::InsertElements: no XFilterController, cannot sync data!" );
352 if ( xController.is() )
354 if ( _bAdd )
355 xController->addFilterControllerListener( this );
356 else
357 xController->removeFilterControllerListener( this );
363 void FmFilterAdapter::setText(sal_Int32 nRowPos,
364 const FmFilterItem* pFilterItem,
365 const OUString& rText)
367 FmFormItem* pFormItem = PTR_CAST( FmFormItem, pFilterItem->GetParent()->GetParent() );
371 Reference< XFilterController > xController( pFormItem->GetController(), UNO_QUERY_THROW );
372 xController->setPredicateExpression( pFilterItem->GetComponentIndex(), nRowPos, rText );
374 catch( const Exception& )
376 DBG_UNHANDLED_EXCEPTION();
381 // XEventListener
383 void SAL_CALL FmFilterAdapter::disposing(const EventObject& /*e*/) throw( RuntimeException, std::exception )
388 namespace
390 OUString lcl_getLabelName_nothrow( const Reference< XControl >& _rxControl )
392 OUString sLabelName;
395 Reference< XPropertySet > xModel( _rxControl->getModel(), UNO_QUERY_THROW );
396 sLabelName = getLabelName( xModel );
398 catch( const Exception& )
400 DBG_UNHANDLED_EXCEPTION();
402 return sLabelName;
405 Reference< XPropertySet > lcl_getBoundField_nothrow( const Reference< XControl >& _rxControl )
407 Reference< XPropertySet > xField;
410 Reference< XPropertySet > xModelProps( _rxControl->getModel(), UNO_QUERY_THROW );
411 xField.set( xModelProps->getPropertyValue( FM_PROP_BOUNDFIELD ), UNO_QUERY_THROW );
413 catch( const Exception& )
415 DBG_UNHANDLED_EXCEPTION();
417 return xField;
421 // XFilterControllerListener
423 void FmFilterAdapter::predicateExpressionChanged( const FilterEvent& _Event ) throw( RuntimeException, std::exception )
425 SolarMutexGuard aGuard;
427 if ( !m_pModel )
428 return;
430 // the controller which sent the event
431 Reference< XFormController > xController( _Event.Source, UNO_QUERY_THROW );
432 Reference< XFilterController > xFilterController( _Event.Source, UNO_QUERY_THROW );
433 Reference< XForm > xForm( xController->getModel(), UNO_QUERY_THROW );
435 FmFormItem* pFormItem = m_pModel->Find( m_pModel->m_aChildren, xForm );
436 OSL_ENSURE( pFormItem, "FmFilterAdapter::predicateExpressionChanged: don't know this form!" );
437 if ( !pFormItem )
438 return;
440 const sal_Int32 nActiveTerm( xFilterController->getActiveTerm() );
442 FmFilterItems* pFilter = PTR_CAST( FmFilterItems, pFormItem->GetChildren()[ nActiveTerm ] );
443 FmFilterItem* pFilterItem = pFilter->Find( _Event.FilterComponent );
444 if ( pFilterItem )
446 if ( !_Event.PredicateExpression.isEmpty())
448 pFilterItem->SetText( _Event.PredicateExpression );
449 // UI benachrichtigen
450 FmFilterTextChangedHint aChangeHint(pFilterItem);
451 m_pModel->Broadcast( aChangeHint );
453 else
455 // no text anymore so remove the condition
456 m_pModel->Remove(pFilterItem);
459 else
461 // searching the component by field name
462 OUString aFieldName( lcl_getLabelName_nothrow( xFilterController->getFilterComponent( _Event.FilterComponent ) ) );
464 pFilterItem = new FmFilterItem( pFilter, aFieldName, _Event.PredicateExpression, _Event.FilterComponent );
465 m_pModel->Insert(pFilter->GetChildren().end(), pFilterItem);
468 // ensure there's one empty term in the filter, just in case the active term was previously empty
469 m_pModel->EnsureEmptyFilterRows( *pFormItem );
473 void SAL_CALL FmFilterAdapter::disjunctiveTermRemoved( const FilterEvent& _Event ) throw (RuntimeException, std::exception)
475 SolarMutexGuard aGuard;
477 Reference< XFormController > xController( _Event.Source, UNO_QUERY_THROW );
478 Reference< XFilterController > xFilterController( _Event.Source, UNO_QUERY_THROW );
479 Reference< XForm > xForm( xController->getModel(), UNO_QUERY_THROW );
481 FmFormItem* pFormItem = m_pModel->Find( m_pModel->m_aChildren, xForm );
482 OSL_ENSURE( pFormItem, "FmFilterAdapter::disjunctiveTermRemoved: don't know this form!" );
483 if ( !pFormItem )
484 return;
486 ::std::vector< FmFilterData* >& rTermItems = pFormItem->GetChildren();
487 const bool bValidIndex = ( _Event.DisjunctiveTerm >= 0 ) && ( (size_t)_Event.DisjunctiveTerm < rTermItems.size() );
488 OSL_ENSURE( bValidIndex, "FmFilterAdapter::disjunctiveTermRemoved: invalid term index!" );
489 if ( !bValidIndex )
490 return;
492 // if the first term was removed, then the to-be first term needs its text updated
493 if ( _Event.DisjunctiveTerm == 0 )
495 rTermItems[1]->SetText( SVX_RESSTR(RID_STR_FILTER_FILTER_FOR));
496 FmFilterTextChangedHint aChangeHint( rTermItems[1] );
497 m_pModel->Broadcast( aChangeHint );
500 // finally remove the entry from the model
501 m_pModel->Remove( rTermItems.begin() + _Event.DisjunctiveTerm );
503 // ensure there's one empty term in the filter, just in case the currently removed one was the last empty one
504 m_pModel->EnsureEmptyFilterRows( *pFormItem );
508 void SAL_CALL FmFilterAdapter::disjunctiveTermAdded( const FilterEvent& _Event ) throw (RuntimeException, std::exception)
510 SolarMutexGuard aGuard;
512 Reference< XFormController > xController( _Event.Source, UNO_QUERY_THROW );
513 Reference< XFilterController > xFilterController( _Event.Source, UNO_QUERY_THROW );
514 Reference< XForm > xForm( xController->getModel(), UNO_QUERY_THROW );
516 FmFormItem* pFormItem = m_pModel->Find( m_pModel->m_aChildren, xForm );
517 OSL_ENSURE( pFormItem, "FmFilterAdapter::disjunctiveTermAdded: don't know this form!" );
518 if ( !pFormItem )
519 return;
521 const sal_Int32 nInsertPos = _Event.DisjunctiveTerm;
522 bool bValidIndex = ( nInsertPos >= 0 ) && ( (size_t)nInsertPos <= pFormItem->GetChildren().size() );
523 if ( !bValidIndex )
525 OSL_FAIL( "FmFilterAdapter::disjunctiveTermAdded: invalid index!" );
526 return;
529 const ::std::vector< FmFilterData* >::iterator insertPos = pFormItem->GetChildren().begin() + nInsertPos;
531 FmFilterItems* pFilterItems = new FmFilterItems(pFormItem, SVX_RESSTR(RID_STR_FILTER_FILTER_OR));
532 m_pModel->Insert( insertPos, pFilterItems );
535 TYPEINIT1(FmFilterModel, FmParentData);
537 FmFilterModel::FmFilterModel()
538 :FmParentData(NULL, OUString())
539 ,OSQLParserClient(comphelper::getProcessComponentContext())
540 ,m_pAdapter(NULL)
541 ,m_pCurrentItems(NULL)
546 FmFilterModel::~FmFilterModel()
548 Clear();
552 void FmFilterModel::Clear()
554 // notify
555 FilterClearingHint aClearedHint;
556 Broadcast( aClearedHint );
558 // lose endings
559 if (m_pAdapter)
561 m_pAdapter->dispose();
562 m_pAdapter->release();
563 m_pAdapter= NULL;
566 m_pCurrentItems = NULL;
567 m_xController = NULL;
568 m_xControllers = NULL;
570 for (::std::vector<FmFilterData*>::const_iterator i = m_aChildren.begin();
571 i != m_aChildren.end(); ++i)
572 delete (*i);
574 m_aChildren.clear();
578 void FmFilterModel::Update(const Reference< XIndexAccess > & xControllers, const Reference< XFormController > & xCurrent)
580 if ( xCurrent == m_xController )
581 return;
583 if (!xControllers.is())
585 Clear();
586 return;
589 // there is only a new current controller
590 if ( m_xControllers != xControllers )
592 Clear();
594 m_xControllers = xControllers;
595 Update(m_xControllers, this);
597 DBG_ASSERT(xCurrent.is(), "FmFilterModel::Update(...) no current controller");
599 // Listening for TextChanges
600 m_pAdapter = new FmFilterAdapter(this, xControllers);
601 m_pAdapter->acquire();
603 SetCurrentController(xCurrent);
604 EnsureEmptyFilterRows( *this );
606 else
607 SetCurrentController(xCurrent);
611 void FmFilterModel::Update(const Reference< XIndexAccess > & xControllers, FmParentData* pParent)
615 sal_Int32 nCount = xControllers->getCount();
616 for ( sal_Int32 i = 0; i < nCount; ++i )
618 Reference< XFormController > xController( xControllers->getByIndex(i), UNO_QUERY_THROW );
620 Reference< XPropertySet > xFormProperties( xController->getModel(), UNO_QUERY_THROW );
621 OUString aName;
622 OSL_VERIFY( xFormProperties->getPropertyValue( FM_PROP_NAME ) >>= aName );
624 // Insert a new item for the form
625 FmFormItem* pFormItem = new FmFormItem( pParent, xController, aName );
626 Insert( pParent->GetChildren().end(), pFormItem );
628 Reference< XFilterController > xFilterController( pFormItem->GetFilterController(), UNO_SET_THROW );
630 // insert the existing filters for the form
631 OUString aTitle(SVX_RESSTR(RID_STR_FILTER_FILTER_FOR));
633 Sequence< Sequence< OUString > > aExpressions = xFilterController->getPredicateExpressions();
634 for ( const Sequence< OUString >* pConjunctionTerm = aExpressions.getConstArray();
635 pConjunctionTerm != aExpressions.getConstArray() + aExpressions.getLength();
636 ++pConjunctionTerm
639 // we always display one row, even if there's no term to be displayed
640 FmFilterItems* pFilterItems = new FmFilterItems( pFormItem, aTitle );
641 Insert( pFormItem->GetChildren().end(), pFilterItems );
643 const Sequence< OUString >& rDisjunction( *pConjunctionTerm );
644 for ( const OUString* pDisjunctiveTerm = rDisjunction.getConstArray();
645 pDisjunctiveTerm != rDisjunction.getConstArray() + rDisjunction.getLength();
646 ++pDisjunctiveTerm
649 if ( pDisjunctiveTerm->isEmpty() )
650 // no condition for this particular component in this particular conjunction term
651 continue;
653 const sal_Int32 nComponentIndex = pDisjunctiveTerm - rDisjunction.getConstArray();
655 // determine the display name of the control
656 const Reference< XControl > xFilterControl( xFilterController->getFilterComponent( nComponentIndex ) );
657 const OUString sDisplayName( lcl_getLabelName_nothrow( xFilterControl ) );
659 // insert a new entry
660 FmFilterItem* pANDCondition = new FmFilterItem( pFilterItems, sDisplayName, *pDisjunctiveTerm, nComponentIndex );
661 Insert( pFilterItems->GetChildren().end(), pANDCondition );
664 // title for the next conditions
665 aTitle = SVX_RESSTR( RID_STR_FILTER_FILTER_OR );
668 // now add dependent controllers
669 Update( xController, pFormItem );
672 catch( const Exception& )
674 DBG_UNHANDLED_EXCEPTION();
679 FmFormItem* FmFilterModel::Find(const ::std::vector<FmFilterData*>& rItems, const Reference< XFormController > & xController) const
681 for (::std::vector<FmFilterData*>::const_iterator i = rItems.begin();
682 i != rItems.end(); ++i)
684 FmFormItem* pForm = PTR_CAST(FmFormItem,*i);
685 if (pForm)
687 if ( xController == pForm->GetController() )
688 return pForm;
689 else
691 pForm = Find(pForm->GetChildren(), xController);
692 if (pForm)
693 return pForm;
697 return NULL;
701 FmFormItem* FmFilterModel::Find(const ::std::vector<FmFilterData*>& rItems, const Reference< XForm >& xForm) const
703 for (::std::vector<FmFilterData*>::const_iterator i = rItems.begin();
704 i != rItems.end(); ++i)
706 FmFormItem* pForm = PTR_CAST(FmFormItem,*i);
707 if (pForm)
709 if (xForm == pForm->GetController()->getModel())
710 return pForm;
711 else
713 pForm = Find(pForm->GetChildren(), xForm);
714 if (pForm)
715 return pForm;
719 return NULL;
723 void FmFilterModel::SetCurrentController(const Reference< XFormController > & xCurrent)
725 if ( xCurrent == m_xController )
726 return;
728 m_xController = xCurrent;
730 FmFormItem* pItem = Find( m_aChildren, xCurrent );
731 if ( !pItem )
732 return;
736 Reference< XFilterController > xFilterController( m_xController, UNO_QUERY_THROW );
737 const sal_Int32 nActiveTerm( xFilterController->getActiveTerm() );
738 if ( pItem->GetChildren().size() > (size_t)nActiveTerm )
740 SetCurrentItems( static_cast< FmFilterItems* >( pItem->GetChildren()[ nActiveTerm ] ) );
743 catch( const Exception& )
745 DBG_UNHANDLED_EXCEPTION();
750 void FmFilterModel::AppendFilterItems( FmFormItem& _rFormItem )
752 // insert the condition behind the last filter items
753 ::std::vector<FmFilterData*>::reverse_iterator iter;
754 for ( iter = _rFormItem.GetChildren().rbegin();
755 iter != _rFormItem.GetChildren().rend();
756 ++iter
759 if ((*iter)->ISA(FmFilterItems))
760 break;
763 sal_Int32 nInsertPos = iter.base() - _rFormItem.GetChildren().begin();
764 // delegate this to the FilterController, it will notify us, which will let us update our model
767 Reference< XFilterController > xFilterController( _rFormItem.GetFilterController(), UNO_SET_THROW );
768 if ( nInsertPos >= xFilterController->getDisjunctiveTerms() )
769 xFilterController->appendEmptyDisjunctiveTerm();
771 catch( const Exception& )
773 DBG_UNHANDLED_EXCEPTION();
778 void FmFilterModel::Insert(const ::std::vector<FmFilterData*>::iterator& rPos, FmFilterData* pData)
780 ::std::vector<FmFilterData*>& rItems = pData->GetParent()->GetChildren();
781 sal_uLong nPos = rPos == rItems.end() ? CONTAINER_APPEND : rPos - rItems.begin();
782 if (nPos == CONTAINER_APPEND)
784 rItems.push_back(pData);
785 nPos = rItems.size() - 1;
787 else
789 rItems.insert(rPos, pData);
792 // UI benachrichtigen
793 FmFilterInsertedHint aInsertedHint(pData, nPos);
794 Broadcast( aInsertedHint );
798 void FmFilterModel::Remove(FmFilterData* pData)
800 FmParentData* pParent = pData->GetParent();
801 ::std::vector<FmFilterData*>& rItems = pParent->GetChildren();
803 // erase the item from the model
804 ::std::vector<FmFilterData*>::iterator i = ::std::find(rItems.begin(), rItems.end(), pData);
805 DBG_ASSERT(i != rItems.end(), "FmFilterModel::Remove(): unknown Item");
806 // position within the parent
807 sal_Int32 nPos = i - rItems.begin();
808 if (pData->ISA(FmFilterItems))
810 FmFormItem* pFormItem = (FmFormItem*)pParent;
814 Reference< XFilterController > xFilterController( pFormItem->GetFilterController(), UNO_SET_THROW );
816 bool bEmptyLastTerm = ( ( nPos == 0 ) && xFilterController->getDisjunctiveTerms() == 1 );
817 if ( bEmptyLastTerm )
819 // remove all children (by setting an empty predicate expression)
820 ::std::vector< FmFilterData* >& rChildren = ((FmFilterItems*)pData)->GetChildren();
821 while ( !rChildren.empty() )
823 ::std::vector< FmFilterData* >::iterator removePos = rChildren.end() - 1;
824 FmFilterItem* pFilterItem = PTR_CAST( FmFilterItem, *removePos );
825 m_pAdapter->setText( nPos, pFilterItem, OUString() );
826 Remove( removePos );
829 else
831 xFilterController->removeDisjunctiveTerm( nPos );
834 catch( const Exception& )
836 DBG_UNHANDLED_EXCEPTION();
839 else // FormItems can not be deleted
841 FmFilterItem* pFilterItem = PTR_CAST(FmFilterItem, pData);
843 // if its the last condition remove the parent
844 if (rItems.size() == 1)
845 Remove(pFilterItem->GetParent());
846 else
848 // find the position of the father within his father
849 ::std::vector<FmFilterData*>& rParentParentItems = pData->GetParent()->GetParent()->GetChildren();
850 ::std::vector<FmFilterData*>::iterator j = ::std::find(rParentParentItems.begin(), rParentParentItems.end(), pFilterItem->GetParent());
851 DBG_ASSERT(j != rParentParentItems.end(), "FmFilterModel::Remove(): unknown Item");
852 sal_Int32 nParentPos = j - rParentParentItems.begin();
854 // EmptyText removes the filter
855 m_pAdapter->setText(nParentPos, pFilterItem, OUString());
856 Remove( i );
862 void FmFilterModel::Remove( const ::std::vector<FmFilterData*>::iterator& rPos )
864 // remove from parent's child list
865 FmFilterData* pData = *rPos;
866 pData->GetParent()->GetChildren().erase( rPos );
868 // notify the view, this will remove the actual SvTreeListEntry
869 FmFilterRemovedHint aRemoveHint( pData );
870 Broadcast( aRemoveHint );
872 delete pData;
876 bool FmFilterModel::ValidateText(FmFilterItem* pItem, OUString& rText, OUString& rErrorMsg) const
878 FmFormItem* pFormItem = PTR_CAST( FmFormItem, pItem->GetParent()->GetParent() );
881 Reference< XFormController > xFormController( pFormItem->GetController() );
882 // obtain the connection of the form belonging to the controller
883 OStaticDataAccessTools aStaticTools;
884 Reference< XRowSet > xRowSet( xFormController->getModel(), UNO_QUERY_THROW );
885 Reference< XConnection > xConnection( aStaticTools.getRowSetConnection( xRowSet ) );
887 // obtain a number formatter for this connection
888 // TODO: shouldn't this be cached?
889 Reference< XNumberFormatsSupplier > xFormatSupplier = aStaticTools.getNumberFormats( xConnection, true );
890 Reference< XNumberFormatter > xFormatter( NumberFormatter::create( comphelper::getProcessComponentContext() ), UNO_QUERY_THROW );
891 xFormatter->attachNumberFormatsSupplier( xFormatSupplier );
893 // get the field (database column) which the item is responsible for
894 Reference< XFilterController > xFilterController( xFormController, UNO_QUERY_THROW );
895 Reference< XPropertySet > xField( lcl_getBoundField_nothrow( xFilterController->getFilterComponent( pItem->GetComponentIndex() ) ), UNO_SET_THROW );
897 // parse the given text as filter predicate
898 OUString aErr, aTxt( rText );
899 ::rtl::Reference< ISQLParseNode > xParseNode = predicateTree( aErr, aTxt, xFormatter, xField );
900 rErrorMsg = aErr;
901 rText = aTxt;
902 if ( xParseNode.is() )
904 OUString aPreparedText;
905 Locale aAppLocale = Application::GetSettings().GetUILanguageTag().getLocale();
906 xParseNode->parseNodeToPredicateStr(
907 aPreparedText, xConnection, xFormatter, xField, OUString(), aAppLocale, '.', getParseContext() );
908 rText = aPreparedText;
909 return true;
912 catch( const Exception& )
914 DBG_UNHANDLED_EXCEPTION();
917 return false;
921 void FmFilterModel::Append(FmFilterItems* pItems, FmFilterItem* pFilterItem)
923 Insert(pItems->GetChildren().end(), pFilterItem);
927 void FmFilterModel::SetTextForItem(FmFilterItem* pItem, const OUString& rText)
929 ::std::vector<FmFilterData*>& rItems = pItem->GetParent()->GetParent()->GetChildren();
930 ::std::vector<FmFilterData*>::iterator i = ::std::find(rItems.begin(), rItems.end(), pItem->GetParent());
931 sal_Int32 nParentPos = i - rItems.begin();
933 m_pAdapter->setText(nParentPos, pItem, rText);
935 if (rText.isEmpty())
936 Remove(pItem);
937 else
939 // Change the text
940 pItem->SetText(rText);
941 FmFilterTextChangedHint aChangeHint(pItem);
942 Broadcast( aChangeHint );
947 void FmFilterModel::SetCurrentItems(FmFilterItems* pCurrent)
949 if (m_pCurrentItems == pCurrent)
950 return;
952 // search for the condition
953 if (pCurrent)
955 FmFormItem* pFormItem = (FmFormItem*)pCurrent->GetParent();
956 ::std::vector<FmFilterData*>& rItems = pFormItem->GetChildren();
957 ::std::vector<FmFilterData*>::const_iterator i = ::std::find(rItems.begin(), rItems.end(), pCurrent);
959 if (i != rItems.end())
961 // determine the filter position
962 sal_Int32 nPos = i - rItems.begin();
965 Reference< XFilterController > xFilterController( pFormItem->GetFilterController(), UNO_SET_THROW );
966 xFilterController->setActiveTerm( nPos );
968 catch( const Exception& )
970 DBG_UNHANDLED_EXCEPTION();
973 if ( m_xController != pFormItem->GetController() )
974 // calls SetCurrentItems again
975 SetCurrentController( pFormItem->GetController() );
976 else
977 m_pCurrentItems = pCurrent;
979 else
980 m_pCurrentItems = NULL;
982 else
983 m_pCurrentItems = NULL;
986 // UI benachrichtigen
987 FmFilterCurrentChangedHint aHint;
988 Broadcast( aHint );
992 void FmFilterModel::EnsureEmptyFilterRows( FmParentData& _rItem )
994 // checks whether for each form there's one free level for input
995 ::std::vector< FmFilterData* >& rChildren = _rItem.GetChildren();
996 bool bAppendLevel = _rItem.ISA( FmFormItem );
998 for ( ::std::vector<FmFilterData*>::iterator i = rChildren.begin();
999 i != rChildren.end();
1003 FmFilterItems* pItems = PTR_CAST(FmFilterItems, *i);
1004 if ( pItems && pItems->GetChildren().empty() )
1006 bAppendLevel = false;
1007 break;
1010 FmFormItem* pFormItem = PTR_CAST(FmFormItem, *i);
1011 if (pFormItem)
1013 EnsureEmptyFilterRows( *pFormItem );
1014 continue;
1018 if ( bAppendLevel )
1020 FmFormItem* pFormItem = PTR_CAST( FmFormItem, &_rItem );
1021 OSL_ENSURE( pFormItem, "FmFilterModel::EnsureEmptyFilterRows: no FmFormItem, but a FmFilterItems child?" );
1022 if ( pFormItem )
1023 AppendFilterItems( *pFormItem );
1028 // class FmFilterItemsString
1030 class FmFilterItemsString : public SvLBoxString
1032 public:
1033 FmFilterItemsString( SvTreeListEntry* pEntry, sal_uInt16 nFlags, const OUString& rStr )
1034 :SvLBoxString(pEntry,nFlags,rStr){}
1036 virtual void Paint(const Point& rPos, SvTreeListBox& rDev, const SvViewDataEntry* pView, const SvTreeListEntry* pEntry) SAL_OVERRIDE;
1037 virtual void InitViewData( SvTreeListBox* pView,SvTreeListEntry* pEntry, SvViewDataItem* pViewData) SAL_OVERRIDE;
1040 const int nxDBmp = 12;
1042 void FmFilterItemsString::Paint(
1043 const Point& rPos, SvTreeListBox& rDev, const SvViewDataEntry* /*pView*/, const SvTreeListEntry* pEntry)
1045 FmFilterItems* pRow = (FmFilterItems*)pEntry->GetUserData();
1046 FmFormItem* pForm = (FmFormItem*)pRow->GetParent();
1048 // current filter is significant painted
1049 const bool bIsCurrentFilter = pForm->GetChildren()[ pForm->GetFilterController()->getActiveTerm() ] == pRow;
1050 if ( bIsCurrentFilter )
1052 rDev.Push( PUSH_LINECOLOR );
1054 rDev.SetLineColor( rDev.GetTextColor() );
1056 Rectangle aRect( rPos, GetSize( &rDev, pEntry ) );
1057 Point aFirst( rPos.X(), aRect.Bottom() - 6 );
1058 Point aSecond(aFirst .X() + 2, aFirst.Y() + 3 );
1060 rDev.DrawLine( aFirst, aSecond );
1062 aFirst = aSecond;
1063 aFirst.X() += 1;
1064 aSecond.X() += 6;
1065 aSecond.Y() -= 5;
1067 rDev.DrawLine( aFirst, aSecond );
1069 rDev.Pop();
1072 rDev.DrawText( Point(rPos.X() + nxDBmp, rPos.Y()), GetText() );
1076 void FmFilterItemsString::InitViewData( SvTreeListBox* pView,SvTreeListEntry* pEntry, SvViewDataItem* pViewData)
1078 if( !pViewData )
1079 pViewData = pView->GetViewDataItem( pEntry, this );
1081 Size aSize(pView->GetTextWidth(GetText()), pView->GetTextHeight());
1082 aSize.Width() += nxDBmp;
1083 pViewData->maSize = aSize;
1087 // class FmFilterString
1089 class FmFilterString : public SvLBoxString
1091 OUString m_aName;
1093 public:
1094 FmFilterString( SvTreeListEntry* pEntry, sal_uInt16 nFlags, const OUString& rStr, const OUString& aName)
1095 :SvLBoxString(pEntry,nFlags,rStr)
1096 ,m_aName(aName)
1098 m_aName += ": ";
1101 virtual void Paint(const Point& rPos, SvTreeListBox& rDev, const SvViewDataEntry* pView, const SvTreeListEntry* pEntry) SAL_OVERRIDE;
1102 virtual void InitViewData( SvTreeListBox* pView,SvTreeListEntry* pEntry, SvViewDataItem* pViewData) SAL_OVERRIDE;
1105 const int nxD = 4;
1108 void FmFilterString::InitViewData( SvTreeListBox* pView,SvTreeListEntry* pEntry, SvViewDataItem* pViewData)
1110 if( !pViewData )
1111 pViewData = pView->GetViewDataItem( pEntry, this );
1113 Font aOldFont( pView->GetFont());
1114 Font aFont( aOldFont );
1115 aFont.SetWeight(WEIGHT_BOLD);
1116 pView->Control::SetFont( aFont );
1118 Size aSize(pView->GetTextWidth(m_aName), pView->GetTextHeight());
1119 pView->Control::SetFont( aOldFont );
1120 aSize.Width() += pView->GetTextWidth(GetText()) + nxD;
1121 pViewData->maSize = aSize;
1125 void FmFilterString::Paint(
1126 const Point& rPos, SvTreeListBox& rDev, const SvViewDataEntry* /*pView*/, const SvTreeListEntry* /*pEntry*/)
1128 Font aOldFont( rDev.GetFont());
1129 Font aFont( aOldFont );
1130 aFont.SetWeight(WEIGHT_BOLD);
1131 rDev.SetFont( aFont );
1133 Point aPos(rPos);
1134 rDev.DrawText( aPos, m_aName );
1136 // position for the second text
1137 aPos.X() += rDev.GetTextWidth(m_aName) + nxD;
1138 rDev.SetFont( aOldFont );
1139 rDev.DrawText( aPos, GetText() );
1143 // class FmFilterNavigator
1145 FmFilterNavigator::FmFilterNavigator( Window* pParent )
1146 :SvTreeListBox( pParent, WB_HASBUTTONS|WB_HASLINES|WB_BORDER|WB_HASBUTTONSATROOT )
1147 ,m_pModel( NULL )
1148 ,m_pEditingCurrently( NULL )
1149 ,m_aControlExchange( this )
1150 ,m_aTimerCounter( 0 )
1151 ,m_aDropActionType( DA_SCROLLUP )
1153 SetHelpId( HID_FILTER_NAVIGATOR );
1156 ImageList aNavigatorImages( SVX_RES( RID_SVXIMGLIST_FMEXPL ) );
1157 SetNodeBitmaps(
1158 aNavigatorImages.GetImage( RID_SVXIMG_COLLAPSEDNODE ),
1159 aNavigatorImages.GetImage( RID_SVXIMG_EXPANDEDNODE )
1163 m_pModel = new FmFilterModel();
1164 StartListening( *m_pModel );
1166 EnableInplaceEditing( true );
1167 SetSelectionMode(MULTIPLE_SELECTION);
1169 SetDragDropMode(0xFFFF);
1171 m_aDropActionTimer.SetTimeoutHdl(LINK(this, FmFilterNavigator, OnDropActionTimer));
1175 FmFilterNavigator::~FmFilterNavigator()
1177 EndListening( *m_pModel );
1178 delete m_pModel;
1182 void FmFilterNavigator::UpdateContent(const Reference< XIndexAccess > & xControllers, const Reference< XFormController > & xCurrent)
1184 if (xCurrent == m_pModel->GetCurrentController())
1185 return;
1187 m_pModel->Update(xControllers, xCurrent);
1189 // expand the filters for the current controller
1190 SvTreeListEntry* pEntry = FindEntry(m_pModel->GetCurrentForm());
1191 if (pEntry && !IsExpanded(pEntry))
1193 SelectAll(false);
1195 if (!IsExpanded(pEntry))
1196 Expand(pEntry);
1198 pEntry = FindEntry(m_pModel->GetCurrentItems());
1199 if (pEntry)
1201 if (!IsExpanded(pEntry))
1202 Expand(pEntry);
1203 Select(pEntry, true);
1209 bool FmFilterNavigator::EditingEntry( SvTreeListEntry* pEntry, Selection& rSelection )
1211 m_pEditingCurrently = pEntry;
1212 if (!SvTreeListBox::EditingEntry( pEntry, rSelection ))
1213 return false;
1215 return pEntry && ((FmFilterData*)pEntry->GetUserData())->ISA(FmFilterItem);
1219 bool FmFilterNavigator::EditedEntry( SvTreeListEntry* pEntry, const OUString& rNewText )
1221 DBG_ASSERT(pEntry == m_pEditingCurrently, "FmFilterNavigator::EditedEntry: suspicious entry!");
1222 m_pEditingCurrently = NULL;
1224 if (EditingCanceled())
1225 return true;
1227 DBG_ASSERT(((FmFilterData*)pEntry->GetUserData())->ISA(FmFilterItem),
1228 "FmFilterNavigator::EditedEntry() wrong entry");
1230 OUString aText(comphelper::string::strip(rNewText, ' '));
1231 if (aText.isEmpty())
1233 // deleting the entry asynchron
1234 PostUserEvent(LINK(this, FmFilterNavigator, OnRemove), pEntry);
1236 else
1238 OUString aErrorMsg;
1240 if (m_pModel->ValidateText((FmFilterItem*)pEntry->GetUserData(), aText, aErrorMsg))
1242 GrabFocus();
1243 // this will set the text at the FmFilterItem, as well as update any filter controls
1244 // which are connected to this particular entry
1245 m_pModel->SetTextForItem( static_cast< FmFilterItem* >( pEntry->GetUserData() ), aText );
1247 SetCursor( pEntry, true );
1248 SetEntryText( pEntry, aText );
1250 else
1252 // display the error and return sal_False
1253 SQLContext aError;
1254 aError.Message = SVX_RESSTR(RID_STR_SYNTAXERROR);
1255 aError.Details = aErrorMsg;
1256 displayException(aError, this);
1258 return false;
1261 return true;
1265 IMPL_LINK( FmFilterNavigator, OnRemove, SvTreeListEntry*, pEntry )
1267 // now remove the entry
1268 m_pModel->Remove((FmFilterData*) pEntry->GetUserData());
1269 return 0L;
1273 IMPL_LINK_NOARG(FmFilterNavigator, OnDropActionTimer)
1275 if (--m_aTimerCounter > 0)
1276 return 0L;
1278 switch (m_aDropActionType)
1280 case DA_SCROLLUP :
1281 ScrollOutputArea(1);
1282 m_aTimerCounter = DROP_ACTION_TIMER_SCROLL_TICKS;
1283 break;
1284 case DA_SCROLLDOWN :
1285 ScrollOutputArea(-1);
1286 m_aTimerCounter = DROP_ACTION_TIMER_SCROLL_TICKS;
1287 break;
1288 case DA_EXPANDNODE:
1290 SvTreeListEntry* pToExpand = GetEntry(m_aTimerTriggered);
1291 if (pToExpand && (GetChildCount(pToExpand) > 0) && !IsExpanded(pToExpand))
1292 // tja, eigentlich muesste ich noch testen, ob die Node nicht schon expandiert ist, aber ich
1293 // habe dazu weder in den Basisklassen noch im Model eine Methode gefunden ...
1294 // aber ich denke, die BK sollte es auch so vertragen
1295 Expand(pToExpand);
1297 // nach dem Expand habe ich im Gegensatz zum Scrollen natuerlich nix mehr zu tun
1298 m_aDropActionTimer.Stop();
1300 break;
1302 return 0L;
1307 sal_Int8 FmFilterNavigator::AcceptDrop( const AcceptDropEvent& rEvt )
1309 Point aDropPos = rEvt.maPosPixel;
1311 // kuemmern wir uns erst mal um moeglich DropActions (Scrollen und Aufklappen)
1312 if (rEvt.mbLeaving)
1314 if (m_aDropActionTimer.IsActive())
1315 m_aDropActionTimer.Stop();
1317 else
1319 bool bNeedTrigger = false;
1320 // auf dem ersten Eintrag ?
1321 if ((aDropPos.Y() >= 0) && (aDropPos.Y() < GetEntryHeight()))
1323 m_aDropActionType = DA_SCROLLUP;
1324 bNeedTrigger = true;
1326 else
1328 // auf dem letzten (bzw. in dem Bereich, den ein Eintrag einnehmen wuerde, wenn er unten genau buendig
1329 // abschliessen wuerde) ?
1330 if ((aDropPos.Y() < GetSizePixel().Height()) && (aDropPos.Y() >= GetSizePixel().Height() - GetEntryHeight()))
1332 m_aDropActionType = DA_SCROLLDOWN;
1333 bNeedTrigger = true;
1335 else
1336 { // is it an entry with children, and not yet expanded?
1337 SvTreeListEntry* pDropppedOn = GetEntry(aDropPos);
1338 if (pDropppedOn && (GetChildCount(pDropppedOn) > 0) && !IsExpanded(pDropppedOn))
1340 // -> aufklappen
1341 m_aDropActionType = DA_EXPANDNODE;
1342 bNeedTrigger = true;
1346 if (bNeedTrigger && (m_aTimerTriggered != aDropPos))
1348 // neu anfangen zu zaehlen
1349 m_aTimerCounter = DROP_ACTION_TIMER_INITIAL_TICKS;
1350 // die Pos merken, da ich auch QueryDrops bekomme, wenn sich die Maus gar nicht bewegt hat
1351 m_aTimerTriggered = aDropPos;
1352 // und den Timer los
1353 if (!m_aDropActionTimer.IsActive()) // gibt es den Timer schon ?
1355 m_aDropActionTimer.SetTimeout(DROP_ACTION_TIMER_TICK_BASE);
1356 m_aDropActionTimer.Start();
1359 else if (!bNeedTrigger)
1360 m_aDropActionTimer.Stop();
1364 // Hat das Object das richtige Format?
1365 if (!m_aControlExchange.isDragSource())
1366 return DND_ACTION_NONE;
1368 if (!m_aControlExchange->hasFormat(GetDataFlavorExVector()))
1369 return DND_ACTION_NONE;
1371 // do we conain the formitem?
1372 if (!FindEntry(m_aControlExchange->getFormItem()))
1373 return DND_ACTION_NONE;
1375 SvTreeListEntry* pDropTarget = GetEntry(aDropPos);
1376 if (!pDropTarget)
1377 return DND_ACTION_NONE;
1379 FmFilterData* pData = (FmFilterData*)pDropTarget->GetUserData();
1380 FmFormItem* pForm = NULL;
1381 if (pData->ISA(FmFilterItem))
1383 pForm = PTR_CAST(FmFormItem,pData->GetParent()->GetParent());
1384 if (pForm != m_aControlExchange->getFormItem())
1385 return DND_ACTION_NONE;
1387 else if (pData->ISA(FmFilterItems))
1389 pForm = PTR_CAST(FmFormItem,pData->GetParent());
1390 if (pForm != m_aControlExchange->getFormItem())
1391 return DND_ACTION_NONE;
1393 else
1394 return DND_ACTION_NONE;
1396 return rEvt.mnAction;
1399 namespace
1401 FmFilterItems* getTargetItems(SvTreeListEntry* _pTarget)
1403 FmFilterData* pData = static_cast<FmFilterData*>(_pTarget->GetUserData());
1404 FmFilterItems* pTargetItems = dynamic_cast<FmFilterItems*>(pData);
1405 if (!pTargetItems)
1406 pTargetItems = dynamic_cast<FmFilterItems*>(pData->GetParent());
1407 return pTargetItems;
1411 sal_Int8 FmFilterNavigator::ExecuteDrop( const ExecuteDropEvent& rEvt )
1413 // ware schlecht, wenn nach dem Droppen noch gescrollt wird ...
1414 if (m_aDropActionTimer.IsActive())
1415 m_aDropActionTimer.Stop();
1417 // Format-Ueberpruefung
1418 if (!m_aControlExchange.isDragSource())
1419 return DND_ACTION_NONE;
1421 // das Ziel des Drop sowie einige Daten darueber
1422 Point aDropPos = rEvt.maPosPixel;
1423 SvTreeListEntry* pDropTarget = GetEntry( aDropPos );
1424 if (!pDropTarget)
1425 return DND_ACTION_NONE;
1427 // search the container where to add the items
1428 FmFilterItems* pTargetItems = getTargetItems(pDropTarget);
1429 SelectAll(false);
1430 SvTreeListEntry* pEntry = FindEntry(pTargetItems);
1431 Select(pEntry, true);
1432 SetCurEntry(pEntry);
1434 insertFilterItem(m_aControlExchange->getDraggedEntries(),pTargetItems,DND_ACTION_COPY == rEvt.mnAction);
1436 return sal_True;
1440 void FmFilterNavigator::InitEntry(SvTreeListEntry* pEntry,
1441 const OUString& rStr,
1442 const Image& rImg1,
1443 const Image& rImg2,
1444 SvLBoxButtonKind eButtonKind)
1446 SvTreeListBox::InitEntry( pEntry, rStr, rImg1, rImg2, eButtonKind );
1447 SvLBoxString* pString = NULL;
1449 if (((FmFilterData*)pEntry->GetUserData())->ISA(FmFilterItem))
1450 pString = new FmFilterString(pEntry, 0, rStr, ((FmFilterItem*)pEntry->GetUserData())->GetFieldName());
1451 else if (((FmFilterData*)pEntry->GetUserData())->ISA(FmFilterItems))
1452 pString = new FmFilterItemsString(pEntry, 0, rStr );
1454 if (pString)
1455 pEntry->ReplaceItem( pString, 1 );
1459 bool FmFilterNavigator::Select( SvTreeListEntry* pEntry, bool bSelect )
1461 if (bSelect == IsSelected(pEntry)) // das passiert manchmal, ich glaube, die Basisklasse geht zu sehr auf Nummer sicher ;)
1462 return true;
1464 if (SvTreeListBox::Select(pEntry, bSelect))
1466 if (bSelect)
1468 FmFormItem* pFormItem = NULL;
1469 if (((FmFilterData*)pEntry->GetUserData())->ISA(FmFilterItem))
1470 pFormItem = (FmFormItem*)((FmFilterItem*)pEntry->GetUserData())->GetParent()->GetParent();
1471 else if (((FmFilterData*)pEntry->GetUserData())->ISA(FmFilterItems))
1472 pFormItem = (FmFormItem*)((FmFilterItem*)pEntry->GetUserData())->GetParent()->GetParent();
1473 else if (((FmFilterData*)pEntry->GetUserData())->ISA(FmFormItem))
1474 pFormItem = (FmFormItem*)pEntry->GetUserData();
1476 if (pFormItem)
1478 // will the controller be exchanged?
1479 if (((FmFilterData*)pEntry->GetUserData())->ISA(FmFilterItem))
1480 m_pModel->SetCurrentItems((FmFilterItems*)((FmFilterItem*)pEntry->GetUserData())->GetParent());
1481 else if (((FmFilterData*)pEntry->GetUserData())->ISA(FmFilterItems))
1482 m_pModel->SetCurrentItems((FmFilterItems*)pEntry->GetUserData());
1483 else if (((FmFilterData*)pEntry->GetUserData())->ISA(FmFormItem))
1484 m_pModel->SetCurrentController(((FmFormItem*)pEntry->GetUserData())->GetController());
1487 return true;
1489 else
1490 return false;
1494 void FmFilterNavigator::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
1496 if (rHint.ISA(FmFilterInsertedHint))
1498 FmFilterInsertedHint* pHint = (FmFilterInsertedHint*)&rHint;
1499 Insert(pHint->GetData(), pHint->GetPos());
1501 else if( rHint.ISA(FilterClearingHint) )
1503 SvTreeListBox::Clear();
1505 else if( rHint.ISA(FmFilterRemovedHint) )
1507 FmFilterRemovedHint* pHint = (FmFilterRemovedHint*)&rHint;
1508 Remove(pHint->GetData());
1510 else if( rHint.ISA(FmFilterTextChangedHint) )
1512 FmFilterTextChangedHint* pHint = (FmFilterTextChangedHint*)&rHint;
1513 SvTreeListEntry* pEntry = FindEntry(pHint->GetData());
1514 if (pEntry)
1515 SetEntryText( pEntry, pHint->GetData()->GetText());
1517 else if( rHint.ISA(FmFilterCurrentChangedHint) )
1519 // invalidate the entries
1520 for (SvTreeListEntry* pEntry = First(); pEntry != NULL;
1521 pEntry = Next(pEntry))
1522 GetModel()->InvalidateEntry( pEntry );
1527 SvTreeListEntry* FmFilterNavigator::FindEntry(const FmFilterData* pItem) const
1529 SvTreeListEntry* pEntry = NULL;
1530 if (pItem)
1532 for (pEntry = First(); pEntry != NULL; pEntry = Next( pEntry ))
1534 FmFilterData* pEntryItem = (FmFilterData*)pEntry->GetUserData();
1535 if (pEntryItem == pItem)
1536 break;
1539 return pEntry;
1543 void FmFilterNavigator::Insert(FmFilterData* pItem, sal_uLong nPos)
1545 const FmParentData* pParent = pItem->GetParent() ? pItem->GetParent() : GetFilterModel();
1547 // insert the item
1548 SvTreeListEntry* pParentEntry = FindEntry( pParent );
1549 InsertEntry( pItem->GetText(), pItem->GetImage(), pItem->GetImage(), pParentEntry, false, nPos, pItem );
1550 if ( pParentEntry )
1551 Expand( pParentEntry );
1555 void FmFilterNavigator::Remove(FmFilterData* pItem)
1557 // der Entry zu den Daten
1558 SvTreeListEntry* pEntry = FindEntry(pItem);
1560 if (pEntry == m_pEditingCurrently)
1561 // cancel editing
1562 EndEditing(true);
1564 if (pEntry)
1565 GetModel()->Remove( pEntry );
1568 FmFormItem* FmFilterNavigator::getSelectedFilterItems(::std::vector<FmFilterItem*>& _rItemList)
1570 // be sure that the data is only used within only one form!
1571 FmFormItem* pFirstItem = NULL;
1573 bool bHandled = true;
1574 bool bFoundSomething = false;
1575 for (SvTreeListEntry* pEntry = FirstSelected();
1576 bHandled && pEntry != NULL;
1577 pEntry = NextSelected(pEntry))
1579 FmFilterItem* pFilter = PTR_CAST(FmFilterItem, (FmFilterData*)pEntry->GetUserData());
1580 if (pFilter)
1582 FmFormItem* pForm = PTR_CAST(FmFormItem,pFilter->GetParent()->GetParent());
1583 if (!pForm)
1584 bHandled = false;
1585 else if (!pFirstItem)
1586 pFirstItem = pForm;
1587 else if (pFirstItem != pForm)
1588 bHandled = false;
1590 if (bHandled)
1592 _rItemList.push_back(pFilter);
1593 bFoundSomething = true;
1597 if ( !bHandled || !bFoundSomething )
1598 pFirstItem = NULL;
1599 return pFirstItem;
1602 void FmFilterNavigator::insertFilterItem(const ::std::vector<FmFilterItem*>& _rFilterList,FmFilterItems* _pTargetItems,bool _bCopy)
1604 ::std::vector<FmFilterItem*>::const_iterator aEnd = _rFilterList.end();
1605 for ( ::std::vector< FmFilterItem* >::const_iterator i = _rFilterList.begin();
1606 i != aEnd;
1610 FmFilterItem* pLookupItem( *i );
1611 if ( pLookupItem->GetParent() == _pTargetItems )
1612 continue;
1614 FmFilterItem* pFilterItem = _pTargetItems->Find( pLookupItem->GetComponentIndex() );
1615 OUString aText = pLookupItem->GetText();
1616 if ( !pFilterItem )
1618 pFilterItem = new FmFilterItem( _pTargetItems, pLookupItem->GetFieldName(), aText, pLookupItem->GetComponentIndex() );
1619 m_pModel->Append( _pTargetItems, pFilterItem );
1622 if ( !_bCopy )
1623 m_pModel->Remove( pLookupItem );
1625 // now set the text for the new dragged item
1626 m_pModel->SetTextForItem( pFilterItem, aText );
1629 m_pModel->EnsureEmptyFilterRows( *_pTargetItems->GetParent() );
1633 void FmFilterNavigator::StartDrag( sal_Int8 /*_nAction*/, const Point& /*_rPosPixel*/ )
1635 EndSelection();
1637 // be sure that the data is only used within a only one form!
1638 m_aControlExchange.prepareDrag();
1640 ::std::vector<FmFilterItem*> aItemList;
1641 if ( FmFormItem* pFirstItem = getSelectedFilterItems(aItemList) )
1643 m_aControlExchange->setDraggedEntries(aItemList);
1644 m_aControlExchange->setFormItem(pFirstItem);
1645 m_aControlExchange.startDrag( DND_ACTION_COPYMOVE );
1650 void FmFilterNavigator::Command( const CommandEvent& rEvt )
1652 bool bHandled = false;
1653 switch (rEvt.GetCommand())
1655 case COMMAND_CONTEXTMENU:
1657 // die Stelle, an der geklickt wurde
1658 Point aWhere;
1659 SvTreeListEntry* pClicked = NULL;
1660 if (rEvt.IsMouseEvent())
1662 aWhere = rEvt.GetMousePosPixel();
1663 pClicked = GetEntry(aWhere);
1664 if (pClicked == NULL)
1665 break;
1667 if (!IsSelected(pClicked))
1669 SelectAll(false);
1670 Select(pClicked, true);
1671 SetCurEntry(pClicked);
1674 else
1676 pClicked = GetCurEntry();
1677 if (!pClicked)
1678 break;
1679 aWhere = GetEntryPosition( pClicked );
1682 ::std::vector<FmFilterData*> aSelectList;
1683 for (SvTreeListEntry* pEntry = FirstSelected();
1684 pEntry != NULL;
1685 pEntry = NextSelected(pEntry))
1687 // don't delete forms
1688 FmFormItem* pForm = PTR_CAST(FmFormItem, (FmFilterData*)pEntry->GetUserData());
1689 if (!pForm)
1690 aSelectList.push_back((FmFilterData*)pEntry->GetUserData());
1692 if (aSelectList.size() == 1)
1694 // don't delete the only empty row of a form
1695 FmFilterItems* pFilterItems = PTR_CAST(FmFilterItems, aSelectList[0]);
1696 if (pFilterItems && pFilterItems->GetChildren().empty()
1697 && pFilterItems->GetParent()->GetChildren().size() == 1)
1698 aSelectList.clear();
1701 PopupMenu aContextMenu(SVX_RES(RID_FM_FILTER_MENU));
1703 // every condition could be deleted except the first one if its the only one
1704 aContextMenu.EnableItem( SID_FM_DELETE, !aSelectList.empty() );
1707 bool bEdit = PTR_CAST(FmFilterItem, (FmFilterData*)pClicked->GetUserData()) != NULL &&
1708 IsSelected(pClicked) && GetSelectionCount() == 1;
1710 aContextMenu.EnableItem( SID_FM_FILTER_EDIT,
1711 bEdit );
1712 aContextMenu.EnableItem( SID_FM_FILTER_IS_NULL,
1713 bEdit );
1714 aContextMenu.EnableItem( SID_FM_FILTER_IS_NOT_NULL,
1715 bEdit );
1717 aContextMenu.RemoveDisabledEntries(true, true);
1718 sal_uInt16 nSlotId = aContextMenu.Execute( this, aWhere );
1719 switch( nSlotId )
1721 case SID_FM_FILTER_EDIT:
1723 EditEntry( pClicked );
1724 } break;
1725 case SID_FM_FILTER_IS_NULL:
1726 case SID_FM_FILTER_IS_NOT_NULL:
1728 OUString aErrorMsg;
1729 OUString aText;
1730 if (nSlotId == SID_FM_FILTER_IS_NULL)
1731 aText = "IS NULL";
1732 else
1733 aText = "IS NOT NULL";
1735 m_pModel->ValidateText((FmFilterItem*)pClicked->GetUserData(),
1736 aText, aErrorMsg);
1737 m_pModel->SetTextForItem((FmFilterItem*)pClicked->GetUserData(), aText);
1738 } break;
1739 case SID_FM_DELETE:
1741 DeleteSelection();
1742 } break;
1744 bHandled = true;
1745 } break;
1748 if (!bHandled)
1749 SvTreeListBox::Command( rEvt );
1752 SvTreeListEntry* FmFilterNavigator::getNextEntry(SvTreeListEntry* _pStartWith)
1754 SvTreeListEntry* pEntry = _pStartWith ? _pStartWith : LastSelected();
1755 pEntry = Next(pEntry);
1756 // we need the next filter entry
1757 while( pEntry && GetChildCount( pEntry ) == 0 && pEntry != Last() )
1758 pEntry = Next(pEntry);
1759 return pEntry;
1762 SvTreeListEntry* FmFilterNavigator::getPrevEntry(SvTreeListEntry* _pStartWith)
1764 SvTreeListEntry* pEntry = _pStartWith ? _pStartWith : FirstSelected();
1765 pEntry = Prev(pEntry);
1766 // check if the previous entry is a filter, if so get the next prev
1767 if ( pEntry && GetChildCount( pEntry ) != 0 )
1769 pEntry = Prev(pEntry);
1770 // if the entry is still no leaf return
1771 if ( pEntry && GetChildCount( pEntry ) != 0 )
1772 pEntry = NULL;
1774 return pEntry;
1777 void FmFilterNavigator::KeyInput(const KeyEvent& rKEvt)
1779 const KeyCode& rKeyCode = rKEvt.GetKeyCode();
1781 switch ( rKeyCode.GetCode() )
1783 case KEY_UP:
1784 case KEY_DOWN:
1786 if ( !rKeyCode.IsMod1() || !rKeyCode.IsMod2() || rKeyCode.IsShift() )
1787 break;
1789 ::std::vector<FmFilterItem*> aItemList;
1790 if ( !getSelectedFilterItems( aItemList ) )
1791 break;
1793 ::std::mem_fun1_t<SvTreeListEntry*,FmFilterNavigator,SvTreeListEntry*> getter = ::std::mem_fun(&FmFilterNavigator::getNextEntry);
1794 if ( rKeyCode.GetCode() == KEY_UP )
1795 getter = ::std::mem_fun(&FmFilterNavigator::getPrevEntry);
1797 SvTreeListEntry* pTarget = getter( this, NULL );
1798 if ( !pTarget )
1799 break;
1801 FmFilterItems* pTargetItems = getTargetItems( pTarget );
1802 if ( !pTargetItems )
1803 break;
1805 ::std::vector<FmFilterItem*>::const_iterator aEnd = aItemList.end();
1806 bool bNextTargetItem = true;
1807 while ( bNextTargetItem )
1809 ::std::vector<FmFilterItem*>::const_iterator i = aItemList.begin();
1810 for (; i != aEnd; ++i)
1812 if ( (*i)->GetParent() == pTargetItems )
1814 pTarget = getter(this,pTarget);
1815 if ( !pTarget )
1816 return;
1817 pTargetItems = getTargetItems( pTarget );
1818 break;
1820 else
1822 FmFilterItem* pFilterItem = pTargetItems->Find( (*i)->GetComponentIndex() );
1823 // we found the text component so jump above
1824 if ( pFilterItem )
1826 pTarget = getter( this, pTarget );
1827 if ( !pTarget )
1828 return;
1830 pTargetItems = getTargetItems( pTarget );
1831 break;
1835 bNextTargetItem = i != aEnd && pTargetItems;
1838 if ( pTargetItems )
1840 insertFilterItem( aItemList, pTargetItems );
1841 return;
1844 break;
1846 case KEY_DELETE:
1848 if ( rKeyCode.GetModifier() )
1849 break;
1851 if ( !IsSelected( First() ) || GetEntryCount() > 1 )
1852 DeleteSelection();
1853 return;
1857 SvTreeListBox::KeyInput(rKEvt);
1861 void FmFilterNavigator::DeleteSelection()
1863 // to avoid the deletion of an entry twice (e.g. deletion of a parent and afterward
1864 // the deletion of its child, i have to shrink the selecton list
1865 ::std::vector<SvTreeListEntry*> aEntryList;
1866 for (SvTreeListEntry* pEntry = FirstSelected();
1867 pEntry != NULL;
1868 pEntry = NextSelected(pEntry))
1870 FmFilterItem* pFilterItem = PTR_CAST(FmFilterItem, (FmFilterData*)pEntry->GetUserData());
1871 if (pFilterItem && IsSelected(GetParent(pEntry)))
1872 continue;
1874 FmFormItem* pForm = PTR_CAST(FmFormItem, (FmFilterData*)pEntry->GetUserData());
1875 if (!pForm)
1876 aEntryList.push_back(pEntry);
1879 // Remove the selection
1880 SelectAll(false);
1882 for (::std::vector<SvTreeListEntry*>::reverse_iterator i = aEntryList.rbegin();
1883 // link problems with operator ==
1884 i.base() != aEntryList.rend().base(); ++i)
1886 m_pModel->Remove((FmFilterData*)(*i)->GetUserData());
1892 // class FmFilterNavigatorWin
1894 FmFilterNavigatorWin::FmFilterNavigatorWin( SfxBindings* _pBindings, SfxChildWindow* _pMgr,
1895 Window* _pParent )
1896 :SfxDockingWindow( _pBindings, _pMgr, _pParent, WinBits(WB_STDMODELESS|WB_SIZEABLE|WB_ROLLABLE|WB_3DLOOK|WB_DOCKABLE) )
1897 ,SfxControllerItem( SID_FM_FILTER_NAVIGATOR_CONTROL, *_pBindings )
1899 SetHelpId( HID_FILTER_NAVIGATOR_WIN );
1901 m_pNavigator = new FmFilterNavigator( this );
1902 m_pNavigator->Show();
1903 SetText( SVX_RES(RID_STR_FILTER_NAVIGATOR) );
1904 SfxDockingWindow::SetFloatingSize( Size(200,200) );
1908 FmFilterNavigatorWin::~FmFilterNavigatorWin()
1910 delete m_pNavigator;
1914 void FmFilterNavigatorWin::UpdateContent(FmFormShell* pFormShell)
1916 if (!m_pNavigator)
1917 return;
1919 if (!pFormShell)
1920 m_pNavigator->UpdateContent( NULL, NULL );
1921 else
1923 Reference< XFormController > xController(pFormShell->GetImpl()->getActiveInternalController());
1924 Reference< XIndexAccess > xContainer;
1925 if (xController.is())
1927 Reference< XChild > xChild(xController, UNO_QUERY);
1928 for (Reference< XInterface > xParent(xChild->getParent());
1929 xParent.is();
1930 xParent = xChild.is() ? xChild->getParent() : Reference< XInterface > ())
1932 xContainer = Reference< XIndexAccess > (xParent, UNO_QUERY);
1933 xChild = Reference< XChild > (xParent, UNO_QUERY);
1936 m_pNavigator->UpdateContent(xContainer, xController);
1941 void FmFilterNavigatorWin::StateChanged( sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState )
1943 if( !pState || SID_FM_FILTER_NAVIGATOR_CONTROL != nSID )
1944 return;
1946 if( eState >= SFX_ITEM_AVAILABLE )
1948 FmFormShell* pShell = PTR_CAST( FmFormShell,((SfxObjectItem*)pState)->GetShell() );
1949 UpdateContent( pShell );
1951 else
1952 UpdateContent( NULL );
1956 bool FmFilterNavigatorWin::Close()
1958 if ( m_pNavigator && m_pNavigator->IsEditingActive() )
1959 m_pNavigator->EndEditing();
1961 if ( m_pNavigator && m_pNavigator->IsEditingActive() )
1962 // the EndEditing was vetoed (perhaps of an syntax error or such)
1963 return false;
1965 UpdateContent( NULL );
1966 return SfxDockingWindow::Close();
1970 void FmFilterNavigatorWin::FillInfo( SfxChildWinInfo& rInfo ) const
1972 SfxDockingWindow::FillInfo( rInfo );
1973 rInfo.bVisible = false;
1977 Size FmFilterNavigatorWin::CalcDockingSize( SfxChildAlignment eAlign )
1979 if ( ( eAlign == SFX_ALIGN_TOP ) || ( eAlign == SFX_ALIGN_BOTTOM ) )
1980 return Size();
1982 return SfxDockingWindow::CalcDockingSize( eAlign );
1986 SfxChildAlignment FmFilterNavigatorWin::CheckAlignment( SfxChildAlignment eActAlign, SfxChildAlignment eAlign )
1988 switch (eAlign)
1990 case SFX_ALIGN_LEFT:
1991 case SFX_ALIGN_RIGHT:
1992 case SFX_ALIGN_NOALIGNMENT:
1993 return (eAlign);
1994 default:
1995 break;
1998 return (eActAlign);
2002 void FmFilterNavigatorWin::Resize()
2004 SfxDockingWindow::Resize();
2006 Size aLogOutputSize = PixelToLogic( GetOutputSizePixel(), MAP_APPFONT );
2007 Size aLogExplSize = aLogOutputSize;
2008 aLogExplSize.Width() -= 6;
2009 aLogExplSize.Height() -= 6;
2011 Point aExplPos = LogicToPixel( Point(3,3), MAP_APPFONT );
2012 Size aExplSize = LogicToPixel( aLogExplSize, MAP_APPFONT );
2014 m_pNavigator->SetPosSizePixel( aExplPos, aExplSize );
2017 void FmFilterNavigatorWin::GetFocus()
2019 // oj #97405#
2020 if ( m_pNavigator )
2021 m_pNavigator->GrabFocus();
2027 // class FmFilterNavigatorWinMgr
2029 SFX_IMPL_DOCKINGWINDOW( FmFilterNavigatorWinMgr, SID_FM_FILTER_NAVIGATOR )
2032 FmFilterNavigatorWinMgr::FmFilterNavigatorWinMgr( Window *_pParent, sal_uInt16 _nId,
2033 SfxBindings *_pBindings, SfxChildWinInfo* _pInfo )
2034 :SfxChildWindow( _pParent, _nId )
2036 pWindow = new FmFilterNavigatorWin( _pBindings, this, _pParent );
2037 eChildAlignment = SFX_ALIGN_NOALIGNMENT;
2038 ((SfxDockingWindow*)pWindow)->Initialize( _pInfo );
2042 } // namespace svxform
2045 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */