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