LibreOffice Module reportdesign (master)  1
CondFormat.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 <CondFormat.hxx>
21 
22 #include <strings.hxx>
23 #include <strings.hrc>
24 #include <core_resource.hxx>
25 #include <ReportController.hxx>
26 #include "Condition.hxx"
27 
28 #include <com/sun/star/lang/IllegalArgumentException.hpp>
29 #include <o3tl/safeint.hxx>
31 
32 #include <tools/diagnose_ex.h>
33 
34 #include <comphelper/property.hxx>
35 
36 #include <algorithm>
37 #include <UndoActions.hxx>
38 
39 
40 namespace rptui
41 {
42 
43 
44  using ::com::sun::star::uno::Reference;
45  using ::com::sun::star::uno::UNO_QUERY_THROW;
46  using ::com::sun::star::uno::UNO_QUERY;
47  using ::com::sun::star::uno::Exception;
48  using ::com::sun::star::lang::IllegalArgumentException;
49  using ::com::sun::star::uno::Sequence;
50  using ::com::sun::star::beans::PropertyValue;
51  using ::com::sun::star::uno::Any;
52 
53  using namespace ::com::sun::star::report;
54 
56  {
57  if (!m_bConstructed && !bFirst)
58  return;
59 
60  //allow dialog to resize itself
61  size_t nCount = impl_getConditionCount();
62  if (!nCount)
63  return;
64 
65  auto nHeight = m_aConditions[0]->get_preferred_size().Height();
66  size_t nVisibleConditions = ::std::min(nCount, MAX_CONDITIONS);
67  nHeight *= nVisibleConditions;
68  nHeight += 2;
69  if (nHeight != m_xScrollWindow->get_size_request().Height())
70  {
71  m_xScrollWindow->set_size_request(-1, nHeight);
72  if (!bFirst)
73  m_xDialog->resize_to_request();
74  }
75  }
76 
78  weld::Window* _pParent, const Reference< XReportControlModel >& _rxFormatConditions, ::rptui::OReportController& _rController)
79  : GenericDialogController(_pParent, "modules/dbreport/ui/condformatdialog.ui", "CondFormat")
80  , m_rController(_rController)
81  , m_xFormatConditions(_rxFormatConditions)
82  , m_bConstructed(false)
83  , m_xScrollWindow(m_xBuilder->weld_scrolled_window("scrolledwindow"))
84  , m_xConditionPlayground(m_xBuilder->weld_box("condPlaygroundDrawingarea"))
85  {
86  OSL_ENSURE( m_xFormatConditions.is(), "ConditionalFormattingDialog::ConditionalFormattingDialog: ReportControlModel is NULL -> Prepare for GPF!" );
87 
88  m_xCopy.set( m_xFormatConditions->createClone(), UNO_QUERY_THROW );
89 
90  m_xScrollWindow->connect_vadjustment_changed(LINK(this, ConditionalFormattingDialog, OnScroll));
91 
93 
94  impl_setPrefHeight(true);
95 
96  m_bConstructed = true;
97  }
98 
100  {
101  }
102 
104  {
105  sal_Int32 nIndex = 0;
106  for (const auto& rxCondition : m_aConditions)
107  {
108  rxCondition->setConditionIndex( nIndex, impl_getConditionCount() );
109  m_xConditionPlayground->reorder_child(rxCondition->get_widget(), nIndex);
110  ++nIndex;
111  }
112  }
113 
115  {
116  if ( m_aConditions.empty() )
118 
119  impl_setPrefHeight(false);
120 
122  impl_layoutAll();
123  }
124 
125  void ConditionalFormattingDialog::addCondition( size_t _nAddAfterIndex )
126  {
127  OSL_PRECOND( _nAddAfterIndex < impl_getConditionCount(), "ConditionalFormattingDialog::addCondition: illegal condition index!" );
128  impl_addCondition_nothrow( _nAddAfterIndex + 1 );
129  }
130 
131 
133  {
134  impl_deleteCondition_nothrow( _nCondIndex );
135  }
136 
137 
139  {
140  try
141  {
142  if ( _nNewCondIndex > o3tl::make_unsigned(m_xCopy->getCount()) )
143  throw IllegalArgumentException();
144 
145  Reference< XFormatCondition > xCond = m_xCopy->createFormatCondition();
146  ::comphelper::copyProperties(m_xCopy.get(),xCond.get());
147  m_xCopy->insertByIndex( _nNewCondIndex, makeAny( xCond ) );
148  auto xCon = std::make_unique<Condition>(m_xConditionPlayground.get(), m_xDialog.get(), *this, m_rController);
149  xCon->setCondition(xCond);
150  m_xConditionPlayground->reorder_child(xCon->get_widget(), _nNewCondIndex);
151  m_aConditions.insert(m_aConditions.begin() + _nNewCondIndex, std::move(xCon));
152  }
153  catch( const Exception& )
154  {
155  DBG_UNHANDLED_EXCEPTION("reportdesign");
156  }
157 
159 
160  impl_ensureConditionVisible( _nNewCondIndex );
161  }
162 
164  {
165  OSL_PRECOND( _nCondIndex < impl_getConditionCount(),
166  "ConditionalFormattingDialog::impl_focusCondition: illegal index!" );
167 
168  impl_ensureConditionVisible( _nCondIndex );
169  m_aConditions[ _nCondIndex ]->grab_focus();
170  }
171 
173  {
174  OSL_PRECOND( _nCondIndex < impl_getConditionCount(),
175  "ConditionalFormattingDialog::impl_deleteCondition_nothrow: illegal index!" );
176 
177  bool bLastCondition = ( impl_getConditionCount() == 1 );
178 
179  bool bSetNewFocus = false;
180  size_t nNewFocusIndex( _nCondIndex );
181  try
182  {
183  if ( !bLastCondition )
184  m_xCopy->removeByIndex( _nCondIndex );
185 
186  Conditions::iterator pos = m_aConditions.begin() + _nCondIndex;
187  if ( bLastCondition )
188  {
189  Reference< XFormatCondition > xFormatCondition( m_xCopy->getByIndex( 0 ), UNO_QUERY_THROW );
190  xFormatCondition->setFormula( OUString() );
191  (*pos)->setCondition( xFormatCondition );
192  }
193  else
194  {
195  bSetNewFocus = (*pos)->has_focus();
196 
197  auto xMovedCondition = std::move(*pos);
198  m_aConditions.erase(pos);
199  m_xConditionPlayground->move(xMovedCondition->get_widget(), nullptr);
200  }
201 
202  if ( bSetNewFocus )
203  {
204  if ( nNewFocusIndex >= impl_getConditionCount() )
205  nNewFocusIndex = impl_getConditionCount() - 1;
206  }
207  }
208  catch( const Exception& )
209  {
210  DBG_UNHANDLED_EXCEPTION("reportdesign");
211  }
212 
214  if ( bSetNewFocus )
215  impl_focusCondition( nNewFocusIndex );
216  }
217 
218 
219  void ConditionalFormattingDialog::impl_moveCondition_nothrow( size_t _nCondIndex, bool _bMoveUp )
220  {
221  size_t nOldConditionIndex( _nCondIndex );
222  size_t nNewConditionIndex( _bMoveUp ? _nCondIndex - 1 : _nCondIndex + 1 );
223 
224  // do this in two steps, so we don't become inconsistent if any of the UNO actions fails
225  Any aMovedCondition;
226  std::unique_ptr<Condition> xMovedCondition;
227  try
228  {
229  aMovedCondition = m_xCopy->getByIndex( static_cast<sal_Int32>(nOldConditionIndex) );
230  m_xCopy->removeByIndex( static_cast<sal_Int32>(nOldConditionIndex) );
231 
232  Conditions::iterator aRemovePos( m_aConditions.begin() + nOldConditionIndex );
233  xMovedCondition = std::move(*aRemovePos);
234  m_aConditions.erase( aRemovePos );
235  }
236  catch( const Exception& )
237  {
238  DBG_UNHANDLED_EXCEPTION("reportdesign");
239  return;
240  }
241 
242  try
243  {
244  m_xCopy->insertByIndex( static_cast<sal_Int32>(nNewConditionIndex), aMovedCondition );
245  m_aConditions.insert(m_aConditions.begin() + nNewConditionIndex, std::move(xMovedCondition));
246  }
247  catch( const Exception& )
248  {
249  DBG_UNHANDLED_EXCEPTION("reportdesign");
250  }
251 
252  // at least the two swapped conditions need to know their new index
254 
255  // ensure the moved condition is visible
256  impl_ensureConditionVisible( nNewConditionIndex );
257  }
258 
260  {
261  size_t nFirstCondIndex( impl_getFirstVisibleConditionIndex() );
262  size_t nFocusCondIndex = impl_getFocusedConditionIndex( nFirstCondIndex );
263 
264  if ( nFocusCondIndex < nFirstCondIndex )
265  impl_focusCondition( nFirstCondIndex );
266  else if ( nFocusCondIndex >= nFirstCondIndex + MAX_CONDITIONS )
267  impl_focusCondition( nFirstCondIndex + MAX_CONDITIONS - 1 );
268  }
269 
271  {
272  // scrollbar visibility
273  if ( m_aConditions.size() <= MAX_CONDITIONS )
274  // normalize the position, so it can, in all situations, be used as top index
275  m_xScrollWindow->vadjustment_set_value(0);
276  }
277 
279  {
280  try
281  {
282  sal_Int32 nCount = m_xCopy->getCount();
283  for ( sal_Int32 i = 0; i < nCount ; ++i )
284  {
285  auto xCon = std::make_unique<Condition>(m_xConditionPlayground.get(), m_xDialog.get(), *this, m_rController);
286  Reference< XFormatCondition > xCond( m_xCopy->getByIndex(i), UNO_QUERY );
287  m_xConditionPlayground->reorder_child(xCon->get_widget(), i);
288  xCon->setCondition(xCond);
289  xCon->updateToolbar(xCond.get());
290  m_aConditions.push_back(std::move(xCon));
291  }
292  }
293  catch(Exception&)
294  {
295  OSL_FAIL("Can not access format condition!");
296  }
297 
299  }
300 
301  void ConditionalFormattingDialog::applyCommand(size_t _nCondIndex, sal_uInt16 _nCommandId, const ::Color& rColor)
302  {
303  OSL_PRECOND( _nCommandId, "ConditionalFormattingDialog::applyCommand: illegal command id!" );
304  try
305  {
306  Reference< XReportControlFormat > xReportControlFormat( m_xCopy->getByIndex( _nCondIndex ), UNO_QUERY_THROW );
307 
308  Sequence< PropertyValue > aArgs(3);
309 
310  aArgs[0].Name = REPORTCONTROLFORMAT;
311  aArgs[0].Value <<= xReportControlFormat;
312 
313  aArgs[1].Name = CURRENT_WINDOW;
314  aArgs[1].Value <<= m_xDialog->GetXWindow();
315 
316  aArgs[2].Name = PROPERTY_FONTCOLOR;
317  aArgs[2].Value <<= rColor;
318 
319  // we use this way to create undo actions
320  m_rController.executeUnChecked(_nCommandId,aArgs);
321  m_aConditions[ _nCondIndex ]->updateToolbar(xReportControlFormat);
322  }
323  catch( Exception& )
324  {
325  DBG_UNHANDLED_EXCEPTION("reportdesign");
326  }
327  }
328 
329 
331  {
332  OSL_PRECOND( _nCondIndex > 0, "ConditionalFormattingDialog::moveConditionUp: cannot move up the first condition!" );
333  if ( _nCondIndex > 0 )
334  impl_moveCondition_nothrow( _nCondIndex, true );
335  }
336 
337 
339  {
340  OSL_PRECOND( _nCondIndex < impl_getConditionCount(), "ConditionalFormattingDialog::moveConditionDown: cannot move down the last condition!" );
341  if ( _nCondIndex < impl_getConditionCount() )
342  impl_moveCondition_nothrow( _nCondIndex, false );
343  }
344 
346  {
347  OUString sDataField;
348  try
349  {
350  sDataField = m_xFormatConditions->getDataField();
351  }
352  catch( const Exception& )
353  {
354  DBG_UNHANDLED_EXCEPTION("reportdesign");
355  }
356  return sDataField;
357  }
358 
360  {
361  short nRet = GenericDialogController::run();
362  if (nRet == RET_OK)
363  {
364  const OUString sUndoAction( RptResId( RID_STR_UNDO_CONDITIONAL_FORMATTING ) );
365  const UndoContext aUndoContext( m_rController.getUndoManager(), sUndoAction );
366  try
367  {
368  sal_Int32 j(0), i(0);
369  for ( Conditions::const_iterator cond = m_aConditions.begin();
370  cond != m_aConditions.end();
371  ++cond, ++i
372  )
373  {
374  Reference< XFormatCondition > xCond( m_xCopy->getByIndex(i), UNO_QUERY_THROW );
375  (*cond)->fillFormatCondition( xCond );
376 
377  if ( (*cond)->isEmpty() )
378  continue;
379 
381  bool bAppend = j >= m_xFormatConditions->getCount();
382  if ( bAppend )
383  {
384  xNewCond = m_xFormatConditions->createFormatCondition();
385  m_xFormatConditions->insertByIndex( i, makeAny( xNewCond ) );
386  }
387  else
388  xNewCond.set( m_xFormatConditions->getByIndex(j), UNO_QUERY );
389  ++j;
390 
391  ::comphelper::copyProperties(xCond.get(),xNewCond.get());
392  }
393 
394  for ( sal_Int32 k = m_xFormatConditions->getCount()-1; k >= j; --k )
395  m_xFormatConditions->removeByIndex(k);
396 
397  ::comphelper::copyProperties( m_xCopy.get(), m_xFormatConditions.get() );
398  }
399  catch ( const Exception& )
400  {
401  DBG_UNHANDLED_EXCEPTION("reportdesign");
402  nRet = RET_NO;
403  }
404  }
405  return nRet;
406  }
407 
409  {
410  auto nHeight = m_aConditions[0]->get_preferred_size().Height();
411  return m_xScrollWindow->vadjustment_get_value() / nHeight;
412  }
413 
415  {
417  }
418 
419  size_t ConditionalFormattingDialog::impl_getFocusedConditionIndex( sal_Int32 _nFallBackIfNone ) const
420  {
421  auto cond = std::find_if(m_aConditions.begin(), m_aConditions.end(),
422  [](const std::unique_ptr<Condition>& rxCondition) { return rxCondition->has_focus(); });
423  if (cond != m_aConditions.end())
424  return static_cast<size_t>(std::distance(m_aConditions.begin(), cond));
425  return _nFallBackIfNone;
426  }
427 
428  void ConditionalFormattingDialog::impl_scrollTo( size_t nTopCondIndex )
429  {
430  OSL_PRECOND( nTopCondIndex + MAX_CONDITIONS <= impl_getConditionCount(),
431  "ConditionalFormattingDialog::impl_scrollTo: illegal index!" );
432 
433  auto nHeight = m_aConditions[0]->get_preferred_size().Height();
434  m_xScrollWindow->vadjustment_set_value(nTopCondIndex * nHeight);
435  OnScroll(*m_xScrollWindow);
436  }
437 
439  {
440  OSL_PRECOND( _nCondIndex < impl_getConditionCount(),
441  "ConditionalFormattingDialog::impl_ensureConditionVisible: illegal index!" );
442 
443  if ( _nCondIndex < impl_getFirstVisibleConditionIndex() )
444  impl_scrollTo( _nCondIndex );
445  else if ( _nCondIndex > impl_getLastVisibleConditionIndex() )
446  impl_scrollTo( _nCondIndex - MAX_CONDITIONS + 1 );
447  }
448 
449 
450 } // rptui
451 
452 
453 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
virtual void moveConditionUp(size_t _nCondIndex) override
Definition: CondFormat.cxx:330
std::shared_ptr< weld::Dialog > m_xDialog
sal_Int32 nIndex
void impl_addCondition_nothrow(size_t _nNewCondIndex)
adds a condition
Definition: CondFormat.cxx:138
void impl_deleteCondition_nothrow(size_t _nCondIndex)
deletes the condition with the given index
Definition: CondFormat.cxx:172
size_t impl_getConditionCount() const
returns the current number of conditions
Definition: CondFormat.hxx:98
::rptui::OReportController & m_rController
Definition: CondFormat.hxx:63
size_t impl_getFirstVisibleConditionIndex() const
returns the index of the first visible condition
Definition: CondFormat.cxx:408
SfxUndoManager & getUndoManager() const
RET_NO
virtual short run() override
Definition: CondFormat.cxx:359
void impl_ensureConditionVisible(size_t _nCondIndex)
ensures the condition with the given index is visible
Definition: CondFormat.cxx:438
size_t pos
int nCount
void impl_scrollTo(size_t _nTopCondIndex)
scrolls the condition with the given index to the top position
Definition: CondFormat.cxx:428
#define CURRENT_WINDOW
Definition: strings.hxx:260
void impl_layoutAll()
does the dialog layouting
Definition: CondFormat.cxx:270
#define DBG_UNHANDLED_EXCEPTION(...)
int i
std::unique_ptr< weld::Box > m_xConditionPlayground
Definition: CondFormat.hxx:72
css::uno::Reference< css::report::XReportControlModel > m_xCopy
Definition: CondFormat.hxx:67
size_t impl_getFocusedConditionIndex(sal_Int32 _nFallBackIfNone) const
returns the number of the condition which has the (child path) focus
Definition: CondFormat.cxx:419
std::unique_ptr< weld::ScrolledWindow > m_xScrollWindow
Definition: CondFormat.hxx:71
virtual void applyCommand(size_t _nCondIndex, sal_uInt16 _nCommandId, const ::Color &rColor) override
Definition: CondFormat.cxx:301
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
ConditionalFormattingDialog(weld::Window *pParent, const css::uno::Reference< css::report::XReportControlModel > &_xHoldAlive,::rptui::OReportController &_rController)
Definition: CondFormat.cxx:77
OUString RptResId(const char *pId)
css::uno::Reference< css::report::XReportControlModel > m_xFormatConditions
Definition: CondFormat.hxx:65
void impl_initializeConditions()
initializes the conditions from m_xCopy
Definition: CondFormat.cxx:278
virtual void addCondition(size_t _nAddAfterIndex) override
Definition: CondFormat.cxx:125
void impl_moveCondition_nothrow(size_t _nCondIndex, bool _bMoveUp)
moves the condition with the given index one position
Definition: CondFormat.cxx:219
void impl_updateConditionIndicies()
tells all our Condition instances their new index
Definition: CondFormat.cxx:103
virtual void moveConditionDown(size_t _nCondIndex) override
Definition: CondFormat.cxx:338
RET_OK
IMPL_LINK_NOARG(OAddFieldWindow, FocusChangeHdl, weld::Widget &, void)
Definition: AddField.cxx:120
virtual ~ConditionalFormattingDialog() override
Definition: CondFormat.cxx:99
#define REPORTCONTROLFORMAT
Definition: strings.hxx:259
virtual OUString getDataField() const override
Definition: CondFormat.cxx:345
void impl_setPrefHeight(bool bFirst)
set the preferred height of the action_area
Definition: CondFormat.cxx:55
size_t impl_getLastVisibleConditionIndex() const
returns the index of the last visible condition
Definition: CondFormat.cxx:414
void impl_conditionCountChanged()
called when the number of conditions has changed in any way
Definition: CondFormat.cxx:114
virtual void deleteCondition(size_t _nCondIndex) override
Definition: CondFormat.cxx:132
#define PROPERTY_FONTCOLOR
Definition: strings.hxx:261
void impl_focusCondition(size_t _nCondIndex)
focuses the condition with the given index, making it visible if necessary
Definition: CondFormat.cxx:163
constexpr size_t MAX_CONDITIONS
Definition: CondFormat.hxx:31
css::uno::Any SAL_CALL makeAny(const SharedUNOComponent< INTERFACE, COMPONENT > &value)