LibreOffice Module svx (master)  1
filtnav.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <memory>
21 #include <filtnav.hxx>
22 #include <fmexch.hxx>
23 #include <helpids.h>
24 #include <fmprop.hxx>
25 #include <svx/strings.hrc>
26 
27 #include <com/sun/star/awt/XControlModel.hpp>
28 #include <com/sun/star/awt/XControl.hpp>
29 #include <com/sun/star/form/runtime/XFormController.hpp>
30 #include <com/sun/star/lang/XUnoTunnel.hpp>
31 #include <com/sun/star/util/NumberFormatter.hpp>
32 #include <com/sun/star/beans/XFastPropertySet.hpp>
33 #include <com/sun/star/sdb/SQLContext.hpp>
34 
36 #include <comphelper/string.hxx>
37 #include <connectivity/dbtools.hxx>
38 #include <connectivity/sqlnode.hxx>
39 #include <cppuhelper/implbase.hxx>
41 #include <fmservs.hxx>
42 #include <fmshimp.hxx>
43 #include <o3tl/safeint.hxx>
44 #include <sfx2/dispatch.hxx>
45 #include <sfx2/objitem.hxx>
46 #include <sfx2/objsh.hxx>
47 #include <sfx2/request.hxx>
48 #include <svx/dialmgr.hxx>
49 #include <svx/fmshell.hxx>
50 #include <svx/fmtools.hxx>
51 #include <svx/svxids.hrc>
52 #include <vcl/settings.hxx>
53 #include <tools/diagnose_ex.h>
54 #include <vcl/commandevent.hxx>
55 #include <vcl/event.hxx>
56 #include <vcl/svlbitm.hxx>
57 #include <vcl/treelistentry.hxx>
58 #include <vcl/viewdataentry.hxx>
59 #include <vcl/svapp.hxx>
60 
61 #include <bitmaps.hlst>
62 
63 #include <functional>
64 
65 #define DROP_ACTION_TIMER_INITIAL_TICKS 10
66  // it takes this long for the scrolling to begin
67 #define DROP_ACTION_TIMER_SCROLL_TICKS 3
68  // a line is scrolled in these intervals
69 #define DROP_ACTION_TIMER_TICK_BASE 10
70  // this is the basis for multiplying both figures (in ms)
71 
72 using namespace ::svxform;
73 using namespace ::connectivity;
74 using namespace ::dbtools;
75 
76 
77 namespace svxform
78 {
79 
80 
81  using ::com::sun::star::uno::Reference;
82  using ::com::sun::star::container::XIndexAccess;
83  using ::com::sun::star::uno::UNO_QUERY;
85  using ::com::sun::star::form::runtime::XFormController;
86  using ::com::sun::star::form::runtime::XFilterController;
87  using ::com::sun::star::form::runtime::XFilterControllerListener;
88  using ::com::sun::star::form::runtime::FilterEvent;
89  using ::com::sun::star::lang::EventObject;
90  using ::com::sun::star::uno::RuntimeException;
91  using ::com::sun::star::form::XForm;
92  using ::com::sun::star::container::XChild;
93  using ::com::sun::star::awt::XControl;
94  using ::com::sun::star::sdbc::XConnection;
95  using ::com::sun::star::util::XNumberFormatsSupplier;
96  using ::com::sun::star::util::XNumberFormatter;
97  using ::com::sun::star::util::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::uno::Sequence;
106 
107 
109  : m_pFormItem(nullptr)
110 {
111 }
112 
114 {
116 }
117 
118 
120 {
121  static SotClipboardFormatId s_nFormat =
122  SotExchange::RegisterFormatName("application/x-openoffice;windows_formatname=\"form.FilterControlExchange\"");
123  DBG_ASSERT(static_cast<SotClipboardFormatId>(-1) != s_nFormat, "OFilterExchangeHelper::getFormatId: bad exchange id!");
124  return s_nFormat;
125 }
126 
127 
129 {
130  return new OFilterItemExchange;
131 }
132 
133 
135 {
136  return Image();
137 }
138 
140 {
141 }
142 
144 {
145  return Image(StockImage::Yes, RID_SVXBMP_FORM);
146 }
147 
148 FmFilterItem* FmFilterItems::Find( const ::sal_Int32 _nFilterComponentIndex ) const
149 {
150  for ( auto & pData : m_aChildren )
151  {
152  FmFilterItem& rCondition = dynamic_cast<FmFilterItem&>(*pData);
153  if ( _nFilterComponentIndex == rCondition.GetComponentIndex() )
154  return &rCondition;
155  }
156  return nullptr;
157 }
158 
160 {
161  return Image(StockImage::Yes, RID_SVXBMP_FILTER);
162 }
163 
165  const OUString& aFieldName,
166  const OUString& aText,
167  const sal_Int32 _nComponentIndex )
168  :FmFilterData(pParent, aText)
169  ,m_aFieldName(aFieldName)
170  ,m_nComponentIndex( _nComponentIndex )
171 {
172 }
173 
175 {
176  return Image(StockImage::Yes, RID_SVXBMP_FIELD);
177 }
178 
179 // Hints for communication between model and view
180 
181 namespace {
182 
183 class FmFilterHint : public SfxHint
184 {
185  FmFilterData* const m_pData;
186 
187 public:
188  explicit FmFilterHint(FmFilterData* pData):m_pData(pData){}
189  FmFilterData* GetData() const { return m_pData; }
190 };
191 
192 class FmFilterInsertedHint : public FmFilterHint
193 {
194  size_t const m_nPos; // Position relative to the parent of the data
195 
196 public:
197  FmFilterInsertedHint(FmFilterData* pData, size_t nRelPos)
198  :FmFilterHint(pData)
199  ,m_nPos(nRelPos){}
200 
201  size_t GetPos() const { return m_nPos; }
202 };
203 
204 class FmFilterRemovedHint : public FmFilterHint
205 {
206 public:
207  explicit FmFilterRemovedHint(FmFilterData* pData)
208  :FmFilterHint(pData){}
209 };
210 
211 
212 class FmFilterTextChangedHint : public FmFilterHint
213 {
214 public:
215  explicit FmFilterTextChangedHint(FmFilterData* pData)
216  :FmFilterHint(pData){}
217 };
218 
219 class FilterClearingHint : public SfxHint
220 {
221 public:
222  FilterClearingHint(){}
223 };
224 
225 class FmFilterCurrentChangedHint : public SfxHint
226 {
227 public:
228  FmFilterCurrentChangedHint(){}
229 };
230 
231 }
232 
233 // class FmFilterAdapter, listener at the FilterControls
234 class FmFilterAdapter : public ::cppu::WeakImplHelper< XFilterControllerListener >
235 {
237  Reference< XIndexAccess > m_xControllers;
238 
239 public:
240  FmFilterAdapter(FmFilterModel* pModel, const Reference< XIndexAccess >& xControllers);
241 
242 // XEventListener
243  virtual void SAL_CALL disposing(const EventObject& Source) override;
244 
245 // XFilterControllerListener
246  virtual void SAL_CALL predicateExpressionChanged( const FilterEvent& Event ) override;
247  virtual void SAL_CALL disjunctiveTermRemoved( const FilterEvent& Event ) override;
248  virtual void SAL_CALL disjunctiveTermAdded( const FilterEvent& Event ) override;
249 
250 // helpers
252  void dispose();
253 
254  void AddOrRemoveListener( const Reference< XIndexAccess >& _rxControllers, const bool _bAdd );
255 
256  static void setText(sal_Int32 nPos,
257  const FmFilterItem* pFilterItem,
258  const OUString& rText);
259 };
260 
261 
262 FmFilterAdapter::FmFilterAdapter(FmFilterModel* pModel, const Reference< XIndexAccess >& xControllers)
263  :m_pModel( pModel )
264  ,m_xControllers( xControllers )
265 {
267 }
268 
269 
271 {
273 }
274 
275 
276 void FmFilterAdapter::AddOrRemoveListener( const Reference< XIndexAccess >& _rxControllers, const bool _bAdd )
277 {
278  for (sal_Int32 i = 0, nLen = _rxControllers->getCount(); i < nLen; ++i)
279  {
280  Reference< XIndexAccess > xElement( _rxControllers->getByIndex(i), UNO_QUERY );
281 
282  // step down
283  AddOrRemoveListener( xElement, _bAdd );
284 
285  // handle this particular controller
286  Reference< XFilterController > xController( xElement, UNO_QUERY );
287  OSL_ENSURE( xController.is(), "FmFilterAdapter::InsertElements: no XFilterController, cannot sync data!" );
288  if ( xController.is() )
289  {
290  if ( _bAdd )
291  xController->addFilterControllerListener( this );
292  else
293  xController->removeFilterControllerListener( this );
294  }
295  }
296 }
297 
298 
299 void FmFilterAdapter::setText(sal_Int32 nRowPos,
300  const FmFilterItem* pFilterItem,
301  const OUString& rText)
302 {
303  FmFormItem* pFormItem = dynamic_cast<FmFormItem*>( pFilterItem->GetParent()->GetParent() );
304  assert(pFormItem);
305  try
306  {
307  Reference< XFilterController > xController( pFormItem->GetController(), UNO_QUERY_THROW );
308  xController->setPredicateExpression( pFilterItem->GetComponentIndex(), nRowPos, rText );
309  }
310  catch( const Exception& )
311  {
313  }
314 }
315 
316 
317 // XEventListener
318 
319 void SAL_CALL FmFilterAdapter::disposing(const EventObject& /*e*/)
320 {
321 }
322 
323 
324 namespace
325 {
326  OUString lcl_getLabelName_nothrow( const Reference< XControl >& _rxControl )
327  {
328  OUString sLabelName;
329  try
330  {
331  Reference< XPropertySet > xModel( _rxControl->getModel(), UNO_QUERY_THROW );
332  sLabelName = getLabelName( xModel );
333  }
334  catch( const Exception& )
335  {
337  }
338  return sLabelName;
339  }
340 
341  Reference< XPropertySet > lcl_getBoundField_nothrow( const Reference< XControl >& _rxControl )
342  {
343  Reference< XPropertySet > xField;
344  try
345  {
346  Reference< XPropertySet > xModelProps( _rxControl->getModel(), UNO_QUERY_THROW );
347  xField.set( xModelProps->getPropertyValue( FM_PROP_BOUNDFIELD ), UNO_QUERY_THROW );
348  }
349  catch( const Exception& )
350  {
352  }
353  return xField;
354  }
355 }
356 
357 // XFilterControllerListener
358 
359 void FmFilterAdapter::predicateExpressionChanged( const FilterEvent& Event )
360 {
361  SolarMutexGuard aGuard;
362 
363  if ( !m_pModel )
364  return;
365 
366  // the controller which sent the event
367  Reference< XFormController > xController( Event.Source, UNO_QUERY_THROW );
368  Reference< XFilterController > xFilterController( Event.Source, UNO_QUERY_THROW );
369  Reference< XForm > xForm( xController->getModel(), UNO_QUERY_THROW );
370 
371  FmFormItem* pFormItem = m_pModel->Find( m_pModel->m_aChildren, xForm );
372  OSL_ENSURE( pFormItem, "FmFilterAdapter::predicateExpressionChanged: don't know this form!" );
373  if ( !pFormItem )
374  return;
375 
376  const sal_Int32 nActiveTerm( xFilterController->getActiveTerm() );
377 
378  FmFilterData* pData = pFormItem->GetChildren()[nActiveTerm].get();
379  FmFilterItems& rFilter = dynamic_cast<FmFilterItems&>(*pData);
380  FmFilterItem* pFilterItem = rFilter.Find( Event.FilterComponent );
381  if ( pFilterItem )
382  {
383  if ( !Event.PredicateExpression.isEmpty())
384  {
385  pFilterItem->SetText( Event.PredicateExpression );
386  // notify the UI
387  FmFilterTextChangedHint aChangeHint(pFilterItem);
388  m_pModel->Broadcast( aChangeHint );
389  }
390  else
391  {
392  // no text anymore so remove the condition
393  m_pModel->Remove(pFilterItem);
394  }
395  }
396  else
397  {
398  // searching the component by field name
399  OUString aFieldName( lcl_getLabelName_nothrow( xFilterController->getFilterComponent( Event.FilterComponent ) ) );
400 
401  std::unique_ptr<FmFilterItem> pNewFilterItem(new FmFilterItem(&rFilter, aFieldName, Event.PredicateExpression, Event.FilterComponent));
402  m_pModel->Insert(rFilter.GetChildren().end(), std::move(pNewFilterItem));
403  }
404 
405  // ensure there's one empty term in the filter, just in case the active term was previously empty
406  m_pModel->EnsureEmptyFilterRows( *pFormItem );
407 }
408 
409 
410 void SAL_CALL FmFilterAdapter::disjunctiveTermRemoved( const FilterEvent& Event )
411 {
412  SolarMutexGuard aGuard;
413 
414  Reference< XFormController > xController( Event.Source, UNO_QUERY_THROW );
415  Reference< XFilterController > xFilterController( Event.Source, UNO_QUERY_THROW );
416  Reference< XForm > xForm( xController->getModel(), UNO_QUERY_THROW );
417 
418  FmFormItem* pFormItem = m_pModel->Find( m_pModel->m_aChildren, xForm );
419  OSL_ENSURE( pFormItem, "FmFilterAdapter::disjunctiveTermRemoved: don't know this form!" );
420  if ( !pFormItem )
421  return;
422 
423  auto& rTermItems = pFormItem->GetChildren();
424  const bool bValidIndex = ( Event.DisjunctiveTerm >= 0 ) && ( o3tl::make_unsigned(Event.DisjunctiveTerm) < rTermItems.size() );
425  OSL_ENSURE( bValidIndex, "FmFilterAdapter::disjunctiveTermRemoved: invalid term index!" );
426  if ( !bValidIndex )
427  return;
428 
429  // if the first term was removed, then the to-be first term needs its text updated
430  if ( Event.DisjunctiveTerm == 0 )
431  {
432  rTermItems[1]->SetText( SvxResId(RID_STR_FILTER_FILTER_FOR));
433  FmFilterTextChangedHint aChangeHint( rTermItems[1].get() );
434  m_pModel->Broadcast( aChangeHint );
435  }
436 
437  // finally remove the entry from the model
438  m_pModel->Remove( rTermItems.begin() + Event.DisjunctiveTerm );
439 
440  // ensure there's one empty term in the filter, just in case the currently removed one was the last empty one
441  m_pModel->EnsureEmptyFilterRows( *pFormItem );
442 }
443 
444 
445 void SAL_CALL FmFilterAdapter::disjunctiveTermAdded( const FilterEvent& Event )
446 {
447  SolarMutexGuard aGuard;
448 
449  Reference< XFormController > xController( Event.Source, UNO_QUERY_THROW );
450  Reference< XFilterController > xFilterController( Event.Source, UNO_QUERY_THROW );
451  Reference< XForm > xForm( xController->getModel(), UNO_QUERY_THROW );
452 
453  FmFormItem* pFormItem = m_pModel->Find( m_pModel->m_aChildren, xForm );
454  OSL_ENSURE( pFormItem, "FmFilterAdapter::disjunctiveTermAdded: don't know this form!" );
455  if ( !pFormItem )
456  return;
457 
458  const sal_Int32 nInsertPos = Event.DisjunctiveTerm;
459  bool bValidIndex = ( nInsertPos >= 0 ) && ( o3tl::make_unsigned(nInsertPos) <= pFormItem->GetChildren().size() );
460  if ( !bValidIndex )
461  {
462  OSL_FAIL( "FmFilterAdapter::disjunctiveTermAdded: invalid index!" );
463  return;
464  }
465 
466  auto insertPos = pFormItem->GetChildren().begin() + nInsertPos;
467 
468  // "Filter for" for first position, "Or" for the other positions
469  std::unique_ptr<FmFilterItems> pFilterItems(new FmFilterItems(pFormItem, (nInsertPos?SvxResId(RID_STR_FILTER_FILTER_OR):SvxResId(RID_STR_FILTER_FILTER_FOR))));
470  m_pModel->Insert( insertPos, std::move(pFilterItems) );
471 }
472 
473 
475  :FmParentData(nullptr, OUString())
477  ,m_pCurrentItems(nullptr)
478 {
479 }
480 
481 
483 {
484  Clear();
485 }
486 
487 
489 {
490  // notify
491  FilterClearingHint aClearedHint;
492  Broadcast( aClearedHint );
493 
494  // lose endings
495  if (m_pAdapter.is())
496  {
497  m_pAdapter->dispose();
498  m_pAdapter.clear();
499  }
500 
501  m_pCurrentItems = nullptr;
502  m_xController = nullptr;
503  m_xControllers = nullptr;
504 
505  m_aChildren.clear();
506 }
507 
508 
509 void FmFilterModel::Update(const Reference< XIndexAccess > & xControllers, const Reference< XFormController > & xCurrent)
510 {
511  if ( xCurrent == m_xController )
512  return;
513 
514  if (!xControllers.is())
515  {
516  Clear();
517  return;
518  }
519 
520  // there is only a new current controller
521  if ( m_xControllers != xControllers )
522  {
523  Clear();
524 
525  m_xControllers = xControllers;
526  Update(m_xControllers, this);
527 
528  DBG_ASSERT(xCurrent.is(), "FmFilterModel::Update(...) no current controller");
529 
530  // Listening for TextChanges
531  m_pAdapter = new FmFilterAdapter(this, xControllers);
532 
533  SetCurrentController(xCurrent);
534  EnsureEmptyFilterRows( *this );
535  }
536  else
537  SetCurrentController(xCurrent);
538 }
539 
540 
541 void FmFilterModel::Update(const Reference< XIndexAccess > & xControllers, FmParentData* pParent)
542 {
543  try
544  {
545  sal_Int32 nCount = xControllers->getCount();
546  for ( sal_Int32 i = 0; i < nCount; ++i )
547  {
548  Reference< XFormController > xController( xControllers->getByIndex(i), UNO_QUERY_THROW );
549 
550  Reference< XPropertySet > xFormProperties( xController->getModel(), UNO_QUERY_THROW );
551  OUString aName;
552  OSL_VERIFY( xFormProperties->getPropertyValue( FM_PROP_NAME ) >>= aName );
553 
554  // Insert a new item for the form
555  FmFormItem* pFormItem = new FmFormItem( pParent, xController, aName );
556  Insert( pParent->GetChildren().end(), std::unique_ptr<FmFilterData>(pFormItem) );
557 
558  Reference< XFilterController > xFilterController( pFormItem->GetFilterController(), UNO_SET_THROW );
559 
560  // insert the existing filters for the form
561  OUString aTitle(SvxResId(RID_STR_FILTER_FILTER_FOR));
562 
563  const Sequence< Sequence< OUString > > aExpressions = xFilterController->getPredicateExpressions();
564  for ( auto const & conjunctionTerm : aExpressions )
565  {
566  // we always display one row, even if there's no term to be displayed
567  FmFilterItems* pFilterItems = new FmFilterItems( pFormItem, aTitle );
568  Insert( pFormItem->GetChildren().end(), std::unique_ptr<FmFilterData>(pFilterItems) );
569 
570  const Sequence< OUString >& rDisjunction( conjunctionTerm );
571  sal_Int32 nComponentIndex = -1;
572  for ( const OUString& rDisjunctiveTerm : rDisjunction )
573  {
574  ++nComponentIndex;
575 
576  if ( rDisjunctiveTerm.isEmpty() )
577  // no condition for this particular component in this particular conjunction term
578  continue;
579 
580  // determine the display name of the control
581  const Reference< XControl > xFilterControl( xFilterController->getFilterComponent( nComponentIndex ) );
582  const OUString sDisplayName( lcl_getLabelName_nothrow( xFilterControl ) );
583 
584  // insert a new entry
585  std::unique_ptr<FmFilterItem> pANDCondition(new FmFilterItem( pFilterItems, sDisplayName, rDisjunctiveTerm, nComponentIndex ));
586  Insert( pFilterItems->GetChildren().end(), std::move(pANDCondition) );
587  }
588 
589  // title for the next conditions
590  aTitle = SvxResId( RID_STR_FILTER_FILTER_OR );
591  }
592 
593  // now add dependent controllers
594  Update( xController, pFormItem );
595  }
596  }
597  catch( const Exception& )
598  {
600  }
601 }
602 
603 
604 FmFormItem* FmFilterModel::Find(const ::std::vector<std::unique_ptr<FmFilterData>>& rItems, const Reference< XFormController > & xController) const
605 {
606  for (const auto& rItem : rItems)
607  {
608  FmFormItem* pForm = dynamic_cast<FmFormItem*>( rItem.get() );
609  if (pForm)
610  {
611  if ( xController == pForm->GetController() )
612  return pForm;
613  else
614  {
615  pForm = Find(pForm->GetChildren(), xController);
616  if (pForm)
617  return pForm;
618  }
619  }
620  }
621  return nullptr;
622 }
623 
624 
625 FmFormItem* FmFilterModel::Find(const ::std::vector<std::unique_ptr<FmFilterData>>& rItems, const Reference< XForm >& xForm) const
626 {
627  for (const auto& rItem : rItems)
628  {
629  FmFormItem* pForm = dynamic_cast<FmFormItem*>( rItem.get() );
630  if (pForm)
631  {
632  if (xForm == pForm->GetController()->getModel())
633  return pForm;
634  else
635  {
636  pForm = Find(pForm->GetChildren(), xForm);
637  if (pForm)
638  return pForm;
639  }
640  }
641  }
642  return nullptr;
643 }
644 
645 
646 void FmFilterModel::SetCurrentController(const Reference< XFormController > & xCurrent)
647 {
648  if ( xCurrent == m_xController )
649  return;
650 
651  m_xController = xCurrent;
652 
653  FmFormItem* pItem = Find( m_aChildren, xCurrent );
654  if ( !pItem )
655  return;
656 
657  try
658  {
659  Reference< XFilterController > xFilterController( m_xController, UNO_QUERY_THROW );
660  const sal_Int32 nActiveTerm( xFilterController->getActiveTerm() );
661  if ( pItem->GetChildren().size() > o3tl::make_unsigned(nActiveTerm) )
662  {
663  SetCurrentItems( static_cast< FmFilterItems* >( pItem->GetChildren()[ nActiveTerm ].get() ) );
664  }
665  }
666  catch( const Exception& )
667  {
669  }
670 }
671 
672 
674 {
675  // insert the condition behind the last filter items
676  auto iter = std::find_if(_rFormItem.GetChildren().rbegin(), _rFormItem.GetChildren().rend(),
677  [](const std::unique_ptr<FmFilterData>& rChild) { return dynamic_cast<const FmFilterItems*>(rChild.get()) != nullptr; });
678 
679  sal_Int32 nInsertPos = iter.base() - _rFormItem.GetChildren().begin();
680  // delegate this to the FilterController, it will notify us, which will let us update our model
681  try
682  {
683  Reference< XFilterController > xFilterController( _rFormItem.GetFilterController(), UNO_SET_THROW );
684  if ( nInsertPos >= xFilterController->getDisjunctiveTerms() )
685  xFilterController->appendEmptyDisjunctiveTerm();
686  }
687  catch( const Exception& )
688  {
690  }
691 }
692 
693 void FmFilterModel::Insert(const ::std::vector<std::unique_ptr<FmFilterData>>::iterator& rPos, std::unique_ptr<FmFilterData> pData)
694 {
695  auto pTemp = pData.get();
696  size_t nPos;
697  ::std::vector<std::unique_ptr<FmFilterData>>& rItems = pData->GetParent()->GetChildren();
698  if (rPos == rItems.end())
699  {
700  nPos = rItems.size();
701  rItems.push_back(std::move(pData));
702  }
703  else
704  {
705  nPos = rPos - rItems.begin();
706  rItems.insert(rPos, std::move(pData));
707  }
708 
709  // notify the UI
710  FmFilterInsertedHint aInsertedHint(pTemp, nPos);
711  Broadcast( aInsertedHint );
712 }
713 
715 {
716  FmParentData* pParent = pData->GetParent();
717  ::std::vector<std::unique_ptr<FmFilterData>>& rItems = pParent->GetChildren();
718 
719  // erase the item from the model
720  auto i = ::std::find_if(rItems.begin(), rItems.end(),
721  [&](const std::unique_ptr<FmFilterData>& p) { return p.get() == pData; } );
722  DBG_ASSERT(i != rItems.end(), "FmFilterModel::Remove(): unknown Item");
723  // position within the parent
724  sal_Int32 nPos = i - rItems.begin();
725  if (dynamic_cast<const FmFilterItems*>( pData) != nullptr)
726  {
727  FmFormItem* pFormItem = static_cast<FmFormItem*>(pParent);
728 
729  try
730  {
731  Reference< XFilterController > xFilterController( pFormItem->GetFilterController(), UNO_SET_THROW );
732 
733  bool bEmptyLastTerm = ( ( nPos == 0 ) && xFilterController->getDisjunctiveTerms() == 1 );
734  if ( bEmptyLastTerm )
735  {
736  // remove all children (by setting an empty predicate expression)
737  ::std::vector< std::unique_ptr<FmFilterData> >& rChildren = static_cast<FmFilterItems*>(pData)->GetChildren();
738  while ( !rChildren.empty() )
739  {
740  auto removePos = rChildren.end() - 1;
741  if (FmFilterItem* pFilterItem = dynamic_cast<FmFilterItem*>( removePos->get() ))
742  {
743  FmFilterAdapter::setText( nPos, pFilterItem, OUString() );
744  }
745  Remove( removePos );
746  }
747  }
748  else
749  {
750  xFilterController->removeDisjunctiveTerm( nPos );
751  }
752  }
753  catch( const Exception& )
754  {
756  }
757  }
758  else // FormItems can not be deleted
759  {
760  FmFilterItem& rFilterItem = dynamic_cast<FmFilterItem&>(*pData);
761 
762  // if it's the last condition remove the parent
763  if (rItems.size() == 1)
764  Remove(rFilterItem.GetParent());
765  else
766  {
767  // find the position of the father within his father
768  ::std::vector<std::unique_ptr<FmFilterData>>& rParentParentItems = pData->GetParent()->GetParent()->GetChildren();
769  auto j = ::std::find_if(rParentParentItems.begin(), rParentParentItems.end(),
770  [&](const std::unique_ptr<FmFilterData>& p) { return p.get() == rFilterItem.GetParent(); });
771  DBG_ASSERT(j != rParentParentItems.end(), "FmFilterModel::Remove(): unknown Item");
772  sal_Int32 nParentPos = j - rParentParentItems.begin();
773 
774  // EmptyText removes the filter
775  FmFilterAdapter::setText(nParentPos, &rFilterItem, OUString());
776  Remove( i );
777  }
778  }
779 }
780 
781 void FmFilterModel::Remove( const ::std::vector<std::unique_ptr<FmFilterData>>::iterator& rPos )
782 {
783  // remove from parent's child list
784  std::unique_ptr<FmFilterData> pData = std::move(*rPos);
785  pData->GetParent()->GetChildren().erase( rPos );
786 
787  // notify the view, this will remove the actual SvTreeListEntry
788  FmFilterRemovedHint aRemoveHint( pData.get() );
789  Broadcast( aRemoveHint );
790 }
791 
792 
793 bool FmFilterModel::ValidateText(FmFilterItem const * pItem, OUString& rText, OUString& rErrorMsg) const
794 {
795  FmFormItem* pFormItem = dynamic_cast<FmFormItem*>( pItem->GetParent()->GetParent() );
796  assert(pFormItem);
797  try
798  {
799  Reference< XFormController > xFormController( pFormItem->GetController() );
800  // obtain the connection of the form belonging to the controller
801  Reference< XRowSet > xRowSet( xFormController->getModel(), UNO_QUERY_THROW );
802  Reference< XConnection > xConnection( getConnection( xRowSet ) );
803 
804  // obtain a number formatter for this connection
805  // TODO: shouldn't this be cached?
806  Reference< XNumberFormatsSupplier > xFormatSupplier = getNumberFormats( xConnection, true );
807  Reference< XNumberFormatter > xFormatter( NumberFormatter::create( comphelper::getProcessComponentContext() ), UNO_QUERY_THROW );
808  xFormatter->attachNumberFormatsSupplier( xFormatSupplier );
809 
810  // get the field (database column) which the item is responsible for
811  Reference< XFilterController > xFilterController( xFormController, UNO_QUERY_THROW );
812  Reference< XPropertySet > xField( lcl_getBoundField_nothrow( xFilterController->getFilterComponent( pItem->GetComponentIndex() ) ), UNO_SET_THROW );
813 
814  // parse the given text as filter predicate
815  OUString aErr, aTxt( rText );
816  std::unique_ptr< OSQLParseNode > pParseNode = predicateTree( aErr, aTxt, xFormatter, xField );
817  rErrorMsg = aErr;
818  rText = aTxt;
819  if ( pParseNode != nullptr )
820  {
821  OUString aPreparedText;
823  pParseNode->parseNodeToPredicateStr(
824  aPreparedText, xConnection, xFormatter, xField, OUString(), aAppLocale, OUString("."), getParseContext() );
825  rText = aPreparedText;
826  return true;
827  }
828  }
829  catch( const Exception& )
830  {
832  }
833 
834  return false;
835 }
836 
837 
838 void FmFilterModel::Append(FmFilterItems* pItems, std::unique_ptr<FmFilterItem> pFilterItem)
839 {
840  Insert(pItems->GetChildren().end(), std::move(pFilterItem));
841 }
842 
843 
844 void FmFilterModel::SetTextForItem(FmFilterItem* pItem, const OUString& rText)
845 {
846  ::std::vector<std::unique_ptr<FmFilterData>>& rItems = pItem->GetParent()->GetParent()->GetChildren();
847  auto i = ::std::find_if(rItems.begin(), rItems.end(),
848  [&](const std::unique_ptr<FmFilterData>& p) { return p.get() == pItem->GetParent(); });
849  sal_Int32 nParentPos = i - rItems.begin();
850 
851  FmFilterAdapter::setText(nParentPos, pItem, rText);
852 
853  if (rText.isEmpty())
854  Remove(pItem);
855  else
856  {
857  // Change the text
858  pItem->SetText(rText);
859  FmFilterTextChangedHint aChangeHint(pItem);
860  Broadcast( aChangeHint );
861  }
862 }
863 
864 
866 {
867  if (m_pCurrentItems == pCurrent)
868  return;
869 
870  // search for the condition
871  if (pCurrent)
872  {
873  FmFormItem* pFormItem = static_cast<FmFormItem*>(pCurrent->GetParent());
874  ::std::vector<std::unique_ptr<FmFilterData>>& rItems = pFormItem->GetChildren();
875  auto i = ::std::find_if(rItems.begin(), rItems.end(),
876  [&](const std::unique_ptr<FmFilterData>& p) { return p.get() == pCurrent; });
877 
878  if (i != rItems.end())
879  {
880  // determine the filter position
881  sal_Int32 nPos = i - rItems.begin();
882  try
883  {
884  Reference< XFilterController > xFilterController( pFormItem->GetFilterController(), UNO_SET_THROW );
885  xFilterController->setActiveTerm( nPos );
886  }
887  catch( const Exception& )
888  {
890  }
891 
892  if ( m_xController != pFormItem->GetController() )
893  // calls SetCurrentItems again
894  SetCurrentController( pFormItem->GetController() );
895  else
896  m_pCurrentItems = pCurrent;
897  }
898  else
899  m_pCurrentItems = nullptr;
900  }
901  else
902  m_pCurrentItems = nullptr;
903 
904 
905  // notify the UI
906  FmFilterCurrentChangedHint aHint;
907  Broadcast( aHint );
908 }
909 
910 
912 {
913  // checks whether for each form there's one free level for input
914  ::std::vector< std::unique_ptr<FmFilterData> >& rChildren = _rItem.GetChildren();
915  bool bAppendLevel = dynamic_cast<const FmFormItem*>(&_rItem) != nullptr;
916 
917  for ( const auto& rpChild : rChildren )
918  {
919  FmFilterItems* pItems = dynamic_cast<FmFilterItems*>( rpChild.get() );
920  if ( pItems && pItems->GetChildren().empty() )
921  {
922  bAppendLevel = false;
923  break;
924  }
925 
926  FmFormItem* pFormItem = dynamic_cast<FmFormItem*>( rpChild.get() );
927  if (pFormItem)
928  {
929  EnsureEmptyFilterRows( *pFormItem );
930  continue;
931  }
932  }
933 
934  if ( bAppendLevel )
935  {
936  FmFormItem* pFormItem = dynamic_cast<FmFormItem*>( &_rItem );
937  OSL_ENSURE( pFormItem, "FmFilterModel::EnsureEmptyFilterRows: no FmFormItem, but a FmFilterItems child?" );
938  if ( pFormItem )
939  AppendFilterItems( *pFormItem );
940  }
941 }
942 
943 namespace {
944 
945 class FmFilterItemsString : public SvLBoxString
946 {
947 public:
948  explicit FmFilterItemsString(const OUString& rStr)
949  : SvLBoxString(rStr)
950  {
951  }
952 
953  virtual void Paint(const Point& rPos, SvTreeListBox& rDev, vcl::RenderContext& rRenderContext,
954  const SvViewDataEntry* pView, const SvTreeListEntry& rEntry) override;
955  virtual void InitViewData( SvTreeListBox* pView,SvTreeListEntry* pEntry, SvViewDataItem* pViewData = nullptr) override;
956 };
957 
958 }
959 
960 const int nxDBmp = 12;
961 
962 void FmFilterItemsString::Paint(const Point& rPos, SvTreeListBox& rDev, vcl::RenderContext& rRenderContext,
963  const SvViewDataEntry* /*pView*/, const SvTreeListEntry& rEntry)
964 {
965  FmFilterItems* pRow = static_cast<FmFilterItems*>(rEntry.GetUserData());
966  FmFormItem* pForm = static_cast<FmFormItem*>(pRow->GetParent());
967 
968  // current filter is significant painted
969  const bool bIsCurrentFilter = pForm->GetChildren()[ pForm->GetFilterController()->getActiveTerm() ].get() == pRow;
970  if (bIsCurrentFilter)
971  {
972  rRenderContext.Push(PushFlags::LINECOLOR);
973  rRenderContext.SetLineColor(rRenderContext.GetTextColor());
974 
975  Size aSize(GetWidth(&rDev, &rEntry), GetHeight(&rDev, &rEntry));
976  tools::Rectangle aRect(rPos, aSize);
977  Point aFirst(rPos.X(), aRect.Bottom() - 6);
978  Point aSecond(aFirst .X() + 2, aFirst.Y() + 3);
979 
980  rRenderContext.DrawLine(aFirst, aSecond);
981 
982  aFirst = aSecond;
983  aFirst.AdjustX(1 );
984  aSecond.AdjustX(6 );
985  aSecond.AdjustY( -5 );
986 
987  rRenderContext.DrawLine(aFirst, aSecond);
988  rRenderContext.Pop();
989  }
990 
991  rRenderContext.DrawText(Point(rPos.X() + nxDBmp, rPos.Y()), GetText());
992 }
993 
994 
995 void FmFilterItemsString::InitViewData( SvTreeListBox* pView,SvTreeListEntry* pEntry, SvViewDataItem* pViewData)
996 {
997  if( !pViewData )
998  pViewData = pView->GetViewDataItem( pEntry, this );
999 
1000  Size aSize(pView->GetTextWidth(GetText()), pView->GetTextHeight());
1001  aSize.AdjustWidth(nxDBmp );
1002  pViewData->mnWidth = aSize.Width();
1003  pViewData->mnHeight = aSize.Height();
1004 }
1005 
1006 namespace {
1007 
1008 class FmFilterString : public SvLBoxString
1009 {
1010  OUString m_aName;
1011 
1012 public:
1013  FmFilterString( const OUString& rStr, const OUString& aName)
1014  : SvLBoxString(rStr)
1015  , m_aName(aName)
1016  {
1017  m_aName += ": ";
1018  }
1019 
1020  virtual void Paint(const Point& rPos, SvTreeListBox& rDev, vcl::RenderContext& rRenderContext,
1021  const SvViewDataEntry* pView, const SvTreeListEntry& rEntry) override;
1022  virtual void InitViewData( SvTreeListBox* pView,SvTreeListEntry* pEntry, SvViewDataItem* pViewData = nullptr) override;
1023 };
1024 
1025 }
1026 
1027 const int nxD = 4;
1028 
1029 void FmFilterString::InitViewData( SvTreeListBox* pView,SvTreeListEntry* pEntry, SvViewDataItem* pViewData)
1030 {
1031  if( !pViewData )
1032  pViewData = pView->GetViewDataItem( pEntry, this );
1033 
1034  vcl::Font aOldFont( pView->GetFont());
1035  vcl::Font aFont( aOldFont );
1036  aFont.SetWeight(WEIGHT_BOLD);
1037  pView->Control::SetFont( aFont );
1038 
1039  Size aSize(pView->GetTextWidth(m_aName), pView->GetTextHeight());
1040  pView->Control::SetFont( aOldFont );
1041  aSize.AdjustWidth(pView->GetTextWidth(GetText()) + nxD );
1042  pViewData->mnWidth = aSize.Width();
1043  pViewData->mnHeight = aSize.Height();
1044 }
1045 
1046 void FmFilterString::Paint(const Point& rPos, SvTreeListBox& rDev, vcl::RenderContext& rRenderContext,
1047  const SvViewDataEntry* /*pView*/, const SvTreeListEntry& /*rEntry*/)
1048 {
1049  rRenderContext.Push(PushFlags::FONT);
1050  vcl::Font aFont(rRenderContext.GetFont());
1051  aFont.SetWeight(WEIGHT_BOLD);
1052  rRenderContext.SetFont(aFont);
1053 
1054  Point aPos(rPos);
1055  rRenderContext.DrawText(aPos, m_aName);
1056 
1057  // position for the second text
1058  aPos.AdjustX(rDev.GetTextWidth(m_aName) + nxD );
1059  rRenderContext.Pop();
1060  rDev.DrawText(aPos, GetText());
1061 }
1062 
1065  ,m_pEditingCurrently( nullptr )
1066  ,m_aControlExchange( this )
1067  ,m_aTimerCounter( 0 )
1068  ,m_aDropActionType( DA_SCROLLUP )
1069 {
1071 
1073  Image(StockImage::Yes, RID_SVXBMP_COLLAPSEDNODE),
1074  Image(StockImage::Yes, RID_SVXBMP_EXPANDEDNODE)
1075  );
1076 
1077  m_pModel.reset( new FmFilterModel() );
1079 
1080  EnableInplaceEditing( true );
1081  SetSelectionMode(SelectionMode::Multiple);
1082 
1083  SetDragDropMode(DragDropMode::ALL);
1084 
1085  m_aDropActionTimer.SetInvokeHandler(LINK(this, FmFilterNavigator, OnDropActionTimer));
1086 }
1087 
1088 
1090 {
1091  disposeOnce();
1092 }
1093 
1095 {
1096  EndListening( *m_pModel );
1097  m_pModel.reset();
1099 }
1100 
1101 
1102 void FmFilterNavigator::UpdateContent(const Reference< XIndexAccess > & xControllers, const Reference< XFormController > & xCurrent)
1103 {
1104  if (xCurrent == m_pModel->GetCurrentController())
1105  return;
1106 
1107  m_pModel->Update(xControllers, xCurrent);
1108 
1109  // expand the filters for the current controller
1110  SvTreeListEntry* pEntry = FindEntry(m_pModel->GetCurrentForm());
1111  if (pEntry && !IsExpanded(pEntry))
1112  {
1113  SelectAll(false);
1114 
1115  if (!IsExpanded(pEntry))
1116  Expand(pEntry);
1117 
1118  pEntry = FindEntry(m_pModel->GetCurrentItems());
1119  if (pEntry)
1120  {
1121  if (!IsExpanded(pEntry))
1122  Expand(pEntry);
1123  Select(pEntry);
1124  }
1125  }
1126 }
1127 
1128 
1130 {
1131  m_pEditingCurrently = pEntry;
1132  if (!SvTreeListBox::EditingEntry( pEntry, rSelection ))
1133  return false;
1134 
1135  return pEntry && dynamic_cast<const FmFilterItem*>(static_cast<FmFilterData*>(pEntry->GetUserData())) != nullptr;
1136 }
1137 
1138 
1139 bool FmFilterNavigator::EditedEntry( SvTreeListEntry* pEntry, const OUString& rNewText )
1140 {
1141  DBG_ASSERT(pEntry == m_pEditingCurrently, "FmFilterNavigator::EditedEntry: suspicious entry!");
1142  m_pEditingCurrently = nullptr;
1143 
1144  if (EditingCanceled())
1145  return true;
1146 
1147  DBG_ASSERT(dynamic_cast<const FmFilterItem*>(static_cast<FmFilterData*>(pEntry->GetUserData())) != nullptr,
1148  "FmFilterNavigator::EditedEntry() wrong entry");
1149 
1150  OUString aText(comphelper::string::strip(rNewText, ' '));
1151  if (aText.isEmpty())
1152  {
1153  // deleting the entry asynchron
1154  PostUserEvent(LINK(this, FmFilterNavigator, OnRemove), pEntry, true);
1155  }
1156  else
1157  {
1158  OUString aErrorMsg;
1159 
1160  if (m_pModel->ValidateText(static_cast<FmFilterItem*>(pEntry->GetUserData()), aText, aErrorMsg))
1161  {
1162  GrabFocus();
1163  // this will set the text at the FmFilterItem, as well as update any filter controls
1164  // which are connected to this particular entry
1165  m_pModel->SetTextForItem( static_cast< FmFilterItem* >( pEntry->GetUserData() ), aText );
1166 
1167  SetCursor( pEntry, true );
1168  SetEntryText( pEntry, aText );
1169  }
1170  else
1171  {
1172  // display the error and return sal_False
1173  SQLContext aError;
1174  aError.Message = SvxResId(RID_STR_SYNTAXERROR);
1175  aError.Details = aErrorMsg;
1176  displayException(aError, this);
1177 
1178  return false;
1179  }
1180  }
1181  return true;
1182 }
1183 
1184 
1185 IMPL_LINK( FmFilterNavigator, OnRemove, void*, p, void )
1186 {
1187  SvTreeListEntry* pEntry = static_cast<SvTreeListEntry*>(p);
1188  // now remove the entry
1189  m_pModel->Remove(static_cast<FmFilterData*>(pEntry->GetUserData()));
1190 }
1191 
1192 
1193 IMPL_LINK_NOARG(FmFilterNavigator, OnDropActionTimer, Timer *, void)
1194 {
1195  if (--m_aTimerCounter > 0)
1196  return;
1197 
1198  switch (m_aDropActionType)
1199  {
1200  case DA_SCROLLUP :
1201  ScrollOutputArea(1);
1202  m_aTimerCounter = DROP_ACTION_TIMER_SCROLL_TICKS;
1203  break;
1204  case DA_SCROLLDOWN :
1205  ScrollOutputArea(-1);
1206  m_aTimerCounter = DROP_ACTION_TIMER_SCROLL_TICKS;
1207  break;
1208  case DA_EXPANDNODE:
1209  {
1210  SvTreeListEntry* pToExpand = GetEntry(m_aTimerTriggered);
1211  if (pToExpand && (GetChildCount(pToExpand) > 0) && !IsExpanded(pToExpand))
1212  Expand(pToExpand);
1213  m_aDropActionTimer.Stop();
1214  }
1215  break;
1216  }
1217 }
1218 
1219 
1221 {
1222  Point aDropPos = rEvt.maPosPixel;
1223 
1224  // possible DropActions scroll and expand
1225  if (rEvt.mbLeaving)
1226  {
1229  }
1230  else
1231  {
1232  bool bNeedTrigger = false;
1233  // first entry ?
1234  if ((aDropPos.Y() >= 0) && (aDropPos.Y() < GetEntryHeight()))
1235  {
1237  bNeedTrigger = true;
1238  }
1239  else
1240  {
1241  if ((aDropPos.Y() < GetSizePixel().Height()) && (aDropPos.Y() >= GetSizePixel().Height() - GetEntryHeight()))
1242  {
1244  bNeedTrigger = true;
1245  }
1246  else
1247  { // is it an entry with children, and not yet expanded?
1248  SvTreeListEntry* pDroppedOn = GetEntry(aDropPos);
1249  if (pDroppedOn && (GetChildCount(pDroppedOn) > 0) && !IsExpanded(pDroppedOn))
1250  {
1251  // -> expand
1253  bNeedTrigger = true;
1254  }
1255  }
1256  }
1257  if (bNeedTrigger && (m_aTimerTriggered != aDropPos))
1258  {
1260  // remember DropPos because there are QueryDrops even though the mouse was not moved
1261  m_aTimerTriggered = aDropPos;
1263  {
1266  }
1267  }
1268  else if (!bNeedTrigger)
1270  }
1271 
1273  return DND_ACTION_NONE;
1274 
1276  return DND_ACTION_NONE;
1277 
1278  // do we contain the formitem?
1280  return DND_ACTION_NONE;
1281 
1282  SvTreeListEntry* pDropTarget = GetEntry(aDropPos);
1283  if (!pDropTarget)
1284  return DND_ACTION_NONE;
1285 
1286  FmFilterData* pData = static_cast<FmFilterData*>(pDropTarget->GetUserData());
1287  FmFormItem* pForm = nullptr;
1288  if (dynamic_cast<const FmFilterItem*>(pData) != nullptr)
1289  {
1290  pForm = dynamic_cast<FmFormItem*>( pData->GetParent()->GetParent() );
1291  if (pForm != m_aControlExchange->getFormItem())
1292  return DND_ACTION_NONE;
1293  }
1294  else if (dynamic_cast<const FmFilterItems*>( pData) != nullptr)
1295  {
1296  pForm = dynamic_cast<FmFormItem*>( pData->GetParent() );
1297  if (pForm != m_aControlExchange->getFormItem())
1298  return DND_ACTION_NONE;
1299  }
1300  else
1301  return DND_ACTION_NONE;
1302 
1303  return rEvt.mnAction;
1304 }
1305 
1306 namespace
1307 {
1308  FmFilterItems* getTargetItems(SvTreeListEntry const * _pTarget)
1309  {
1310  FmFilterData* pData = static_cast<FmFilterData*>(_pTarget->GetUserData());
1311  FmFilterItems* pTargetItems = dynamic_cast<FmFilterItems*>(pData);
1312  if (!pTargetItems)
1313  pTargetItems = dynamic_cast<FmFilterItems*>(pData->GetParent());
1314  return pTargetItems;
1315  }
1316 }
1317 
1319 {
1320  // you can't scroll after dropping...
1323 
1325  return DND_ACTION_NONE;
1326 
1327  Point aDropPos = rEvt.maPosPixel;
1328  SvTreeListEntry* pDropTarget = GetEntry( aDropPos );
1329  if (!pDropTarget)
1330  return DND_ACTION_NONE;
1331 
1332  // search the container where to add the items
1333  FmFilterItems* pTargetItems = getTargetItems(pDropTarget);
1334  SelectAll(false);
1335  SvTreeListEntry* pEntry = FindEntry(pTargetItems);
1336  Select(pEntry);
1337  SetCurEntry(pEntry);
1338 
1340 
1341  return DND_ACTION_COPY;
1342 }
1343 
1344 
1346  const OUString& rStr,
1347  const Image& rImg1,
1348  const Image& rImg2)
1349 {
1350  SvTreeListBox::InitEntry( pEntry, rStr, rImg1, rImg2 );
1351  std::unique_ptr<SvLBoxString> pString;
1352 
1353  if (dynamic_cast<const FmFilterItem*>(static_cast<FmFilterData*>(pEntry->GetUserData())) != nullptr)
1354  pString.reset(new FmFilterString(rStr,
1355  static_cast<FmFilterItem*>(pEntry->GetUserData())->GetFieldName()));
1356  else if (dynamic_cast<const FmFilterItems*>(static_cast<FmFilterData*>(pEntry->GetUserData())) != nullptr)
1357  pString.reset(new FmFilterItemsString(rStr));
1358 
1359  if (pString)
1360  pEntry->ReplaceItem(std::move(pString), 1 );
1361 }
1362 
1363 
1364 bool FmFilterNavigator::Select( SvTreeListEntry* pEntry, bool bSelect )
1365 {
1366  if (bSelect == IsSelected(pEntry)) // This happens sometimes. I think the basic class errs too much on the side of caution. ;)
1367  return true;
1368 
1369  if (SvTreeListBox::Select(pEntry, bSelect))
1370  {
1371  if (bSelect)
1372  {
1373  FmFormItem* pFormItem = nullptr;
1374  if ( dynamic_cast<const FmFilterItem*>(static_cast<FmFilterData*>(pEntry->GetUserData())) != nullptr)
1375  pFormItem = static_cast<FmFormItem*>(static_cast<FmFilterItem*>(pEntry->GetUserData())->GetParent()->GetParent());
1376  else if (dynamic_cast<const FmFilterItems*>(static_cast<FmFilterData*>(pEntry->GetUserData())) != nullptr)
1377  pFormItem = static_cast<FmFormItem*>(static_cast<FmFilterItem*>(pEntry->GetUserData())->GetParent()->GetParent());
1378  else if (dynamic_cast<const FmFormItem*>(static_cast<FmFilterData*>(pEntry->GetUserData())) != nullptr)
1379  pFormItem = static_cast<FmFormItem*>(pEntry->GetUserData());
1380 
1381  if (pFormItem)
1382  {
1383  // will the controller be exchanged?
1384  if (dynamic_cast<const FmFilterItem*>(static_cast<FmFilterData*>(pEntry->GetUserData())) != nullptr)
1385  m_pModel->SetCurrentItems(static_cast<FmFilterItems*>(static_cast<FmFilterItem*>(pEntry->GetUserData())->GetParent()));
1386  else if (dynamic_cast<const FmFilterItems*>(static_cast<FmFilterData*>(pEntry->GetUserData())) != nullptr)
1387  m_pModel->SetCurrentItems(static_cast<FmFilterItems*>(pEntry->GetUserData()));
1388  else if (dynamic_cast<const FmFormItem*>(static_cast<FmFilterData*>(pEntry->GetUserData())) != nullptr)
1389  m_pModel->SetCurrentController(static_cast<FmFormItem*>(pEntry->GetUserData())->GetController());
1390  }
1391  }
1392  return true;
1393  }
1394  else
1395  return false;
1396 }
1397 
1398 void FmFilterNavigator::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
1399 {
1400  if (const FmFilterInsertedHint* pInsertHint = dynamic_cast<const FmFilterInsertedHint*>(&rHint))
1401  {
1402  Insert(pInsertHint->GetData(), pInsertHint->GetPos());
1403  }
1404  else if( dynamic_cast<const FilterClearingHint*>(&rHint) )
1405  {
1407  }
1408  else if (const FmFilterRemovedHint* pRemoveHint = dynamic_cast<const FmFilterRemovedHint*>(&rHint))
1409  {
1410  Remove(pRemoveHint->GetData());
1411  }
1412  else if (const FmFilterTextChangedHint *pChangeHint = dynamic_cast<const FmFilterTextChangedHint*>(&rHint))
1413  {
1414  SvTreeListEntry* pEntry = FindEntry(pChangeHint->GetData());
1415  if (pEntry)
1416  SetEntryText( pEntry, pChangeHint->GetData()->GetText());
1417  }
1418  else if( dynamic_cast<const FmFilterCurrentChangedHint*>(&rHint) )
1419  {
1420  // invalidate the entries
1421  for (SvTreeListEntry* pEntry = First(); pEntry != nullptr;
1422  pEntry = Next(pEntry))
1423  GetModel()->InvalidateEntry( pEntry );
1424  }
1425 }
1426 
1428 {
1429  SvTreeListEntry* pEntry = nullptr;
1430  if (pItem)
1431  {
1432  for (pEntry = First(); pEntry != nullptr; pEntry = Next( pEntry ))
1433  {
1434  FmFilterData* pEntryItem = static_cast<FmFilterData*>(pEntry->GetUserData());
1435  if (pEntryItem == pItem)
1436  break;
1437  }
1438  }
1439  return pEntry;
1440 }
1441 
1442 
1444 {
1445  const FmParentData* pParent = pItem->GetParent() ? pItem->GetParent() : m_pModel.get();
1446 
1447  // insert the item
1448  SvTreeListEntry* pParentEntry = FindEntry( pParent );
1449  InsertEntry( pItem->GetText(), pItem->GetImage(), pItem->GetImage(), pParentEntry, false, nPos, pItem );
1450  if ( pParentEntry )
1451  Expand( pParentEntry );
1452 }
1453 
1454 
1456 {
1457  // the entry for the data
1458  SvTreeListEntry* pEntry = FindEntry(pItem);
1459 
1460  if (pEntry == m_pEditingCurrently)
1461  // cancel editing
1462  EndEditing(true);
1463 
1464  if (pEntry)
1465  GetModel()->Remove( pEntry );
1466 }
1467 
1468 FmFormItem* FmFilterNavigator::getSelectedFilterItems(::std::vector<FmFilterItem*>& _rItemList)
1469 {
1470  // be sure that the data is only used within only one form!
1471  FmFormItem* pFirstItem = nullptr;
1472 
1473  bool bHandled = true;
1474  bool bFoundSomething = false;
1475  for (SvTreeListEntry* pEntry = FirstSelected();
1476  bHandled && pEntry != nullptr;
1477  pEntry = NextSelected(pEntry))
1478  {
1479  FmFilterItem* pFilter = dynamic_cast<FmFilterItem*>( static_cast<FmFilterData*>(pEntry->GetUserData()) );
1480  if (pFilter)
1481  {
1482  FmFormItem* pForm = dynamic_cast<FmFormItem*>( pFilter->GetParent()->GetParent() );
1483  if (!pForm)
1484  bHandled = false;
1485  else if (!pFirstItem)
1486  pFirstItem = pForm;
1487  else if (pFirstItem != pForm)
1488  bHandled = false;
1489 
1490  if (bHandled)
1491  {
1492  _rItemList.push_back(pFilter);
1493  bFoundSomething = true;
1494  }
1495  }
1496  }
1497  if ( !bHandled || !bFoundSomething )
1498  pFirstItem = nullptr;
1499  return pFirstItem;
1500 }
1501 
1502 void FmFilterNavigator::insertFilterItem(const ::std::vector<FmFilterItem*>& _rFilterList,FmFilterItems* _pTargetItems,bool _bCopy)
1503 {
1504  for (FmFilterItem* pLookupItem : _rFilterList)
1505  {
1506  if ( pLookupItem->GetParent() == _pTargetItems )
1507  continue;
1508 
1509  FmFilterItem* pFilterItem = _pTargetItems->Find( pLookupItem->GetComponentIndex() );
1510  OUString aText = pLookupItem->GetText();
1511  if ( !pFilterItem )
1512  {
1513  pFilterItem = new FmFilterItem( _pTargetItems, pLookupItem->GetFieldName(), aText, pLookupItem->GetComponentIndex() );
1514  m_pModel->Append( _pTargetItems, std::unique_ptr<FmFilterItem>(pFilterItem) );
1515  }
1516 
1517  if ( !_bCopy )
1518  m_pModel->Remove( pLookupItem );
1519 
1520  // now set the text for the new dragged item
1521  m_pModel->SetTextForItem( pFilterItem, aText );
1522  }
1523 
1524  m_pModel->EnsureEmptyFilterRows( *_pTargetItems->GetParent() );
1525 }
1526 
1527 
1528 void FmFilterNavigator::StartDrag( sal_Int8 /*_nAction*/, const Point& /*_rPosPixel*/ )
1529 {
1530  EndSelection();
1531 
1532  // be sure that the data is only used within an only one form!
1534 
1535  ::std::vector<FmFilterItem*> aItemList;
1536  if ( FmFormItem* pFirstItem = getSelectedFilterItems(aItemList) )
1537  {
1539  m_aControlExchange->setFormItem(pFirstItem);
1541  }
1542 }
1543 
1544 
1546 {
1547  bool bHandled = false;
1548  switch (rEvt.GetCommand())
1549  {
1550  case CommandEventId::ContextMenu:
1551  {
1552  // the place where it was clicked
1553  Point aWhere;
1554  SvTreeListEntry* pClicked = nullptr;
1555  if (rEvt.IsMouseEvent())
1556  {
1557  aWhere = rEvt.GetMousePosPixel();
1558  pClicked = GetEntry(aWhere);
1559  if (pClicked == nullptr)
1560  break;
1561 
1562  if (!IsSelected(pClicked))
1563  {
1564  SelectAll(false);
1565  Select(pClicked);
1566  SetCurEntry(pClicked);
1567  }
1568  }
1569  else
1570  {
1571  pClicked = GetCurEntry();
1572  if (!pClicked)
1573  break;
1574  aWhere = GetEntryPosition( pClicked );
1575  }
1576 
1577  ::std::vector<FmFilterData*> aSelectList;
1578  for (SvTreeListEntry* pEntry = FirstSelected();
1579  pEntry != nullptr;
1580  pEntry = NextSelected(pEntry))
1581  {
1582  // don't delete forms
1583  FmFormItem* pForm = dynamic_cast<FmFormItem*>( static_cast<FmFilterData*>(pEntry->GetUserData()) );
1584  if (!pForm)
1585  aSelectList.push_back(static_cast<FmFilterData*>(pEntry->GetUserData()));
1586  }
1587  if (aSelectList.size() == 1)
1588  {
1589  // don't delete the only empty row of a form
1590  FmFilterItems* pFilterItems = dynamic_cast<FmFilterItems*>( aSelectList[0] );
1591  if (pFilterItems && pFilterItems->GetChildren().empty()
1592  && pFilterItems->GetParent()->GetChildren().size() == 1)
1593  aSelectList.clear();
1594  }
1595 
1596  VclBuilder aBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "svx/ui/filtermenu.ui", "");
1597  VclPtr<PopupMenu> aContextMenu(aBuilder.get_menu("menu"));
1598 
1599  // every condition could be deleted except the first one if it's the only one
1600  aContextMenu->EnableItem(aContextMenu->GetItemId("delete"), !aSelectList.empty());
1601 
1602 
1603  bool bEdit = dynamic_cast<FmFilterItem*>( static_cast<FmFilterData*>(pClicked->GetUserData()) ) != nullptr &&
1604  IsSelected(pClicked) && GetSelectionCount() == 1;
1605 
1606  aContextMenu->EnableItem(aContextMenu->GetItemId("edit"), bEdit);
1607  aContextMenu->EnableItem(aContextMenu->GetItemId("isnull"), bEdit);
1608  aContextMenu->EnableItem(aContextMenu->GetItemId("isnotnull"), bEdit);
1609 
1610  aContextMenu->RemoveDisabledEntries(true, true);
1611  aContextMenu->Execute(this, aWhere);
1612  OString sIdent = aContextMenu->GetCurItemIdent();
1613  if (sIdent == "edit")
1614  EditEntry( pClicked );
1615  else if (sIdent == "isnull")
1616  {
1617  OUString aErrorMsg;
1618  OUString aText = "IS NULL";
1619  m_pModel->ValidateText(static_cast<FmFilterItem*>(pClicked->GetUserData()),
1620  aText, aErrorMsg);
1621  m_pModel->SetTextForItem(static_cast<FmFilterItem*>(pClicked->GetUserData()), aText);
1622  }
1623  else if (sIdent == "isnotnull")
1624  {
1625  OUString aErrorMsg;
1626  OUString aText = "IS NOT NULL";
1627 
1628  m_pModel->ValidateText(static_cast<FmFilterItem*>(pClicked->GetUserData()),
1629  aText, aErrorMsg);
1630  m_pModel->SetTextForItem(static_cast<FmFilterItem*>(pClicked->GetUserData()), aText);
1631  }
1632  else if (sIdent == "delete")
1633  {
1634  DeleteSelection();
1635  }
1636  bHandled = true;
1637  }
1638  break;
1639  default: break;
1640  }
1641 
1642  if (!bHandled)
1643  SvTreeListBox::Command( rEvt );
1644 }
1645 
1647 {
1648  SvTreeListEntry* pEntry = _pStartWith ? _pStartWith : LastSelected();
1649  pEntry = Next(pEntry);
1650  // we need the next filter entry
1651  while( pEntry && GetChildCount( pEntry ) == 0 && pEntry != Last() )
1652  pEntry = Next(pEntry);
1653  return pEntry;
1654 }
1655 
1657 {
1658  SvTreeListEntry* pEntry = _pStartWith ? _pStartWith : FirstSelected();
1659  pEntry = Prev(pEntry);
1660  // check if the previous entry is a filter, if so get the next prev
1661  if ( pEntry && GetChildCount( pEntry ) != 0 )
1662  {
1663  pEntry = Prev(pEntry);
1664  // if the entry is still no leaf return
1665  if ( pEntry && GetChildCount( pEntry ) != 0 )
1666  pEntry = nullptr;
1667  }
1668  return pEntry;
1669 }
1670 
1672 {
1673  const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
1674 
1675  switch ( rKeyCode.GetCode() )
1676  {
1677  case KEY_UP:
1678  case KEY_DOWN:
1679  {
1680  if ( !rKeyCode.IsMod1() || !rKeyCode.IsMod2() || rKeyCode.IsShift() )
1681  break;
1682 
1683  ::std::vector<FmFilterItem*> aItemList;
1684  if ( !getSelectedFilterItems( aItemList ) )
1685  break;
1686 
1687  ::std::function<SvTreeListEntry*(FmFilterNavigator *, SvTreeListEntry*)> getter = ::std::mem_fn(&FmFilterNavigator::getNextEntry);
1688  if ( rKeyCode.GetCode() == KEY_UP )
1689  getter = ::std::mem_fn(&FmFilterNavigator::getPrevEntry);
1690 
1691  SvTreeListEntry* pTarget = getter( this, nullptr );
1692  if ( !pTarget )
1693  break;
1694 
1695  FmFilterItems* pTargetItems = getTargetItems( pTarget );
1696  if ( !pTargetItems )
1697  break;
1698 
1699  ::std::vector<FmFilterItem*>::const_iterator aEnd = aItemList.end();
1700  bool bNextTargetItem = true;
1701  while ( bNextTargetItem )
1702  {
1703  ::std::vector<FmFilterItem*>::const_iterator i = aItemList.begin();
1704  for (; i != aEnd; ++i)
1705  {
1706  if ( (*i)->GetParent() == pTargetItems )
1707  {
1708  pTarget = getter(this,pTarget);
1709  if ( !pTarget )
1710  return;
1711  pTargetItems = getTargetItems( pTarget );
1712  break;
1713  }
1714  else
1715  {
1716  FmFilterItem* pFilterItem = pTargetItems->Find( (*i)->GetComponentIndex() );
1717  // we found the text component so jump above
1718  if ( pFilterItem )
1719  {
1720  pTarget = getter( this, pTarget );
1721  if ( !pTarget )
1722  return;
1723 
1724  pTargetItems = getTargetItems( pTarget );
1725  break;
1726  }
1727  }
1728  }
1729  bNextTargetItem = i != aEnd && pTargetItems;
1730  }
1731 
1732  if ( pTargetItems )
1733  {
1734  insertFilterItem( aItemList, pTargetItems, false );
1735  return;
1736  }
1737  }
1738  break;
1739 
1740  case KEY_DELETE:
1741  {
1742  if ( rKeyCode.GetModifier() )
1743  break;
1744 
1745  if ( !IsSelected( First() ) || GetEntryCount() > 1 )
1746  DeleteSelection();
1747  return;
1748  }
1749  }
1750 
1751  SvTreeListBox::KeyInput(rKEvt);
1752 }
1753 
1754 
1756 {
1757  // to avoid the deletion of an entry twice (e.g. deletion of a parent and afterward
1758  // the deletion of its child, I have to shrink the selection list
1759  ::std::vector<SvTreeListEntry*> aEntryList;
1760  for (SvTreeListEntry* pEntry = FirstSelected();
1761  pEntry != nullptr;
1762  pEntry = NextSelected(pEntry))
1763  {
1764  FmFilterItem* pFilterItem = dynamic_cast<FmFilterItem*>( static_cast<FmFilterData*>(pEntry->GetUserData()) );
1765  if (pFilterItem && IsSelected(GetParent(pEntry)))
1766  continue;
1767 
1768  FmFormItem* pForm = dynamic_cast<FmFormItem*>( static_cast<FmFilterData*>(pEntry->GetUserData()) );
1769  if (!pForm)
1770  aEntryList.push_back(pEntry);
1771  }
1772 
1773  // Remove the selection
1774  SelectAll(false);
1775 
1776  for (::std::vector<SvTreeListEntry*>::reverse_iterator i = aEntryList.rbegin();
1777  // link problems with operator ==
1778  i.base() != aEntryList.rend().base(); ++i)
1779  {
1780  m_pModel->Remove(static_cast<FmFilterData*>((*i)->GetUserData()));
1781  }
1782 }
1783 
1785  vcl::Window* _pParent )
1787  ,SfxControllerItem( SID_FM_FILTER_NAVIGATOR_CONTROL, *_pBindings )
1788 {
1789  SetHelpId( HID_FILTER_NAVIGATOR_WIN );
1790 
1792  m_pNavigator->Show();
1793  SetText( SvxResId(RID_STR_FILTER_NAVIGATOR) );
1795 }
1796 
1797 
1799 {
1800  disposeOnce();
1801 }
1802 
1804 {
1805  m_pNavigator.disposeAndClear();
1808 }
1809 
1810 
1812 {
1813  if (!m_pNavigator)
1814  return;
1815 
1816  if (!pFormShell)
1817  m_pNavigator->UpdateContent( nullptr, nullptr );
1818  else
1819  {
1820  Reference<XFormController> const xController(pFormShell->GetImpl()->getActiveInternalController_Lock());
1821  Reference< XIndexAccess > xContainer;
1822  if (xController.is())
1823  {
1824  Reference< XChild > xChild = xController;
1825  for (Reference< XInterface > xParent(xChild->getParent());
1826  xParent.is();
1827  xParent = xChild.is() ? xChild->getParent() : Reference< XInterface > ())
1828  {
1829  xContainer.set(xParent, UNO_QUERY);
1830  xChild.set(xParent, UNO_QUERY);
1831  }
1832  }
1833  m_pNavigator->UpdateContent(xContainer, xController);
1834  }
1835 }
1836 
1837 
1838 void FmFilterNavigatorWin::StateChanged( sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState )
1839 {
1840  if( !pState || SID_FM_FILTER_NAVIGATOR_CONTROL != nSID )
1841  return;
1842 
1843  if( eState >= SfxItemState::DEFAULT )
1844  {
1845  FmFormShell* pShell = dynamic_cast<FmFormShell*>( static_cast<const SfxObjectItem*>(pState)->GetShell() );
1846  UpdateContent( pShell );
1847  }
1848  else
1849  UpdateContent( nullptr );
1850 }
1851 
1852 
1854 {
1855  if ( m_pNavigator && m_pNavigator->IsEditingActive() )
1856  m_pNavigator->EndEditing();
1857 
1858  if ( m_pNavigator && m_pNavigator->IsEditingActive() )
1859  // the EndEditing was vetoed (perhaps of an syntax error or such)
1860  return false;
1861 
1862  UpdateContent( nullptr );
1863  return SfxDockingWindow::Close();
1864 }
1865 
1866 
1868 {
1869  SfxDockingWindow::FillInfo( rInfo );
1870  rInfo.bVisible = false;
1871 }
1872 
1873 
1875 {
1876  if ( ( eAlign == SfxChildAlignment::TOP ) || ( eAlign == SfxChildAlignment::BOTTOM ) )
1877  return Size();
1878 
1879  return SfxDockingWindow::CalcDockingSize( eAlign );
1880 }
1881 
1882 
1884 {
1885  switch (eAlign)
1886  {
1887  case SfxChildAlignment::LEFT:
1888  case SfxChildAlignment::RIGHT:
1889  case SfxChildAlignment::NOALIGNMENT:
1890  return eAlign;
1891  default:
1892  break;
1893  }
1894 
1895  return eActAlign;
1896 }
1897 
1898 
1900 {
1902 
1903  Size aLogOutputSize = PixelToLogic(GetOutputSizePixel(), MapMode(MapUnit::MapAppFont));
1904  Size aLogExplSize = aLogOutputSize;
1905  aLogExplSize.AdjustWidth( -6 );
1906  aLogExplSize.AdjustHeight( -6 );
1907 
1908  Point aExplPos = LogicToPixel(Point(3,3), MapMode(MapUnit::MapAppFont));
1909  Size aExplSize = LogicToPixel(aLogExplSize, MapMode(MapUnit::MapAppFont));
1910 
1911  m_pNavigator->SetPosSizePixel( aExplPos, aExplSize );
1912 }
1913 
1915 {
1916  // oj #97405#
1917  if ( m_pNavigator )
1918  m_pNavigator->GrabFocus();
1919 }
1920 
1921 SFX_IMPL_DOCKINGWINDOW( FmFilterNavigatorWinMgr, SID_FM_FILTER_NAVIGATOR )
1922 
1923 
1924 FmFilterNavigatorWinMgr::FmFilterNavigatorWinMgr( vcl::Window *_pParent, sal_uInt16 _nId,
1925  SfxBindings *_pBindings, SfxChildWinInfo* _pInfo )
1926  :SfxChildWindow( _pParent, _nId )
1927 {
1928  SetWindow( VclPtr<FmFilterNavigatorWin>::Create( _pBindings, this, _pParent ) );
1929  static_cast<SfxDockingWindow*>(GetWindow())->Initialize( _pInfo );
1930 }
1931 
1932 
1933 }
1934 
1935 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
virtual ~FmFilterModel() override
Definition: filtnav.cxx:482
friend class FmFilterAdapter
Definition: filtnav.hxx:151
WinBits const WB_ROLLABLE
virtual Image GetImage() const override
Definition: filtnav.cxx:174
const Color & GetTextColor() const
void DrawText(const Point &rStartPt, const OUString &rStr, sal_Int32 nIndex=0, sal_Int32 nLen=-1, MetricVector *pVector=nullptr, OUString *pDisplayText=nullptr, const SalLayoutGlyphs *pLayoutCache=nullptr)
WinBits const WB_DOCKABLE
void UpdateContent(const css::uno::Reference< css::container::XIndexAccess > &xControllers, const css::uno::Reference< css::form::runtime::XFormController > &xCurrent)
Definition: filtnav.cxx:1102
virtual SfxChildAlignment CheckAlignment(SfxChildAlignment, SfxChildAlignment) override
Definition: filtnav.cxx:1883
void EnsureEmptyFilterRows(FmParentData &_rItem)
Definition: filtnav.cxx:911
SvTreeListEntry * NextSelected(SvTreeListEntry *pEntry) const
static SotClipboardFormatId RegisterFormatName(const OUString &rName)
void insertFilterItem(const ::std::vector< FmFilterItem * > &_rFilterList, FmFilterItems *_pTargetItems, bool _bCopy)
inserts the filter items into the tree model and creates new FilterItems if needed.
Definition: filtnav.cxx:1502
virtual bool EditedEntry(SvTreeListEntry *pEntry, const OUString &rNewText) override
Definition: filtnav.cxx:1139
FmFilterNavigator(vcl::Window *pParent)
Definition: filtnav.cxx:1063
void InvalidateEntry(SvTreeListEntry *)
SvTreeListEntry * FindEntry(const FmFilterData *pItem) const
Definition: filtnav.cxx:1427
virtual void SAL_CALL disjunctiveTermRemoved(const FilterEvent &Event) override
Definition: filtnav.cxx:410
long AdjustWidth(long n)
#define DND_ACTION_COPY
virtual Image GetImage() const override
Definition: filtnav.cxx:159
const OSystemParseContext * getParseContext() const
FmXFormShell * GetImpl() const
Definition: fmshell.hxx:118
const LanguageTag & GetUILanguageTag() const
std::unique_ptr< ContentProperties > pData
virtual void Command(const CommandEvent &rCEvt) override
void startDrag(sal_Int8 nDragSourceActions)
Definition: fmexch.cxx:353
void Insert(FmFilterData *pItem, sal_uLong nPos)
Definition: filtnav.cxx:1443
virtual ~FmFilterNavigatorWin() override
Definition: filtnav.cxx:1798
void setDraggedEntries(const ::std::vector< FmFilterItem * > &_rList)
Definition: filtnav.hxx:200
long Height() const
signed char sal_Int8
SvTreeList * GetModel() const
static SotClipboardFormatId getFormatId()
Definition: filtnav.cxx:119
WinBits const WB_HASBUTTONSATROOT
sal_uIntPtr sal_uLong
unsigned short m_aTimerCounter
Definition: filtnav.hxx:236
void Remove(FmFilterData *pFilterItem)
Definition: filtnav.cxx:714
sal_uLong GetEntryCount() const
static const AllSettings & GetSettings()
virtual Size GetSizePixel() const
void SetWeight(FontWeight)
#define DND_ACTION_COPYMOVE
sal_uInt16 GetCode() const
void SetCursor(SvTreeListEntry *pEntry, bool bForceNoSelect=false)
void SetEntryText(SvTreeListEntry *, const OUString &)
void SetCurEntry(SvTreeListEntry *_pEntry)
void SetHelpId(const OString &)
virtual void Notify(SfxBroadcaster &rBC, const SfxHint &rHint) override
Definition: filtnav.cxx:1398
virtual void SAL_CALL disposing(const EventObject &Source) override
Definition: filtnav.cxx:319
Reference< XNumberFormatsSupplier > getNumberFormats(const Reference< XConnection > &_rxConn, bool _bAlloweDefault, const Reference< XComponentContext > &_rxContext)
SvTreeListEntry * GetCurEntry() const
long AdjustHeight(long n)
SvTreeListEntry * LastSelected() const
virtual ~FmParentData() override
Definition: filtnav.cxx:139
virtual void Command(const CommandEvent &rEvt) override
Definition: filtnav.cxx:1545
constexpr sal_uInt16 KEY_UP
const css::lang::Locale & getLocale(bool bResolveSystem=true) const
virtual void SAL_CALL predicateExpressionChanged(const FilterEvent &Event) override
Definition: filtnav.cxx:359
void SetText(const OUString &rText)
Definition: filtnav.hxx:67
void setFormItem(FmFormItem *_pItem)
Definition: filtnav.hxx:203
FmFilterItem * Find(const ::sal_Int32 _nFilterComponentIndex) const
Definition: filtnav.cxx:148
bool IsActive() const
WEIGHT_BOLD
void AddFormat(SotClipboardFormatId nFormat)
Reference< XIndexAccess > m_xControllers
Definition: filtnav.cxx:237
void UpdateContent(FmFormShell const *pFormShell)
Definition: filtnav.cxx:1811
sal_Int64 WinBits
css::uno::Reference< css::container::XIndexAccess > m_xControllers
Definition: filtnav.hxx:153
virtual OLocalExchange * createExchange() const override
Definition: filtnav.cxx:128
Reference< XController > xController
SvViewDataItem * GetViewDataItem(SvTreeListEntry const *, SvLBoxItem const *)
std::unique_ptr< ::connectivity::OSQLParseNode > predicateTree(OUString &_rErrorMessage, const OUString &_rStatement, const css::uno::Reference< css::util::XNumberFormatter > &_rxFormatter, const css::uno::Reference< css::beans::XPropertySet > &_rxField) const
OUString SvxResId(const char *pId)
Definition: dialmgr.cxx:28
virtual void Resize() override
Definition: filtnav.cxx:1899
SvTreeListEntry * FirstSelected() const
const vcl::Font & GetFont() const
#define X
bool IsMouseEvent() const
void SetDragDropMode(DragDropMode)
const DataFlavorExVector & GetDataFlavorExVector() const
virtual void KeyInput(const KeyEvent &rKEvt) override
int nCount
#define DND_ACTION_NONE
void SetFloatingSize(const Size &rSize)
const int nxDBmp
Definition: filtnav.cxx:960
#define FM_PROP_BOUNDFIELD
Definition: fmprop.hxx:101
void Append(FmFilterItems *pItems, std::unique_ptr< FmFilterItem > pFilterItem)
Definition: filtnav.cxx:838
void EndEditing(bool bCancel=false)
FmFilterAdapter(FmFilterModel *pModel, const Reference< XIndexAccess > &xControllers)
Definition: filtnav.cxx:262
void SelectAll(bool bSelect, bool bPaint=true)
sal_uInt16 GetModifier() const
SotClipboardFormatId
virtual bool Close() override
FmParentData * GetParent() const
Definition: filtnav.hxx:69
void Update(const css::uno::Reference< css::container::XIndexAccess > &xControllers, const css::uno::Reference< css::form::runtime::XFormController > &xCurrent)
static void AppendFilterItems(FmFormItem &_rItem)
Definition: filtnav.cxx:673
void DrawLine(const Point &rStartPt, const Point &rEndPt)
short GetEntryHeight() const
void EnableInplaceEditing(bool bEnable)
void FillInfo(SfxChildWinInfo &rInfo) const override
Definition: filtnav.cxx:1867
virtual void StartDrag(sal_Int8 nAction, const Point &rPosPixel) override
Definition: filtnav.cxx:1528
rtl::Reference< FmFilterAdapter > m_pAdapter
Definition: filtnav.hxx:155
constexpr sal_uInt16 KEY_DOWN
OUString m_aName
Definition: filtnav.cxx:1010
void Remove(FmFilterData const *pItem)
Definition: filtnav.cxx:1455
bool EditingCanceled() const
FmFormItem * getFormItem() const
Definition: filtnav.hxx:201
virtual void GetFocus() override
Definition: filtnav.cxx:1914
#define DBG_UNHANDLED_EXCEPTION(...)
void SetLineColor()
virtual void KeyInput(const KeyEvent &rKEvt) override
Definition: filtnav.cxx:1671
virtual void InitEntry(SvTreeListEntry *pEntry, const OUString &rStr, const Image &rImg1, const Image &rImg2) override
Definition: filtnav.cxx:1345
virtual void AddSupportedFormats() override
Definition: filtnav.cxx:113
bool ValidateText(FmFilterItem const *pItem, OUString &rText, OUString &rErrorMsg) const
Definition: filtnav.cxx:793
virtual bool EditingEntry(SvTreeListEntry *pEntry, Selection &)
Shell * GetShell()
#define DBG_ASSERT(sCon, aError)
bool Remove(const SvTreeListEntry *pEntry)
SvTreeListEntry * m_pEditingCurrently
Definition: filtnav.hxx:231
virtual void dispose()
class SAL_NO_VTABLE XPropertySet
Definition: xmlexchg.hxx:31
virtual Size CalcDockingSize(SfxChildAlignment)
void displayException(const Any &_rExcept, vcl::Window *_pParent)
Definition: fmtools.cxx:122
IMPL_LINK(DataNavigatorWindow, ModelSelectListBoxHdl, ListBox &, rBox, void)
Definition: datanavi.cxx:1423
const ::std::vector< FmFilterItem * > & getDraggedEntries() const
Definition: filtnav.hxx:199
#define DROP_ACTION_TIMER_INITIAL_TICKS
Definition: filtnav.cxx:65
SAL_DLLPRIVATE const css::uno::Reference< css::form::runtime::XFormController > & getActiveInternalController_Lock() const
Definition: fmshimp.hxx:340
bool isDragSource() const
Definition: fmexch.hxx:107
int i
const css::uno::Reference< css::form::runtime::XFormController > & GetController() const
Definition: filtnav.hxx:108
bool IsSelected(SvTreeListEntry *pEntry) const
virtual Image GetImage() const
Definition: filtnav.cxx:134
void * GetUserData() const
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
CommandEventId GetCommand() const
long Bottom() const
size_t const m_nPos
Definition: filtnav.cxx:194
virtual void Start() override
FmFilterItems * m_pCurrentItems
Definition: filtnav.hxx:156
SvTreeListEntry * getPrevEntry(SvTreeListEntry *_pStartWith)
Definition: filtnav.cxx:1656
virtual SvTreeListEntry * InsertEntry(const OUString &rText, SvTreeListEntry *pParent=nullptr, bool bChildrenOnDemand=false, sal_uLong nPos=TREELIST_APPEND, void *pUserData=nullptr)
void Insert(const ::std::vector< std::unique_ptr< FmFilterData >>::iterator &rPos, std::unique_ptr< FmFilterData > pFilterItem)
Definition: filtnav.cxx:693
void StartListening(SfxBroadcaster &rBroadcaster, DuplicateHandling eDuplicateHanding=DuplicateHandling::Unexpected)
static OUString getUIRootDir()
virtual void InitEntry(SvTreeListEntry *, const OUString &, const Image &, const Image &)
virtual bool Expand(SvTreeListEntry *pParent)
#define HID_FILTER_NAVIGATOR_WIN
Definition: helpids.h:49
void SetTimeout(sal_uInt64 nTimeoutMs)
void GrabFocus()
long GetTextHeight() const
vcl::Window * GetParent() const
FmFilterModel * m_pModel
Definition: filtnav.cxx:236
long X() const
virtual sal_Int8 AcceptDrop(const AcceptDropEvent &rEvt) override
Definition: filtnav.cxx:1220
virtual void SAL_CALL disjunctiveTermAdded(const FilterEvent &Event) override
Definition: filtnav.cxx:445
FmFilterData *const m_pData
Definition: filtnav.cxx:185
void EnableItem(sal_uInt16 nItemId, bool bEnable=true)
Point GetEntryPosition(SvTreeListEntry *) const
OFilterExchangeHelper m_aControlExchange
Definition: filtnav.hxx:232
const Point & GetMousePosPixel() const
SvTreeListEntry * Next(SvTreeListEntry *pEntry) const
IMPL_LINK_NOARG(XFormsPage, TbxSelectHdl, ToolBox *, void)
Definition: datanavi.cxx:401
WinBits const WB_HASLINES
WinBits const WB_3DLOOK
bool IsExpanded(SvTreeListEntry *pEntry) const
WinBits const WB_SIZEABLE
SvTreeListEntry * First() const
SvTreeListEntry * getNextEntry(SvTreeListEntry *_pStartWith)
Definition: filtnav.cxx:1646
static void setText(sal_Int32 nPos, const FmFilterItem *pFilterItem, const OUString &rText)
Definition: filtnav.cxx:299
sal_uInt16 GetChildCount() const
FmFormItem * getSelectedFilterItems(::std::vector< FmFilterItem * > &_rItemList)
returns the first form item and the selected FilterItems in the vector
Definition: filtnav.cxx:1468
const vcl::KeyCode & GetKeyCode() const
const OUString & GetText() const
Definition: filtnav.hxx:68
void Broadcast(const SfxHint &rHint)
void SetSelectionMode(SelectionMode)
bool IsShift() const
virtual sal_Int8 ExecuteDrop(const ExecuteDropEvent &rEvt) override
Definition: filtnav.cxx:1318
css::uno::Reference< css::form::runtime::XFormController > m_xController
Definition: filtnav.hxx:154
virtual void FillInfo(SfxChildWinInfo &) const
const int nxD
Definition: filtnav.cxx:1027
SfxItemState
SfxChildAlignment
void SetCurrentItems(FmFilterItems *pCurrent)
Definition: filtnav.cxx:865
void Stop()
FmFormItem * Find(const ::std::vector< std::unique_ptr< FmFilterData >> &rItems, const css::uno::Reference< css::form::runtime::XFormController > &xController) const
#define HID_FILTER_NAVIGATOR
Definition: helpids.h:48
WinBits const WB_BORDER
void SetFont(const vcl::Font &rNewFont)
FmFilterItem(FmFilterItems *pParent, const OUString &aFieldName, const OUString &aCondition, const sal_Int32 _nComponentIndex)
Definition: filtnav.cxx:164
void ReplaceItem(std::unique_ptr< SvLBoxItem > pNewItem, size_t nPos)
ImplSVEvent * PostUserEvent(const Link< void *, void > &rLink, void *pCaller=nullptr, bool bReferenceLink=false)
OUString aName
FmFilterNavigatorWin(SfxBindings *pBindings, SfxChildWindow *pMgr, vcl::Window *pParent)
Definition: filtnav.cxx:1784
::std::vector< std::unique_ptr< FmFilterData > > m_aChildren
Definition: filtnav.hxx:78
SvTreeListEntry * GetEntry(SvTreeListEntry *pParent, sal_uLong nPos) const
virtual void dispose() override
Definition: filtnav.cxx:1094
OString strip(const OString &rIn, char c)
virtual bool Close() override
Definition: filtnav.cxx:1853
bool IsMod1() const
static VclPtr< reference_type > Create(Arg &&...arg)
void EndListening(SfxBroadcaster &rBroadcaster, bool bRemoveAllDuplicates=false)
void EndSelection()
virtual bool Select(SvTreeListEntry *pEntry, bool bSelect=true) override
Definition: filtnav.cxx:1364
void SetNodeBitmaps(const Image &rCollapsedNodeBmp, const Image &rExpandedNodeBmp)
void * p
Reference< XComponentContext > getProcessComponentContext()
void SetCurrentController(const css::uno::Reference< css::form::runtime::XFormController > &xController)
Definition: filtnav.cxx:646
SvTreeListEntry * Last() const
virtual Size CalcDockingSize(SfxChildAlignment) override
Definition: filtnav.cxx:1874
void SetInvokeHandler(const Link< Timer *, void > &rLink)
PopupMenu * get_menu(const OString &sID)
DROP_ACTION m_aDropActionType
Definition: filtnav.hxx:238
void EditEntry(SvTreeListEntry *pEntry)
std::unique_ptr< FmFilterModel > m_pModel
Definition: filtnav.hxx:230
const css::uno::Reference< css::form::runtime::XFilterController > & GetFilterController() const
Definition: filtnav.hxx:111
long GetTextWidth(const OUString &rStr, sal_Int32 nIndex=0, sal_Int32 nLen=-1, vcl::TextLayoutCache const *=nullptr, SalLayoutGlyphs const *const pLayoutCache=nullptr) const
Reference< XConnection > getConnection(const Reference< XRowSet > &_rxRowSet)
void SetTextForItem(FmFilterItem *pItem, const OUString &rText)
Definition: filtnav.cxx:844
::std::vector< std::unique_ptr< FmFilterData > > & GetChildren()
Definition: filtnav.hxx:86
virtual void dispose() override
virtual bool EditingEntry(SvTreeListEntry *pEntry, Selection &rSelection) override
Definition: filtnav.cxx:1129
WinBits const WB_HASBUTTONS
OUString getLabelName(const Reference< css::beans::XPropertySet > &xControlModel)
Definition: fmtools.cxx:196
Reference< XModel > xModel
class FmSearchEngine - Impl class for FmSearchDialog
sal_Int32 GetComponentIndex() const
Definition: filtnav.hxx:141
virtual void Resize() override
constexpr sal_uInt16 KEY_DELETE
WinBits const WB_STDMODELESS
virtual bool Select(SvTreeListEntry *pEntry, bool bSelect=true)
static bool hasFormat(const DataFlavorExVector &_rFormats)
Definition: filtnav.hxx:209
VclPtr< FmFilterNavigator > m_pNavigator
Definition: filtnav.hxx:301
#define DROP_ACTION_TIMER_SCROLL_TICKS
Definition: filtnav.cxx:67
sal_Int8 mnAction
virtual void dispose() override
void StateChanged(sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem *pState) override
Definition: filtnav.cxx:1838
sal_uLong GetSelectionCount() const
void Push(PushFlags nFlags=PushFlags::ALL)
void AddOrRemoveListener(const Reference< XIndexAccess > &_rxControllers, const bool _bAdd)
Definition: filtnav.cxx:276
virtual Image GetImage() const override
Definition: filtnav.cxx:143
virtual ~FmFilterNavigator() override
Definition: filtnav.cxx:1089
SvTreeListEntry * Prev(SvTreeListEntry *pEntry) const
long Y() const
sal_uInt16 nPos
virtual void dispose() override
Definition: filtnav.cxx:1803
#define DROP_ACTION_TIMER_TICK_BASE
Definition: filtnav.cxx:69
OUString sDisplayName
bool IsMod2() const