/* -*- 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 "sdrtableobjimpl.hxx" #include #include using namespace css; 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, XIndexReplace, XModifiable, XModifyListener, XPropertySet > 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; // XIndexReplace virtual void SAL_CALL replaceByIndex( sal_Int32 Index, const Any& Element ) override; // XNameReplace virtual void SAL_CALL replaceByName( const OUString& aName, const Any& aElement ) 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; // XModifiable virtual sal_Bool SAL_CALL isModified() override; virtual void SAL_CALL setModified( sal_Bool bModified ) 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(); void resetUserDefined(); // this function is called upon disposing the component virtual void disposing(std::unique_lock& aGuard) override; static const CellStyleNameMap& getCellStyleNameMap(); bool mbUserDefined, mbModified; 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, form::XReset > { 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; // XReset virtual void SAL_CALL reset() override; virtual void SAL_CALL addResetListener( const Reference& aListener ) override; virtual void SAL_CALL removeResetListener( const Reference& aListener ) override; TableDesignStyleVector maDesigns; }; } TableDesignStyle::TableDesignStyle() : mbUserDefined(true) , mbModified(false) { } const CellStyleNameMap& TableDesignStyle::getCellStyleNameMap() { static CellStyleNameMap const aMap { { u"first-row"_ustr , first_row_style }, { u"last-row"_ustr , last_row_style }, { u"first-column"_ustr , first_column_style }, { u"last-column"_ustr , last_column_style }, { u"body"_ustr , body_style }, { u"even-rows"_ustr , even_rows_style }, { u"odd-rows"_ustr , odd_rows_style }, { u"even-columns"_ustr , even_columns_style }, { u"odd-columns"_ustr , odd_columns_style }, { u"background"_ustr , background_style }, }; return aMap; } // XServiceInfo OUString SAL_CALL TableDesignStyle::getImplementationName() { return u"TableDesignStyle"_ustr; } sal_Bool SAL_CALL TableDesignStyle::supportsService( const OUString& ServiceName ) { return cppu::supportsService( this, ServiceName ); } Sequence< OUString > SAL_CALL TableDesignStyle::getSupportedServiceNames() { return { u"com.sun.star.style.Style"_ustr }; } // XStyle sal_Bool SAL_CALL TableDesignStyle::isUserDefined() { return mbUserDefined; } void TableDesignStyle::resetUserDefined() { mbUserDefined = 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() ) { SdrTableObjImpl* pUser = dynamic_cast< SdrTableObjImpl* >( 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] ); } // XIndexReplace void SAL_CALL TableDesignStyle::replaceByIndex( sal_Int32 Index, const Any& aElement ) { if( (Index < 0) || (Index >= style_count) ) throw IndexOutOfBoundsException(); const CellStyleNameMap& rMap = getCellStyleNameMap(); auto iter = std::find_if(rMap.begin(), rMap.end(), [&Index](const auto& item) { return Index == item.second; }); if (iter != rMap.end()) replaceByName(iter->first, aElement); } // 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 ); if (xNewStyle && xNewStyle->isUserDefined()) mbModified = true; maCellStyles[nIndex] = xNewStyle; } // XComponent void TableDesignStyle::disposing(std::unique_lock& aGuard) { maModifyListeners.disposeAndClear(aGuard, EventObject(Reference(this))); for(Reference & rCellStyle : maCellStyles) { Reference xBroadcaster(rCellStyle, UNO_QUERY); if (xBroadcaster) xBroadcaster->removeModifyListener(this); rCellStyle.clear(); } } // XPropertySet Reference TableDesignStyle::getPropertySetInfo() { return {}; } void TableDesignStyle::setPropertyValue( const OUString&, const Any& ) { } Any TableDesignStyle::getPropertyValue( const OUString& PropertyName ) { if (PropertyName != "IsPhysical") throw UnknownPropertyException("unknown property: " + PropertyName, getXWeak()); return Any(mbModified || mbUserDefined); } void TableDesignStyle::addPropertyChangeListener( const OUString&, const Reference& ) { } void TableDesignStyle::removePropertyChangeListener( const OUString&, const Reference& ) { } void TableDesignStyle::addVetoableChangeListener( const OUString&, const Reference& ) { } void TableDesignStyle::removeVetoableChangeListener( const OUString&,const Reference& ) { } // XModifiable sal_Bool TableDesignStyle::isModified() { return mbModified; } void TableDesignStyle::setModified( sal_Bool bModified ) { mbModified = bModified; notifyModifyListener(); } // XModifyBroadcaster void SAL_CALL TableDesignStyle::addModifyListener( const Reference< XModifyListener >& xListener ) { std::unique_lock aGuard( m_aMutex ); if (m_bDisposed) { aGuard.unlock(); EventObject aEvt( getXWeak() ); 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( getXWeak() ); 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 u"TableDesignFamily"_ustr; } sal_Bool SAL_CALL TableDesignFamily::supportsService( const OUString& ServiceName ) { return cppu::supportsService( this, ServiceName ); } Sequence< OUString > SAL_CALL TableDesignFamily::getSupportedServiceNames() { return { u"com.sun.star.style.StyleFamily"_ustr }; } // XNamed OUString SAL_CALL TableDesignFamily::getName() { return u"table"_ustr; } 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()) { Reference xComponent(*iter, UNO_QUERY); if (xComponent) xComponent->dispose(); 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()) { if (!(*iter)->isUserDefined()) static_cast(xStyle.get())->resetUserDefined(); Reference xComponent(*iter, UNO_QUERY); if (xComponent) xComponent->dispose(); (*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, getXWeak() ); } 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!" ); } // XReset void TableDesignFamily::reset() { for (const auto& aDesign : maDesigns) { auto aStyle = static_cast(aDesign.get()); aStyle->resetUserDefined(); aStyle->setModified(false); } } void TableDesignFamily::addResetListener( const Reference& ) { } void TableDesignFamily::removeResetListener( const Reference& ) { } Reference< XNameAccess > CreateTableDesignFamily() { return new TableDesignFamily; } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */