/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace ::com::sun::star::uno; using namespace ::com::sun::star::style; using namespace ::com::sun::star::lang; using namespace ::com::sun::star::beans; using namespace ::com::sun::star::util; using namespace ::com::sun::star::container; namespace sdr::table { typedef std::map< OUString, sal_Int32 > CellStyleNameMap; typedef ::comphelper::WeakComponentImplHelper< XStyle, XNameReplace, XServiceInfo, XIndexAccess, XModifyBroadcaster, XModifyListener > TableDesignStyleBase; namespace { class TableDesignStyle : public TableDesignStyleBase { public: TableDesignStyle(); // XServiceInfo virtual OUString SAL_CALL getImplementationName() override; virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override; // XStyle virtual sal_Bool SAL_CALL isUserDefined() override; virtual sal_Bool SAL_CALL isInUse() override; virtual OUString SAL_CALL getParentStyle() override; virtual void SAL_CALL setParentStyle( const OUString& aParentStyle ) override; // XNamed virtual OUString SAL_CALL getName() override; virtual void SAL_CALL setName( const OUString& aName ) override; // XNameAccess virtual Any SAL_CALL getByName( const OUString& aName ) override; virtual Sequence< OUString > SAL_CALL getElementNames() override; virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override; // XElementAccess virtual css::uno::Type SAL_CALL getElementType() override; virtual sal_Bool SAL_CALL hasElements() override; // XIndexAccess virtual sal_Int32 SAL_CALL getCount() override ; virtual Any SAL_CALL getByIndex( sal_Int32 Index ) override; // XNameReplace virtual void SAL_CALL replaceByName( const OUString& aName, const Any& aElement ) override; // XModifyBroadcaster virtual void SAL_CALL addModifyListener( const Reference< XModifyListener >& aListener ) override; virtual void SAL_CALL removeModifyListener( const Reference< XModifyListener >& aListener ) override; // XModifyListener virtual void SAL_CALL modified( const css::lang::EventObject& aEvent ) override; virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; void notifyModifyListener(); // this function is called upon disposing the component virtual void disposing(std::unique_lock&) override; static const CellStyleNameMap& getCellStyleNameMap(); OUString msName; Reference< XStyle > maCellStyles[style_count]; comphelper::OInterfaceContainerHelper4 maModifyListeners; }; } typedef std::vector< Reference< XStyle > > TableDesignStyleVector; namespace { class TableDesignFamily : public ::cppu::WeakImplHelper< XNameContainer, XNamed, XIndexAccess, XSingleServiceFactory, XServiceInfo, XComponent, XPropertySet > { public: // XServiceInfo virtual OUString SAL_CALL getImplementationName() override; virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override; // XNamed virtual OUString SAL_CALL getName( ) override; virtual void SAL_CALL setName( const OUString& aName ) override; // XNameAccess virtual Any SAL_CALL getByName( const OUString& aName ) override; virtual Sequence< OUString > SAL_CALL getElementNames() override; virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override; // XElementAccess virtual Type SAL_CALL getElementType() override; virtual sal_Bool SAL_CALL hasElements() override; // XIndexAccess virtual sal_Int32 SAL_CALL getCount() override ; virtual Any SAL_CALL getByIndex( sal_Int32 Index ) override; // XNameContainer virtual void SAL_CALL insertByName( const OUString& aName, const Any& aElement ) override; virtual void SAL_CALL removeByName( const OUString& Name ) override; // XNameReplace virtual void SAL_CALL replaceByName( const OUString& aName, const Any& aElement ) override; // XSingleServiceFactory virtual Reference< XInterface > SAL_CALL createInstance( ) override; virtual Reference< XInterface > SAL_CALL createInstanceWithArguments( const Sequence< Any >& aArguments ) override; // XComponent virtual void SAL_CALL dispose( ) override; virtual void SAL_CALL addEventListener( const Reference< XEventListener >& xListener ) override; virtual void SAL_CALL removeEventListener( const Reference< XEventListener >& aListener ) override; // XPropertySet virtual Reference SAL_CALL getPropertySetInfo() override; virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const Any& aValue ) override; virtual Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override; virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const Reference& xListener ) override; virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const Reference& aListener ) override; virtual void SAL_CALL addVetoableChangeListener(const OUString& PropertyName, const Reference& aListener ) override; virtual void SAL_CALL removeVetoableChangeListener(const OUString& PropertyName,const Reference&aListener ) override; TableDesignStyleVector maDesigns; }; } TableDesignStyle::TableDesignStyle() { } const CellStyleNameMap& TableDesignStyle::getCellStyleNameMap() { static CellStyleNameMap const aMap { { OUString( "first-row" ) , first_row_style }, { OUString( "last-row" ) , last_row_style }, { OUString( "first-column" ) , first_column_style }, { OUString( "last-column" ) , last_column_style }, { OUString( "body" ) , body_style }, { OUString( "even-rows" ) , even_rows_style }, { OUString( "odd-rows" ) , odd_rows_style }, { OUString( "even-columns" ) , even_columns_style }, { OUString( "odd-columns" ) , odd_columns_style }, { OUString( "background" ) , background_style }, }; return aMap; } // XServiceInfo OUString SAL_CALL TableDesignStyle::getImplementationName() { return "TableDesignStyle"; } sal_Bool SAL_CALL TableDesignStyle::supportsService( const OUString& ServiceName ) { return cppu::supportsService( this, ServiceName ); } Sequence< OUString > SAL_CALL TableDesignStyle::getSupportedServiceNames() { return { "com.sun.star.style.Style" }; } // XStyle sal_Bool SAL_CALL TableDesignStyle::isUserDefined() { return false; } sal_Bool SAL_CALL TableDesignStyle::isInUse() { std::unique_lock aGuard( m_aMutex ); if (maModifyListeners.getLength(aGuard)) { comphelper::OInterfaceIteratorHelper4 it(aGuard, maModifyListeners); while ( it.hasMoreElements() ) { TableDesignUser* pUser = dynamic_cast< TableDesignUser* >( it.next().get() ); if( pUser && pUser->isInUse() ) return true; } } return false; } OUString SAL_CALL TableDesignStyle::getParentStyle() { return OUString(); } void SAL_CALL TableDesignStyle::setParentStyle( const OUString& ) { } // XNamed OUString SAL_CALL TableDesignStyle::getName() { return msName; } void SAL_CALL TableDesignStyle::setName( const OUString& rName ) { msName = rName; } // XNameAccess Any SAL_CALL TableDesignStyle::getByName( const OUString& rName ) { const CellStyleNameMap& rMap = getCellStyleNameMap(); CellStyleNameMap::const_iterator iter = rMap.find( rName ); if( iter == rMap.end() ) throw NoSuchElementException(); return Any( maCellStyles[(*iter).second] ); } Sequence< OUString > SAL_CALL TableDesignStyle::getElementNames() { return comphelper::mapKeysToSequence( getCellStyleNameMap() ); } sal_Bool SAL_CALL TableDesignStyle::hasByName( const OUString& rName ) { const CellStyleNameMap& rMap = getCellStyleNameMap(); CellStyleNameMap::const_iterator iter = rMap.find( rName ); return iter != rMap.end(); } // XElementAccess Type SAL_CALL TableDesignStyle::getElementType() { return cppu::UnoType::get(); } sal_Bool SAL_CALL TableDesignStyle::hasElements() { return true; } // XIndexAccess sal_Int32 SAL_CALL TableDesignStyle::getCount() { return style_count; } Any SAL_CALL TableDesignStyle::getByIndex( sal_Int32 Index ) { if( (Index < 0) || (Index >= style_count) ) throw IndexOutOfBoundsException(); std::unique_lock aGuard( m_aMutex ); return Any( maCellStyles[Index] ); } // XNameReplace void SAL_CALL TableDesignStyle::replaceByName( const OUString& rName, const Any& aElement ) { const CellStyleNameMap& rMap = getCellStyleNameMap(); CellStyleNameMap::const_iterator iter = rMap.find( rName ); if( iter == rMap.end() ) throw NoSuchElementException(); Reference< XStyle > xNewStyle; if( !(aElement >>= xNewStyle) ) throw IllegalArgumentException(); const sal_Int32 nIndex = (*iter).second; std::unique_lock aGuard( m_aMutex ); Reference< XStyle > xOldStyle( maCellStyles[nIndex] ); if( xNewStyle == xOldStyle ) return; Reference< XModifyListener > xListener( this ); // end listening to old style, if possible Reference< XModifyBroadcaster > xOldBroadcaster( xOldStyle, UNO_QUERY ); if( xOldBroadcaster.is() ) xOldBroadcaster->removeModifyListener( xListener ); // start listening to new style, if possible Reference< XModifyBroadcaster > xNewBroadcaster( xNewStyle, UNO_QUERY ); if( xNewBroadcaster.is() ) xNewBroadcaster->addModifyListener( xListener ); maCellStyles[nIndex] = xNewStyle; } // XComponent void TableDesignStyle::disposing(std::unique_lock&) { for(Reference & rCellStyle : maCellStyles) rCellStyle.clear(); } // XModifyBroadcaster void SAL_CALL TableDesignStyle::addModifyListener( const Reference< XModifyListener >& xListener ) { std::unique_lock aGuard( m_aMutex ); if (m_bDisposed) { aGuard.unlock(); EventObject aEvt( static_cast< OWeakObject * >( this ) ); xListener->disposing( aEvt ); } else { maModifyListeners.addInterface( aGuard, xListener ); } } void SAL_CALL TableDesignStyle::removeModifyListener( const Reference< XModifyListener >& xListener ) { std::unique_lock aGuard( m_aMutex ); maModifyListeners.removeInterface( aGuard, xListener ); } void TableDesignStyle::notifyModifyListener() { std::unique_lock aGuard( m_aMutex ); if( maModifyListeners.getLength(aGuard) ) { EventObject aEvt( static_cast< OWeakObject * >( this ) ); maModifyListeners.forEach(aGuard, [&] (Reference const& xListener) { return xListener->modified(aEvt); }); } } // XModifyListener // if we get a modify hint from a style, notify all registered XModifyListener void SAL_CALL TableDesignStyle::modified( const css::lang::EventObject& ) { notifyModifyListener(); } void SAL_CALL TableDesignStyle::disposing( const css::lang::EventObject& ) { } // TableStyle // XServiceInfo OUString SAL_CALL TableDesignFamily::getImplementationName() { return "TableDesignFamily"; } sal_Bool SAL_CALL TableDesignFamily::supportsService( const OUString& ServiceName ) { return cppu::supportsService( this, ServiceName ); } Sequence< OUString > SAL_CALL TableDesignFamily::getSupportedServiceNames() { return { "com.sun.star.style.StyleFamily" }; } // XNamed OUString SAL_CALL TableDesignFamily::getName() { return "table"; } void SAL_CALL TableDesignFamily::setName( const OUString& ) { } // XNameAccess Any SAL_CALL TableDesignFamily::getByName( const OUString& rName ) { SolarMutexGuard aGuard; auto iter = std::find_if(maDesigns.begin(), maDesigns.end(), [&rName](const Reference& rpStyle) { return rpStyle->getName() == rName; }); if (iter != maDesigns.end()) return Any( (*iter) ); throw NoSuchElementException(); } Sequence< OUString > SAL_CALL TableDesignFamily::getElementNames() { SolarMutexGuard aGuard; Sequence< OUString > aRet( maDesigns.size() ); OUString* pNames = aRet.getArray(); for( const auto& rpStyle : maDesigns ) *pNames++ = rpStyle->getName(); return aRet; } sal_Bool SAL_CALL TableDesignFamily::hasByName( const OUString& aName ) { SolarMutexGuard aGuard; return std::any_of(maDesigns.begin(), maDesigns.end(), [&aName](const Reference& rpStyle) { return rpStyle->getName() == aName; }); } // XElementAccess Type SAL_CALL TableDesignFamily::getElementType() { return cppu::UnoType::get(); } sal_Bool SAL_CALL TableDesignFamily::hasElements() { SolarMutexGuard aGuard; return !maDesigns.empty(); } // XIndexAccess sal_Int32 SAL_CALL TableDesignFamily::getCount() { SolarMutexGuard aGuard; return sal::static_int_cast< sal_Int32 >( maDesigns.size() ); } Any SAL_CALL TableDesignFamily::getByIndex( sal_Int32 Index ) { SolarMutexGuard aGuard; if( (Index >= 0) && (Index < sal::static_int_cast< sal_Int32 >( maDesigns.size() ) ) ) return Any( maDesigns[Index] ); throw IndexOutOfBoundsException(); } // XNameContainer void SAL_CALL TableDesignFamily::insertByName( const OUString& rName, const Any& rElement ) { SolarMutexGuard aGuard; Reference< XStyle > xStyle( rElement, UNO_QUERY ); if( !xStyle.is() ) throw IllegalArgumentException(); xStyle->setName( rName ); if (std::any_of(maDesigns.begin(), maDesigns.end(), [&rName](const Reference& rpStyle) { return rpStyle->getName() == rName; })) throw ElementExistException(); maDesigns.push_back( xStyle ); } void SAL_CALL TableDesignFamily::removeByName( const OUString& rName ) { SolarMutexGuard aGuard; auto iter = std::find_if(maDesigns.begin(), maDesigns.end(), [&rName](const Reference& rpStyle) { return rpStyle->getName() == rName; }); if (iter != maDesigns.end()) { maDesigns.erase( iter ); return; } throw NoSuchElementException(); } // XNameReplace void SAL_CALL TableDesignFamily::replaceByName( const OUString& rName, const Any& aElement ) { SolarMutexGuard aGuard; Reference< XStyle > xStyle( aElement, UNO_QUERY ); if( !xStyle.is() ) throw IllegalArgumentException(); auto iter = std::find_if(maDesigns.begin(), maDesigns.end(), [&rName](const Reference& rpStyle) { return rpStyle->getName() == rName; }); if (iter != maDesigns.end()) { (*iter) = xStyle; xStyle->setName( rName ); return; } throw NoSuchElementException(); } // XSingleServiceFactory Reference< XInterface > SAL_CALL TableDesignFamily::createInstance() { return Reference< XInterface >( static_cast< XStyle* >( new TableDesignStyle ) ); } Reference< XInterface > SAL_CALL TableDesignFamily::createInstanceWithArguments( const Sequence< Any >& ) { return createInstance(); } // XComponent void SAL_CALL TableDesignFamily::dispose( ) { TableDesignStyleVector aDesigns; aDesigns.swap( maDesigns ); for( const auto& rStyle : aDesigns ) { Reference< XComponent > xComp( rStyle, UNO_QUERY ); if( xComp.is() ) xComp->dispose(); } } void SAL_CALL TableDesignFamily::addEventListener( const Reference< XEventListener >& ) { } void SAL_CALL TableDesignFamily::removeEventListener( const Reference< XEventListener >& ) { } // XPropertySet Reference TableDesignFamily::getPropertySetInfo() { OSL_FAIL( "###unexpected!" ); return Reference(); } void TableDesignFamily::setPropertyValue( const OUString& , const Any& ) { OSL_FAIL( "###unexpected!" ); } Any TableDesignFamily::getPropertyValue( const OUString& PropertyName ) { if ( PropertyName != "DisplayName" ) { throw UnknownPropertyException( "unknown property: " + PropertyName, static_cast(this) ); } OUString sDisplayName( SvxResId( RID_SVXSTR_STYLEFAMILY_TABLEDESIGN ) ); return Any( sDisplayName ); } void TableDesignFamily::addPropertyChangeListener( const OUString& , const Reference& ) { OSL_FAIL( "###unexpected!" ); } void TableDesignFamily::removePropertyChangeListener( const OUString& , const Reference& ) { OSL_FAIL( "###unexpected!" ); } void TableDesignFamily::addVetoableChangeListener( const OUString& , const Reference& ) { OSL_FAIL( "###unexpected!" ); } void TableDesignFamily::removeVetoableChangeListener( const OUString& , const Reference& ) { OSL_FAIL( "###unexpected!" ); } Reference< XNameAccess > CreateTableDesignFamily() { return new TableDesignFamily; } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */