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 <com/sun/star/table/CellAddress.hpp>
21 #include <com/sun/star/table/CellRangeAddress.hpp>
22 #include <cppuhelper/supportsservice.hxx>
23 
24 #include <svl/itemprop.hxx>
25 #include <vcl/svapp.hxx>
26 
27 #include <docsh.hxx>
28 #include <unonames.hxx>
29 #include <miscuno.hxx>
30 #include <convuno.hxx>
31 #include <addruno.hxx>
32 
33 using namespace com::sun::star;
34 
ScAddressConversionObj(ScDocShell * pDocSh,bool _bIsRange)35 ScAddressConversionObj::ScAddressConversionObj(ScDocShell* pDocSh, bool _bIsRange) :
36     pDocShell( pDocSh ),
37     nRefSheet( 0 ),
38     bIsRange( _bIsRange )
39 {
40     pDocShell->GetDocument().AddUnoObject(*this);
41 }
42 
~ScAddressConversionObj()43 ScAddressConversionObj::~ScAddressConversionObj()
44 {
45     SolarMutexGuard g;
46 
47     if (pDocShell)
48         pDocShell->GetDocument().RemoveUnoObject(*this);
49 }
50 
Notify(SfxBroadcaster &,const SfxHint & rHint)51 void ScAddressConversionObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
52 {
53     if ( rHint.GetId() == SfxHintId::Dying )
54     {
55         pDocShell = nullptr;       // invalid
56     }
57 }
58 
ParseUIString(const OUString & rUIString,::formula::FormulaGrammar::AddressConvention eConv)59 bool ScAddressConversionObj::ParseUIString( const OUString& rUIString, ::formula::FormulaGrammar::AddressConvention eConv )
60 {
61     if (!pDocShell)
62         return false;
63 
64     ScDocument& rDoc = pDocShell->GetDocument();
65     bool bSuccess = false;
66     if ( bIsRange )
67     {
68         ScRefFlags nResult = aRange.ParseAny( rUIString, &rDoc, eConv );
69         if ( nResult & ScRefFlags::VALID )
70         {
71             if ( ( nResult & ScRefFlags::TAB_3D ) == ScRefFlags::ZERO )
72                 aRange.aStart.SetTab( static_cast<SCTAB>(nRefSheet) );
73             if ( ( nResult & ScRefFlags::TAB2_3D ) == ScRefFlags::ZERO )
74                 aRange.aEnd.SetTab( aRange.aStart.Tab() );
75             // different sheets are not supported in CellRangeAddress
76             if ( aRange.aStart.Tab() == aRange.aEnd.Tab() )
77                 bSuccess = true;
78         }
79     }
80     else
81     {
82         ScRefFlags nResult = aRange.aStart.Parse( rUIString, &rDoc, eConv );
83         if ( nResult & ScRefFlags::VALID )
84         {
85             if ( ( nResult & ScRefFlags::TAB_3D ) == ScRefFlags::ZERO )
86                 aRange.aStart.SetTab( static_cast<SCTAB>(nRefSheet) );
87             bSuccess = true;
88         }
89     }
90     return bSuccess;
91 }
92 
93 // XPropertySet
94 
getPropertySetInfo()95 uno::Reference<beans::XPropertySetInfo> SAL_CALL ScAddressConversionObj::getPropertySetInfo()
96 {
97     SolarMutexGuard aGuard;
98 
99     if ( bIsRange )
100     {
101         static const SfxItemPropertyMapEntry aPropertyMap[] =
102         {
103             { OUString(SC_UNONAME_ADDRESS),  0,  cppu::UnoType<table::CellRangeAddress>::get(), 0, 0 },
104             { OUString(SC_UNONAME_PERSREPR), 0,  cppu::UnoType<OUString>::get(),    0, 0 },
105             { OUString(SC_UNONAME_XLA1REPR), 0,  cppu::UnoType<OUString>::get(),    0, 0 },
106             { OUString(SC_UNONAME_REFSHEET), 0,  cppu::UnoType<sal_Int32>::get(),        0, 0 },
107             { OUString(SC_UNONAME_UIREPR),   0,  cppu::UnoType<OUString>::get(),    0, 0 },
108             { OUString(SC_UNONAME_XLA1REPR), 0,  cppu::UnoType<OUString>::get(),    0, 0 },
109             { OUString(), 0, css::uno::Type(), 0, 0 }
110         };
111         static uno::Reference<beans::XPropertySetInfo> aRef(new SfxItemPropertySetInfo( aPropertyMap ));
112         return aRef;
113     }
114     else
115     {
116         static const SfxItemPropertyMapEntry aPropertyMap[] =
117         {
118             { OUString(SC_UNONAME_ADDRESS),  0,  cppu::UnoType<table::CellAddress>::get(), 0, 0 },
119             { OUString(SC_UNONAME_PERSREPR), 0,  cppu::UnoType<OUString>::get(),    0, 0 },
120             { OUString(SC_UNONAME_XLA1REPR), 0,  cppu::UnoType<OUString>::get(),    0, 0 },
121             { OUString(SC_UNONAME_REFSHEET), 0,  cppu::UnoType<sal_Int32>::get(),        0, 0 },
122             { OUString(SC_UNONAME_UIREPR),   0,  cppu::UnoType<OUString>::get(),    0, 0 },
123             { OUString(SC_UNONAME_XLA1REPR), 0,  cppu::UnoType<OUString>::get(),    0, 0 },
124             { OUString(), 0, css::uno::Type(), 0, 0 }
125         };
126         static uno::Reference<beans::XPropertySetInfo> aRef(new SfxItemPropertySetInfo( aPropertyMap ));
127         return aRef;
128     }
129 }
130 
setPropertyValue(const OUString & aPropertyName,const uno::Any & aValue)131 void SAL_CALL ScAddressConversionObj::setPropertyValue( const OUString& aPropertyName, const uno::Any& aValue )
132 {
133     if ( !pDocShell )
134         throw uno::RuntimeException();
135 
136     bool bSuccess = false;
137     if ( aPropertyName == SC_UNONAME_ADDRESS )
138     {
139         //  read the cell/range address from API struct
140         if ( bIsRange )
141         {
142             table::CellRangeAddress aRangeAddress;
143             if ( aValue >>= aRangeAddress )
144             {
145                 ScUnoConversion::FillScRange( aRange, aRangeAddress );
146                 bSuccess = true;
147             }
148         }
149         else
150         {
151             table::CellAddress aCellAddress;
152             if ( aValue >>= aCellAddress )
153             {
154                 ScUnoConversion::FillScAddress( aRange.aStart, aCellAddress );
155                 bSuccess = true;
156             }
157         }
158     }
159     else if ( aPropertyName == SC_UNONAME_REFSHEET )
160     {
161         //  set the reference sheet
162         sal_Int32 nIntVal = 0;
163         if ( aValue >>= nIntVal )
164         {
165             nRefSheet = nIntVal;
166             bSuccess = true;
167         }
168     }
169     else if ( aPropertyName == SC_UNONAME_UIREPR )
170     {
171         //  parse the UI representation string
172         OUString sRepresentation;
173         if (aValue >>= sRepresentation)
174         {
175             bSuccess = ParseUIString( sRepresentation );
176         }
177     }
178     else if ( aPropertyName == SC_UNONAME_PERSREPR || aPropertyName == SC_UNONAME_XLA1REPR )
179     {
180         ::formula::FormulaGrammar::AddressConvention eConv = aPropertyName == SC_UNONAME_XLA1REPR ?
181             ::formula::FormulaGrammar::CONV_XL_A1 : ::formula::FormulaGrammar::CONV_OOO;
182 
183         //  parse the file format string
184         OUString sRepresentation;
185         if (aValue >>= sRepresentation)
186         {
187             OUString aUIString(sRepresentation);
188 
189             //  cell or range: strip a single "." at the start
190             if ( aUIString[0]== '.' )
191                 aUIString = aUIString.copy( 1 );
192 
193             if ( bIsRange )
194             {
195                 //  range: also strip a "." after the last colon
196                 sal_Int32 nColon = aUIString.lastIndexOf( ':' );
197                 if ( nColon >= 0 && nColon < aUIString.getLength() - 1 &&
198                      aUIString[nColon+1] == '.' )
199                     aUIString = aUIString.replaceAt( nColon+1, 1, "" );
200             }
201 
202             //  parse the rest like a UI string
203             bSuccess = ParseUIString( aUIString, eConv );
204         }
205     }
206     else
207         throw beans::UnknownPropertyException(aPropertyName);
208 
209     if ( !bSuccess )
210         throw lang::IllegalArgumentException();
211 }
212 
getPropertyValue(const OUString & aPropertyName)213 uno::Any SAL_CALL ScAddressConversionObj::getPropertyValue( const OUString& aPropertyName )
214 {
215     if ( !pDocShell )
216         throw uno::RuntimeException();
217 
218     ScDocument& rDoc = pDocShell->GetDocument();
219     uno::Any aRet;
220 
221     if ( aPropertyName == SC_UNONAME_ADDRESS )
222     {
223         if ( bIsRange )
224         {
225             table::CellRangeAddress aRangeAddress;
226             ScUnoConversion::FillApiRange( aRangeAddress, aRange );
227             aRet <<= aRangeAddress;
228         }
229         else
230         {
231             table::CellAddress aCellAddress;
232             ScUnoConversion::FillApiAddress( aCellAddress, aRange.aStart );
233             aRet <<= aCellAddress;
234         }
235     }
236     else if ( aPropertyName == SC_UNONAME_REFSHEET )
237     {
238         aRet <<= nRefSheet;
239     }
240     else if ( aPropertyName == SC_UNONAME_UIREPR )
241     {
242         //  generate UI representation string - include sheet only if different from ref sheet
243         OUString aFormatStr;
244         ScRefFlags nFlags = ScRefFlags::VALID;
245         if ( aRange.aStart.Tab() != nRefSheet )
246             nFlags |= ScRefFlags::TAB_3D;
247         if ( bIsRange )
248             aFormatStr = aRange.Format(nFlags, &rDoc);
249         else
250             aFormatStr = aRange.aStart.Format(nFlags, &rDoc);
251         aRet <<= aFormatStr;
252     }
253     else if ( aPropertyName == SC_UNONAME_PERSREPR || aPropertyName == SC_UNONAME_XLA1REPR )
254     {
255         ::formula::FormulaGrammar::AddressConvention eConv = aPropertyName == SC_UNONAME_XLA1REPR ?
256             ::formula::FormulaGrammar::CONV_XL_A1 : ::formula::FormulaGrammar::CONV_OOO;
257 
258         //  generate file format string - always include sheet
259         OUString aFormatStr(aRange.aStart.Format(ScRefFlags::VALID | ScRefFlags::TAB_3D, &rDoc, eConv));
260         if ( bIsRange )
261         {
262             //  manually concatenate range so both parts always have the sheet name
263             aFormatStr += ":";
264             ScRefFlags nFlags = ScRefFlags::VALID;
265             if( eConv != ::formula::FormulaGrammar::CONV_XL_A1 )
266                 nFlags |= ScRefFlags::TAB_3D;
267             OUString aSecond(aRange.aEnd.Format(nFlags, &rDoc, eConv));
268             aFormatStr += aSecond ;
269         }
270         aRet <<= aFormatStr;
271     }
272     else
273         throw beans::UnknownPropertyException(aPropertyName);
274 
275     return aRet;
276 }
277 
SC_IMPL_DUMMY_PROPERTY_LISTENER(ScAddressConversionObj)278 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScAddressConversionObj )
279 
280 // lang::XServiceInfo
281 
282 OUString SAL_CALL ScAddressConversionObj::getImplementationName()
283 {
284     return "ScAddressConversionObj";
285 }
286 
supportsService(const OUString & rServiceName)287 sal_Bool SAL_CALL ScAddressConversionObj::supportsService( const OUString& rServiceName )
288 {
289     return cppu::supportsService(this, rServiceName);
290 }
291 
getSupportedServiceNames()292 uno::Sequence<OUString> SAL_CALL ScAddressConversionObj::getSupportedServiceNames()
293 {
294     if (bIsRange)
295         return {SC_SERVICENAME_RANGEADDRESS};
296     else
297         return {SC_SERVICENAME_CELLADDRESS};
298 }
299 
300 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
301