1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 #include "vbahyperlinks.hxx"
25 #include <algorithm>
26 #include <vector>
27 #include <ooo/vba/office/MsoHyperlinkType.hpp>
28 #include "rangelst.hxx"
29 #include "vbahyperlink.hxx"
30 #include "vbarange.hxx"
31
32 using namespace ::ooo::vba;
33 using namespace ::com::sun::star;
34 using ::rtl::OUString;
35
36 // ============================================================================
37
38 namespace {
39
40 /** Returns true, if every range of rxInner is contained in any range of rScOuter. */
lclContains(const ScRangeList & rScOuter,const uno::Reference<excel::XRange> & rxInner)41 bool lclContains( const ScRangeList& rScOuter, const uno::Reference< excel::XRange >& rxInner )
42 {
43 const ScRangeList& rScInner = ScVbaRange::getScRangeList( rxInner );
44 if( (rScInner.Count() == 0) || (rScOuter.Count() == 0) )
45 throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Empty range objects" ) ), uno::Reference< uno::XInterface >() );
46
47 for( sal_uLong nIndex = 0, nCount = rScInner.Count(); nIndex < nCount; ++nIndex )
48 if( !rScOuter.In( *rScInner.GetObject( nIndex ) ) )
49 return false;
50 return true;
51 }
52
53 // ----------------------------------------------------------------------------
54
55 /** Functor to decide whether the anchors of two Hyperlink objects are equal. */
56 struct EqualAnchorFunctor
57 {
58 uno::Reference< excel::XRange > mxAnchorRange;
59 uno::Reference< msforms::XShape > mxAnchorShape;
60 sal_Int32 mnType;
61 EqualAnchorFunctor( const uno::Reference< excel::XHyperlink >& rxHlink );
62 bool operator()( const uno::Reference< excel::XHyperlink >& rxHlink ) const;
63 };
64
EqualAnchorFunctor(const uno::Reference<excel::XHyperlink> & rxHlink)65 EqualAnchorFunctor::EqualAnchorFunctor( const uno::Reference< excel::XHyperlink >& rxHlink ) :
66 mnType( rxHlink->getType() )
67 {
68 switch( mnType )
69 {
70 case office::MsoHyperlinkType::msoHyperlinkRange:
71 mxAnchorRange.set( rxHlink->getRange(), uno::UNO_QUERY_THROW );
72 break;
73 case office::MsoHyperlinkType::msoHyperlinkShape:
74 case office::MsoHyperlinkType::msoHyperlinkInlineShape:
75 mxAnchorShape.set( rxHlink->getShape(), uno::UNO_QUERY_THROW );
76 break;
77 default:
78 throw uno::RuntimeException();
79 }
80 }
81
operator ()(const uno::Reference<excel::XHyperlink> & rxHlink) const82 bool EqualAnchorFunctor::operator()( const uno::Reference< excel::XHyperlink >& rxHlink ) const
83 {
84 sal_Int32 nType = rxHlink->getType();
85 if( nType != mnType )
86 return false;
87
88 switch( nType )
89 {
90 case office::MsoHyperlinkType::msoHyperlinkRange:
91 {
92 uno::Reference< excel::XRange > xAnchorRange( rxHlink->getRange(), uno::UNO_QUERY_THROW );
93 const ScRangeList& rScRanges1 = ScVbaRange::getScRangeList( xAnchorRange );
94 const ScRangeList& rScRanges2 = ScVbaRange::getScRangeList( mxAnchorRange );
95 return (rScRanges1.Count() == 1) && (rScRanges2.Count() == 1) && (*rScRanges1.GetObject( 0 ) == *rScRanges2.GetObject( 0 ));
96 }
97 case office::MsoHyperlinkType::msoHyperlinkShape:
98 case office::MsoHyperlinkType::msoHyperlinkInlineShape:
99 {
100 uno::Reference< msforms::XShape > xAnchorShape( rxHlink->getShape(), uno::UNO_QUERY_THROW );
101 return xAnchorShape.get() == mxAnchorShape.get();
102 }
103 default:
104 throw uno::RuntimeException();
105 }
106 }
107
108 } // namespace
109
110 // ============================================================================
111
112 namespace vba_detail {
113
114 class ScVbaHlinkContainer : public ::cppu::WeakImplHelper1< container::XIndexAccess >
115 {
116 public:
117 explicit ScVbaHlinkContainer();
118 explicit ScVbaHlinkContainer( const ScVbaHlinkContainerRef& rxSheetContainer, const ScRangeList& rScRanges );
119 virtual ~ScVbaHlinkContainer();
120
121 /** Inserts the passed hyperlink into the collection. Will remove a
122 Hyperlink object with the same anchor as the passed Hyperlink object. */
123 void insertHyperlink( const uno::Reference< excel::XHyperlink >& rxHlink );
124
125 // XIndexAccess
126 virtual sal_Int32 SAL_CALL getCount();
127 virtual uno::Any SAL_CALL getByIndex( sal_Int32 nIndex );
128
129 // XElementAccess
130 virtual uno::Type SAL_CALL getElementType();
131 virtual sal_Bool SAL_CALL hasElements();
132
133 private:
134 typedef ::std::vector< uno::Reference< excel::XHyperlink > > HyperlinkVector;
135 HyperlinkVector maHlinks;
136 };
137
138 // ----------------------------------------------------------------------------
139
ScVbaHlinkContainer()140 ScVbaHlinkContainer::ScVbaHlinkContainer()
141 {
142 // TODO FIXME: fill with existing hyperlinks
143 }
144
ScVbaHlinkContainer(const ScVbaHlinkContainerRef & rxSheetContainer,const ScRangeList & rScRanges)145 ScVbaHlinkContainer::ScVbaHlinkContainer( const ScVbaHlinkContainerRef& rxSheetContainer,
146 const ScRangeList& rScRanges )
147 {
148 for( sal_Int32 nIndex = 0, nCount = rxSheetContainer->getCount(); nIndex < nCount; ++nIndex )
149 {
150 uno::Reference< excel::XHyperlink > xHlink( rxSheetContainer->getByIndex( nIndex ), uno::UNO_QUERY_THROW );
151 uno::Reference< excel::XRange > xHlinkRange( xHlink->getRange(), uno::UNO_QUERY_THROW );
152 if( lclContains( rScRanges, xHlinkRange ) )
153 maHlinks.push_back( xHlink );
154 }
155 }
156
~ScVbaHlinkContainer()157 ScVbaHlinkContainer::~ScVbaHlinkContainer()
158 {
159 }
160
insertHyperlink(const uno::Reference<excel::XHyperlink> & rxHlink)161 void ScVbaHlinkContainer::insertHyperlink( const uno::Reference< excel::XHyperlink >& rxHlink )
162 {
163 HyperlinkVector::iterator aIt = ::std::find_if( maHlinks.begin(), maHlinks.end(), EqualAnchorFunctor( rxHlink ) );
164 if( aIt == maHlinks.end() )
165 maHlinks.push_back( rxHlink );
166 else
167 *aIt = rxHlink;
168 }
169
getCount()170 sal_Int32 SAL_CALL ScVbaHlinkContainer::getCount()
171 {
172 return static_cast< sal_Int32 >( maHlinks.size() );
173 }
174
getByIndex(sal_Int32 nIndex)175 uno::Any SAL_CALL ScVbaHlinkContainer::getByIndex( sal_Int32 nIndex )
176 {
177 if( (0 <= nIndex) && (nIndex < getCount()) )
178 return uno::Any( maHlinks[ static_cast< size_t >( nIndex ) ] );
179 throw lang::IndexOutOfBoundsException();
180 }
181
getElementType()182 uno::Type SAL_CALL ScVbaHlinkContainer::getElementType()
183 {
184 return excel::XHyperlink::static_type( 0 );
185 }
186
hasElements()187 sal_Bool SAL_CALL ScVbaHlinkContainer::hasElements()
188 {
189 return !maHlinks.empty();
190 }
191
192 // ============================================================================
193
ScVbaHlinkContainerMember(ScVbaHlinkContainer * pContainer)194 ScVbaHlinkContainerMember::ScVbaHlinkContainerMember( ScVbaHlinkContainer* pContainer ) :
195 mxContainer( pContainer )
196 {
197 }
198
~ScVbaHlinkContainerMember()199 ScVbaHlinkContainerMember::~ScVbaHlinkContainerMember()
200 {
201 }
202
203 } // namespace vba_detail
204
205 // ============================================================================
206
ScVbaHyperlinks(const uno::Reference<XHelperInterface> & rxParent,const uno::Reference<uno::XComponentContext> & rxContext)207 ScVbaHyperlinks::ScVbaHyperlinks( const uno::Reference< XHelperInterface >& rxParent,
208 const uno::Reference< uno::XComponentContext >& rxContext ) :
209 vba_detail::ScVbaHlinkContainerMember( new vba_detail::ScVbaHlinkContainer ),
210 ScVbaHyperlinks_BASE( rxParent, rxContext, uno::Reference< container::XIndexAccess >( mxContainer.get() ) )
211 {
212 }
213
ScVbaHyperlinks(const uno::Reference<XHelperInterface> & rxParent,const uno::Reference<uno::XComponentContext> & rxContext,const ScVbaHyperlinksRef & rxSheetHlinks,const ScRangeList & rScRanges)214 ScVbaHyperlinks::ScVbaHyperlinks( const uno::Reference< XHelperInterface >& rxParent,
215 const uno::Reference< uno::XComponentContext >& rxContext,
216 const ScVbaHyperlinksRef& rxSheetHlinks, const ScRangeList& rScRanges ) :
217 vba_detail::ScVbaHlinkContainerMember( new vba_detail::ScVbaHlinkContainer( rxSheetHlinks->mxContainer, rScRanges ) ),
218 ScVbaHyperlinks_BASE( rxParent, rxContext, uno::Reference< container::XIndexAccess >( mxContainer.get() ) ),
219 mxSheetHlinks( rxSheetHlinks )
220 {
221 }
222
~ScVbaHyperlinks()223 ScVbaHyperlinks::~ScVbaHyperlinks()
224 {
225 }
226
227 // XHyperlinks ----------------------------------------------------------------
228
Add(const uno::Any & rAnchor,const uno::Any & rAddress,const uno::Any & rSubAddress,const uno::Any & rScreenTip,const uno::Any & rTextToDisplay)229 uno::Reference< excel::XHyperlink > SAL_CALL ScVbaHyperlinks::Add(
230 const uno::Any& rAnchor, const uno::Any& rAddress, const uno::Any& rSubAddress,
231 const uno::Any& rScreenTip, const uno::Any& rTextToDisplay )
232 {
233 /* If this Hyperlinks object has been created from a Range object, the
234 call to Add() is passed to the Hyperlinks object of the parent
235 worksheet. This container will not be modified (it will not contain the
236 inserted hyperlink).
237 For details, see documentation in hyperlinks.hxx.
238 */
239 if( mxSheetHlinks.is() )
240 return mxSheetHlinks->Add( rAnchor, rAddress, rSubAddress, rScreenTip, rTextToDisplay );
241
242 // get anchor object (can be a Range or a Shape object)
243 uno::Reference< XHelperInterface > xAnchor( rAnchor, uno::UNO_QUERY_THROW );
244
245 /* Create the Hyperlink object, this tries to insert the hyperlink into
246 the spreadsheet document. Parent of the Hyperlink is the anchor object. */
247 uno::Reference< excel::XHyperlink > xHlink( new ScVbaHyperlink(
248 xAnchor, mxContext, rAddress, rSubAddress, rScreenTip, rTextToDisplay ) );
249
250 /* If creation of the hyperlink did not throw, insert it into the
251 collection. */
252 mxContainer->insertHyperlink( xHlink );
253 return xHlink;
254 }
255
Delete()256 void SAL_CALL ScVbaHyperlinks::Delete()
257 {
258 // FIXME not implemented
259 throw uno::RuntimeException();
260 }
261
262 // XEnumerationAccess ---------------------------------------------------------
263
createEnumeration()264 uno::Reference< container::XEnumeration > SAL_CALL ScVbaHyperlinks::createEnumeration()
265 {
266 return new SimpleIndexAccessToEnumeration( m_xIndexAccess );
267 }
268
269 // XElementAccess -------------------------------------------------------------
270
getElementType()271 uno::Type SAL_CALL ScVbaHyperlinks::getElementType()
272 {
273 return excel::XHyperlink::static_type( 0 );
274 }
275
276 // ScVbaCollectionBase --------------------------------------------------------
277
createCollectionObject(const uno::Any & rSource)278 uno::Any ScVbaHyperlinks::createCollectionObject( const uno::Any& rSource )
279 {
280 // container stores XHyperlink objects, just return the passed object
281 return rSource;
282 }
283
284 // XHelperInterface -----------------------------------------------------------
285
286 VBAHELPER_IMPL_XHELPERINTERFACE( ScVbaHyperlinks, "ooo.vba.excel.Hyperlinks" )
287
288 // ============================================================================
289