lok: Don't attempt to select the exact text after a failed search.
[LibreOffice.git] / svx / source / form / filtnav.cxx
blob0ac78dfb6d075ffdb233483727314b9448bb0575
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 <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"
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;
71 using namespace ::dbtools;
74 namespace svxform
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()
110 : m_pFormItem(NULL)
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!");
128 return s_nFormat;
132 OLocalExchange* OFilterExchangeHelper::createExchange() const
134 return new OFilterItemExchange;
138 TYPEINIT0(FmFilterData);
139 Image FmFilterData::GetImage() const
141 return Image();
145 TYPEINIT1(FmParentData, FmFilterData);
147 FmParentData::~FmParentData()
149 for (::std::vector<FmFilterData*>::const_iterator i = m_aChildren.begin();
150 i != m_aChildren.end(); ++i)
151 delete (*i);
155 TYPEINIT1(FmFormItem, FmParentData);
157 Image FmFormItem::GetImage() const
159 static Image aImage;
161 if (!aImage)
163 ImageList aNavigatorImages( SVX_RES( RID_SVXIMGLIST_FMEXPL ) );
164 aImage = aNavigatorImages.GetImage( RID_SVXIMG_FORM );
166 return aImage;
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() )
182 return pCondition;
184 return NULL;
188 Image FmFilterItems::GetImage() const
190 static Image aImage;
192 if (!aImage)
194 ImageList aNavigatorImages( SVX_RES( RID_SVXIMGLIST_FMEXPL ) );
195 aImage = aNavigatorImages.GetImage( RID_SVXIMG_FILTER );
197 return aImage;
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
216 static Image aImage;
218 if (!aImage)
220 ImageList aNavigatorImages( SVX_RES( RID_SVXIMGLIST_FMEXPL ) );
221 aImage = aNavigatorImages.GetImage( RID_SVXIMG_FIELD );
223 return aImage;
227 // Hints for communicatition between model and view
229 class FmFilterHint : public SfxHint
231 FmFilterData* m_pData;
233 public:
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
243 public:
244 FmFilterInsertedHint(FmFilterData* pData, sal_uLong nRelPos)
245 :FmFilterHint(pData)
246 ,m_nPos(nRelPos){}
248 sal_uLong GetPos() const { return m_nPos; }
252 class FmFilterRemovedHint : public FmFilterHint
254 public:
255 FmFilterRemovedHint(FmFilterData* pData)
256 :FmFilterHint(pData){}
260 class FmFilterTextChangedHint : public FmFilterHint
262 public:
263 FmFilterTextChangedHint(FmFilterData* pData)
264 :FmFilterHint(pData){}
268 class FilterClearingHint : public SfxHint
270 public:
271 FilterClearingHint(){}
275 class FmFilterCurrentChangedHint : public SfxHint
277 public:
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;
289 public:
290 FmFilterAdapter(FmFilterModel* pModel, const Reference< XIndexAccess >& xControllers);
292 // XEventListener
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;
300 // helpers
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)
312 :m_pModel( pModel )
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 );
331 // step down
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() )
339 if ( _bAdd )
340 xController->addFilterControllerListener( this );
341 else
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();
366 // XEventListener
368 void SAL_CALL FmFilterAdapter::disposing(const EventObject& /*e*/) throw( RuntimeException, std::exception )
373 namespace
375 OUString lcl_getLabelName_nothrow( const Reference< XControl >& _rxControl )
377 OUString sLabelName;
380 Reference< XPropertySet > xModel( _rxControl->getModel(), UNO_QUERY_THROW );
381 sLabelName = getLabelName( xModel );
383 catch( const Exception& )
385 DBG_UNHANDLED_EXCEPTION();
387 return sLabelName;
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();
402 return xField;
406 // XFilterControllerListener
408 void FmFilterAdapter::predicateExpressionChanged( const FilterEvent& _Event ) throw( RuntimeException, std::exception )
410 SolarMutexGuard aGuard;
412 if ( !m_pModel )
413 return;
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!" );
422 if ( !pFormItem )
423 return;
425 const sal_Int32 nActiveTerm( xFilterController->getActiveTerm() );
427 FmFilterItems* pFilter = PTR_CAST( FmFilterItems, pFormItem->GetChildren()[ nActiveTerm ] );
428 FmFilterItem* pFilterItem = pFilter->Find( _Event.FilterComponent );
429 if ( pFilterItem )
431 if ( !_Event.PredicateExpression.isEmpty())
433 pFilterItem->SetText( _Event.PredicateExpression );
434 // UI benachrichtigen
435 FmFilterTextChangedHint aChangeHint(pFilterItem);
436 m_pModel->Broadcast( aChangeHint );
438 else
440 // no text anymore so remove the condition
441 m_pModel->Remove(pFilterItem);
444 else
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!" );
468 if ( !pFormItem )
469 return;
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!" );
474 if ( !bValidIndex )
475 return;
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!" );
503 if ( !pFormItem )
504 return;
506 const sal_Int32 nInsertPos = _Event.DisjunctiveTerm;
507 bool bValidIndex = ( nInsertPos >= 0 ) && ( (size_t)nInsertPos <= pFormItem->GetChildren().size() );
508 if ( !bValidIndex )
510 OSL_FAIL( "FmFilterAdapter::disjunctiveTermAdded: invalid index!" );
511 return;
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())
525 ,m_pAdapter(NULL)
526 ,m_pCurrentItems(NULL)
531 FmFilterModel::~FmFilterModel()
533 Clear();
537 void FmFilterModel::Clear()
539 // notify
540 FilterClearingHint aClearedHint;
541 Broadcast( aClearedHint );
543 // lose endings
544 if (m_pAdapter)
546 m_pAdapter->dispose();
547 m_pAdapter->release();
548 m_pAdapter= NULL;
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)
557 delete (*i);
559 m_aChildren.clear();
563 void FmFilterModel::Update(const Reference< XIndexAccess > & xControllers, const Reference< XFormController > & xCurrent)
565 if ( xCurrent == m_xController )
566 return;
568 if (!xControllers.is())
570 Clear();
571 return;
574 // there is only a new current controller
575 if ( m_xControllers != xControllers )
577 Clear();
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 );
591 else
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 );
606 OUString aName;
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();
621 ++pConjunctionTerm
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();
631 ++pDisjunctiveTerm
634 if ( pDisjunctiveTerm->isEmpty() )
635 // no condition for this particular component in this particular conjunction term
636 continue;
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);
670 if (pForm)
672 if ( xController == pForm->GetController() )
673 return pForm;
674 else
676 pForm = Find(pForm->GetChildren(), xController);
677 if (pForm)
678 return pForm;
682 return NULL;
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);
692 if (pForm)
694 if (xForm == pForm->GetController()->getModel())
695 return pForm;
696 else
698 pForm = Find(pForm->GetChildren(), xForm);
699 if (pForm)
700 return pForm;
704 return NULL;
708 void FmFilterModel::SetCurrentController(const Reference< XFormController > & xCurrent)
710 if ( xCurrent == m_xController )
711 return;
713 m_xController = xCurrent;
715 FmFormItem* pItem = Find( m_aChildren, xCurrent );
716 if ( !pItem )
717 return;
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();
741 ++iter
744 if ((*iter)->ISA(FmFilterItems))
745 break;
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;
772 else
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() );
811 Remove( removePos );
814 else
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());
831 else
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());
841 Remove( i );
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 );
857 delete pData;
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 );
884 rErrorMsg = aErr;
885 rText = aTxt;
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;
893 return true;
896 catch( const Exception& )
898 DBG_UNHANDLED_EXCEPTION();
901 return false;
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);
919 if (rText.isEmpty())
920 Remove(pItem);
921 else
923 // Change the text
924 pItem->SetText(rText);
925 FmFilterTextChangedHint aChangeHint(pItem);
926 Broadcast( aChangeHint );
931 void FmFilterModel::SetCurrentItems(FmFilterItems* pCurrent)
933 if (m_pCurrentItems == pCurrent)
934 return;
936 // search for the condition
937 if (pCurrent)
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() );
960 else
961 m_pCurrentItems = pCurrent;
963 else
964 m_pCurrentItems = NULL;
966 else
967 m_pCurrentItems = NULL;
970 // UI benachrichtigen
971 FmFilterCurrentChangedHint aHint;
972 Broadcast( 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;
991 break;
994 FmFormItem* pFormItem = PTR_CAST(FmFormItem, *i);
995 if (pFormItem)
997 EnsureEmptyFilterRows( *pFormItem );
998 continue;
1002 if ( bAppendLevel )
1004 FmFormItem* pFormItem = PTR_CAST( FmFormItem, &_rItem );
1005 OSL_ENSURE( pFormItem, "FmFilterModel::EnsureEmptyFilterRows: no FmFormItem, but a FmFilterItems child?" );
1006 if ( pFormItem )
1007 AppendFilterItems( *pFormItem );
1011 class FmFilterItemsString : public SvLBoxString
1013 public:
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);
1043 aFirst = aSecond;
1044 aFirst.X() += 1;
1045 aSecond.X() += 6;
1046 aSecond.Y() -= 5;
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)
1058 if( !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
1068 OUString m_aName;
1070 public:
1071 FmFilterString( SvTreeListEntry* pEntry, sal_uInt16 nFlags, const OUString& rStr, const OUString& aName)
1072 : SvLBoxString(pEntry,nFlags,rStr)
1073 , m_aName(aName)
1075 m_aName += ": ";
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;
1083 const int nxD = 4;
1086 void FmFilterString::InitViewData( SvTreeListBox* pView,SvTreeListEntry* pEntry, SvViewDataItem* pViewData)
1088 if( !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);
1111 Point aPos(rPos);
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 )
1122 ,m_pModel( NULL )
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 ) );
1132 SetNodeBitmaps(
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()
1152 disposeOnce();
1155 void FmFilterNavigator::dispose()
1157 EndListening( *m_pModel );
1158 delete m_pModel;
1159 SvTreeListBox::dispose();
1163 void FmFilterNavigator::UpdateContent(const Reference< XIndexAccess > & xControllers, const Reference< XFormController > & xCurrent)
1165 if (xCurrent == m_pModel->GetCurrentController())
1166 return;
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))
1174 SelectAll(false);
1176 if (!IsExpanded(pEntry))
1177 Expand(pEntry);
1179 pEntry = FindEntry(m_pModel->GetCurrentItems());
1180 if (pEntry)
1182 if (!IsExpanded(pEntry))
1183 Expand(pEntry);
1184 Select(pEntry, true);
1190 bool FmFilterNavigator::EditingEntry( SvTreeListEntry* pEntry, Selection& rSelection )
1192 m_pEditingCurrently = pEntry;
1193 if (!SvTreeListBox::EditingEntry( pEntry, rSelection ))
1194 return false;
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())
1206 return true;
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);
1217 else
1219 OUString aErrorMsg;
1221 if (m_pModel->ValidateText(static_cast<FmFilterItem*>(pEntry->GetUserData()), aText, aErrorMsg))
1223 GrabFocus();
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 );
1231 else
1233 // display the error and return sal_False
1234 SQLContext aError;
1235 aError.Message = SVX_RESSTR(RID_STR_SYNTAXERROR);
1236 aError.Details = aErrorMsg;
1237 displayException(aError, this);
1239 return false;
1242 return true;
1246 IMPL_LINK( FmFilterNavigator, OnRemove, SvTreeListEntry*, pEntry )
1248 // now remove the entry
1249 m_pModel->Remove(static_cast<FmFilterData*>(pEntry->GetUserData()));
1250 return 0L;
1254 IMPL_LINK_NOARG_TYPED(FmFilterNavigator, OnDropActionTimer, Timer *, void)
1256 if (--m_aTimerCounter > 0)
1257 return;
1259 switch (m_aDropActionType)
1261 case DA_SCROLLUP :
1262 ScrollOutputArea(1);
1263 m_aTimerCounter = DROP_ACTION_TIMER_SCROLL_TICKS;
1264 break;
1265 case DA_SCROLLDOWN :
1266 ScrollOutputArea(-1);
1267 m_aTimerCounter = DROP_ACTION_TIMER_SCROLL_TICKS;
1268 break;
1269 case DA_EXPANDNODE:
1271 SvTreeListEntry* pToExpand = GetEntry(m_aTimerTriggered);
1272 if (pToExpand && (GetChildCount(pToExpand) > 0) && !IsExpanded(pToExpand))
1273 Expand(pToExpand);
1274 m_aDropActionTimer.Stop();
1276 break;
1282 sal_Int8 FmFilterNavigator::AcceptDrop( const AcceptDropEvent& rEvt )
1284 Point aDropPos = rEvt.maPosPixel;
1286 // possible DropActions scroll and expand
1287 if (rEvt.mbLeaving)
1289 if (m_aDropActionTimer.IsActive())
1290 m_aDropActionTimer.Stop();
1292 else
1294 bool bNeedTrigger = false;
1295 // first entry ?
1296 if ((aDropPos.Y() >= 0) && (aDropPos.Y() < GetEntryHeight()))
1298 m_aDropActionType = DA_SCROLLUP;
1299 bNeedTrigger = true;
1301 else
1303 if ((aDropPos.Y() < GetSizePixel().Height()) && (aDropPos.Y() >= GetSizePixel().Height() - GetEntryHeight()))
1305 m_aDropActionType = DA_SCROLLDOWN;
1306 bNeedTrigger = true;
1308 else
1309 { // is it an entry with children, and not yet expanded?
1310 SvTreeListEntry* pDropppedOn = GetEntry(aDropPos);
1311 if (pDropppedOn && (GetChildCount(pDropppedOn) > 0) && !IsExpanded(pDropppedOn))
1313 // -> expand
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);
1345 if (!pDropTarget)
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;
1362 else
1363 return DND_ACTION_NONE;
1365 return rEvt.mnAction;
1368 namespace
1370 FmFilterItems* getTargetItems(SvTreeListEntry* _pTarget)
1372 FmFilterData* pData = static_cast<FmFilterData*>(_pTarget->GetUserData());
1373 FmFilterItems* pTargetItems = dynamic_cast<FmFilterItems*>(pData);
1374 if (!pTargetItems)
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 );
1391 if (!pDropTarget)
1392 return DND_ACTION_NONE;
1394 // search the container where to add the items
1395 FmFilterItems* pTargetItems = getTargetItems(pDropTarget);
1396 SelectAll(false);
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,
1409 const Image& rImg1,
1410 const Image& rImg2,
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 );
1421 if (pString)
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 ;)
1429 return true;
1431 if (SvTreeListBox::Select(pEntry, bSelect))
1433 if (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());
1443 if (pFormItem)
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());
1454 return true;
1456 else
1457 return false;
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());
1477 if (pEntry)
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;
1492 if (pItem)
1494 for (pEntry = First(); pEntry != NULL; pEntry = Next( pEntry ))
1496 FmFilterData* pEntryItem = static_cast<FmFilterData*>(pEntry->GetUserData());
1497 if (pEntryItem == pItem)
1498 break;
1501 return pEntry;
1505 void FmFilterNavigator::Insert(FmFilterData* pItem, sal_uLong nPos)
1507 const FmParentData* pParent = pItem->GetParent() ? pItem->GetParent() : GetFilterModel();
1509 // insert the item
1510 SvTreeListEntry* pParentEntry = FindEntry( pParent );
1511 InsertEntry( pItem->GetText(), pItem->GetImage(), pItem->GetImage(), pParentEntry, false, nPos, pItem );
1512 if ( pParentEntry )
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)
1523 // cancel editing
1524 EndEditing(true);
1526 if (pEntry)
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()));
1542 if (pFilter)
1544 FmFormItem* pForm = PTR_CAST(FmFormItem,pFilter->GetParent()->GetParent());
1545 if (!pForm)
1546 bHandled = false;
1547 else if (!pFirstItem)
1548 pFirstItem = pForm;
1549 else if (pFirstItem != pForm)
1550 bHandled = false;
1552 if (bHandled)
1554 _rItemList.push_back(pFilter);
1555 bFoundSomething = true;
1559 if ( !bHandled || !bFoundSomething )
1560 pFirstItem = NULL;
1561 return pFirstItem;
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();
1568 i != aEnd;
1572 FmFilterItem* pLookupItem( *i );
1573 if ( pLookupItem->GetParent() == _pTargetItems )
1574 continue;
1576 FmFilterItem* pFilterItem = _pTargetItems->Find( pLookupItem->GetComponentIndex() );
1577 OUString aText = pLookupItem->GetText();
1578 if ( !pFilterItem )
1580 pFilterItem = new FmFilterItem( _pTargetItems, pLookupItem->GetFieldName(), aText, pLookupItem->GetComponentIndex() );
1581 m_pModel->Append( _pTargetItems, pFilterItem );
1584 if ( !_bCopy )
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*/ )
1597 EndSelection();
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
1620 Point aWhere;
1621 SvTreeListEntry* pClicked = NULL;
1622 if (rEvt.IsMouseEvent())
1624 aWhere = rEvt.GetMousePosPixel();
1625 pClicked = GetEntry(aWhere);
1626 if (pClicked == NULL)
1627 break;
1629 if (!IsSelected(pClicked))
1631 SelectAll(false);
1632 Select(pClicked, true);
1633 SetCurEntry(pClicked);
1636 else
1638 pClicked = GetCurEntry();
1639 if (!pClicked)
1640 break;
1641 aWhere = GetEntryPosition( pClicked );
1644 ::std::vector<FmFilterData*> aSelectList;
1645 for (SvTreeListEntry* pEntry = FirstSelected();
1646 pEntry != NULL;
1647 pEntry = NextSelected(pEntry))
1649 // don't delete forms
1650 FmFormItem* pForm = PTR_CAST(FmFormItem, static_cast<FmFilterData*>(pEntry->GetUserData()));
1651 if (!pForm)
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,
1673 bEdit );
1674 aContextMenu.EnableItem( SID_FM_FILTER_IS_NULL,
1675 bEdit );
1676 aContextMenu.EnableItem( SID_FM_FILTER_IS_NOT_NULL,
1677 bEdit );
1679 aContextMenu.RemoveDisabledEntries(true, true);
1680 sal_uInt16 nSlotId = aContextMenu.Execute( this, aWhere );
1681 switch( nSlotId )
1683 case SID_FM_FILTER_EDIT:
1685 EditEntry( pClicked );
1686 } break;
1687 case SID_FM_FILTER_IS_NULL:
1688 case SID_FM_FILTER_IS_NOT_NULL:
1690 OUString aErrorMsg;
1691 OUString aText;
1692 if (nSlotId == SID_FM_FILTER_IS_NULL)
1693 aText = "IS NULL";
1694 else
1695 aText = "IS NOT NULL";
1697 m_pModel->ValidateText(static_cast<FmFilterItem*>(pClicked->GetUserData()),
1698 aText, aErrorMsg);
1699 m_pModel->SetTextForItem(static_cast<FmFilterItem*>(pClicked->GetUserData()), aText);
1700 } break;
1701 case SID_FM_DELETE:
1703 DeleteSelection();
1704 } break;
1706 bHandled = true;
1708 break;
1709 default: break;
1712 if (!bHandled)
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);
1723 return 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 )
1736 pEntry = NULL;
1738 return pEntry;
1741 void FmFilterNavigator::KeyInput(const KeyEvent& rKEvt)
1743 const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
1745 switch ( rKeyCode.GetCode() )
1747 case KEY_UP:
1748 case KEY_DOWN:
1750 if ( !rKeyCode.IsMod1() || !rKeyCode.IsMod2() || rKeyCode.IsShift() )
1751 break;
1753 ::std::vector<FmFilterItem*> aItemList;
1754 if ( !getSelectedFilterItems( aItemList ) )
1755 break;
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 );
1762 if ( !pTarget )
1763 break;
1765 FmFilterItems* pTargetItems = getTargetItems( pTarget );
1766 if ( !pTargetItems )
1767 break;
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);
1779 if ( !pTarget )
1780 return;
1781 pTargetItems = getTargetItems( pTarget );
1782 break;
1784 else
1786 FmFilterItem* pFilterItem = pTargetItems->Find( (*i)->GetComponentIndex() );
1787 // we found the text component so jump above
1788 if ( pFilterItem )
1790 pTarget = getter( this, pTarget );
1791 if ( !pTarget )
1792 return;
1794 pTargetItems = getTargetItems( pTarget );
1795 break;
1799 bNextTargetItem = i != aEnd && pTargetItems;
1802 if ( pTargetItems )
1804 insertFilterItem( aItemList, pTargetItems );
1805 return;
1808 break;
1810 case KEY_DELETE:
1812 if ( rKeyCode.GetModifier() )
1813 break;
1815 if ( !IsSelected( First() ) || GetEntryCount() > 1 )
1816 DeleteSelection();
1817 return;
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();
1831 pEntry != NULL;
1832 pEntry = NextSelected(pEntry))
1834 FmFilterItem* pFilterItem = PTR_CAST(FmFilterItem, static_cast<FmFilterData*>(pEntry->GetUserData()));
1835 if (pFilterItem && IsSelected(GetParent(pEntry)))
1836 continue;
1838 FmFormItem* pForm = PTR_CAST(FmFormItem, static_cast<FmFilterData*>(pEntry->GetUserData()));
1839 if (!pForm)
1840 aEntryList.push_back(pEntry);
1843 // Remove the selection
1844 SelectAll(false);
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()
1870 disposeOnce();
1873 void FmFilterNavigatorWin::dispose()
1875 m_pNavigator.disposeAndClear();
1876 SfxDockingWindow::dispose();
1880 void FmFilterNavigatorWin::UpdateContent(FmFormShell* pFormShell)
1882 if (!m_pNavigator)
1883 return;
1885 if (!pFormShell)
1886 m_pNavigator->UpdateContent( NULL, NULL );
1887 else
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());
1895 xParent.is();
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 )
1910 return;
1912 if( eState >= SfxItemState::DEFAULT )
1914 FmFormShell* pShell = PTR_CAST( FmFormShell, static_cast<const SfxObjectItem*>(pState)->GetShell() );
1915 UpdateContent( pShell );
1917 else
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)
1929 return false;
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 ) )
1946 return Size();
1948 return SfxDockingWindow::CalcDockingSize( eAlign );
1952 SfxChildAlignment FmFilterNavigatorWin::CheckAlignment( SfxChildAlignment eActAlign, SfxChildAlignment eAlign )
1954 switch (eAlign)
1956 case SfxChildAlignment::LEFT:
1957 case SfxChildAlignment::RIGHT:
1958 case SfxChildAlignment::NOALIGNMENT:
1959 return eAlign;
1960 default:
1961 break;
1964 return eActAlign;
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()
1985 // oj #97405#
1986 if ( m_pNavigator )
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: */