xref: /trunk/main/sc/source/ui/vba/vbahyperlinks.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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