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 <RptUndo.hxx>
21 #include <strings.hxx>
22 #include <rptui_slotid.hrc>
23 #include <UITools.hxx>
24 #include <UndoEnv.hxx>
25 
26 #include <dbaccess/IController.hxx>
27 #include <com/sun/star/report/XSection.hpp>
28 #include <com/sun/star/beans/PropertyAttribute.hpp>
29 
30 #include <com/sun/star/awt/Point.hpp>
31 #include <com/sun/star/awt/Size.hpp>
32 #include <comphelper/types.hxx>
33 #include <svx/unoshape.hxx>
34 #include <utility>
35 #include <tools/diagnose_ex.h>
36 
37 #include <functional>
38 
39 namespace rptui
40 {
41     using namespace ::com::sun::star;
42     using namespace uno;
43     using namespace lang;
44     using namespace beans;
45     using namespace awt;
46     using namespace util;
47     using namespace container;
48     using namespace report;
49 
50 
51 namespace
52 {
lcl_collectElements(const uno::Reference<report::XSection> & _xSection,::std::vector<uno::Reference<drawing::XShape>> & _rControls)53     void lcl_collectElements(const uno::Reference< report::XSection >& _xSection,::std::vector< uno::Reference< drawing::XShape> >& _rControls)
54     {
55         if ( _xSection.is() )
56         {
57             sal_Int32 nCount = _xSection->getCount();
58             _rControls.reserve(nCount);
59             while ( nCount )
60             {
61                 uno::Reference< drawing::XShape> xShape(_xSection->getByIndex(nCount-1),uno::UNO_QUERY);
62                 _rControls.push_back(xShape);
63                 _xSection->remove(xShape);
64                 --nCount;
65             }
66         }
67     }
68 
lcl_insertElements(const uno::Reference<report::XSection> & _xSection,const::std::vector<uno::Reference<drawing::XShape>> & _aControls)69     void lcl_insertElements(const uno::Reference< report::XSection >& _xSection,const ::std::vector< uno::Reference< drawing::XShape> >& _aControls)
70     {
71         if ( !_xSection.is() )
72             return;
73 
74         ::std::vector< uno::Reference< drawing::XShape> >::const_reverse_iterator aIter = _aControls.rbegin();
75         ::std::vector< uno::Reference< drawing::XShape> >::const_reverse_iterator aEnd = _aControls.rend();
76         for (; aIter != aEnd; ++aIter)
77         {
78             try
79             {
80                 const awt::Point aPos = (*aIter)->getPosition();
81                 const awt::Size aSize = (*aIter)->getSize();
82                 _xSection->add(*aIter);
83                 (*aIter)->setPosition( aPos );
84                 (*aIter)->setSize( aSize );
85             }
86             catch(const uno::Exception&)
87             {
88                 TOOLS_WARN_EXCEPTION( "reportdesign", "lcl_insertElements");
89             }
90         }
91     }
92 
lcl_setValues(const uno::Reference<report::XSection> & _xSection,const::std::vector<::std::pair<OUString,uno::Any>> & _aValues)93     void lcl_setValues(const uno::Reference< report::XSection >& _xSection,const ::std::vector< ::std::pair< OUString ,uno::Any> >& _aValues)
94     {
95         if ( !_xSection.is() )
96             return;
97 
98         for (const auto& [rPropName, rValue] : _aValues)
99         {
100             try
101             {
102                 _xSection->setPropertyValue(rPropName, rValue);
103             }
104             catch(const uno::Exception&)
105             {
106                 TOOLS_WARN_EXCEPTION( "reportdesign", "lcl_setValues");
107             }
108         }
109     }
110 }
111 
112 
OSectionUndo(OReportModel & _rMod,sal_uInt16 _nSlot,Action _eAction,const char * pCommentID)113 OSectionUndo::OSectionUndo(OReportModel& _rMod
114                            ,sal_uInt16 _nSlot
115                            ,Action _eAction
116                            ,const char* pCommentID)
117 : OCommentUndoAction(_rMod,pCommentID)
118 ,m_eAction(_eAction)
119 ,m_nSlot(_nSlot)
120 ,m_bInserted(false)
121 {
122 }
123 
~OSectionUndo()124 OSectionUndo::~OSectionUndo()
125 {
126     if ( m_bInserted )
127         return;
128 
129     OXUndoEnvironment& rEnv = static_cast< OReportModel& >( rMod ).GetUndoEnv();
130     for (uno::Reference<drawing::XShape>& xShape : m_aControls)
131     {
132         rEnv.RemoveElement(xShape);
133 
134 #if OSL_DEBUG_LEVEL > 0
135         SvxShape* pShape = comphelper::getUnoTunnelImplementation<SvxShape>( xShape );
136         SdrObject* pObject = pShape ? pShape->GetSdrObject() : nullptr;
137         OSL_ENSURE( pShape && pShape->HasSdrObjectOwnership() && pObject && !pObject->IsInserted(),
138             "OSectionUndo::~OSectionUndo: inconsistency in the shape/object ownership!" );
139 #endif
140         try
141         {
142             comphelper::disposeComponent(xShape);
143         }
144         catch(const uno::Exception &)
145         {
146             TOOLS_WARN_EXCEPTION( "reportdesign", "");
147         }
148     }
149 }
150 
collectControls(const uno::Reference<report::XSection> & _xSection)151 void OSectionUndo::collectControls(const uno::Reference< report::XSection >& _xSection)
152 {
153     m_aControls.clear();
154     try
155     {
156         // copy all properties for restoring
157         uno::Reference< beans::XPropertySetInfo> xInfo = _xSection->getPropertySetInfo();
158         const uno::Sequence< beans::Property> aSeq = xInfo->getProperties();
159         for(const beans::Property& rProp : aSeq)
160         {
161             if ( 0 == (rProp.Attributes & beans::PropertyAttribute::READONLY) )
162                 m_aValues.emplace_back(rProp.Name,_xSection->getPropertyValue(rProp.Name));
163         }
164         lcl_collectElements(_xSection,m_aControls);
165     }
166     catch(uno::Exception&)
167     {
168     }
169 }
170 
Undo()171 void OSectionUndo::Undo()
172 {
173     try
174     {
175         switch ( m_eAction )
176         {
177         case Inserted:
178             implReRemove();
179             break;
180 
181         case Removed:
182             implReInsert();
183             break;
184         }
185     }
186     catch( const Exception& )
187     {
188         TOOLS_WARN_EXCEPTION( "reportdesign", "OSectionUndo::Undo" );
189     }
190 }
191 
Redo()192 void OSectionUndo::Redo()
193 {
194     try
195     {
196         switch ( m_eAction )
197         {
198         case Inserted:
199             implReInsert();
200             break;
201 
202         case Removed:
203             implReRemove();
204             break;
205         }
206     }
207     catch( const Exception& )
208     {
209         TOOLS_WARN_EXCEPTION( "reportdesign", "OSectionUndo::Redo" );
210     }
211 }
212 
OReportSectionUndo(OReportModel & _rMod,sal_uInt16 _nSlot,::std::function<uno::Reference<report::XSection> (OReportHelper *)> _pMemberFunction,const uno::Reference<report::XReportDefinition> & _xReport,Action _eAction)213 OReportSectionUndo::OReportSectionUndo(
214     OReportModel& _rMod, sal_uInt16 _nSlot,
215     ::std::function<uno::Reference<report::XSection>(OReportHelper*)> _pMemberFunction,
216     const uno::Reference<report::XReportDefinition>& _xReport, Action _eAction)
217     : OSectionUndo(_rMod, _nSlot, _eAction, nullptr)
218     , m_aReportHelper(_xReport)
219     , m_pMemberFunction(std::move(_pMemberFunction))
220 {
221     if( m_eAction == Removed )
222         collectControls(m_pMemberFunction(&m_aReportHelper));
223 }
224 
~OReportSectionUndo()225 OReportSectionUndo::~OReportSectionUndo()
226 {
227 }
228 
implReInsert()229 void OReportSectionUndo::implReInsert( )
230 {
231     const uno::Sequence< beans::PropertyValue > aArgs;
232     m_pController->executeChecked(m_nSlot,aArgs);
233     uno::Reference< report::XSection > xSection = m_pMemberFunction(&m_aReportHelper);
234     lcl_insertElements(xSection,m_aControls);
235     lcl_setValues(xSection,m_aValues);
236     m_bInserted = true;
237 }
238 
implReRemove()239 void OReportSectionUndo::implReRemove( )
240 {
241     if( m_eAction == Removed )
242         collectControls(m_pMemberFunction(&m_aReportHelper));
243     const uno::Sequence< beans::PropertyValue > aArgs;
244     m_pController->executeChecked(m_nSlot,aArgs);
245     m_bInserted = false;
246 }
247 
OGroupSectionUndo(OReportModel & _rMod,sal_uInt16 _nSlot,::std::function<uno::Reference<report::XSection> (OGroupHelper *)> _pMemberFunction,const uno::Reference<report::XGroup> & _xGroup,Action _eAction,const char * pCommentID)248 OGroupSectionUndo::OGroupSectionUndo(
249     OReportModel& _rMod, sal_uInt16 _nSlot,
250     ::std::function<uno::Reference<report::XSection>(OGroupHelper*)> _pMemberFunction,
251     const uno::Reference<report::XGroup>& _xGroup, Action _eAction, const char* pCommentID)
252     : OSectionUndo(_rMod, _nSlot, _eAction, pCommentID)
253     , m_aGroupHelper(_xGroup)
254     , m_pMemberFunction(std::move(_pMemberFunction))
255 {
256     if( m_eAction == Removed )
257     {
258         uno::Reference< report::XSection > xSection = m_pMemberFunction(&m_aGroupHelper);
259         if ( xSection.is() )
260             m_sName = xSection->getName();
261         collectControls(xSection);
262     }
263 }
264 
GetComment() const265 OUString OGroupSectionUndo::GetComment() const
266 {
267     if ( m_sName.isEmpty() )
268     {
269         try
270         {
271             uno::Reference< report::XSection > xSection = const_cast<OGroupSectionUndo*>(this)->m_pMemberFunction(&const_cast<OGroupSectionUndo*>(this)->m_aGroupHelper);
272 
273             if ( xSection.is() )
274                 m_sName = xSection->getName();
275         }
276         catch (const uno::Exception&)
277         {
278         }
279     }
280     return m_strComment + m_sName;
281 }
282 
implReInsert()283 void OGroupSectionUndo::implReInsert( )
284 {
285     uno::Sequence< beans::PropertyValue > aArgs(2);
286 
287     aArgs[0].Name = SID_GROUPHEADER_WITHOUT_UNDO == m_nSlot? OUStringLiteral(u"" PROPERTY_HEADERON) : OUStringLiteral(u"" PROPERTY_FOOTERON);
288     aArgs[0].Value <<= true;
289     aArgs[1].Name = PROPERTY_GROUP;
290     aArgs[1].Value <<= m_aGroupHelper.getGroup();
291     m_pController->executeChecked(m_nSlot,aArgs);
292 
293     uno::Reference< report::XSection > xSection = m_pMemberFunction(&m_aGroupHelper);
294     lcl_insertElements(xSection,m_aControls);
295     lcl_setValues(xSection,m_aValues);
296     m_bInserted = true;
297 }
298 
implReRemove()299 void OGroupSectionUndo::implReRemove( )
300 {
301     if( m_eAction == Removed )
302         collectControls(m_pMemberFunction(&m_aGroupHelper));
303 
304     uno::Sequence< beans::PropertyValue > aArgs(2);
305 
306     aArgs[0].Name = SID_GROUPHEADER_WITHOUT_UNDO == m_nSlot? OUStringLiteral(u"" PROPERTY_HEADERON) : OUStringLiteral(u"" PROPERTY_FOOTERON);
307     aArgs[0].Value <<= false;
308     aArgs[1].Name = PROPERTY_GROUP;
309     aArgs[1].Value <<= m_aGroupHelper.getGroup();
310 
311     m_pController->executeChecked(m_nSlot,aArgs);
312     m_bInserted = false;
313 }
314 
315 
OGroupUndo(OReportModel & _rMod,const char * pCommentID,Action _eAction,const uno::Reference<report::XGroup> & _xGroup,const uno::Reference<report::XReportDefinition> & _xReportDefinition)316 OGroupUndo::OGroupUndo(OReportModel& _rMod
317                        ,const char* pCommentID
318                        ,Action  _eAction
319                        ,const uno::Reference< report::XGroup>& _xGroup
320                        ,const uno::Reference< report::XReportDefinition >& _xReportDefinition)
321 : OCommentUndoAction(_rMod,pCommentID)
322 ,m_xGroup(_xGroup)
323 ,m_xReportDefinition(_xReportDefinition)
324 ,m_eAction(_eAction)
325 {
326     m_nLastPosition = getPositionInIndexAccess(m_xReportDefinition->getGroups(),m_xGroup);
327 }
328 
implReInsert()329 void OGroupUndo::implReInsert( )
330 {
331     try
332     {
333         m_xReportDefinition->getGroups()->insertByIndex(m_nLastPosition,uno::makeAny(m_xGroup));
334     }
335     catch(uno::Exception&)
336     {
337         TOOLS_WARN_EXCEPTION( "reportdesign", "Exception caught while undoing remove group");
338     }
339 }
340 
implReRemove()341 void OGroupUndo::implReRemove( )
342 {
343     try
344     {
345         m_xReportDefinition->getGroups()->removeByIndex(m_nLastPosition);
346     }
347     catch(uno::Exception&)
348     {
349         TOOLS_WARN_EXCEPTION( "reportdesign", "Exception caught while redoing remove group");
350     }
351 }
352 
Undo()353 void OGroupUndo::Undo()
354 {
355     switch ( m_eAction )
356     {
357     case Inserted:
358         implReRemove();
359         break;
360 
361     case Removed:
362         implReInsert();
363         break;
364     }
365 
366 }
367 
Redo()368 void OGroupUndo::Redo()
369 {
370     switch ( m_eAction )
371     {
372     case Inserted:
373         implReInsert();
374         break;
375 
376     case Removed:
377         implReRemove();
378         break;
379     }
380 }
381 
382 
383 } // rptui
384 
385 
386 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
387