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