xref: /trunk/main/svx/source/form/filtnav.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_svx.hxx"
30 
31 
32 #include "filtnav.hxx"
33 #include "fmexch.hxx"
34 #include "fmhelp.hrc"
35 #include "fmitems.hxx"
36 #include "fmprop.hrc"
37 #include "svx/fmresids.hrc"
38 #include "gridcell.hxx"
39 
40 /** === begin UNO includes === **/
41 #include <com/sun/star/form/runtime/XFormController.hpp>
42 #include <com/sun/star/lang/XUnoTunnel.hpp>
43 #include <com/sun/star/util/XNumberFormatter.hpp>
44 /** === end UNO includes === **/
45 
46 #include <comphelper/processfactory.hxx>
47 #include <svx/fmtools.hxx>
48 #include <comphelper/property.hxx>
49 #include <comphelper/sequence.hxx>
50 #include <comphelper/uno3.hxx>
51 #include <connectivity/dbtools.hxx>
52 #include <cppuhelper/implbase1.hxx>
53 #include <fmservs.hxx>
54 #include <fmshimp.hxx>
55 #include <rtl/logfile.hxx>
56 #include <sfx2/dispatch.hxx>
57 #include <sfx2/objitem.hxx>
58 #include <sfx2/objsh.hxx>
59 #include <sfx2/request.hxx>
60 #include <svx/dialmgr.hxx>
61 #include <svx/fmshell.hxx>
62 #include <svx/svxids.hrc>
63 #include <tools/shl.hxx>
64 #include <vcl/wrkwin.hxx>
65 
66 #include <functional>
67 
68 #define SYNC_DELAY                      200
69 #define DROP_ACTION_TIMER_INITIAL_TICKS     10
70     // solange dauert es, bis das Scrollen anspringt
71 #define DROP_ACTION_TIMER_SCROLL_TICKS      3
72     // in diesen Intervallen wird jeweils eine Zeile gescrollt
73 #define DROP_ACTION_TIMER_TICK_BASE         10
74     // das ist die Basis, mit der beide Angaben multipliziert werden (in ms)
75 
76 using namespace ::svxform;
77 using namespace ::connectivity::simple;
78 using namespace ::connectivity;
79 
80 
81 //........................................................................
82 namespace svxform
83 {
84 //........................................................................
85 
86     /** === begin UNO using === **/
87     using ::com::sun::star::uno::Reference;
88     using ::com::sun::star::lang::XMultiServiceFactory;
89     using ::com::sun::star::awt::TextEvent;
90     using ::com::sun::star::container::XIndexAccess;
91     using ::com::sun::star::uno::UNO_QUERY;
92     using ::com::sun::star::beans::XPropertySet;
93     using ::com::sun::star::form::runtime::XFormController;
94     using ::com::sun::star::form::runtime::XFilterController;
95     using ::com::sun::star::form::runtime::XFilterControllerListener;
96     using ::com::sun::star::form::runtime::FilterEvent;
97     using ::com::sun::star::lang::EventObject;
98     using ::com::sun::star::uno::RuntimeException;
99     using ::com::sun::star::form::XForm;
100     using ::com::sun::star::container::XChild;
101     using ::com::sun::star::awt::XControl;
102     using ::com::sun::star::sdbc::XConnection;
103     using ::com::sun::star::util::XNumberFormatsSupplier;
104     using ::com::sun::star::beans::XPropertySet;
105     using ::com::sun::star::util::XNumberFormatter;
106     using ::com::sun::star::sdbc::XRowSet;
107     using ::com::sun::star::lang::Locale;
108     using ::com::sun::star::sdb::SQLContext;
109     using ::com::sun::star::uno::XInterface;
110     using ::com::sun::star::uno::UNO_QUERY_THROW;
111     using ::com::sun::star::uno::UNO_SET_THROW;
112     using ::com::sun::star::uno::Exception;
113     using ::com::sun::star::awt::XTextComponent;
114     using ::com::sun::star::uno::Sequence;
115     /** === end UNO using === **/
116 
117 //========================================================================
118 OFilterItemExchange::OFilterItemExchange()
119 {
120 }
121 
122 //------------------------------------------------------------------------
123 void OFilterItemExchange::AddSupportedFormats()
124 {
125     AddFormat(getFormatId());
126 }
127 
128 //------------------------------------------------------------------------
129 sal_uInt32 OFilterItemExchange::getFormatId()
130 {
131     static sal_uInt32 s_nFormat = (sal_uInt32)-1;
132     if ((sal_uInt32)-1 == s_nFormat)
133     {
134         s_nFormat = SotExchange::RegisterFormatName(String::CreateFromAscii("application/x-openoffice;windows_formatname=\"form.FilterControlExchange\""));
135         DBG_ASSERT((sal_uInt32)-1 != s_nFormat, "OFilterExchangeHelper::getFormatId: bad exchange id!");
136     }
137     return s_nFormat;
138 }
139 
140 //------------------------------------------------------------------------
141 OLocalExchange* OFilterExchangeHelper::createExchange() const
142 {
143     return new OFilterItemExchange;
144 }
145 
146 //========================================================================
147 TYPEINIT0(FmFilterData);
148 Image FmFilterData::GetImage( BmpColorMode /*_eMode*/ ) const
149 {
150     return Image();
151 }
152 
153 //========================================================================
154 TYPEINIT1(FmParentData, FmFilterData);
155 //------------------------------------------------------------------------
156 FmParentData::~FmParentData()
157 {
158     for (::std::vector<FmFilterData*>::const_iterator i = m_aChildren.begin();
159          i != m_aChildren.end(); i++)
160         delete (*i);
161 }
162 
163 //========================================================================
164 TYPEINIT1(FmFormItem, FmParentData);
165 //------------------------------------------------------------------------
166 Image FmFormItem::GetImage( BmpColorMode _eMode ) const
167 {
168     static Image aImage;
169     static Image aImage_HC;
170 
171     if (!aImage)
172     {
173         ImageList aNavigatorImages( SVX_RES( RID_SVXIMGLIST_FMEXPL ) );
174         ImageList aNavigatorImages_HC( SVX_RES( RID_SVXIMGLIST_FMEXPL_HC ) );
175 
176         aImage = aNavigatorImages.GetImage( RID_SVXIMG_FORM );
177         aImage_HC = aNavigatorImages_HC.GetImage( RID_SVXIMG_FORM );
178     }
179     return ( BMP_COLOR_HIGHCONTRAST == _eMode ) ? aImage_HC : aImage;
180 }
181 
182 //========================================================================
183 TYPEINIT1(FmFilterItems, FmParentData);
184 //------------------------------------------------------------------------
185 FmFilterItem* FmFilterItems::Find( const ::sal_Int32 _nFilterComponentIndex ) const
186 {
187     for (   ::std::vector< FmFilterData* >::const_iterator i = m_aChildren.begin();
188             i != m_aChildren.end();
189             ++i
190         )
191     {
192         FmFilterItem* pCondition = PTR_CAST( FmFilterItem, *i );
193         DBG_ASSERT( pCondition, "FmFilterItems::Find: Wrong element in container!" );
194         if ( _nFilterComponentIndex == pCondition->GetComponentIndex() )
195             return pCondition;
196     }
197     return NULL;
198 }
199 
200 //------------------------------------------------------------------------
201 Image FmFilterItems::GetImage( BmpColorMode _eMode ) const
202 {
203     static Image aImage;
204     static Image aImage_HC;
205 
206     if (!aImage)
207     {
208         ImageList aNavigatorImages( SVX_RES( RID_SVXIMGLIST_FMEXPL ) );
209         ImageList aNavigatorImages_HC( SVX_RES( RID_SVXIMGLIST_FMEXPL_HC ) );
210 
211         aImage = aNavigatorImages.GetImage( RID_SVXIMG_FILTER );
212         aImage_HC = aNavigatorImages_HC.GetImage( RID_SVXIMG_FILTER );
213     }
214     return ( BMP_COLOR_HIGHCONTRAST == _eMode ) ? aImage_HC : aImage;
215 }
216 
217 //========================================================================
218 TYPEINIT1(FmFilterItem, FmFilterData);
219 //------------------------------------------------------------------------
220 FmFilterItem::FmFilterItem( const Reference< XMultiServiceFactory >& _rxFactory,
221                             FmFilterItems* pParent,
222                             const ::rtl::OUString& aFieldName,
223                             const ::rtl::OUString& aText,
224                             const sal_Int32 _nComponentIndex )
225           :FmFilterData(_rxFactory,pParent, aText)
226           ,m_aFieldName(aFieldName)
227           ,m_nComponentIndex( _nComponentIndex )
228 {
229 }
230 
231 //------------------------------------------------------------------------
232 Image FmFilterItem::GetImage( BmpColorMode _eMode ) const
233 {
234     static Image aImage;
235     static Image aImage_HC;
236 
237     if (!aImage)
238     {
239         ImageList aNavigatorImages( SVX_RES( RID_SVXIMGLIST_FMEXPL ) );
240         ImageList aNavigatorImages_HC( SVX_RES( RID_SVXIMGLIST_FMEXPL_HC ) );
241 
242         aImage = aNavigatorImages.GetImage( RID_SVXIMG_FIELD );
243         aImage_HC = aNavigatorImages_HC.GetImage( RID_SVXIMG_FIELD );
244     }
245     return ( BMP_COLOR_HIGHCONTRAST == _eMode ) ? aImage_HC : aImage;
246 }
247 
248 //========================================================================
249 // Hints for communicatition between model and view
250 //========================================================================
251 class FmFilterHint : public SfxHint
252 {
253     FmFilterData*   m_pData;
254 
255 public:
256     TYPEINFO();
257     FmFilterHint(FmFilterData* pData):m_pData(pData){}
258     FmFilterData* GetData() const { return m_pData; }
259 };
260 TYPEINIT1( FmFilterHint, SfxHint );
261 
262 //========================================================================
263 class FmFilterInsertedHint : public FmFilterHint
264 {
265     sal_Int32 m_nPos;   // Position relative to the parent of the data
266 
267 public:
268     TYPEINFO();
269     FmFilterInsertedHint(FmFilterData* pData, sal_Int32 nRelPos)
270         :FmFilterHint(pData)
271         ,m_nPos(nRelPos){}
272 
273     sal_Int32 GetPos() const { return m_nPos; }
274 };
275 TYPEINIT1( FmFilterInsertedHint, FmFilterHint );
276 
277 //========================================================================
278 class FmFilterRemovedHint : public FmFilterHint
279 {
280 public:
281     TYPEINFO();
282     FmFilterRemovedHint(FmFilterData* pData)
283         :FmFilterHint(pData){}
284 
285 };
286 TYPEINIT1( FmFilterRemovedHint, FmFilterHint );
287 
288 //========================================================================
289 class FmFilterTextChangedHint : public FmFilterHint
290 {
291 public:
292     TYPEINFO();
293     FmFilterTextChangedHint(FmFilterData* pData)
294         :FmFilterHint(pData){}
295 
296 };
297 TYPEINIT1( FmFilterTextChangedHint, FmFilterHint );
298 
299 //========================================================================
300 class FilterClearingHint : public SfxHint
301 {
302 public:
303     TYPEINFO();
304     FilterClearingHint(){}
305 };
306 TYPEINIT1( FilterClearingHint, SfxHint );
307 
308 //========================================================================
309 class FmFilterCurrentChangedHint : public SfxHint
310 {
311 public:
312     TYPEINFO();
313     FmFilterCurrentChangedHint(){}
314 };
315 TYPEINIT1( FmFilterCurrentChangedHint, SfxHint );
316 
317 //========================================================================
318 // class FmFilterAdapter, Listener an den FilterControls
319 //========================================================================
320 class FmFilterAdapter : public ::cppu::WeakImplHelper1< XFilterControllerListener >
321 {
322     FmFilterModel*              m_pModel;
323     Reference< XIndexAccess >   m_xControllers;
324 
325 public:
326     FmFilterAdapter(FmFilterModel* pModel, const Reference< XIndexAccess >& xControllers);
327 
328 // XEventListener
329     virtual void SAL_CALL disposing(const EventObject& Source) throw( RuntimeException );
330 
331 // XFilterControllerListener
332     virtual void SAL_CALL predicateExpressionChanged( const FilterEvent& _Event ) throw (RuntimeException);
333     virtual void SAL_CALL disjunctiveTermRemoved( const FilterEvent& _Event ) throw (RuntimeException);
334     virtual void SAL_CALL disjunctiveTermAdded( const FilterEvent& _Event ) throw (RuntimeException);
335 
336 // helpers
337     void dispose() throw( RuntimeException );
338 
339     void AddOrRemoveListener( const Reference< XIndexAccess >& _rxControllers, const bool _bAdd );
340 
341     void setText(sal_Int32 nPos,
342         const FmFilterItem* pFilterItem,
343         const ::rtl::OUString& rText);
344 };
345 
346 //------------------------------------------------------------------------
347 FmFilterAdapter::FmFilterAdapter(FmFilterModel* pModel, const Reference< XIndexAccess >& xControllers)
348     :m_pModel( pModel )
349     ,m_xControllers( xControllers )
350 {
351     AddOrRemoveListener( m_xControllers, true );
352 }
353 
354 //------------------------------------------------------------------------
355 void FmFilterAdapter::dispose() throw( RuntimeException )
356 {
357     AddOrRemoveListener( m_xControllers, false );
358 }
359 
360 //------------------------------------------------------------------------
361 void FmFilterAdapter::AddOrRemoveListener( const Reference< XIndexAccess >& _rxControllers, const bool _bAdd )
362 {
363     for (sal_Int32 i = 0, nLen = _rxControllers->getCount(); i < nLen; ++i)
364     {
365         Reference< XIndexAccess > xElement( _rxControllers->getByIndex(i), UNO_QUERY );
366 
367         // step down
368         AddOrRemoveListener( xElement, _bAdd );
369 
370         // handle this particular controller
371         Reference< XFilterController > xController( xElement, UNO_QUERY );
372         OSL_ENSURE( xController.is(), "FmFilterAdapter::InsertElements: no XFilterController, cannot sync data!" );
373         if ( xController.is() )
374         {
375             if ( _bAdd )
376                 xController->addFilterControllerListener( this );
377             else
378                 xController->removeFilterControllerListener( this );
379         }
380     }
381 }
382 
383 //------------------------------------------------------------------------
384 void FmFilterAdapter::setText(sal_Int32 nRowPos,
385                               const FmFilterItem* pFilterItem,
386                               const ::rtl::OUString& rText)
387 {
388     FmFormItem* pFormItem = PTR_CAST( FmFormItem, pFilterItem->GetParent()->GetParent() );
389 
390     try
391     {
392         Reference< XFilterController > xController( pFormItem->GetController(), UNO_QUERY_THROW );
393         xController->setPredicateExpression( pFilterItem->GetComponentIndex(), nRowPos, rText );
394     }
395     catch( const Exception& )
396     {
397         DBG_UNHANDLED_EXCEPTION();
398     }
399 }
400 
401 
402 // XEventListener
403 //------------------------------------------------------------------------
404 void SAL_CALL FmFilterAdapter::disposing(const EventObject& /*e*/) throw( RuntimeException )
405 {
406 }
407 
408 //------------------------------------------------------------------------
409 namespace
410 {
411     ::rtl::OUString lcl_getLabelName_nothrow( const Reference< XControl >& _rxControl )
412     {
413         ::rtl::OUString sLabelName;
414         try
415         {
416             Reference< XControl > xControl( _rxControl, UNO_SET_THROW );
417             Reference< XPropertySet > xModel( xControl->getModel(), UNO_QUERY_THROW );
418             sLabelName = getLabelName( xModel );
419         }
420         catch( const Exception& )
421         {
422             DBG_UNHANDLED_EXCEPTION();
423         }
424         return sLabelName;
425     }
426 
427     Reference< XPropertySet > lcl_getBoundField_nothrow( const Reference< XControl >& _rxControl )
428     {
429         Reference< XPropertySet > xField;
430         try
431         {
432             Reference< XControl > xControl( _rxControl, UNO_SET_THROW );
433             Reference< XPropertySet > xModelProps( xControl->getModel(), UNO_QUERY_THROW );
434             xField.set( xModelProps->getPropertyValue( FM_PROP_BOUNDFIELD ), UNO_QUERY_THROW );
435         }
436         catch( const Exception& )
437         {
438             DBG_UNHANDLED_EXCEPTION();
439         }
440         return xField;
441     }
442 }
443 
444 // XFilterControllerListener
445 //------------------------------------------------------------------------
446 void FmFilterAdapter::predicateExpressionChanged( const FilterEvent& _Event ) throw( RuntimeException )
447 {
448     ::vos::OGuard aGuard( Application::GetSolarMutex() );
449 
450     if ( !m_pModel )
451         return;
452 
453     // the controller which sent the event
454     Reference< XFormController > xController( _Event.Source, UNO_QUERY_THROW );
455     Reference< XFilterController > xFilterController( _Event.Source, UNO_QUERY_THROW );
456     Reference< XForm > xForm( xController->getModel(), UNO_QUERY_THROW );
457 
458     FmFormItem* pFormItem = m_pModel->Find( m_pModel->m_aChildren, xForm );
459     OSL_ENSURE( pFormItem, "FmFilterAdapter::predicateExpressionChanged: don't know this form!" );
460     if ( !pFormItem )
461         return;
462 
463     const sal_Int32 nActiveTerm( xFilterController->getActiveTerm() );
464 
465     FmFilterItems* pFilter = PTR_CAST( FmFilterItems, pFormItem->GetChildren()[ nActiveTerm ] );
466     FmFilterItem* pFilterItem = pFilter->Find( _Event.FilterComponent );
467     if ( pFilterItem )
468     {
469         if ( _Event.PredicateExpression.getLength())
470         {
471             pFilterItem->SetText( _Event.PredicateExpression );
472             // UI benachrichtigen
473             FmFilterTextChangedHint aChangeHint(pFilterItem);
474             m_pModel->Broadcast( aChangeHint );
475         }
476         else
477         {
478             // no text anymore so remove the condition
479             m_pModel->Remove(pFilterItem);
480         }
481     }
482     else
483     {
484         // searching the component by field name
485         ::rtl::OUString aFieldName( lcl_getLabelName_nothrow( xFilterController->getFilterComponent( _Event.FilterComponent ) ) );
486 
487         pFilterItem = new FmFilterItem( m_pModel->getORB(), pFilter, aFieldName, _Event.PredicateExpression, _Event.FilterComponent );
488         m_pModel->Insert(pFilter->GetChildren().end(), pFilterItem);
489     }
490 
491     // ensure there's one empty term in the filter, just in case the active term was previously empty
492     m_pModel->EnsureEmptyFilterRows( *pFormItem );
493 }
494 
495 //------------------------------------------------------------------------
496 void SAL_CALL FmFilterAdapter::disjunctiveTermRemoved( const FilterEvent& _Event ) throw (RuntimeException)
497 {
498     ::vos::OGuard aGuard( Application::GetSolarMutex() );
499 
500     Reference< XFormController > xController( _Event.Source, UNO_QUERY_THROW );
501     Reference< XFilterController > xFilterController( _Event.Source, UNO_QUERY_THROW );
502     Reference< XForm > xForm( xController->getModel(), UNO_QUERY_THROW );
503 
504     FmFormItem* pFormItem = m_pModel->Find( m_pModel->m_aChildren, xForm );
505     OSL_ENSURE( pFormItem, "FmFilterAdapter::disjunctiveTermRemoved: don't know this form!" );
506     if ( !pFormItem )
507         return;
508 
509     ::std::vector< FmFilterData* >& rTermItems = pFormItem->GetChildren();
510     const bool bValidIndex = ( _Event.DisjunctiveTerm >= 0 ) && ( (size_t)_Event.DisjunctiveTerm < rTermItems.size() );
511     OSL_ENSURE( bValidIndex, "FmFilterAdapter::disjunctiveTermRemoved: invalid term index!" );
512     if ( !bValidIndex )
513         return;
514 
515     // if the first term was removed, then the to-be first term needs its text updated
516     if ( _Event.DisjunctiveTerm == 0 )
517     {
518         rTermItems[1]->SetText( String( SVX_RES( RID_STR_FILTER_FILTER_FOR ) ) );
519         FmFilterTextChangedHint aChangeHint( rTermItems[1] );
520         m_pModel->Broadcast( aChangeHint );
521     }
522 
523     // finally remove the entry from the model
524     m_pModel->Remove( rTermItems.begin() + _Event.DisjunctiveTerm );
525 
526     // ensure there's one empty term in the filter, just in case the currently removed one was the last empty one
527     m_pModel->EnsureEmptyFilterRows( *pFormItem );
528 }
529 
530 //------------------------------------------------------------------------
531 void SAL_CALL FmFilterAdapter::disjunctiveTermAdded( const FilterEvent& _Event ) throw (RuntimeException)
532 {
533     ::vos::OGuard aGuard( Application::GetSolarMutex() );
534 
535     Reference< XFormController > xController( _Event.Source, UNO_QUERY_THROW );
536     Reference< XFilterController > xFilterController( _Event.Source, UNO_QUERY_THROW );
537     Reference< XForm > xForm( xController->getModel(), UNO_QUERY_THROW );
538 
539     FmFormItem* pFormItem = m_pModel->Find( m_pModel->m_aChildren, xForm );
540     OSL_ENSURE( pFormItem, "FmFilterAdapter::disjunctiveTermAdded: don't know this form!" );
541     if ( !pFormItem )
542         return;
543 
544     const sal_Int32 nInsertPos = _Event.DisjunctiveTerm;
545     bool bValidIndex = ( nInsertPos >= 0 ) && ( (size_t)nInsertPos <= pFormItem->GetChildren().size() );
546     if ( !bValidIndex )
547     {
548         OSL_ENSURE( false, "FmFilterAdapter::disjunctiveTermAdded: invalid index!" );
549         return;
550     }
551 
552     const ::std::vector< FmFilterData* >::iterator insertPos = pFormItem->GetChildren().begin() + nInsertPos;
553 
554     FmFilterItems* pFilterItems = new FmFilterItems( m_pModel->getORB(), pFormItem, String( SVX_RES( RID_STR_FILTER_FILTER_OR ) ) );
555     m_pModel->Insert( insertPos, pFilterItems );
556 }
557 
558 //========================================================================
559 // class FmFilterModel
560 //========================================================================
561 TYPEINIT1(FmFilterModel, FmParentData);
562 //------------------------------------------------------------------------
563 FmFilterModel::FmFilterModel(const Reference< XMultiServiceFactory >& _rxFactory)
564               :FmParentData(_rxFactory,NULL, ::rtl::OUString())
565               ,OSQLParserClient(_rxFactory)
566               ,m_xORB(_rxFactory)
567               ,m_pAdapter(NULL)
568               ,m_pCurrentItems(NULL)
569 {
570 }
571 
572 //------------------------------------------------------------------------
573 FmFilterModel::~FmFilterModel()
574 {
575     Clear();
576 }
577 
578 //------------------------------------------------------------------------
579 void FmFilterModel::Clear()
580 {
581     // notify
582     FilterClearingHint aClearedHint;
583     Broadcast( aClearedHint );
584 
585     // loose endings
586     if (m_pAdapter)
587     {
588         m_pAdapter->dispose();
589         m_pAdapter->release();
590         m_pAdapter= NULL;
591     }
592 
593     m_pCurrentItems  = NULL;
594     m_xController    = NULL;
595     m_xControllers   = NULL;
596 
597     for (::std::vector<FmFilterData*>::const_iterator i = m_aChildren.begin();
598          i != m_aChildren.end(); i++)
599         delete (*i);
600 
601     m_aChildren.clear();
602 }
603 
604 //------------------------------------------------------------------------
605 void FmFilterModel::Update(const Reference< XIndexAccess > & xControllers, const Reference< XFormController > & xCurrent)
606 {
607     if ( xCurrent == m_xController )
608         return;
609 
610     if (!xControllers.is())
611     {
612         Clear();
613         return;
614     }
615 
616     // there is only a new current controller
617     if ( m_xControllers != xControllers )
618     {
619         Clear();
620 
621         m_xControllers = xControllers;
622         Update(m_xControllers, this);
623 
624         DBG_ASSERT(xCurrent.is(), "FmFilterModel::Update(...) no current controller");
625 
626         // Listening for TextChanges
627         m_pAdapter = new FmFilterAdapter(this, xControllers);
628         m_pAdapter->acquire();
629 
630         SetCurrentController(xCurrent);
631         EnsureEmptyFilterRows( *this );
632     }
633     else
634         SetCurrentController(xCurrent);
635 }
636 
637 //------------------------------------------------------------------------
638 void FmFilterModel::Update(const Reference< XIndexAccess > & xControllers, FmParentData* pParent)
639 {
640     try
641     {
642         sal_Int32 nCount = xControllers->getCount();
643         for ( sal_Int32 i = 0; i < nCount; ++i )
644         {
645             Reference< XFormController > xController( xControllers->getByIndex(i), UNO_QUERY_THROW );
646 
647             Reference< XPropertySet > xFormProperties( xController->getModel(), UNO_QUERY_THROW );
648             ::rtl::OUString aName;
649             OSL_VERIFY( xFormProperties->getPropertyValue( FM_PROP_NAME ) >>= aName );
650 
651             // Insert a new item for the form
652             FmFormItem* pFormItem = new FmFormItem( m_xORB, pParent, xController, aName );
653             Insert( pParent->GetChildren().end(), pFormItem );
654 
655             Reference< XFilterController > xFilterController( pFormItem->GetFilterController(), UNO_SET_THROW );
656 
657             // insert the existing filters for the form
658             String aTitle( SVX_RES( RID_STR_FILTER_FILTER_FOR ) );
659 
660             Sequence< Sequence< ::rtl::OUString > > aExpressions = xFilterController->getPredicateExpressions();
661             for (   const Sequence< ::rtl::OUString >* pConjunctionTerm = aExpressions.getConstArray();
662                     pConjunctionTerm != aExpressions.getConstArray() + aExpressions.getLength();
663                     ++pConjunctionTerm
664                 )
665             {
666                 // we always display one row, even if there's no term to be displayed
667                 FmFilterItems* pFilterItems = new FmFilterItems( m_xORB, pFormItem, aTitle );
668                 Insert( pFormItem->GetChildren().end(), pFilterItems );
669 
670                 const Sequence< ::rtl::OUString >& rDisjunction( *pConjunctionTerm );
671                 for (   const ::rtl::OUString* pDisjunctiveTerm = rDisjunction.getConstArray();
672                         pDisjunctiveTerm != rDisjunction.getConstArray() + rDisjunction.getLength();
673                         ++pDisjunctiveTerm
674                     )
675                 {
676                     if ( pDisjunctiveTerm->getLength() == 0 )
677                         // no condition for this particular component in this particular conjunction term
678                         continue;
679 
680                     const sal_Int32 nComponentIndex = pDisjunctiveTerm - rDisjunction.getConstArray();
681 
682                     // determine the display name of the control
683                     const Reference< XControl > xFilterControl( xFilterController->getFilterComponent( nComponentIndex ) );
684                     const ::rtl::OUString sDisplayName( lcl_getLabelName_nothrow( xFilterControl ) );
685 
686                     // insert a new entry
687                     FmFilterItem* pANDCondition = new FmFilterItem( m_xORB, pFilterItems, sDisplayName, *pDisjunctiveTerm, nComponentIndex );
688                     Insert( pFilterItems->GetChildren().end(), pANDCondition );
689                 }
690 
691                 // title for the next conditions
692                 aTitle = SVX_RES( RID_STR_FILTER_FILTER_OR );
693             }
694 
695             // now add dependent controllers
696             Reference< XIndexAccess > xControllerAsIndex( xController, UNO_QUERY );
697             Update( xControllerAsIndex, pFormItem );
698         }
699     }
700     catch( const Exception& )
701     {
702         DBG_UNHANDLED_EXCEPTION();
703     }
704 }
705 
706 //------------------------------------------------------------------------
707 FmFormItem* FmFilterModel::Find(const ::std::vector<FmFilterData*>& rItems, const Reference< XFormController > & xController) const
708 {
709     for (::std::vector<FmFilterData*>::const_iterator i = rItems.begin();
710          i != rItems.end(); i++)
711     {
712         FmFormItem* pForm = PTR_CAST(FmFormItem,*i);
713         if (pForm)
714         {
715             if ( xController == pForm->GetController() )
716                 return pForm;
717             else
718             {
719                 pForm = Find(pForm->GetChildren(), xController);
720                 if (pForm)
721                     return pForm;
722             }
723         }
724     }
725     return NULL;
726 }
727 
728 //------------------------------------------------------------------------
729 FmFormItem* FmFilterModel::Find(const ::std::vector<FmFilterData*>& rItems, const Reference< XForm >& xForm) const
730 {
731     for (::std::vector<FmFilterData*>::const_iterator i = rItems.begin();
732          i != rItems.end(); i++)
733     {
734         FmFormItem* pForm = PTR_CAST(FmFormItem,*i);
735         if (pForm)
736         {
737             if (xForm == pForm->GetController()->getModel())
738                 return pForm;
739             else
740             {
741                 pForm = Find(pForm->GetChildren(), xForm);
742                 if (pForm)
743                     return pForm;
744             }
745         }
746     }
747     return NULL;
748 }
749 
750 //------------------------------------------------------------------------
751 void FmFilterModel::SetCurrentController(const Reference< XFormController > & xCurrent)
752 {
753     if ( xCurrent == m_xController )
754         return;
755 
756     m_xController = xCurrent;
757 
758     FmFormItem* pItem = Find( m_aChildren, xCurrent );
759     if ( !pItem )
760         return;
761 
762     try
763     {
764         Reference< XFilterController > xFilterController( m_xController, UNO_QUERY_THROW );
765         const sal_Int32 nActiveTerm( xFilterController->getActiveTerm() );
766         if ( pItem->GetChildren().size() > (size_t)nActiveTerm )
767         {
768             SetCurrentItems( static_cast< FmFilterItems* >( pItem->GetChildren()[ nActiveTerm ] ) );
769         }
770     }
771     catch( const Exception& )
772     {
773         DBG_UNHANDLED_EXCEPTION();
774     }
775 }
776 
777 //------------------------------------------------------------------------
778 void FmFilterModel::AppendFilterItems( FmFormItem& _rFormItem )
779 {
780     // insert the condition behind the last filter items
781     ::std::vector<FmFilterData*>::reverse_iterator iter;
782     for (   iter = _rFormItem.GetChildren().rbegin();
783             iter != _rFormItem.GetChildren().rend();
784             ++iter
785         )
786     {
787         if ((*iter)->ISA(FmFilterItems))
788             break;
789     }
790 
791     sal_Int32 nInsertPos = iter.base() - _rFormItem.GetChildren().begin();
792     // delegate this to the FilterController, it will notify us, which will let us update our model
793     try
794     {
795         Reference< XFilterController > xFilterController( _rFormItem.GetFilterController(), UNO_SET_THROW );
796         if ( nInsertPos >= xFilterController->getDisjunctiveTerms() )
797             xFilterController->appendEmptyDisjunctiveTerm();
798     }
799     catch( const Exception& )
800     {
801         DBG_UNHANDLED_EXCEPTION();
802     }
803 }
804 
805 //------------------------------------------------------------------------
806 void FmFilterModel::Insert(const ::std::vector<FmFilterData*>::iterator& rPos, FmFilterData* pData)
807 {
808     ::std::vector<FmFilterData*>& rItems = pData->GetParent()->GetChildren();
809     sal_Int32 nPos = rPos == rItems.end() ? LIST_APPEND : rPos - rItems.begin();
810     rItems.insert(rPos, pData);
811 
812     // UI benachrichtigen
813     FmFilterInsertedHint aInsertedHint(pData, nPos);
814     Broadcast( aInsertedHint );
815 }
816 
817 //------------------------------------------------------------------------
818 void FmFilterModel::Remove(FmFilterData* pData)
819 {
820     FmParentData* pParent = pData->GetParent();
821     ::std::vector<FmFilterData*>& rItems = pParent->GetChildren();
822 
823     // erase the item from the model
824     ::std::vector<FmFilterData*>::iterator i = ::std::find(rItems.begin(), rItems.end(), pData);
825     DBG_ASSERT(i != rItems.end(), "FmFilterModel::Remove(): unknown Item");
826     // position within the parent
827     sal_Int32 nPos = i - rItems.begin();
828     if (pData->ISA(FmFilterItems))
829     {
830         FmFormItem* pFormItem = (FmFormItem*)pParent;
831 
832         try
833         {
834             Reference< XFilterController > xFilterController( pFormItem->GetFilterController(), UNO_SET_THROW );
835 
836             bool bEmptyLastTerm = ( ( nPos == 0 ) && xFilterController->getDisjunctiveTerms() == 1 );
837             if ( bEmptyLastTerm )
838             {
839                 // remove all children (by setting an empty predicate expression)
840                 ::std::vector< FmFilterData* >& rChildren = ((FmFilterItems*)pData)->GetChildren();
841                 while ( !rChildren.empty() )
842                 {
843                     ::std::vector< FmFilterData* >::iterator removePos = rChildren.end() - 1;
844                     FmFilterItem* pFilterItem = PTR_CAST( FmFilterItem, *removePos );
845                     m_pAdapter->setText( nPos, pFilterItem, ::rtl::OUString() );
846                     Remove( removePos );
847                 }
848             }
849             else
850             {
851                 xFilterController->removeDisjunctiveTerm( nPos );
852             }
853         }
854         catch( const Exception& )
855         {
856             DBG_UNHANDLED_EXCEPTION();
857         }
858     }
859     else // FormItems can not be deleted
860     {
861         FmFilterItem* pFilterItem = PTR_CAST(FmFilterItem, pData);
862 
863         // if its the last condition remove the parent
864         if (rItems.size() == 1)
865             Remove(pFilterItem->GetParent());
866         else
867         {
868             // find the position of the father within his father
869             ::std::vector<FmFilterData*>& rParentParentItems = pData->GetParent()->GetParent()->GetChildren();
870             ::std::vector<FmFilterData*>::iterator j = ::std::find(rParentParentItems.begin(), rParentParentItems.end(), pFilterItem->GetParent());
871             DBG_ASSERT(j != rParentParentItems.end(), "FmFilterModel::Remove(): unknown Item");
872             sal_Int32 nParentPos = j - rParentParentItems.begin();
873 
874             // EmptyText removes the filter
875             m_pAdapter->setText(nParentPos, pFilterItem, ::rtl::OUString());
876             Remove( i );
877         }
878     }
879 }
880 
881 //------------------------------------------------------------------------
882 void FmFilterModel::Remove( const ::std::vector<FmFilterData*>::iterator& rPos )
883 {
884     // remove from parent's child list
885     FmFilterData* pData = *rPos;
886     pData->GetParent()->GetChildren().erase( rPos );
887 
888     // notify the view, this will remove the actual SvLBoxEntry
889     FmFilterRemovedHint aRemoveHint( pData );
890     Broadcast( aRemoveHint );
891 
892     delete pData;
893 }
894 
895 //------------------------------------------------------------------------
896 sal_Bool FmFilterModel::ValidateText(FmFilterItem* pItem, UniString& rText, UniString& rErrorMsg) const
897 {
898     FmFormItem* pFormItem = PTR_CAST( FmFormItem, pItem->GetParent()->GetParent() );
899     try
900     {
901         Reference< XFormController > xFormController( pFormItem->GetController() );
902         // obtain the connection of the form belonging to the controller
903         OStaticDataAccessTools aStaticTools;
904         Reference< XRowSet > xRowSet( xFormController->getModel(), UNO_QUERY_THROW );
905         Reference< XConnection > xConnection( aStaticTools.getRowSetConnection( xRowSet ) );
906 
907         // obtain a number formatter for this connection
908         // TODO: shouldn't this be cached?
909         Reference< XNumberFormatsSupplier > xFormatSupplier = aStaticTools.getNumberFormats( xConnection, sal_True );
910         Reference< XNumberFormatter > xFormatter( m_xORB->createInstance( FM_NUMBER_FORMATTER ), UNO_QUERY );
911         xFormatter->attachNumberFormatsSupplier( xFormatSupplier );
912 
913         // get the field (database column) which the item is responsible for
914         Reference< XFilterController > xFilterController( xFormController, UNO_QUERY_THROW );
915         Reference< XPropertySet > xField( lcl_getBoundField_nothrow( xFilterController->getFilterComponent( pItem->GetComponentIndex() ) ), UNO_SET_THROW );
916 
917         // parse the given text as filter predicate
918         ::rtl::OUString aErr, aTxt( rText );
919         ::rtl::Reference< ISQLParseNode > xParseNode = predicateTree( aErr, aTxt, xFormatter, xField );
920         rErrorMsg = aErr;
921         rText = aTxt;
922         if ( xParseNode.is() )
923         {
924             ::rtl::OUString aPreparedText;
925             Locale aAppLocale = Application::GetSettings().GetUILocale();
926             xParseNode->parseNodeToPredicateStr(
927                 aPreparedText, xConnection, xFormatter, xField, aAppLocale, '.', getParseContext() );
928             rText = aPreparedText;
929             return sal_True;
930         }
931     }
932     catch( const Exception& )
933     {
934         DBG_UNHANDLED_EXCEPTION();
935     }
936 
937     return sal_False;
938 }
939 
940 //------------------------------------------------------------------------
941 void FmFilterModel::Append(FmFilterItems* pItems, FmFilterItem* pFilterItem)
942 {
943     Insert(pItems->GetChildren().end(), pFilterItem);
944 }
945 
946 //------------------------------------------------------------------------
947 void FmFilterModel::SetTextForItem(FmFilterItem* pItem, const ::rtl::OUString& rText)
948 {
949     ::std::vector<FmFilterData*>& rItems = pItem->GetParent()->GetParent()->GetChildren();
950     ::std::vector<FmFilterData*>::iterator i = ::std::find(rItems.begin(), rItems.end(), pItem->GetParent());
951     sal_Int32 nParentPos = i - rItems.begin();
952 
953     m_pAdapter->setText(nParentPos, pItem, rText);
954 
955     if (!rText)
956         Remove(pItem);
957     else
958     {
959         // Change the text
960         pItem->SetText(rText);
961         FmFilterTextChangedHint aChangeHint(pItem);
962         Broadcast( aChangeHint );
963     }
964 }
965 
966 //------------------------------------------------------------------------
967 void FmFilterModel::SetCurrentItems(FmFilterItems* pCurrent)
968 {
969     if (m_pCurrentItems == pCurrent)
970         return;
971 
972     // search for the condition
973     if (pCurrent)
974     {
975         FmFormItem* pFormItem = (FmFormItem*)pCurrent->GetParent();
976         ::std::vector<FmFilterData*>& rItems = pFormItem->GetChildren();
977         ::std::vector<FmFilterData*>::const_iterator i = ::std::find(rItems.begin(), rItems.end(), pCurrent);
978 
979         if (i != rItems.end())
980         {
981             // determine the filter position
982             sal_Int32 nPos = i - rItems.begin();
983             try
984             {
985                 Reference< XFilterController > xFilterController( pFormItem->GetFilterController(), UNO_SET_THROW );
986                 xFilterController->setActiveTerm( nPos );
987             }
988             catch( const Exception& )
989             {
990                 DBG_UNHANDLED_EXCEPTION();
991             }
992 
993             if ( m_xController != pFormItem->GetController() )
994                 // calls SetCurrentItems again
995                 SetCurrentController( pFormItem->GetController() );
996             else
997                 m_pCurrentItems = pCurrent;
998         }
999         else
1000             m_pCurrentItems = NULL;
1001     }
1002     else
1003         m_pCurrentItems = NULL;
1004 
1005 
1006     // UI benachrichtigen
1007     FmFilterCurrentChangedHint aHint;
1008     Broadcast( aHint );
1009 }
1010 
1011 //------------------------------------------------------------------------
1012 void FmFilterModel::EnsureEmptyFilterRows( FmParentData& _rItem )
1013 {
1014     // checks whether for each form there's one free level for input
1015     ::std::vector< FmFilterData* >& rChildren = _rItem.GetChildren();
1016     sal_Bool bAppendLevel = _rItem.ISA( FmFormItem );
1017 
1018     for (   ::std::vector<FmFilterData*>::iterator i = rChildren.begin();
1019             i != rChildren.end();
1020             ++i
1021         )
1022     {
1023         FmFilterItems* pItems = PTR_CAST(FmFilterItems, *i);
1024         if ( pItems && pItems->GetChildren().empty() )
1025         {
1026             bAppendLevel = sal_False;
1027             break;
1028         }
1029 
1030         FmFormItem* pFormItem = PTR_CAST(FmFormItem, *i);
1031         if (pFormItem)
1032         {
1033             EnsureEmptyFilterRows( *pFormItem );
1034             continue;
1035         }
1036     }
1037 
1038     if ( bAppendLevel )
1039     {
1040         FmFormItem* pFormItem = PTR_CAST( FmFormItem, &_rItem );
1041         OSL_ENSURE( pFormItem, "FmFilterModel::EnsureEmptyFilterRows: no FmFormItem, but a FmFilterItems child?" );
1042         if ( pFormItem )
1043             AppendFilterItems( *pFormItem );
1044     }
1045 }
1046 
1047 //========================================================================
1048 // class FmFilterItemsString
1049 //========================================================================
1050 class FmFilterItemsString : public SvLBoxString
1051 {
1052 public:
1053     FmFilterItemsString( SvLBoxEntry* pEntry, sal_uInt16 nFlags,    const XubString& rStr )
1054         :SvLBoxString(pEntry,nFlags,rStr){}
1055 
1056     virtual void Paint(const Point& rPos, SvLBox& rDev, sal_uInt16 nFlags, SvLBoxEntry* pEntry);
1057     virtual void InitViewData( SvLBox* pView,SvLBoxEntry* pEntry, SvViewDataItem* pViewData);
1058 };
1059 
1060 const int nxDBmp = 12;
1061 //------------------------------------------------------------------------
1062 void FmFilterItemsString::Paint(const Point& rPos, SvLBox& rDev, sal_uInt16 /*nFlags*/, SvLBoxEntry* pEntry )
1063 {
1064     FmFilterItems* pRow = (FmFilterItems*)pEntry->GetUserData();
1065     FmFormItem* pForm = (FmFormItem*)pRow->GetParent();
1066 
1067     // current filter is significant painted
1068     const bool bIsCurrentFilter = pForm->GetChildren()[ pForm->GetFilterController()->getActiveTerm() ] == pRow;
1069     if ( bIsCurrentFilter )
1070     {
1071         rDev.Push( PUSH_LINECOLOR );
1072 
1073         rDev.SetLineColor( rDev.GetTextColor() );
1074 
1075         Rectangle aRect( rPos, GetSize( &rDev, pEntry ) );
1076         Point aFirst( rPos.X(), aRect.Bottom() - 6 );
1077         Point aSecond(aFirst .X() + 2, aFirst.Y() + 3 );
1078 
1079         rDev.DrawLine( aFirst, aSecond );
1080 
1081         aFirst = aSecond;
1082         aFirst.X() += 1;
1083         aSecond.X() += 6;
1084         aSecond.Y() -= 5;
1085 
1086         rDev.DrawLine( aFirst, aSecond );
1087 
1088         rDev.Pop();
1089     }
1090 
1091     rDev.DrawText( Point(rPos.X() + nxDBmp, rPos.Y()), GetText() );
1092 }
1093 
1094 //------------------------------------------------------------------------
1095 void FmFilterItemsString::InitViewData( SvLBox* pView,SvLBoxEntry* pEntry, SvViewDataItem* pViewData)
1096 {
1097     if( !pViewData )
1098         pViewData = pView->GetViewDataItem( pEntry, this );
1099 
1100     Size aSize(pView->GetTextWidth(GetText()), pView->GetTextHeight());
1101     aSize.Width() += nxDBmp;
1102     pViewData->aSize = aSize;
1103 }
1104 
1105 //========================================================================
1106 // class FmFilterString
1107 //========================================================================
1108 class FmFilterString : public SvLBoxString
1109 {
1110     UniString m_aName;
1111 
1112 public:
1113     FmFilterString( SvLBoxEntry* pEntry, sal_uInt16 nFlags, const XubString& rStr, const UniString& aName)
1114         :SvLBoxString(pEntry,nFlags,rStr)
1115         ,m_aName(aName)
1116     {
1117         m_aName.AppendAscii(": ");
1118     }
1119 
1120     virtual void Paint(const Point& rPos, SvLBox& rDev, sal_uInt16 nFlags, SvLBoxEntry* pEntry);
1121     virtual void InitViewData( SvLBox* pView,SvLBoxEntry* pEntry, SvViewDataItem* pViewData);
1122 };
1123 
1124 const int nxD = 4;
1125 
1126 //------------------------------------------------------------------------
1127 void FmFilterString::InitViewData( SvLBox* pView,SvLBoxEntry* pEntry, SvViewDataItem* pViewData)
1128 {
1129     if( !pViewData )
1130         pViewData = pView->GetViewDataItem( pEntry, this );
1131 
1132     Font aOldFont( pView->GetFont());
1133     Font aFont( aOldFont );
1134     aFont.SetWeight(WEIGHT_BOLD);
1135     pView->SetFont( aFont );
1136 
1137     Size aSize(pView->GetTextWidth(m_aName), pView->GetTextHeight());
1138     pView->SetFont( aOldFont );
1139     aSize.Width() += pView->GetTextWidth(GetText()) + nxD;
1140     pViewData->aSize = aSize;
1141 }
1142 
1143 //------------------------------------------------------------------------
1144 void FmFilterString::Paint(const Point& rPos, SvLBox& rDev, sal_uInt16 /*nFlags*/, SvLBoxEntry* /*pEntry*/ )
1145 {
1146     Font aOldFont( rDev.GetFont());
1147     Font aFont( aOldFont );
1148     aFont.SetWeight(WEIGHT_BOLD);
1149     rDev.SetFont( aFont );
1150 
1151     Point aPos(rPos);
1152     rDev.DrawText( aPos, m_aName );
1153 
1154     // position for the second text
1155     aPos.X() += rDev.GetTextWidth(m_aName) + nxD;
1156     rDev.SetFont( aOldFont );
1157     rDev.DrawText( aPos, GetText() );
1158 }
1159 
1160 //========================================================================
1161 // class FmFilterNavigator
1162 //========================================================================
1163 FmFilterNavigator::FmFilterNavigator( Window* pParent )
1164                   :SvTreeListBox( pParent, WB_HASBUTTONS|WB_HASLINES|WB_BORDER|WB_HASBUTTONSATROOT )
1165                   ,m_pModel( NULL )
1166                   ,m_pEditingCurrently( NULL )
1167                   ,m_aControlExchange( this )
1168                   ,m_aTimerCounter( 0 )
1169                   ,m_aDropActionType( DA_SCROLLUP )
1170 {
1171     SetHelpId( HID_FILTER_NAVIGATOR );
1172 
1173     {
1174         {
1175             ImageList aNavigatorImages( SVX_RES( RID_SVXIMGLIST_FMEXPL ) );
1176             SetNodeBitmaps(
1177                 aNavigatorImages.GetImage( RID_SVXIMG_COLLAPSEDNODE ),
1178                 aNavigatorImages.GetImage( RID_SVXIMG_EXPANDEDNODE ),
1179                 BMP_COLOR_NORMAL
1180             );
1181         }
1182         {
1183             ImageList aNavigatorImages( SVX_RES( RID_SVXIMGLIST_FMEXPL_HC ) );
1184             SetNodeBitmaps(
1185                 aNavigatorImages.GetImage( RID_SVXIMG_COLLAPSEDNODE ),
1186                 aNavigatorImages.GetImage( RID_SVXIMG_EXPANDEDNODE ),
1187                 BMP_COLOR_HIGHCONTRAST
1188             );
1189         }
1190     }
1191 
1192     m_pModel = new FmFilterModel(comphelper::getProcessServiceFactory());
1193     StartListening( *m_pModel );
1194 
1195     EnableInplaceEditing( sal_True );
1196     SetSelectionMode(MULTIPLE_SELECTION);
1197 
1198     SetDragDropMode(0xFFFF);
1199 
1200     m_aDropActionTimer.SetTimeoutHdl(LINK(this, FmFilterNavigator, OnDropActionTimer));
1201 }
1202 
1203 //------------------------------------------------------------------------
1204 FmFilterNavigator::~FmFilterNavigator()
1205 {
1206     EndListening( *m_pModel );
1207     delete m_pModel;
1208 }
1209 
1210 //------------------------------------------------------------------------
1211 void FmFilterNavigator::Clear()
1212 {
1213     m_pModel->Clear();
1214 }
1215 
1216 //------------------------------------------------------------------------
1217 void FmFilterNavigator::UpdateContent(const Reference< XIndexAccess > & xControllers, const Reference< XFormController > & xCurrent)
1218 {
1219     if (xCurrent == m_pModel->GetCurrentController())
1220         return;
1221 
1222     m_pModel->Update(xControllers, xCurrent);
1223 
1224     // expand the filters for the current controller
1225     SvLBoxEntry* pEntry = FindEntry(m_pModel->GetCurrentForm());
1226     if (pEntry && !IsExpanded(pEntry))
1227     {
1228         SelectAll(sal_False);
1229 
1230         if (!IsExpanded(pEntry))
1231             Expand(pEntry);
1232 
1233         pEntry = FindEntry(m_pModel->GetCurrentItems());
1234         if (pEntry)
1235         {
1236             if (!IsExpanded(pEntry))
1237                 Expand(pEntry);
1238             Select(pEntry, sal_True);
1239         }
1240     }
1241 }
1242 
1243 //------------------------------------------------------------------------
1244 sal_Bool FmFilterNavigator::EditingEntry( SvLBoxEntry* pEntry, Selection& rSelection )
1245 {
1246     m_pEditingCurrently = pEntry;
1247     if (!SvTreeListBox::EditingEntry( pEntry, rSelection ))
1248         return sal_False;
1249 
1250     return pEntry && ((FmFilterData*)pEntry->GetUserData())->ISA(FmFilterItem);
1251 }
1252 
1253 //------------------------------------------------------------------------
1254 sal_Bool FmFilterNavigator::EditedEntry( SvLBoxEntry* pEntry, const XubString& rNewText )
1255 {
1256     DBG_ASSERT(pEntry == m_pEditingCurrently, "FmFilterNavigator::EditedEntry: suspicious entry!");
1257     m_pEditingCurrently = NULL;
1258 
1259     if (EditingCanceled())
1260         return sal_True;
1261 
1262     DBG_ASSERT(((FmFilterData*)pEntry->GetUserData())->ISA(FmFilterItem),
1263                     "FmFilterNavigator::EditedEntry() wrong entry");
1264 
1265     UniString aText(rNewText);
1266     aText.EraseTrailingChars();
1267     aText.EraseLeadingChars();
1268     if (aText.Len() == 0)
1269     {
1270         // deleting the entry asynchron
1271         sal_uLong nEvent;
1272         PostUserEvent(nEvent, LINK(this, FmFilterNavigator, OnRemove), pEntry);
1273     }
1274     else
1275     {
1276         UniString aErrorMsg;
1277 
1278         if (m_pModel->ValidateText((FmFilterItem*)pEntry->GetUserData(), aText, aErrorMsg))
1279         {
1280             GrabFocus();
1281             // this will set the text at the FmFilterItem, as well as update any filter controls
1282             // which are connected to this particular entry
1283             m_pModel->SetTextForItem( static_cast< FmFilterItem* >( pEntry->GetUserData() ), aText );
1284 
1285             SetCursor( pEntry, sal_True );
1286             SetEntryText( pEntry, aText );
1287         }
1288         else
1289         {
1290             // display the error and return sal_False
1291             SQLContext aError;
1292             aError.Message = String(SVX_RES(RID_STR_SYNTAXERROR));
1293             aError.Details = aErrorMsg;
1294             displayException(aError, this);
1295 
1296             return sal_False;
1297         }
1298     }
1299     return sal_True;
1300 }
1301 
1302 //------------------------------------------------------------------------
1303 IMPL_LINK( FmFilterNavigator, OnRemove, SvLBoxEntry*, pEntry )
1304 {
1305     // now remove the entry
1306     m_pModel->Remove((FmFilterData*) pEntry->GetUserData());
1307     return 0L;
1308 }
1309 
1310 //------------------------------------------------------------------------
1311 IMPL_LINK( FmFilterNavigator, OnDropActionTimer, void*, EMPTYARG )
1312 {
1313     if (--m_aTimerCounter > 0)
1314         return 0L;
1315 
1316     switch (m_aDropActionType)
1317     {
1318         case DA_SCROLLUP :
1319             ScrollOutputArea(1);
1320             m_aTimerCounter = DROP_ACTION_TIMER_SCROLL_TICKS;
1321             break;
1322         case DA_SCROLLDOWN :
1323             ScrollOutputArea(-1);
1324             m_aTimerCounter = DROP_ACTION_TIMER_SCROLL_TICKS;
1325             break;
1326         case DA_EXPANDNODE:
1327         {
1328             SvLBoxEntry* pToExpand = GetEntry(m_aTimerTriggered);
1329             if (pToExpand && (GetChildCount(pToExpand) > 0) &&  !IsExpanded(pToExpand))
1330                 // tja, eigentlich muesste ich noch testen, ob die Node nicht schon expandiert ist, aber ich
1331                 // habe dazu weder in den Basisklassen noch im Model eine Methode gefunden ...
1332                 // aber ich denke, die BK sollte es auch so vertragen
1333                 Expand(pToExpand);
1334 
1335             // nach dem Expand habe ich im Gegensatz zum Scrollen natuerlich nix mehr zu tun
1336             m_aDropActionTimer.Stop();
1337         }
1338         break;
1339     }
1340     return 0L;
1341 }
1342 
1343 
1344 //------------------------------------------------------------------------
1345 sal_Int8 FmFilterNavigator::AcceptDrop( const AcceptDropEvent& rEvt )
1346 {
1347     Point aDropPos = rEvt.maPosPixel;
1348 
1349     // kuemmern wir uns erst mal um moeglich DropActions (Scrollen und Aufklappen)
1350     if (rEvt.mbLeaving)
1351     {
1352         if (m_aDropActionTimer.IsActive())
1353             m_aDropActionTimer.Stop();
1354     }
1355     else
1356     {
1357         sal_Bool bNeedTrigger = sal_False;
1358         // auf dem ersten Eintrag ?
1359         if ((aDropPos.Y() >= 0) && (aDropPos.Y() < GetEntryHeight()))
1360         {
1361             m_aDropActionType = DA_SCROLLUP;
1362             bNeedTrigger = sal_True;
1363         }
1364         else
1365         {
1366             // auf dem letzten (bzw. in dem Bereich, den ein Eintrag einnehmen wuerde, wenn er unten genau buendig
1367             // abschliessen wuerde) ?
1368             if ((aDropPos.Y() < GetSizePixel().Height()) && (aDropPos.Y() >= GetSizePixel().Height() - GetEntryHeight()))
1369             {
1370                 m_aDropActionType = DA_SCROLLDOWN;
1371                 bNeedTrigger = sal_True;
1372             }
1373             else
1374             {   // is it an entry whith children, and not yet expanded?
1375                 SvLBoxEntry* pDropppedOn = GetEntry(aDropPos);
1376                 if (pDropppedOn && (GetChildCount(pDropppedOn) > 0) && !IsExpanded(pDropppedOn))
1377                 {
1378                     // -> aufklappen
1379                     m_aDropActionType = DA_EXPANDNODE;
1380                     bNeedTrigger = sal_True;
1381                 }
1382             }
1383         }
1384         if (bNeedTrigger && (m_aTimerTriggered != aDropPos))
1385         {
1386             // neu anfangen zu zaehlen
1387             m_aTimerCounter = DROP_ACTION_TIMER_INITIAL_TICKS;
1388             // die Pos merken, da ich auch QueryDrops bekomme, wenn sich die Maus gar nicht bewegt hat
1389             m_aTimerTriggered = aDropPos;
1390             // und den Timer los
1391             if (!m_aDropActionTimer.IsActive()) // gibt es den Timer schon ?
1392             {
1393                 m_aDropActionTimer.SetTimeout(DROP_ACTION_TIMER_TICK_BASE);
1394                 m_aDropActionTimer.Start();
1395             }
1396         }
1397         else if (!bNeedTrigger)
1398             m_aDropActionTimer.Stop();
1399     }
1400 
1401 
1402     // Hat das Object das richtige Format?
1403     if (!m_aControlExchange.isDragSource())
1404         return DND_ACTION_NONE;
1405 
1406     if (!m_aControlExchange->hasFormat(GetDataFlavorExVector()))
1407         return DND_ACTION_NONE;
1408 
1409     // do we conain the formitem?
1410     if (!FindEntry(m_aControlExchange->getFormItem()))
1411         return DND_ACTION_NONE;
1412 
1413     SvLBoxEntry* pDropTarget = GetEntry(aDropPos);
1414     if (!pDropTarget)
1415         return DND_ACTION_NONE;
1416 
1417     FmFilterData* pData = (FmFilterData*)pDropTarget->GetUserData();
1418     FmFormItem* pForm = NULL;
1419     if (pData->ISA(FmFilterItem))
1420     {
1421         pForm = PTR_CAST(FmFormItem,pData->GetParent()->GetParent());
1422         if (pForm != m_aControlExchange->getFormItem())
1423             return DND_ACTION_NONE;
1424     }
1425     else if (pData->ISA(FmFilterItems))
1426     {
1427         pForm = PTR_CAST(FmFormItem,pData->GetParent());
1428         if (pForm != m_aControlExchange->getFormItem())
1429             return DND_ACTION_NONE;
1430     }
1431     else
1432         return DND_ACTION_NONE;
1433 
1434     return rEvt.mnAction;
1435 }
1436 // -----------------------------------------------------------------------------
1437 namespace
1438 {
1439     FmFilterItems* getTargetItems(SvLBoxEntry* _pTarget)
1440     {
1441         FmFilterData*   pData = static_cast<FmFilterData*>(_pTarget->GetUserData());
1442         FmFilterItems*  pTargetItems = pData->ISA(FmFilterItems)
1443                                         ?
1444                                         PTR_CAST(FmFilterItems,pData)
1445                                         :
1446                                     PTR_CAST(FmFilterItems,pData->GetParent());
1447         return pTargetItems;
1448     }
1449 }
1450 //------------------------------------------------------------------------
1451 sal_Int8 FmFilterNavigator::ExecuteDrop( const ExecuteDropEvent& rEvt )
1452 {
1453     // ware schlecht, wenn nach dem Droppen noch gescrollt wird ...
1454     if (m_aDropActionTimer.IsActive())
1455         m_aDropActionTimer.Stop();
1456 
1457     // Format-Ueberpruefung
1458     if (!m_aControlExchange.isDragSource())
1459         return DND_ACTION_NONE;
1460 
1461     // das Ziel des Drop sowie einige Daten darueber
1462     Point aDropPos = rEvt.maPosPixel;
1463     SvLBoxEntry* pDropTarget = GetEntry( aDropPos );
1464     if (!pDropTarget)
1465         return DND_ACTION_NONE;
1466 
1467     // search the container where to add the items
1468     FmFilterItems*  pTargetItems = getTargetItems(pDropTarget);
1469     SelectAll(sal_False);
1470     SvLBoxEntry* pEntry = FindEntry(pTargetItems);
1471     Select(pEntry, sal_True);
1472     SetCurEntry(pEntry);
1473 
1474     insertFilterItem(m_aControlExchange->getDraggedEntries(),pTargetItems,DND_ACTION_COPY == rEvt.mnAction);
1475 
1476     return sal_True;
1477 }
1478 
1479 //------------------------------------------------------------------------
1480 void FmFilterNavigator::InitEntry(SvLBoxEntry* pEntry,
1481                                   const XubString& rStr,
1482                                   const Image& rImg1,
1483                                   const Image& rImg2,
1484                                                                   SvLBoxButtonKind eButtonKind)
1485 {
1486     SvTreeListBox::InitEntry( pEntry, rStr, rImg1, rImg2, eButtonKind );
1487     SvLBoxString* pString = NULL;
1488 
1489     if (((FmFilterData*)pEntry->GetUserData())->ISA(FmFilterItem))
1490         pString = new FmFilterString(pEntry, 0, rStr, ((FmFilterItem*)pEntry->GetUserData())->GetFieldName());
1491     else if (((FmFilterData*)pEntry->GetUserData())->ISA(FmFilterItems))
1492         pString = new FmFilterItemsString(pEntry, 0, rStr );
1493 
1494     if (pString)
1495         pEntry->ReplaceItem( pString, 1 );
1496 }
1497 
1498 //------------------------------------------------------------------------
1499 sal_Bool FmFilterNavigator::Select( SvLBoxEntry* pEntry, sal_Bool bSelect )
1500 {
1501     if (bSelect == IsSelected(pEntry))  // das passiert manchmal, ich glaube, die Basisklasse geht zu sehr auf Nummer sicher ;)
1502         return sal_True;
1503 
1504     if (SvTreeListBox::Select(pEntry, bSelect))
1505     {
1506         if (bSelect)
1507         {
1508             FmFormItem* pFormItem = NULL;
1509             if (((FmFilterData*)pEntry->GetUserData())->ISA(FmFilterItem))
1510                 pFormItem = (FmFormItem*)((FmFilterItem*)pEntry->GetUserData())->GetParent()->GetParent();
1511             else if (((FmFilterData*)pEntry->GetUserData())->ISA(FmFilterItems))
1512                 pFormItem = (FmFormItem*)((FmFilterItem*)pEntry->GetUserData())->GetParent()->GetParent();
1513             else if (((FmFilterData*)pEntry->GetUserData())->ISA(FmFormItem))
1514                 pFormItem = (FmFormItem*)pEntry->GetUserData();
1515 
1516             if (pFormItem)
1517             {
1518                 // will the controller be exchanged?
1519                 if (((FmFilterData*)pEntry->GetUserData())->ISA(FmFilterItem))
1520                     m_pModel->SetCurrentItems((FmFilterItems*)((FmFilterItem*)pEntry->GetUserData())->GetParent());
1521                 else if (((FmFilterData*)pEntry->GetUserData())->ISA(FmFilterItems))
1522                     m_pModel->SetCurrentItems((FmFilterItems*)pEntry->GetUserData());
1523                 else if (((FmFilterData*)pEntry->GetUserData())->ISA(FmFormItem))
1524                     m_pModel->SetCurrentController(((FmFormItem*)pEntry->GetUserData())->GetController());
1525             }
1526         }
1527         return sal_True;
1528     }
1529     else
1530         return sal_False;
1531 }
1532 
1533 //------------------------------------------------------------------------
1534 void FmFilterNavigator::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
1535 {
1536     if (rHint.ISA(FmFilterInsertedHint))
1537     {
1538         FmFilterInsertedHint* pHint = (FmFilterInsertedHint*)&rHint;
1539         Insert(pHint->GetData(), pHint->GetPos());
1540     }
1541     else if( rHint.ISA(FilterClearingHint) )
1542     {
1543         SvTreeListBox::Clear();
1544     }
1545     else if( rHint.ISA(FmFilterRemovedHint) )
1546     {
1547         FmFilterRemovedHint* pHint = (FmFilterRemovedHint*)&rHint;
1548         Remove(pHint->GetData());
1549     }
1550     else if( rHint.ISA(FmFilterTextChangedHint) )
1551     {
1552         FmFilterTextChangedHint* pHint = (FmFilterTextChangedHint*)&rHint;
1553         SvLBoxEntry* pEntry = FindEntry(pHint->GetData());
1554         if (pEntry)
1555             SetEntryText( pEntry, pHint->GetData()->GetText());
1556     }
1557     else if( rHint.ISA(FmFilterCurrentChangedHint) )
1558     {
1559         // invalidate the entries
1560         for (SvLBoxEntry* pEntry = First(); pEntry != NULL;
1561              pEntry = Next(pEntry))
1562             GetModel()->InvalidateEntry( pEntry );
1563     }
1564 }
1565 
1566 //------------------------------------------------------------------------
1567 SvLBoxEntry* FmFilterNavigator::FindEntry(const FmFilterData* pItem) const
1568 {
1569     SvLBoxEntry* pEntry = NULL;
1570     if (pItem)
1571     {
1572         for (pEntry = First(); pEntry != NULL; pEntry = Next( pEntry ))
1573         {
1574             FmFilterData* pEntryItem = (FmFilterData*)pEntry->GetUserData();
1575             if (pEntryItem == pItem)
1576                 break;
1577         }
1578     }
1579     return pEntry;
1580 }
1581 
1582 //------------------------------------------------------------------------
1583 void FmFilterNavigator::Insert(FmFilterData* pItem, sal_Int32 nPos)
1584 {
1585     const FmParentData* pParent = pItem->GetParent() ? pItem->GetParent() : GetFilterModel();
1586 
1587     // insert the item
1588     SvLBoxEntry* pParentEntry = FindEntry( pParent );
1589     SvLBoxEntry* pNewEntry = InsertEntry(pItem->GetText(), pItem->GetImage(), pItem->GetImage(), pParentEntry, sal_False, nPos, pItem );
1590     if ( pNewEntry )
1591     {
1592         SetExpandedEntryBmp( pNewEntry, pItem->GetImage( BMP_COLOR_HIGHCONTRAST ), BMP_COLOR_HIGHCONTRAST );
1593         SetCollapsedEntryBmp( pNewEntry, pItem->GetImage( BMP_COLOR_HIGHCONTRAST ), BMP_COLOR_HIGHCONTRAST );
1594     }
1595     if ( pParentEntry )
1596         Expand( pParentEntry );
1597 }
1598 
1599 //------------------------------------------------------------------------
1600 void FmFilterNavigator::Remove(FmFilterData* pItem)
1601 {
1602     // der Entry zu den Daten
1603     SvLBoxEntry* pEntry = FindEntry(pItem);
1604 
1605     if (pEntry == m_pEditingCurrently)
1606         // cancel editing
1607         EndEditing(sal_True);
1608 
1609     if (pEntry)
1610         GetModel()->Remove( pEntry );
1611 }
1612 // -----------------------------------------------------------------------------
1613 FmFormItem* FmFilterNavigator::getSelectedFilterItems(::std::vector<FmFilterItem*>& _rItemList)
1614 {
1615     // be sure that the data is only used within only one form!
1616     FmFormItem* pFirstItem = NULL;
1617 
1618     sal_Bool bHandled = sal_True;
1619     sal_Bool bFoundSomething = sal_False;
1620     for (SvLBoxEntry* pEntry = FirstSelected();
1621          bHandled && pEntry != NULL;
1622          pEntry = NextSelected(pEntry))
1623     {
1624         FmFilterItem* pFilter = PTR_CAST(FmFilterItem, (FmFilterData*)pEntry->GetUserData());
1625         if (pFilter)
1626         {
1627             FmFormItem* pForm = PTR_CAST(FmFormItem,pFilter->GetParent()->GetParent());
1628             if (!pForm)
1629                 bHandled = sal_False;
1630             else if (!pFirstItem)
1631                 pFirstItem = pForm;
1632             else if (pFirstItem != pForm)
1633                 bHandled = sal_False;
1634 
1635             if (bHandled)
1636             {
1637                 _rItemList.push_back(pFilter);
1638                 bFoundSomething = sal_True;
1639             }
1640         }
1641     }
1642     if ( !bHandled || !bFoundSomething )
1643         pFirstItem = NULL;
1644     return pFirstItem;
1645 }
1646 // -----------------------------------------------------------------------------
1647 void FmFilterNavigator::insertFilterItem(const ::std::vector<FmFilterItem*>& _rFilterList,FmFilterItems* _pTargetItems,sal_Bool _bCopy)
1648 {
1649     ::std::vector<FmFilterItem*>::const_iterator aEnd = _rFilterList.end();
1650     for (   ::std::vector< FmFilterItem* >::const_iterator i = _rFilterList.begin();
1651             i != aEnd;
1652             ++i
1653         )
1654     {
1655         FmFilterItem* pLookupItem( *i );
1656         if ( pLookupItem->GetParent() == _pTargetItems )
1657             continue;
1658 
1659         FmFilterItem* pFilterItem = _pTargetItems->Find( pLookupItem->GetComponentIndex() );
1660         String aText = pLookupItem->GetText();
1661         if ( !pFilterItem )
1662         {
1663             pFilterItem = new FmFilterItem( m_pModel->getORB(), _pTargetItems, pLookupItem->GetFieldName(), aText, pLookupItem->GetComponentIndex() );
1664             m_pModel->Append( _pTargetItems, pFilterItem );
1665         }
1666 
1667         if ( !_bCopy )
1668             m_pModel->Remove( pLookupItem );
1669 
1670         // now set the text for the new dragged item
1671         m_pModel->SetTextForItem( pFilterItem, aText );
1672     }
1673 
1674     m_pModel->EnsureEmptyFilterRows( *_pTargetItems->GetParent() );
1675 }
1676 
1677 //------------------------------------------------------------------------------
1678 void FmFilterNavigator::StartDrag( sal_Int8 /*_nAction*/, const Point& /*_rPosPixel*/ )
1679 {
1680     EndSelection();
1681 
1682     // be sure that the data is only used within a only one form!
1683     m_aControlExchange.prepareDrag();
1684 
1685     ::std::vector<FmFilterItem*> aItemList;
1686     if ( FmFormItem* pFirstItem = getSelectedFilterItems(aItemList) )
1687     {
1688         m_aControlExchange->setDraggedEntries(aItemList);
1689         m_aControlExchange->setFormItem(pFirstItem);
1690         m_aControlExchange.startDrag( DND_ACTION_COPYMOVE );
1691     }
1692 }
1693 
1694 //------------------------------------------------------------------------------
1695 void FmFilterNavigator::Command( const CommandEvent& rEvt )
1696 {
1697     sal_Bool bHandled = sal_False;
1698     switch (rEvt.GetCommand())
1699     {
1700         case COMMAND_CONTEXTMENU:
1701         {
1702             // die Stelle, an der geklickt wurde
1703             Point aWhere;
1704             SvLBoxEntry* pClicked = NULL;
1705             if (rEvt.IsMouseEvent())
1706             {
1707                 aWhere = rEvt.GetMousePosPixel();
1708                 pClicked = GetEntry(aWhere);
1709                 if (pClicked == NULL)
1710                     break;
1711 
1712                 if (!IsSelected(pClicked))
1713                 {
1714                     SelectAll(sal_False);
1715                     Select(pClicked, sal_True);
1716                     SetCurEntry(pClicked);
1717                 }
1718             }
1719             else
1720             {
1721                 pClicked = GetCurEntry();
1722                 if (!pClicked)
1723                     break;
1724                 aWhere = GetEntryPosition( pClicked );
1725             }
1726 
1727             ::std::vector<FmFilterData*> aSelectList;
1728             for (SvLBoxEntry* pEntry = FirstSelected();
1729                  pEntry != NULL;
1730                  pEntry = NextSelected(pEntry))
1731             {
1732                 // don't delete forms
1733                 FmFormItem* pForm = PTR_CAST(FmFormItem, (FmFilterData*)pEntry->GetUserData());
1734                 if (!pForm)
1735                     aSelectList.push_back((FmFilterData*)pEntry->GetUserData());
1736             }
1737             if (aSelectList.size() == 1)
1738             {
1739                 // don't delete the only empty row of a form
1740                 FmFilterItems* pFilterItems = PTR_CAST(FmFilterItems, aSelectList[0]);
1741                 if (pFilterItems && pFilterItems->GetChildren().empty()
1742                     && pFilterItems->GetParent()->GetChildren().size() == 1)
1743                     aSelectList.clear();
1744             }
1745 
1746             PopupMenu aContextMenu(SVX_RES(RID_FM_FILTER_MENU));
1747 
1748             // every condition could be deleted except the first one if its the only one
1749             aContextMenu.EnableItem( SID_FM_DELETE, !aSelectList.empty() );
1750 
1751             //
1752             sal_Bool bEdit = PTR_CAST(FmFilterItem, (FmFilterData*)pClicked->GetUserData()) != NULL &&
1753                 IsSelected(pClicked) && GetSelectionCount() == 1;
1754 
1755             aContextMenu.EnableItem( SID_FM_FILTER_EDIT,
1756                 bEdit );
1757             aContextMenu.EnableItem( SID_FM_FILTER_IS_NULL,
1758                 bEdit );
1759             aContextMenu.EnableItem( SID_FM_FILTER_IS_NOT_NULL,
1760                 bEdit );
1761 
1762             aContextMenu.RemoveDisabledEntries(sal_True, sal_True);
1763             sal_uInt16 nSlotId = aContextMenu.Execute( this, aWhere );
1764             switch( nSlotId )
1765             {
1766                 case SID_FM_FILTER_EDIT:
1767                 {
1768                     EditEntry( pClicked );
1769                 }   break;
1770                 case SID_FM_FILTER_IS_NULL:
1771                 case SID_FM_FILTER_IS_NOT_NULL:
1772                 {
1773                     UniString aErrorMsg;
1774                     UniString aText;
1775                     if (nSlotId == SID_FM_FILTER_IS_NULL)
1776                         aText.AssignAscii("IS NULL");
1777                     else
1778                         aText.AssignAscii("IS NOT NULL");
1779 
1780                     m_pModel->ValidateText((FmFilterItem*)pClicked->GetUserData(),
1781                                             aText, aErrorMsg);
1782                     m_pModel->SetTextForItem((FmFilterItem*)pClicked->GetUserData(), aText);
1783                 }   break;
1784                 case SID_FM_DELETE:
1785                 {
1786                     DeleteSelection();
1787                 }   break;
1788             }
1789             bHandled = sal_True;
1790         } break;
1791     }
1792 
1793     if (!bHandled)
1794         SvTreeListBox::Command( rEvt );
1795 }
1796 // -----------------------------------------------------------------------------
1797 SvLBoxEntry* FmFilterNavigator::getNextEntry(SvLBoxEntry* _pStartWith)
1798 {
1799     SvLBoxEntry* pEntry = _pStartWith ? _pStartWith : LastSelected();
1800     pEntry = Next(pEntry);
1801     // we need the next filter entry
1802     while( pEntry && GetChildCount( pEntry ) == 0 && pEntry != Last() )
1803         pEntry = Next(pEntry);
1804     return pEntry;
1805 }
1806 // -----------------------------------------------------------------------------
1807 SvLBoxEntry* FmFilterNavigator::getPrevEntry(SvLBoxEntry* _pStartWith)
1808 {
1809     SvLBoxEntry* pEntry = _pStartWith ? _pStartWith : FirstSelected();
1810     pEntry = Prev(pEntry);
1811     // check if the previous entry is a filter, if so get the next prev
1812     if ( pEntry && GetChildCount( pEntry ) != 0 )
1813     {
1814         pEntry = Prev(pEntry);
1815         // if the entry is still no leaf return
1816         if ( pEntry && GetChildCount( pEntry ) != 0 )
1817             pEntry = NULL;
1818     }
1819     return pEntry;
1820 }
1821 //------------------------------------------------------------------------
1822 void FmFilterNavigator::KeyInput(const KeyEvent& rKEvt)
1823 {
1824     const KeyCode&  rKeyCode = rKEvt.GetKeyCode();
1825 
1826     switch ( rKeyCode.GetCode() )
1827     {
1828     case KEY_UP:
1829     case KEY_DOWN:
1830     {
1831         if ( !rKeyCode.IsMod1() || !rKeyCode.IsMod2() || rKeyCode.IsShift() )
1832             break;
1833 
1834         ::std::vector<FmFilterItem*> aItemList;
1835         if ( !getSelectedFilterItems( aItemList ) )
1836             break;
1837 
1838         ::std::mem_fun1_t<SvLBoxEntry*,FmFilterNavigator,SvLBoxEntry*> getter = ::std::mem_fun(&FmFilterNavigator::getNextEntry);
1839         if ( rKeyCode.GetCode() == KEY_UP )
1840             getter = ::std::mem_fun(&FmFilterNavigator::getPrevEntry);
1841 
1842         SvLBoxEntry* pTarget = getter( this, NULL );
1843         if ( !pTarget )
1844             break;
1845 
1846         FmFilterItems* pTargetItems = getTargetItems( pTarget );
1847         if ( !pTargetItems )
1848             break;
1849 
1850         ::std::vector<FmFilterItem*>::const_iterator aEnd = aItemList.end();
1851         sal_Bool bNextTargetItem = sal_True;
1852         while ( bNextTargetItem )
1853         {
1854             ::std::vector<FmFilterItem*>::const_iterator i = aItemList.begin();
1855             for (; i != aEnd; ++i)
1856             {
1857                 if ( (*i)->GetParent() == pTargetItems )
1858                 {
1859                     pTarget = getter(this,pTarget);
1860                     if ( !pTarget )
1861                         return;
1862                     pTargetItems = getTargetItems( pTarget );
1863                     break;
1864                 }
1865                 else
1866                 {
1867                     FmFilterItem* pFilterItem = pTargetItems->Find( (*i)->GetComponentIndex() );
1868                     // we found the text component so jump above
1869                     if ( pFilterItem )
1870                     {
1871                         pTarget = getter( this, pTarget );
1872                         if ( !pTarget )
1873                             return;
1874 
1875                         pTargetItems = getTargetItems( pTarget );
1876                         break;
1877                     }
1878                 }
1879             }
1880             bNextTargetItem = i != aEnd && pTargetItems;
1881         }
1882 
1883         if ( pTargetItems )
1884         {
1885             insertFilterItem( aItemList, pTargetItems );
1886             return;
1887         }
1888     }
1889     break;
1890 
1891     case KEY_DELETE:
1892     {
1893         if ( rKeyCode.GetModifier() )
1894             break;
1895 
1896         if ( !IsSelected( First() ) || GetEntryCount() > 1 )
1897             DeleteSelection();
1898         return;
1899     }
1900     }
1901 
1902     SvTreeListBox::KeyInput(rKEvt);
1903 }
1904 
1905 //------------------------------------------------------------------------------
1906 void FmFilterNavigator::DeleteSelection()
1907 {
1908     // to avoid the deletion of an entry twice (e.g. deletion of a parent and afterward
1909     // the deletion of it's child, i have to shrink the selecton list
1910     ::std::vector<SvLBoxEntry*> aEntryList;
1911     for (SvLBoxEntry* pEntry = FirstSelected();
1912          pEntry != NULL;
1913          pEntry = NextSelected(pEntry))
1914     {
1915         FmFilterItem* pFilterItem = PTR_CAST(FmFilterItem, (FmFilterData*)pEntry->GetUserData());
1916         if (pFilterItem && IsSelected(GetParent(pEntry)))
1917             continue;
1918 
1919         FmFormItem* pForm = PTR_CAST(FmFormItem, (FmFilterData*)pEntry->GetUserData());
1920         if (!pForm)
1921             aEntryList.push_back(pEntry);
1922     }
1923 
1924     // Remove the selection
1925     SelectAll(sal_False);
1926 
1927     for (::std::vector<SvLBoxEntry*>::reverse_iterator i = aEntryList.rbegin();
1928         // link problems with operator ==
1929         i.base() != aEntryList.rend().base(); i++)
1930     {
1931         m_pModel->Remove((FmFilterData*)(*i)->GetUserData());
1932     }
1933 }
1934 // -----------------------------------------------------------------------------
1935 
1936 //========================================================================
1937 // class FmFilterNavigatorWin
1938 //========================================================================
1939 FmFilterNavigatorWin::FmFilterNavigatorWin( SfxBindings* _pBindings, SfxChildWindow* _pMgr,
1940                               Window* _pParent )
1941                      :SfxDockingWindow( _pBindings, _pMgr, _pParent, WinBits(WB_STDMODELESS|WB_SIZEABLE|WB_ROLLABLE|WB_3DLOOK|WB_DOCKABLE) )
1942                      ,SfxControllerItem( SID_FM_FILTER_NAVIGATOR_CONTROL, *_pBindings )
1943 {
1944     SetHelpId( HID_FILTER_NAVIGATOR_WIN );
1945 
1946     m_pNavigator = new FmFilterNavigator( this );
1947     m_pNavigator->Show();
1948     SetText( SVX_RES(RID_STR_FILTER_NAVIGATOR) );
1949     SfxDockingWindow::SetFloatingSize( Size(200,200) );
1950 }
1951 
1952 //------------------------------------------------------------------------
1953 FmFilterNavigatorWin::~FmFilterNavigatorWin()
1954 {
1955     delete m_pNavigator;
1956 }
1957 
1958 //-----------------------------------------------------------------------
1959 void FmFilterNavigatorWin::UpdateContent(FmFormShell* pFormShell)
1960 {
1961     if (!pFormShell)
1962         m_pNavigator->UpdateContent( NULL, NULL );
1963     else
1964     {
1965         Reference< XFormController >  xController(pFormShell->GetImpl()->getActiveInternalController());
1966         Reference< XIndexAccess >   xContainer;
1967         if (xController.is())
1968         {
1969             Reference< XChild >  xChild(xController, UNO_QUERY);
1970             for (Reference< XInterface >  xParent(xChild->getParent());
1971                  xParent.is();
1972                  xParent = xChild.is() ? xChild->getParent() : Reference< XInterface > ())
1973             {
1974                 xContainer = Reference< XIndexAccess > (xParent, UNO_QUERY);
1975                 xChild = Reference< XChild > (xParent, UNO_QUERY);
1976             }
1977         }
1978         m_pNavigator->UpdateContent(xContainer, xController);
1979     }
1980 }
1981 
1982 //-----------------------------------------------------------------------
1983 void FmFilterNavigatorWin::StateChanged( sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState )
1984 {
1985     if( !pState  || SID_FM_FILTER_NAVIGATOR_CONTROL != nSID )
1986         return;
1987 
1988     if( eState >= SFX_ITEM_AVAILABLE )
1989     {
1990         FmFormShell* pShell = PTR_CAST( FmFormShell,((SfxObjectItem*)pState)->GetShell() );
1991         UpdateContent( pShell );
1992     }
1993     else
1994         UpdateContent( NULL );
1995 }
1996 
1997 //-----------------------------------------------------------------------
1998 sal_Bool FmFilterNavigatorWin::Close()
1999 {
2000     if ( m_pNavigator && m_pNavigator->IsEditingActive() )
2001         m_pNavigator->EndEditing();
2002 
2003     if ( m_pNavigator && m_pNavigator->IsEditingActive() )
2004         // the EndEditing was vetoed (perhaps of an syntax error or such)
2005         return sal_False;
2006 
2007     UpdateContent( NULL );
2008     return SfxDockingWindow::Close();
2009 }
2010 
2011 //-----------------------------------------------------------------------
2012 void FmFilterNavigatorWin::FillInfo( SfxChildWinInfo& rInfo ) const
2013 {
2014     SfxDockingWindow::FillInfo( rInfo );
2015     rInfo.bVisible = sal_False;
2016 }
2017 
2018 //-----------------------------------------------------------------------
2019 Size FmFilterNavigatorWin::CalcDockingSize( SfxChildAlignment eAlign )
2020 {
2021     if ( ( eAlign == SFX_ALIGN_TOP ) || ( eAlign == SFX_ALIGN_BOTTOM ) )
2022         return Size();
2023 
2024     return SfxDockingWindow::CalcDockingSize( eAlign );
2025 }
2026 
2027 //-----------------------------------------------------------------------
2028 SfxChildAlignment FmFilterNavigatorWin::CheckAlignment( SfxChildAlignment eActAlign, SfxChildAlignment eAlign )
2029 {
2030     switch (eAlign)
2031     {
2032         case SFX_ALIGN_LEFT:
2033         case SFX_ALIGN_RIGHT:
2034         case SFX_ALIGN_NOALIGNMENT:
2035             return (eAlign);
2036         default:
2037             break;
2038     }
2039 
2040     return (eActAlign);
2041 }
2042 
2043 //------------------------------------------------------------------------
2044 void FmFilterNavigatorWin::Resize()
2045 {
2046     SfxDockingWindow::Resize();
2047 
2048     Size aLogOutputSize = PixelToLogic( GetOutputSizePixel(), MAP_APPFONT );
2049     Size aLogExplSize = aLogOutputSize;
2050     aLogExplSize.Width() -= 6;
2051     aLogExplSize.Height() -= 6;
2052 
2053     Point aExplPos = LogicToPixel( Point(3,3), MAP_APPFONT );
2054     Size aExplSize = LogicToPixel( aLogExplSize, MAP_APPFONT );
2055 
2056     m_pNavigator->SetPosSizePixel( aExplPos, aExplSize );
2057 }
2058 // -----------------------------------------------------------------------------
2059 void FmFilterNavigatorWin::GetFocus()
2060 {
2061     // oj #97405#
2062     if ( m_pNavigator )
2063         m_pNavigator->GrabFocus();
2064 }
2065 // -----------------------------------------------------------------------------
2066 
2067 
2068 //========================================================================
2069 // class FmFilterNavigatorWinMgr
2070 //========================================================================
2071 SFX_IMPL_DOCKINGWINDOW( FmFilterNavigatorWinMgr, SID_FM_FILTER_NAVIGATOR )
2072 
2073 //-----------------------------------------------------------------------
2074 FmFilterNavigatorWinMgr::FmFilterNavigatorWinMgr( Window *_pParent, sal_uInt16 _nId,
2075                                     SfxBindings *_pBindings, SfxChildWinInfo* _pInfo )
2076                  :SfxChildWindow( _pParent, _nId )
2077 {
2078     pWindow = new FmFilterNavigatorWin( _pBindings, this, _pParent );
2079     eChildAlignment = SFX_ALIGN_NOALIGNMENT;
2080     ((SfxDockingWindow*)pWindow)->Initialize( _pInfo );
2081 }
2082 
2083 //........................................................................
2084 }   // namespace svxform
2085 //........................................................................
2086