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