xref: /trunk/main/sc/source/ui/vba/vbahyperlinks.cxx (revision b3f79822)
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. */
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 
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 
82 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 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 
140 ScVbaHlinkContainer::ScVbaHlinkContainer() throw (uno::RuntimeException)
141 {
142     // TODO FIXME: fill with existing hyperlinks
143 }
144 
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 
157 ScVbaHlinkContainer::~ScVbaHlinkContainer()
158 {
159 }
160 
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 
170 sal_Int32 SAL_CALL ScVbaHlinkContainer::getCount() throw (uno::RuntimeException)
171 {
172     return static_cast< sal_Int32 >( maHlinks.size() );
173 }
174 
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 
183 uno::Type SAL_CALL ScVbaHlinkContainer::getElementType() throw (uno::RuntimeException)
184 {
185     return excel::XHyperlink::static_type( 0 );
186 }
187 
188 sal_Bool SAL_CALL ScVbaHlinkContainer::hasElements() throw (uno::RuntimeException)
189 {
190     return !maHlinks.empty();
191 }
192 
193 // ============================================================================
194 
195 ScVbaHlinkContainerMember::ScVbaHlinkContainerMember( ScVbaHlinkContainer* pContainer ) :
196     mxContainer( pContainer )
197 {
198 }
199 
200 ScVbaHlinkContainerMember::~ScVbaHlinkContainerMember()
201 {
202 }
203 
204 } // namespace detail
205 
206 // ============================================================================
207 
208 ScVbaHyperlinks::ScVbaHyperlinks( const uno::Reference< XHelperInterface >& rxParent,
209         const uno::Reference< uno::XComponentContext >& rxContext ) throw (uno::RuntimeException) :
210     detail::ScVbaHlinkContainerMember( new detail::ScVbaHlinkContainer ),
211     ScVbaHyperlinks_BASE( rxParent, rxContext, uno::Reference< container::XIndexAccess >( mxContainer.get() ) )
212 {
213 }
214 
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     detail::ScVbaHlinkContainerMember( new detail::ScVbaHlinkContainer( rxSheetHlinks->mxContainer, rScRanges ) ),
219     ScVbaHyperlinks_BASE( rxParent, rxContext, uno::Reference< container::XIndexAccess >( mxContainer.get() ) ),
220     mxSheetHlinks( rxSheetHlinks )
221 {
222 }
223 
224 ScVbaHyperlinks::~ScVbaHyperlinks()
225 {
226 }
227 
228 // XHyperlinks ----------------------------------------------------------------
229 
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 
257 void SAL_CALL ScVbaHyperlinks::Delete() throw (uno::RuntimeException)
258 {
259     // FIXME not implemented
260     throw uno::RuntimeException();
261 }
262 
263 // XEnumerationAccess ---------------------------------------------------------
264 
265 uno::Reference< container::XEnumeration > SAL_CALL ScVbaHyperlinks::createEnumeration() throw (uno::RuntimeException)
266 {
267     return new SimpleIndexAccessToEnumeration( m_xIndexAccess );
268 }
269 
270 // XElementAccess -------------------------------------------------------------
271 
272 uno::Type SAL_CALL ScVbaHyperlinks::getElementType() throw (uno::RuntimeException)
273 {
274     return excel::XHyperlink::static_type( 0 );
275 }
276 
277 // ScVbaCollectionBase --------------------------------------------------------
278 
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