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 ) throw (uno::RuntimeException)
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 ) throw (uno::RuntimeException);
62 bool operator()( const uno::Reference< excel::XHyperlink >& rxHlink ) const throw (uno::RuntimeException);
63 };
64
EqualAnchorFunctor(const uno::Reference<excel::XHyperlink> & rxHlink)65 EqualAnchorFunctor::EqualAnchorFunctor( const uno::Reference< excel::XHyperlink >& rxHlink ) throw (uno::RuntimeException) :
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 throw (uno::RuntimeException)
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() throw (uno::RuntimeException);
118 explicit ScVbaHlinkContainer( const ScVbaHlinkContainerRef& rxSheetContainer, const ScRangeList& rScRanges ) throw (uno::RuntimeException);
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 ) throw (uno::RuntimeException);
124
125 // XIndexAccess
126 virtual sal_Int32 SAL_CALL getCount() throw (uno::RuntimeException);
127 virtual uno::Any SAL_CALL getByIndex( sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, lang::WrappedTargetException, uno::RuntimeException);
128
129 // XElementAccess
130 virtual uno::Type SAL_CALL getElementType() throw (uno::RuntimeException);
131 virtual sal_Bool SAL_CALL hasElements() throw (uno::RuntimeException);
132
133 private:
134 typedef ::std::vector< uno::Reference< excel::XHyperlink > > HyperlinkVector;
135 HyperlinkVector maHlinks;
136 };
137
138 // ----------------------------------------------------------------------------
139
ScVbaHlinkContainer()140 ScVbaHlinkContainer::ScVbaHlinkContainer() throw (uno::RuntimeException)
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 ) throw (uno::RuntimeException)
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 ) throw (uno::RuntimeException)
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() throw (uno::RuntimeException)
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 throw (lang::IndexOutOfBoundsException, lang::WrappedTargetException, uno::RuntimeException)
177 {
178 if( (0 <= nIndex) && (nIndex < getCount()) )
179 return uno::Any( maHlinks[ static_cast< size_t >( nIndex ) ] );
180 throw lang::IndexOutOfBoundsException();
181 }
182
getElementType()183 uno::Type SAL_CALL ScVbaHlinkContainer::getElementType() throw (uno::RuntimeException)
184 {
185 return excel::XHyperlink::static_type( 0 );
186 }
187
hasElements()188 sal_Bool SAL_CALL ScVbaHlinkContainer::hasElements() throw (uno::RuntimeException)
189 {
190 return !maHlinks.empty();
191 }
192
193 // ============================================================================
194
ScVbaHlinkContainerMember(ScVbaHlinkContainer * pContainer)195 ScVbaHlinkContainerMember::ScVbaHlinkContainerMember( ScVbaHlinkContainer* pContainer ) :
196 mxContainer( pContainer )
197 {
198 }
199
~ScVbaHlinkContainerMember()200 ScVbaHlinkContainerMember::~ScVbaHlinkContainerMember()
201 {
202 }
203
204 } // namespace vba_detail
205
206 // ============================================================================
207
ScVbaHyperlinks(const uno::Reference<XHelperInterface> & rxParent,const uno::Reference<uno::XComponentContext> & rxContext)208 ScVbaHyperlinks::ScVbaHyperlinks( const uno::Reference< XHelperInterface >& rxParent,
209 const uno::Reference< uno::XComponentContext >& rxContext ) throw (uno::RuntimeException) :
210 vba_detail::ScVbaHlinkContainerMember( new vba_detail::ScVbaHlinkContainer ),
211 ScVbaHyperlinks_BASE( rxParent, rxContext, uno::Reference< container::XIndexAccess >( mxContainer.get() ) )
212 {
213 }
214
ScVbaHyperlinks(const uno::Reference<XHelperInterface> & rxParent,const uno::Reference<uno::XComponentContext> & rxContext,const ScVbaHyperlinksRef & rxSheetHlinks,const ScRangeList & rScRanges)215 ScVbaHyperlinks::ScVbaHyperlinks( const uno::Reference< XHelperInterface >& rxParent,
216 const uno::Reference< uno::XComponentContext >& rxContext,
217 const ScVbaHyperlinksRef& rxSheetHlinks, const ScRangeList& rScRanges ) throw (uno::RuntimeException) :
218 vba_detail::ScVbaHlinkContainerMember( new vba_detail::ScVbaHlinkContainer( rxSheetHlinks->mxContainer, rScRanges ) ),
219 ScVbaHyperlinks_BASE( rxParent, rxContext, uno::Reference< container::XIndexAccess >( mxContainer.get() ) ),
220 mxSheetHlinks( rxSheetHlinks )
221 {
222 }
223
~ScVbaHyperlinks()224 ScVbaHyperlinks::~ScVbaHyperlinks()
225 {
226 }
227
228 // XHyperlinks ----------------------------------------------------------------
229
Add(const uno::Any & rAnchor,const uno::Any & rAddress,const uno::Any & rSubAddress,const uno::Any & rScreenTip,const uno::Any & rTextToDisplay)230 uno::Reference< excel::XHyperlink > SAL_CALL ScVbaHyperlinks::Add(
231 const uno::Any& rAnchor, const uno::Any& rAddress, const uno::Any& rSubAddress,
232 const uno::Any& rScreenTip, const uno::Any& rTextToDisplay ) throw (uno::RuntimeException)
233 {
234 /* If this Hyperlinks object has been craeted from a Range object, the
235 call to Add() is passed to the Hyperlinks object of the parent
236 worksheet. This container will not be modified (it will not contain the
237 inserted hyperlink).
238 For details, see documentation in hyperlinks.hxx.
239 */
240 if( mxSheetHlinks.is() )
241 return mxSheetHlinks->Add( rAnchor, rAddress, rSubAddress, rScreenTip, rTextToDisplay );
242
243 // get anchor object (can be a Range or a Shape object)
244 uno::Reference< XHelperInterface > xAnchor( rAnchor, uno::UNO_QUERY_THROW );
245
246 /* Create the Hyperlink object, this tries to insert the hyperlink into
247 the spreadsheet document. Parent of the Hyperlink is the anchor object. */
248 uno::Reference< excel::XHyperlink > xHlink( new ScVbaHyperlink(
249 xAnchor, mxContext, rAddress, rSubAddress, rScreenTip, rTextToDisplay ) );
250
251 /* If creation of the hyperlink did not throw, insert it into the
252 collection. */
253 mxContainer->insertHyperlink( xHlink );
254 return xHlink;
255 }
256
Delete()257 void SAL_CALL ScVbaHyperlinks::Delete() throw (uno::RuntimeException)
258 {
259 // FIXME not implemented
260 throw uno::RuntimeException();
261 }
262
263 // XEnumerationAccess ---------------------------------------------------------
264
createEnumeration()265 uno::Reference< container::XEnumeration > SAL_CALL ScVbaHyperlinks::createEnumeration() throw (uno::RuntimeException)
266 {
267 return new SimpleIndexAccessToEnumeration( m_xIndexAccess );
268 }
269
270 // XElementAccess -------------------------------------------------------------
271
getElementType()272 uno::Type SAL_CALL ScVbaHyperlinks::getElementType() throw (uno::RuntimeException)
273 {
274 return excel::XHyperlink::static_type( 0 );
275 }
276
277 // ScVbaCollectionBase --------------------------------------------------------
278
createCollectionObject(const uno::Any & rSource)279 uno::Any ScVbaHyperlinks::createCollectionObject( const uno::Any& rSource )
280 {
281 // container stores XHyperlink objects, just return the passed object
282 return rSource;
283 }
284
285 // XHelperInterface -----------------------------------------------------------
286
287 VBAHELPER_IMPL_XHELPERINTERFACE( ScVbaHyperlinks, "ooo.vba.excel.Hyperlinks" )
288
289 // ============================================================================
290