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