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 ) 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 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 82 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 140 ScVbaHlinkContainer::ScVbaHlinkContainer() 141 { 142 // TODO FIXME: fill with existing hyperlinks 143 } 144 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 157 ScVbaHlinkContainer::~ScVbaHlinkContainer() 158 { 159 } 160 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 170 sal_Int32 SAL_CALL ScVbaHlinkContainer::getCount() 171 { 172 return static_cast< sal_Int32 >( maHlinks.size() ); 173 } 174 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 182 uno::Type SAL_CALL ScVbaHlinkContainer::getElementType() 183 { 184 return excel::XHyperlink::static_type( 0 ); 185 } 186 187 sal_Bool SAL_CALL ScVbaHlinkContainer::hasElements() 188 { 189 return !maHlinks.empty(); 190 } 191 192 // ============================================================================ 193 194 ScVbaHlinkContainerMember::ScVbaHlinkContainerMember( ScVbaHlinkContainer* pContainer ) : 195 mxContainer( pContainer ) 196 { 197 } 198 199 ScVbaHlinkContainerMember::~ScVbaHlinkContainerMember() 200 { 201 } 202 203 } // namespace vba_detail 204 205 // ============================================================================ 206 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 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 223 ScVbaHyperlinks::~ScVbaHyperlinks() 224 { 225 } 226 227 // XHyperlinks ---------------------------------------------------------------- 228 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 256 void SAL_CALL ScVbaHyperlinks::Delete() 257 { 258 // FIXME not implemented 259 throw uno::RuntimeException(); 260 } 261 262 // XEnumerationAccess --------------------------------------------------------- 263 264 uno::Reference< container::XEnumeration > SAL_CALL ScVbaHyperlinks::createEnumeration() 265 { 266 return new SimpleIndexAccessToEnumeration( m_xIndexAccess ); 267 } 268 269 // XElementAccess ------------------------------------------------------------- 270 271 uno::Type SAL_CALL ScVbaHyperlinks::getElementType() 272 { 273 return excel::XHyperlink::static_type( 0 ); 274 } 275 276 // ScVbaCollectionBase -------------------------------------------------------- 277 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