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