diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /reportdesign/source/core/sdr | |
parent | Initial commit. (diff) | |
download | libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'reportdesign/source/core/sdr')
-rw-r--r-- | reportdesign/source/core/sdr/PropertyForward.cxx | 180 | ||||
-rw-r--r-- | reportdesign/source/core/sdr/ReportDrawPage.cxx | 149 | ||||
-rw-r--r-- | reportdesign/source/core/sdr/ReportUndoFactory.cxx | 157 | ||||
-rw-r--r-- | reportdesign/source/core/sdr/RptModel.cxx | 187 | ||||
-rw-r--r-- | reportdesign/source/core/sdr/RptObject.cxx | 1219 | ||||
-rw-r--r-- | reportdesign/source/core/sdr/RptObjectListener.cxx | 69 | ||||
-rw-r--r-- | reportdesign/source/core/sdr/RptPage.cxx | 192 | ||||
-rw-r--r-- | reportdesign/source/core/sdr/UndoActions.cxx | 407 | ||||
-rw-r--r-- | reportdesign/source/core/sdr/UndoEnv.cxx | 619 | ||||
-rw-r--r-- | reportdesign/source/core/sdr/formatnormalizer.cxx | 258 | ||||
-rw-r--r-- | reportdesign/source/core/sdr/formatnormalizer.hxx | 86 |
11 files changed, 3523 insertions, 0 deletions
diff --git a/reportdesign/source/core/sdr/PropertyForward.cxx b/reportdesign/source/core/sdr/PropertyForward.cxx new file mode 100644 index 000000000..394edfc12 --- /dev/null +++ b/reportdesign/source/core/sdr/PropertyForward.cxx @@ -0,0 +1,180 @@ +/* -*- 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 <PropertyForward.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <comphelper/property.hxx> +#include <tools/diagnose_ex.h> +#include <strings.hxx> + +namespace rptui +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::beans; + +OPropertyMediator::OPropertyMediator(const Reference< XPropertySet>& _xSource + ,const Reference< XPropertySet>& _xDest + ,TPropertyNamePair&& _aNameMap + ,bool _bReverse) + : OPropertyForward_Base(m_aMutex) + ,m_aNameMap(std::move(_aNameMap)) + ,m_xSource(_xSource) + ,m_xDest(_xDest) + ,m_bInChange(false) +{ + osl_atomic_increment(&m_refCount); + OSL_ENSURE(m_xDest.is(),"Dest is NULL!"); + OSL_ENSURE(m_xSource.is(),"Source is NULL!"); + if ( m_xDest.is() && m_xSource.is() ) + { + try + { + m_xDestInfo = m_xDest->getPropertySetInfo(); + m_xSourceInfo = m_xSource->getPropertySetInfo(); + if ( _bReverse ) + { + ::comphelper::copyProperties(m_xDest,m_xSource); + for (const auto& [rName, rPropConv] : m_aNameMap) + { + Property aProp = m_xSourceInfo->getPropertyByName(rName); + if (0 == (aProp.Attributes & PropertyAttribute::READONLY)) + { + Any aValue = _xDest->getPropertyValue(rPropConv.first); + if ( 0 != (aProp.Attributes & PropertyAttribute::MAYBEVOID) || aValue.hasValue() ) + _xSource->setPropertyValue(rName, rPropConv.second->operator()(rPropConv.first, aValue)); + } + } + } + else + { + ::comphelper::copyProperties(m_xSource,m_xDest); + for (const auto& [rName, rPropConv] : m_aNameMap) + _xDest->setPropertyValue(rPropConv.first, rPropConv.second->operator()(rPropConv.first, _xSource->getPropertyValue(rName))); + } + startListening(); + } + catch(Exception&) + { + DBG_UNHANDLED_EXCEPTION("reportdesign"); + } + } + osl_atomic_decrement(&m_refCount); +} + +OPropertyMediator::~OPropertyMediator() +{ +} + +void SAL_CALL OPropertyMediator::propertyChange( const PropertyChangeEvent& evt ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + if ( m_bInChange ) + return; + + m_bInChange = true; + try + { + bool bDest = (evt.Source == m_xDest); + Reference<XPropertySet> xProp = bDest ? m_xSource : m_xDest; + Reference<XPropertySetInfo> xPropInfo = bDest ? m_xSourceInfo : m_xDestInfo; + if ( xProp.is() && xPropInfo.is() ) + { + if ( xPropInfo->hasPropertyByName(evt.PropertyName) ) + xProp->setPropertyValue(evt.PropertyName,evt.NewValue); + else + { + TPropertyNamePair::const_iterator aFind = m_aNameMap.find(evt.PropertyName); + OUString sPropName; + if ( aFind != m_aNameMap.end() ) + sPropName = aFind->second.first; + else + { + aFind = ::std::find_if( + m_aNameMap.begin(), + m_aNameMap.end(), + [&evt] (const TPropertyNamePair::value_type& namePair) { + return namePair.second.first == evt.PropertyName; + }); + if ( aFind != m_aNameMap.end() ) + sPropName = aFind->first; + } + if (aFind != m_aNameMap.end() && !sPropName.isEmpty() && xPropInfo->hasPropertyByName(sPropName)) + xProp->setPropertyValue(sPropName,aFind->second.second->operator()(sPropName,evt.NewValue)); + else if ( evt.PropertyName == PROPERTY_CHARFONTNAME + || evt.PropertyName == PROPERTY_CHARFONTSTYLENAME + || evt.PropertyName == PROPERTY_CHARSTRIKEOUT + || evt.PropertyName == PROPERTY_CHARWORDMODE + || evt.PropertyName == PROPERTY_CHARROTATION + || evt.PropertyName == PROPERTY_CHARSCALEWIDTH + || evt.PropertyName == PROPERTY_CHARFONTFAMILY + || evt.PropertyName == PROPERTY_CHARFONTCHARSET + || evt.PropertyName == PROPERTY_CHARFONTPITCH + || evt.PropertyName == PROPERTY_CHARHEIGHT + || evt.PropertyName == PROPERTY_CHARUNDERLINE + || evt.PropertyName == PROPERTY_CHARWEIGHT + || evt.PropertyName == PROPERTY_CHARPOSTURE) + { + xProp->setPropertyValue(PROPERTY_FONTDESCRIPTOR,m_xSource->getPropertyValue(PROPERTY_FONTDESCRIPTOR)); + } + } + } + } + catch(Exception&) + { + TOOLS_WARN_EXCEPTION( "reportdesign", ""); + } + m_bInChange = false; +} + +void SAL_CALL OPropertyMediator::disposing( const css::lang::EventObject& /*_rSource*/ ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + disposing(); +} + +void SAL_CALL OPropertyMediator::disposing() +{ + stopListening(); + m_xSource.clear(); + m_xSourceInfo.clear(); + m_xDest.clear(); + m_xDestInfo.clear(); +} + +void OPropertyMediator::stopListening() +{ + if ( m_xSource.is() ) + m_xSource->removePropertyChangeListener(OUString(), this); + if ( m_xDest.is() ) + m_xDest->removePropertyChangeListener(OUString(), this); +} + +void OPropertyMediator::startListening() +{ + if ( m_xSource.is() ) + m_xSource->addPropertyChangeListener(OUString(), this); + if ( m_xDest.is() ) + m_xDest->addPropertyChangeListener(OUString(), this); +} + + +} // namespace dbaccess + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/reportdesign/source/core/sdr/ReportDrawPage.cxx b/reportdesign/source/core/sdr/ReportDrawPage.cxx new file mode 100644 index 000000000..b89c3dac2 --- /dev/null +++ b/reportdesign/source/core/sdr/ReportDrawPage.cxx @@ -0,0 +1,149 @@ +/* -*- 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 <ReportDrawPage.hxx> +#include <RptObject.hxx> +#include <RptModel.hxx> +#include <strings.hxx> +#include <comphelper/mimeconfighelper.hxx> +#include <comphelper/embeddedobjectcontainer.hxx> + +#include <svx/svdmodel.hxx> +#include <com/sun/star/embed/Aspects.hpp> +#include <com/sun/star/embed/XEmbeddedObject.hpp> +#include <tools/diagnose_ex.h> +#include <svx/unoshape.hxx> +#include <svx/svdpage.hxx> + +namespace reportdesign +{ + using namespace ::com::sun::star; + using namespace rptui; + +OReportDrawPage::OReportDrawPage(SdrPage* _pPage + ,const uno::Reference< report::XSection >& _xSection) +: SvxDrawPage(_pPage) +,m_xSection(_xSection) +{ +} + +SdrObject* OReportDrawPage::CreateSdrObject_(const uno::Reference< drawing::XShape > & xDescr) +{ + uno::Reference< report::XReportComponent> xReportComponent(xDescr,uno::UNO_QUERY); + if ( xReportComponent.is() ) + { + return OObjectBase::createObject( + GetSdrPage()->getSdrModelFromSdrPage(), + xReportComponent); + } + + return SvxDrawPage::CreateSdrObject_( xDescr ); +} + +uno::Reference< drawing::XShape > OReportDrawPage::CreateShape( SdrObject *pObj ) const +{ + OObjectBase* pBaseObj = dynamic_cast<OObjectBase*>(pObj); + if ( !pBaseObj ) + return SvxDrawPage::CreateShape( pObj ); + + uno::Reference< report::XSection> xSection = m_xSection; + uno::Reference< lang::XMultiServiceFactory> xFactory; + if ( xSection.is() ) + xFactory.set(xSection->getReportDefinition(),uno::UNO_QUERY); + uno::Reference< drawing::XShape > xRet; + uno::Reference< drawing::XShape > xShape; + if ( xFactory.is() ) + { + bool bChangeOrientation = false; + const OUString& sServiceName = pBaseObj->getServiceName(); + OSL_ENSURE(!sServiceName.isEmpty(),"No Service Name given!"); + + if (dynamic_cast< const OUnoObject* >(pObj) != nullptr) + { + OUnoObject& rUnoObj = dynamic_cast<OUnoObject&>(*pObj); + if (rUnoObj.GetObjIdentifier() == SdrObjKind::ReportDesignFixedText) + { + uno::Reference<beans::XPropertySet> xControlModel(rUnoObj.GetUnoControlModel(),uno::UNO_QUERY); + if ( xControlModel.is() ) + xControlModel->setPropertyValue( PROPERTY_MULTILINE,uno::Any(true)); + } + else + bChangeOrientation = rUnoObj.GetObjIdentifier() == SdrObjKind::ReportDesignHorizontalFixedLine; + rtl::Reference<SvxShapeControl> pShape = new SvxShapeControl( pObj ); + xShape = static_cast<SvxShape_UnoImplHelper *>(pShape.get()); + pShape->setShapeKind(pObj->GetObjIdentifier()); + } + else if (dynamic_cast< const OCustomShape* >(pObj) != nullptr) + { + rtl::Reference<SvxCustomShape> pShape = new SvxCustomShape( pObj ); + xShape = pShape; + pShape->setShapeKind(pObj->GetObjIdentifier()); + } + else if (dynamic_cast< const SdrOle2Obj* >(pObj) != nullptr) + { + SdrOle2Obj& rOle2Obj = dynamic_cast<SdrOle2Obj&>(*pObj); + if (!rOle2Obj.GetObjRef().is()) + { + sal_Int64 nAspect = embed::Aspects::MSOLE_CONTENT; + uno::Reference < embed::XEmbeddedObject > xObj; + OUString sName; + xObj = pObj->getSdrModelFromSdrObject().GetPersist()->getEmbeddedObjectContainer().CreateEmbeddedObject( + ::comphelper::MimeConfigurationHelper::GetSequenceClassIDRepresentation( + u"80243D39-6741-46C5-926E-069164FF87BB"), sName ); + OSL_ENSURE(xObj.is(),"Embedded Object could not be created!"); + + /************************************************** + * The empty OLE object gets a new IPObj + **************************************************/ + pObj->SetEmptyPresObj(false); + rOle2Obj.SetOutlinerParaObject(std::nullopt); + rOle2Obj.SetObjRef(xObj); + rOle2Obj.SetPersistName(sName); + rOle2Obj.SetName(sName); + rOle2Obj.SetAspect(nAspect); + tools::Rectangle aRect = rOle2Obj.GetLogicRect(); + + Size aTmp = aRect.GetSize(); + awt::Size aSz( aTmp.Width(), aTmp.Height() ); + xObj->setVisualAreaSize( nAspect, aSz ); + } + rtl::Reference<SvxOle2Shape> pShape = new SvxOle2Shape( pObj ); + xShape = pShape; + pShape->setShapeKind(pObj->GetObjIdentifier()); + } + + if ( !xShape.is() ) + xShape.set( SvxDrawPage::CreateShape( pObj ) ); + + try + { + OReportModel& rRptModel(static_cast< OReportModel& >(pObj->getSdrModelFromSdrObject())); + xRet.set( rRptModel.createShape(sServiceName,xShape,bChangeOrientation ? 0 : 1), uno::UNO_QUERY_THROW ); + } + catch( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("reportdesign"); + } + } + + return xRet; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/reportdesign/source/core/sdr/ReportUndoFactory.cxx b/reportdesign/source/core/sdr/ReportUndoFactory.cxx new file mode 100644 index 000000000..1c36d836b --- /dev/null +++ b/reportdesign/source/core/sdr/ReportUndoFactory.cxx @@ -0,0 +1,157 @@ +/* -*- 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 <ReportUndoFactory.hxx> +#include <RptObject.hxx> +#include <UndoActions.hxx> +#include <strings.hrc> + +namespace rptui +{ + using namespace ::com::sun::star; + +static std::unique_ptr<SdrUndoAction> lcl_createUndo(SdrObject& rObject, Action _eAction, TranslateId pCommentId) +{ + OObjectBase* pObj = dynamic_cast<OObjectBase*>(&rObject); + if ( !pObj ) + return nullptr; + uno::Reference< report::XReportComponent> xReportComponent = pObj->getReportComponent(); + uno::Reference< report::XSection> xSection = pObj->getSection(); + uno::Reference< report::XGroup> xGroup = xSection->getGroup(); + if ( xGroup.is() ) + return std::make_unique<OUndoGroupSectionAction>(rObject.getSdrModelFromSdrObject(),_eAction,OGroupHelper::getMemberFunction(xSection),xGroup,xReportComponent,pCommentId); + else + return std::make_unique<OUndoReportSectionAction>(rObject.getSdrModelFromSdrObject(),_eAction,OReportHelper::getMemberFunction(xSection),xSection->getReportDefinition(),xReportComponent,pCommentId); +} + + +OReportUndoFactory::OReportUndoFactory() : m_pUndoFactory(new SdrUndoFactory) +{ +} + +OReportUndoFactory::~OReportUndoFactory() +{ +} + +std::unique_ptr<SdrUndoAction> OReportUndoFactory::CreateUndoMoveObject( SdrObject& rObject, const Size& rDist ) +{ + return m_pUndoFactory->CreateUndoMoveObject( rObject, rDist ); +} + +std::unique_ptr<SdrUndoAction> OReportUndoFactory::CreateUndoGeoObject( SdrObject& rObject ) +{ + return m_pUndoFactory->CreateUndoGeoObject( rObject ); +} + +std::unique_ptr<SdrUndoAction> OReportUndoFactory::CreateUndoAttrObject( SdrObject& rObject, bool bStyleSheet1, bool bSaveText ) +{ + return m_pUndoFactory->CreateUndoAttrObject( rObject, bStyleSheet1, bSaveText ); +} + +std::unique_ptr<SdrUndoAction> OReportUndoFactory::CreateUndoRemoveObject(SdrObject& rObject) +{ + return m_pUndoFactory->CreateUndoRemoveObject(rObject); +} + +std::unique_ptr<SdrUndoAction> OReportUndoFactory::CreateUndoInsertObject( SdrObject& rObject, bool /*bOrdNumDirect*/ ) +{ + return lcl_createUndo(rObject,rptui::Inserted,RID_STR_UNDO_INSERT_CONTROL); +} + +std::unique_ptr<SdrUndoAction> OReportUndoFactory::CreateUndoDeleteObject( SdrObject& rObject, bool /*bOrdNumDirect*/ ) +{ + return lcl_createUndo(rObject,rptui::Removed,RID_STR_UNDO_DELETE_CONTROL); +} + +std::unique_ptr<SdrUndoAction> OReportUndoFactory::CreateUndoNewObject( SdrObject& rObject, bool /*bOrdNumDirect*/ ) +{ + return lcl_createUndo(rObject,rptui::Inserted,RID_STR_UNDO_INSERT_CONTROL); +} + +std::unique_ptr<SdrUndoAction> OReportUndoFactory::CreateUndoCopyObject( SdrObject& rObject, bool bOrdNumDirect ) +{ + return m_pUndoFactory->CreateUndoCopyObject( rObject, bOrdNumDirect ); +} + +std::unique_ptr<SdrUndoAction> OReportUndoFactory::CreateUndoObjectOrdNum( SdrObject& rObject, sal_uInt32 nOldOrdNum1, sal_uInt32 nNewOrdNum1) +{ + return m_pUndoFactory->CreateUndoObjectOrdNum( rObject, nOldOrdNum1, nNewOrdNum1 ); +} + +std::unique_ptr<SdrUndoAction> OReportUndoFactory::CreateUndoReplaceObject( SdrObject& rOldObject, SdrObject& rNewObject ) +{ + return m_pUndoFactory->CreateUndoReplaceObject( rOldObject, rNewObject ); +} + +std::unique_ptr<SdrUndoAction> OReportUndoFactory::CreateUndoObjectLayerChange( SdrObject& rObject, SdrLayerID aOldLayer, SdrLayerID aNewLayer ) +{ + return m_pUndoFactory->CreateUndoObjectLayerChange( rObject, aOldLayer, aNewLayer ); +} + +std::unique_ptr<SdrUndoAction> OReportUndoFactory::CreateUndoObjectSetText( SdrObject& rNewObj, sal_Int32 nText ) +{ + return m_pUndoFactory->CreateUndoObjectSetText( rNewObj, nText ); +} + +// layer +std::unique_ptr<SdrUndoAction> OReportUndoFactory::CreateUndoNewLayer(sal_uInt16 nLayerNum, SdrLayerAdmin& rNewLayerAdmin, SdrModel& rNewModel) +{ + return m_pUndoFactory->CreateUndoNewLayer( nLayerNum, rNewLayerAdmin, rNewModel ); +} + +std::unique_ptr<SdrUndoAction> OReportUndoFactory::CreateUndoDeleteLayer(sal_uInt16 nLayerNum, SdrLayerAdmin& rNewLayerAdmin, SdrModel& rNewModel) +{ + return m_pUndoFactory->CreateUndoDeleteLayer( nLayerNum, rNewLayerAdmin, rNewModel ); +} + +// page +std::unique_ptr<SdrUndoAction> OReportUndoFactory::CreateUndoDeletePage(SdrPage& rPage) +{ + return m_pUndoFactory->CreateUndoDeletePage(rPage); +} + +std::unique_ptr<SdrUndoAction> OReportUndoFactory::CreateUndoNewPage(SdrPage& rPage) +{ + return m_pUndoFactory->CreateUndoNewPage( rPage ); +} + +std::unique_ptr<SdrUndoAction> OReportUndoFactory::CreateUndoCopyPage(SdrPage& rPage) +{ + return m_pUndoFactory->CreateUndoCopyPage( rPage ); +} + +std::unique_ptr<SdrUndoAction> OReportUndoFactory::CreateUndoSetPageNum(SdrPage& rNewPg, sal_uInt16 nOldPageNum1, sal_uInt16 nNewPageNum1) +{ + return m_pUndoFactory->CreateUndoSetPageNum( rNewPg, nOldPageNum1, nNewPageNum1 ); +} + // master page +std::unique_ptr<SdrUndoAction> OReportUndoFactory::CreateUndoPageRemoveMasterPage(SdrPage& rChangedPage) +{ + return m_pUndoFactory->CreateUndoPageRemoveMasterPage( rChangedPage ); +} + +std::unique_ptr<SdrUndoAction> OReportUndoFactory::CreateUndoPageChangeMasterPage(SdrPage& rChangedPage) +{ + return m_pUndoFactory->CreateUndoPageChangeMasterPage(rChangedPage); +} + + +} //rptui + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/reportdesign/source/core/sdr/RptModel.cxx b/reportdesign/source/core/sdr/RptModel.cxx new file mode 100644 index 000000000..e7fa935f8 --- /dev/null +++ b/reportdesign/source/core/sdr/RptModel.cxx @@ -0,0 +1,187 @@ +/* -*- 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 <RptModel.hxx> +#include <RptPage.hxx> +#include <dbaccess/dbsubcomponentcontroller.hxx> +#include <vcl/svapp.hxx> + +#include <UndoEnv.hxx> +#include <ReportUndoFactory.hxx> +#include <ReportDefinition.hxx> + +#include <RptDef.hxx> +#include <strings.hxx> +#include <FixedLine.hxx> +#include <FormattedField.hxx> +#include <FixedText.hxx> +#include <ImageControl.hxx> +#include <Shape.hxx> + +namespace rptui +{ +using namespace reportdesign; +using namespace com::sun::star; + + +OReportModel::OReportModel(::reportdesign::OReportDefinition* _pReportDefinition) +: SdrModel( + nullptr, + _pReportDefinition) + ,m_pController(nullptr) + ,m_pReportDefinition(_pReportDefinition) +{ + m_xUndoEnv = new OXUndoEnvironment(*this); + SetSdrUndoFactory(new OReportUndoFactory); +} + + +OReportModel::~OReportModel() +{ + detachController(); +} + +void OReportModel::detachController() +{ + m_pReportDefinition = nullptr; + m_pController = nullptr; + m_xUndoEnv->EndListening( *this ); + ClearUndoBuffer(); + m_xUndoEnv->Clear(OXUndoEnvironment::Accessor()); +} + +rtl::Reference<SdrPage> OReportModel::AllocPage(bool /*bMasterPage*/) +{ + OSL_FAIL("Who called me!"); + return nullptr; +} + + +void OReportModel::SetChanged( bool bChanged ) +{ + SdrModel::SetChanged( bChanged ); + SetModified( bChanged ); +} + + +void OReportModel::SetModified(bool _bModified) +{ + if ( m_pController ) + m_pController->setModified(_bModified); +} + +rtl::Reference<SdrPage> OReportModel::RemovePage(sal_uInt16 nPgNum) +{ + rtl::Reference<OReportPage> pPage = dynamic_cast<OReportPage*>(SdrModel::RemovePage(nPgNum).get()); + return pPage; +} + +OReportPage* OReportModel::createNewPage(const uno::Reference< report::XSection >& _xSection) +{ + SolarMutexGuard aSolarGuard; + rtl::Reference<OReportPage> pPage = new OReportPage( *this ,_xSection); + InsertPage(pPage.get()); + m_xUndoEnv->AddSection(_xSection); + return pPage.get(); +} + +OReportPage* OReportModel::getPage(const uno::Reference< report::XSection >& _xSection) +{ + OReportPage* pPage = nullptr; + sal_uInt16 nCount = GetPageCount(); + for (sal_uInt16 i = 0; i < nCount && !pPage ; ++i) + { + OReportPage* pRptPage = dynamic_cast<OReportPage*>( GetPage(i) ); + if ( pRptPage && pRptPage->getSection() == _xSection ) + pPage = pRptPage; + } + return pPage; +} + +SvxNumType OReportModel::GetPageNumType() const +{ + uno::Reference< report::XReportDefinition > xReportDefinition( getReportDefinition() ); + if ( xReportDefinition.is() ) + return static_cast<SvxNumType>(getStyleProperty<sal_Int16>(xReportDefinition,PROPERTY_NUMBERINGTYPE)); + return SVX_NUM_ARABIC; +} + + +uno::Reference< report::XReportDefinition > OReportModel::getReportDefinition() const +{ + uno::Reference< report::XReportDefinition > xReportDefinition = m_pReportDefinition; + OSL_ENSURE( xReportDefinition.is(), "OReportModel::getReportDefinition: invalid model at our controller!" ); + return xReportDefinition; +} + +uno::Reference< uno::XInterface > OReportModel::createUnoModel() +{ + return uno::Reference< uno::XInterface >(getReportDefinition(),uno::UNO_QUERY); +} + +uno::Reference< uno::XInterface > OReportModel::createShape(const OUString& aServiceSpecifier,uno::Reference< drawing::XShape >& _rShape,sal_Int32 nOrientation) +{ + uno::Reference< uno::XInterface > xRet; + if ( _rShape.is() ) + { + if ( aServiceSpecifier == SERVICE_FORMATTEDFIELD ) + { + uno::Reference<report::XFormattedField> xProp = new OFormattedField(m_pReportDefinition->getContext(),m_pReportDefinition,_rShape); + xRet = xProp; + if ( _rShape.is() ) + throw uno::Exception("no shape", nullptr); + xProp->setPropertyValue( PROPERTY_FORMATSSUPPLIER, uno::Any(uno::Reference< util::XNumberFormatsSupplier >(*m_pReportDefinition,uno::UNO_QUERY)) ); + } + else if ( aServiceSpecifier == SERVICE_FIXEDTEXT) + { + xRet = static_cast<cppu::OWeakObject*>(new OFixedText(m_pReportDefinition->getContext(),m_pReportDefinition,_rShape)); + if ( _rShape.is() ) + throw uno::Exception("no shape", nullptr); + } + else if ( aServiceSpecifier == SERVICE_FIXEDLINE) + { + xRet = static_cast<cppu::OWeakObject*>(new OFixedLine(m_pReportDefinition->getContext(),m_pReportDefinition,_rShape,nOrientation)); + if ( _rShape.is() ) + throw uno::Exception("no shape", nullptr); + } + else if ( aServiceSpecifier == SERVICE_IMAGECONTROL ) + { + xRet = static_cast<cppu::OWeakObject*>(new OImageControl(m_pReportDefinition->getContext(),m_pReportDefinition,_rShape)); + if ( _rShape.is() ) + throw uno::Exception("no shape", nullptr); + } + else if ( aServiceSpecifier == SERVICE_REPORTDEFINITION ) + { + xRet = static_cast<cppu::OWeakObject*>(new OReportDefinition(m_pReportDefinition->getContext(),m_pReportDefinition,_rShape)); + if ( _rShape.is() ) + throw uno::Exception("no shape", nullptr); + } + else if ( _rShape.is() ) + { + xRet = static_cast<cppu::OWeakObject*>(new OShape(m_pReportDefinition->getContext(),m_pReportDefinition,_rShape,aServiceSpecifier)); + if ( _rShape.is() ) + throw uno::Exception("no shape", nullptr); + } + } + return xRet; +} + +} //rptui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/reportdesign/source/core/sdr/RptObject.cxx b/reportdesign/source/core/sdr/RptObject.cxx new file mode 100644 index 000000000..1972e892e --- /dev/null +++ b/reportdesign/source/core/sdr/RptObject.cxx @@ -0,0 +1,1219 @@ +/* -*- 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 <RptObject.hxx> +#include <algorithm> + +#include <RptDef.hxx> +#include <svx/unoshape.hxx> +#include <RptModel.hxx> +#include <RptObjectListener.hxx> +#include <RptPage.hxx> + +#include <strings.hxx> +#include <svtools/embedhlp.hxx> +#include <com/sun/star/style/XStyle.hpp> +#include <com/sun/star/awt/TextAlign.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/embed/XComponentSupplier.hpp> +#include <com/sun/star/embed/XEmbeddedObject.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/report/XFixedLine.hpp> +#include <com/sun/star/chart/ChartDataRowSource.hpp> +#include <com/sun/star/chart2/data/XDataReceiver.hpp> +#include <com/sun/star/chart2/data/XDatabaseDataProvider.hpp> +#include <com/sun/star/chart2/XChartDocument.hpp> +#include <com/sun/star/style/ParagraphAdjust.hpp> +#include <com/sun/star/report/XFormattedField.hpp> +#include <cppuhelper/supportsservice.hxx> +#include <comphelper/namedvaluecollection.hxx> +#include <comphelper/property.hxx> +#include <svx/svdundo.hxx> +#include <tools/diagnose_ex.h> +#include <PropertyForward.hxx> +#include <UndoEnv.hxx> + +namespace rptui +{ + +using namespace ::com::sun::star; +using namespace uno; +using namespace beans; +using namespace reportdesign; +using namespace container; +using namespace report; + +SdrObjKind OObjectBase::getObjectType(const uno::Reference< report::XReportComponent>& _xComponent) +{ + uno::Reference< lang::XServiceInfo > xServiceInfo( _xComponent , uno::UNO_QUERY ); + OSL_ENSURE(xServiceInfo.is(),"Who deletes the XServiceInfo interface!"); + if ( !xServiceInfo ) + return SdrObjKind::NONE; + + if ( xServiceInfo->supportsService( SERVICE_FIXEDTEXT )) + return SdrObjKind::ReportDesignFixedText; + if ( xServiceInfo->supportsService( SERVICE_FIXEDLINE )) + { + uno::Reference< report::XFixedLine> xFixedLine(_xComponent,uno::UNO_QUERY); + return xFixedLine->getOrientation() ? SdrObjKind::ReportDesignHorizontalFixedLine : SdrObjKind::ReportDesignVerticalFixedLine; + } + if ( xServiceInfo->supportsService( SERVICE_IMAGECONTROL)) + return SdrObjKind::ReportDesignImageControl; + if ( xServiceInfo->supportsService( SERVICE_FORMATTEDFIELD )) + return SdrObjKind::ReportDesignFormattedField; + if ( xServiceInfo->supportsService("com.sun.star.drawing.OLE2Shape") ) + return SdrObjKind::OLE2; + if ( xServiceInfo->supportsService( SERVICE_SHAPE )) + return SdrObjKind::CustomShape; + if ( xServiceInfo->supportsService( SERVICE_REPORTDEFINITION ) ) + return SdrObjKind::ReportDesignSubReport; + return SdrObjKind::OLE2; +} + +SdrObject* OObjectBase::createObject( + SdrModel& rTargetModel, + const uno::Reference< report::XReportComponent>& _xComponent) +{ + SdrObject* pNewObj = nullptr; + SdrObjKind nType = OObjectBase::getObjectType(_xComponent); + switch( nType ) + { + case SdrObjKind::ReportDesignFixedText: + { + OUnoObject* pUnoObj = new OUnoObject( + rTargetModel, + _xComponent, + OUString("com.sun.star.form.component.FixedText"), + SdrObjKind::ReportDesignFixedText); + pNewObj = pUnoObj; + + uno::Reference<beans::XPropertySet> xControlModel(pUnoObj->GetUnoControlModel(),uno::UNO_QUERY); + if ( xControlModel.is() ) + xControlModel->setPropertyValue( PROPERTY_MULTILINE,uno::Any(true)); + } + break; + case SdrObjKind::ReportDesignImageControl: + pNewObj = new OUnoObject( + rTargetModel, + _xComponent, + OUString("com.sun.star.form.component.DatabaseImageControl"), + SdrObjKind::ReportDesignImageControl); + break; + case SdrObjKind::ReportDesignFormattedField: + pNewObj = new OUnoObject( + rTargetModel, + _xComponent, + OUString("com.sun.star.form.component.FormattedField"), + SdrObjKind::ReportDesignFormattedField); + break; + case SdrObjKind::ReportDesignHorizontalFixedLine: + case SdrObjKind::ReportDesignVerticalFixedLine: + pNewObj = new OUnoObject( + rTargetModel, + _xComponent, + OUString("com.sun.star.awt.UnoControlFixedLineModel"), + nType); + break; + case SdrObjKind::CustomShape: + pNewObj = OCustomShape::Create( + rTargetModel, + _xComponent); + try + { + bool bOpaque = false; + _xComponent->getPropertyValue(PROPERTY_OPAQUE) >>= bOpaque; + pNewObj->NbcSetLayer(bOpaque ? RPT_LAYER_FRONT : RPT_LAYER_BACK); + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("reportdesign"); + } + break; + case SdrObjKind::ReportDesignSubReport: + case SdrObjKind::OLE2: + pNewObj = OOle2Obj::Create( + rTargetModel, + _xComponent, + nType); + break; + default: + OSL_FAIL("Unknown object id"); + break; + } + + if ( pNewObj ) + pNewObj->SetDoNotInsertIntoPageAutomatically( true ); + + ensureSdrObjectOwnership( _xComponent ); + + return pNewObj; +} + +namespace +{ + class ParaAdjust : public AnyConverter + { + public: + virtual css::uno::Any operator() (const OUString& _sPropertyName,const css::uno::Any& lhs) const override + { + uno::Any aRet; + if (_sPropertyName == PROPERTY_PARAADJUST) + { + sal_Int16 nTextAlign = 0; + lhs >>= nTextAlign; + style::ParagraphAdjust eAdjust; + switch(nTextAlign) + { + case awt::TextAlign::LEFT: + eAdjust = style::ParagraphAdjust_LEFT; + break; + case awt::TextAlign::CENTER: + eAdjust = style::ParagraphAdjust_CENTER; + break; + case awt::TextAlign::RIGHT: + eAdjust = style::ParagraphAdjust_RIGHT; + break; + default: + OSL_FAIL("Illegal text alignment value!"); + break; + } + aRet <<= eAdjust; + } + else + { + sal_Int16 nTextAlign = 0; + sal_Int16 eParagraphAdjust = 0; + lhs >>= eParagraphAdjust; + switch(static_cast<style::ParagraphAdjust>(eParagraphAdjust)) + { + case style::ParagraphAdjust_LEFT: + case style::ParagraphAdjust_BLOCK: + nTextAlign = awt::TextAlign::LEFT; + break; + case style::ParagraphAdjust_CENTER: + nTextAlign = awt::TextAlign::CENTER; + break; + case style::ParagraphAdjust_RIGHT: + nTextAlign = awt::TextAlign::RIGHT; + break; + default: + OSL_FAIL("Illegal text alignment value!"); + break; + } + aRet <<= nTextAlign; + } + return aRet; + } + }; +} + +const TPropertyNamePair& getPropertyNameMap(SdrObjKind _nObjectId) +{ + switch(_nObjectId) + { + case SdrObjKind::ReportDesignImageControl: + { + static TPropertyNamePair s_aNameMap = []() + { + auto aNoConverter = std::make_shared<AnyConverter>(); + TPropertyNamePair tmp; + tmp.emplace(PROPERTY_CONTROLBACKGROUND,TPropertyConverter(PROPERTY_BACKGROUNDCOLOR,aNoConverter)); + tmp.emplace(PROPERTY_CONTROLBORDER,TPropertyConverter(PROPERTY_BORDER,aNoConverter)); + tmp.emplace(PROPERTY_CONTROLBORDERCOLOR,TPropertyConverter(PROPERTY_BORDERCOLOR,aNoConverter)); + return tmp; + }(); + return s_aNameMap; + } + + case SdrObjKind::ReportDesignFixedText: + { + static TPropertyNamePair s_aNameMap = []() + { + auto aNoConverter = std::make_shared<AnyConverter>(); + TPropertyNamePair tmp; + tmp.emplace(PROPERTY_CHARCOLOR,TPropertyConverter(PROPERTY_TEXTCOLOR,aNoConverter)); + tmp.emplace(PROPERTY_CONTROLBACKGROUND,TPropertyConverter(PROPERTY_BACKGROUNDCOLOR,aNoConverter)); + tmp.emplace(PROPERTY_CHARUNDERLINECOLOR,TPropertyConverter(PROPERTY_TEXTLINECOLOR,aNoConverter)); + tmp.emplace(PROPERTY_CHARRELIEF,TPropertyConverter(PROPERTY_FONTRELIEF,aNoConverter)); + tmp.emplace(PROPERTY_CHARFONTHEIGHT,TPropertyConverter(PROPERTY_FONTHEIGHT,aNoConverter)); + tmp.emplace(PROPERTY_CHARSTRIKEOUT,TPropertyConverter(PROPERTY_FONTSTRIKEOUT,aNoConverter)); + tmp.emplace(PROPERTY_CONTROLTEXTEMPHASISMARK,TPropertyConverter(PROPERTY_FONTEMPHASISMARK,aNoConverter)); + tmp.emplace(PROPERTY_CONTROLBORDER,TPropertyConverter(PROPERTY_BORDER,aNoConverter)); + tmp.emplace(PROPERTY_CONTROLBORDERCOLOR,TPropertyConverter(PROPERTY_BORDERCOLOR,aNoConverter)); + + auto aParaAdjust = std::make_shared<ParaAdjust>(); + tmp.emplace(PROPERTY_PARAADJUST,TPropertyConverter(PROPERTY_ALIGN,aParaAdjust)); + return tmp; + }(); + return s_aNameMap; + } + case SdrObjKind::ReportDesignFormattedField: + { + static TPropertyNamePair s_aNameMap = []() + { + auto aNoConverter = std::make_shared<AnyConverter>(); + TPropertyNamePair tmp; + tmp.emplace(PROPERTY_CHARCOLOR,TPropertyConverter(PROPERTY_TEXTCOLOR,aNoConverter)); + tmp.emplace(PROPERTY_CONTROLBACKGROUND,TPropertyConverter(PROPERTY_BACKGROUNDCOLOR,aNoConverter)); + tmp.emplace(PROPERTY_CHARUNDERLINECOLOR,TPropertyConverter(PROPERTY_TEXTLINECOLOR,aNoConverter)); + tmp.emplace(PROPERTY_CHARRELIEF,TPropertyConverter(PROPERTY_FONTRELIEF,aNoConverter)); + tmp.emplace(PROPERTY_CHARFONTHEIGHT,TPropertyConverter(PROPERTY_FONTHEIGHT,aNoConverter)); + tmp.emplace(PROPERTY_CHARSTRIKEOUT,TPropertyConverter(PROPERTY_FONTSTRIKEOUT,aNoConverter)); + tmp.emplace(PROPERTY_CONTROLTEXTEMPHASISMARK,TPropertyConverter(PROPERTY_FONTEMPHASISMARK,aNoConverter)); + tmp.emplace(PROPERTY_CONTROLBORDER,TPropertyConverter(PROPERTY_BORDER,aNoConverter)); + tmp.emplace(PROPERTY_CONTROLBORDERCOLOR,TPropertyConverter(PROPERTY_BORDERCOLOR,aNoConverter)); + auto aParaAdjust = std::make_shared<ParaAdjust>(); + tmp.emplace(PROPERTY_PARAADJUST,TPropertyConverter(PROPERTY_ALIGN,aParaAdjust)); + return tmp; + }(); + return s_aNameMap; + } + + case SdrObjKind::CustomShape: + { + static TPropertyNamePair s_aNameMap = []() + { + auto aNoConverter = std::make_shared<AnyConverter>(); + TPropertyNamePair tmp; + tmp.emplace(OUString("FillColor"),TPropertyConverter(PROPERTY_CONTROLBACKGROUND,aNoConverter)); + tmp.emplace(PROPERTY_PARAADJUST,TPropertyConverter(PROPERTY_ALIGN,aNoConverter)); + return tmp; + }(); + return s_aNameMap; + } + + default: + break; + } + static TPropertyNamePair s_aEmptyNameMap; + return s_aEmptyNameMap; +} + + +OObjectBase::OObjectBase(const uno::Reference< report::XReportComponent>& _xComponent) +:m_bIsListening(false) +{ + m_xReportComponent = _xComponent; +} + +OObjectBase::OObjectBase(const OUString& _sComponentName) +:m_sComponentName(_sComponentName) +,m_bIsListening(false) +{ +} + +OObjectBase::~OObjectBase() +{ + m_xMediator.clear(); + if ( isListening() ) + EndListening(); + m_xReportComponent.clear(); +} + +uno::Reference< report::XSection> OObjectBase::getSection() const +{ + uno::Reference< report::XSection> xSection; + OReportPage* pPage = dynamic_cast<OReportPage*>(GetImplPage()); + if ( pPage ) + xSection = pPage->getSection(); + return xSection; +} + + +uno::Reference< beans::XPropertySet> OObjectBase::getAwtComponent() +{ + return uno::Reference< beans::XPropertySet>(); +} + +void OObjectBase::StartListening() +{ + OSL_ENSURE(!isListening(), "OUnoObject::StartListening: already listening!"); + + if ( !isListening() && m_xReportComponent.is() ) + { + m_bIsListening = true; + + if ( !m_xPropertyChangeListener.is() ) + { + m_xPropertyChangeListener = new OObjectListener( this ); + // register listener to all properties + m_xReportComponent->addPropertyChangeListener( OUString() , m_xPropertyChangeListener ); + } + } +} + +void OObjectBase::EndListening() +{ + OSL_ENSURE(!m_xReportComponent.is() || isListening(), "OUnoObject::EndListening: not listening currently!"); + + if ( isListening() && m_xReportComponent.is() ) + { + // XPropertyChangeListener + if ( m_xPropertyChangeListener.is() ) + { + // remove listener + try + { + m_xReportComponent->removePropertyChangeListener( OUString() , m_xPropertyChangeListener ); + } + catch(const uno::Exception &) + { + TOOLS_WARN_EXCEPTION( "package", "OObjectBase::EndListening"); + } + } + m_xPropertyChangeListener.clear(); + } + m_bIsListening = false; +} + +void OObjectBase::SetPropsFromRect(const tools::Rectangle& _rRect) +{ + // set properties + OReportPage* pPage = dynamic_cast<OReportPage*>(GetImplPage()); + if ( pPage && !_rRect.IsEmpty() ) + { + const uno::Reference<report::XSection>& xSection = pPage->getSection(); + assert(_rRect.getHeight() >= 0); + const sal_uInt32 newHeight( ::std::max(tools::Long(0), _rRect.getHeight()+_rRect.Top()) ); + if ( xSection.is() && ( newHeight > xSection->getHeight() ) ) + xSection->setHeight( newHeight ); + + // TODO + //pModel->GetRefDevice()->Invalidate(InvalidateFlags::Children); + } +} + +void OObjectBase::_propertyChange( const beans::PropertyChangeEvent& /*evt*/ ) +{ +} + +bool OObjectBase::supportsService( const OUString& _sServiceName ) const +{ + // TODO: cache xServiceInfo as member? + Reference< lang::XServiceInfo > xServiceInfo( m_xReportComponent , UNO_QUERY ); + + if ( xServiceInfo.is() ) + return cppu::supportsService(xServiceInfo.get(), _sServiceName); + else + return false; +} + + +void OObjectBase::ensureSdrObjectOwnership( const uno::Reference< uno::XInterface >& _rxShape ) +{ + // UNDO in the report designer is implemented at the level of the XShapes, not + // at the level of SdrObjects. That is, if an object is removed from the report + // design, then this happens by removing the XShape from the UNO DrawPage, and + // putting this XShape (resp. the ReportComponent which wraps it) into an UNDO + // action. + // Unfortunately, the SvxDrawPage implementation usually deletes SdrObjects + // which are removed from it, which is deadly for us. To prevent this, + // we give the XShape implementation the ownership of the SdrObject, which + // ensures the SvxDrawPage won't delete it. + SvxShape* pShape = comphelper::getFromUnoTunnel<SvxShape>( _rxShape ); + OSL_ENSURE( pShape, "OObjectBase::ensureSdrObjectOwnership: can't access the SvxShape!" ); + if ( pShape ) + { + OSL_ENSURE( !pShape->HasSdrObjectOwnership(), "OObjectBase::ensureSdrObjectOwnership: called twice?" ); + pShape->TakeSdrObjectOwnership(); + } +} + + +uno::Reference< drawing::XShape > OObjectBase::getUnoShapeOf( SdrObject& _rSdrObject ) +{ + uno::Reference< drawing::XShape > xShape( _rSdrObject.getWeakUnoShape() ); + if ( xShape.is() ) + return xShape; + + xShape = _rSdrObject.SdrObject::getUnoShape(); + if ( !xShape.is() ) + return xShape; + + ensureSdrObjectOwnership( xShape ); + + m_xKeepShapeAlive = xShape; + return xShape; +} + +OCustomShape::OCustomShape( + SdrModel& rSdrModel, + const uno::Reference< report::XReportComponent>& _xComponent) +: SdrObjCustomShape(rSdrModel) + ,OObjectBase(_xComponent) +{ + setUnoShape( uno::Reference< drawing::XShape >(_xComponent,uno::UNO_QUERY_THROW) ); + m_bIsListening = true; +} + +OCustomShape::OCustomShape( + SdrModel& rSdrModel, + const OUString& _sComponentName) +: SdrObjCustomShape(rSdrModel) + ,OObjectBase(_sComponentName) +{ + m_bIsListening = true; +} + + +OCustomShape::~OCustomShape() +{ +} + +SdrObjKind OCustomShape::GetObjIdentifier() const +{ + return SdrObjKind::CustomShape; +} + +SdrInventor OCustomShape::GetObjInventor() const +{ + return SdrInventor::ReportDesign; +} + +SdrPage* OCustomShape::GetImplPage() const +{ + return getSdrPageFromSdrObject(); +} + +void OCustomShape::NbcMove( const Size& rSize ) +{ + if ( m_bIsListening ) + { + m_bIsListening = false; + + if ( m_xReportComponent.is() ) + { + OReportModel& rRptModel(static_cast< OReportModel& >(getSdrModelFromSdrObject())); + OXUndoEnvironment::OUndoEnvLock aLock(rRptModel.GetUndoEnv()); + m_xReportComponent->setPositionX(m_xReportComponent->getPositionX() + rSize.Width()); + m_xReportComponent->setPositionY(m_xReportComponent->getPositionY() + rSize.Height()); + } + + // set geometry properties + SetPropsFromRect(GetSnapRect()); + + m_bIsListening = true; + } + else + SdrObjCustomShape::NbcMove( rSize ); +} + +void OCustomShape::NbcResize(const Point& rRef, const Fraction& xFract, const Fraction& yFract) +{ + SdrObjCustomShape::NbcResize( rRef, xFract, yFract ); + + SetPropsFromRect(GetSnapRect()); +} + +void OCustomShape::NbcSetLogicRect(const tools::Rectangle& rRect) +{ + SdrObjCustomShape::NbcSetLogicRect(rRect); + SetPropsFromRect(rRect); +} + +bool OCustomShape::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd) +{ + bool bResult = SdrObjCustomShape::EndCreate(rStat, eCmd); + if ( bResult ) + { + OReportModel& rRptModel(static_cast< OReportModel& >(getSdrModelFromSdrObject())); + OXUndoEnvironment::OUndoEnvLock aLock(rRptModel.GetUndoEnv()); + + if ( !m_xReportComponent.is() ) + m_xReportComponent.set(getUnoShape(),uno::UNO_QUERY); + + SetPropsFromRect(GetSnapRect()); + } + + return bResult; +} + + +uno::Reference< beans::XPropertySet> OCustomShape::getAwtComponent() +{ + return m_xReportComponent; +} + + +uno::Reference< drawing::XShape > OCustomShape::getUnoShape() +{ + uno::Reference<drawing::XShape> xShape = OObjectBase::getUnoShapeOf( *this ); + if ( !m_xReportComponent.is() ) + { + OReportModel& rRptModel(static_cast< OReportModel& >(getSdrModelFromSdrObject())); + OXUndoEnvironment::OUndoEnvLock aLock(rRptModel.GetUndoEnv()); + m_xReportComponent.set(xShape,uno::UNO_QUERY); + } + return xShape; +} + +void OCustomShape::setUnoShape( const uno::Reference< drawing::XShape >& rxUnoShape ) +{ + SdrObjCustomShape::setUnoShape( rxUnoShape ); + releaseUnoShape(); + m_xReportComponent.clear(); +} + +OUnoObject::OUnoObject( + SdrModel& rSdrModel, + const OUString& _sComponentName, + const OUString& rModelName, + SdrObjKind _nObjectType) +: SdrUnoObj(rSdrModel, rModelName) + ,OObjectBase(_sComponentName) + ,m_nObjectType(_nObjectType) + // tdf#119067 + ,m_bSetDefaultLabel(false) +{ + if ( !rModelName.isEmpty() ) + impl_initializeModel_nothrow(); +} + +OUnoObject::OUnoObject( + SdrModel& rSdrModel, OUnoObject const & rSource) +: SdrUnoObj(rSdrModel, rSource) + ,OObjectBase(rSource.getServiceName()) + ,m_nObjectType(rSource.m_nObjectType) + // tdf#119067 + ,m_bSetDefaultLabel(rSource.m_bSetDefaultLabel) +{ + if ( !rSource.getUnoControlModelTypeName().isEmpty() ) + impl_initializeModel_nothrow(); + Reference<XPropertySet> xSource(const_cast<OUnoObject&>(rSource).getUnoShape(), uno::UNO_QUERY); + Reference<XPropertySet> xDest(getUnoShape(), uno::UNO_QUERY); + if ( xSource.is() && xDest.is() ) + comphelper::copyProperties(xSource, xDest); +} + +OUnoObject::OUnoObject( + SdrModel& rSdrModel, + const uno::Reference< report::XReportComponent>& _xComponent, + const OUString& rModelName, + SdrObjKind _nObjectType) +: SdrUnoObj(rSdrModel, rModelName) + ,OObjectBase(_xComponent) + ,m_nObjectType(_nObjectType) + // tdf#119067 + ,m_bSetDefaultLabel(false) +{ + setUnoShape( uno::Reference< drawing::XShape >( _xComponent, uno::UNO_QUERY_THROW ) ); + + if ( !rModelName.isEmpty() ) + impl_initializeModel_nothrow(); + +} + +OUnoObject::~OUnoObject() +{ +} + +void OUnoObject::impl_initializeModel_nothrow() +{ + try + { + Reference< XFormattedField > xFormatted( m_xReportComponent, UNO_QUERY ); + if ( xFormatted.is() ) + { + const Reference< XPropertySet > xModelProps( GetUnoControlModel(), UNO_QUERY_THROW ); + xModelProps->setPropertyValue( "TreatAsNumber", Any( false ) ); + xModelProps->setPropertyValue( PROPERTY_VERTICALALIGN,m_xReportComponent->getPropertyValue(PROPERTY_VERTICALALIGN)); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("reportdesign"); + } +} + +SdrObjKind OUnoObject::GetObjIdentifier() const +{ + return m_nObjectType; +} + +SdrInventor OUnoObject::GetObjInventor() const +{ + return SdrInventor::ReportDesign; +} + +SdrPage* OUnoObject::GetImplPage() const +{ + return getSdrPageFromSdrObject(); +} + +void OUnoObject::NbcMove( const Size& rSize ) +{ + + if ( m_bIsListening ) + { + // stop listening + OObjectBase::EndListening(); + + bool bPositionFixed = false; + Size aUndoSize(0,0); + if ( m_xReportComponent.is() ) + { + bool bUndoMode = false; + OReportModel& rRptModel(static_cast< OReportModel& >(getSdrModelFromSdrObject())); + + if (rRptModel.GetUndoEnv().IsUndoMode()) + { + // if we are locked from outside, then we must not handle wrong moves, we are in UNDO mode + bUndoMode = true; + } + OXUndoEnvironment::OUndoEnvLock aLock(rRptModel.GetUndoEnv()); + + // LLA: why there exists getPositionX and getPositionY and NOT getPosition() which return a Point? + int nNewX = m_xReportComponent->getPositionX() + rSize.Width(); + m_xReportComponent->setPositionX(nNewX); + int nNewY = m_xReportComponent->getPositionY() + rSize.Height(); + if (nNewY < 0 && !bUndoMode) + { + aUndoSize.setHeight( abs(nNewY) ); + bPositionFixed = true; + nNewY = 0; + } + m_xReportComponent->setPositionY(nNewY); + } + if (bPositionFixed) + { + getSdrModelFromSdrObject().AddUndo(getSdrModelFromSdrObject().GetSdrUndoFactory().CreateUndoMoveObject(*this, aUndoSize)); + } + // set geometry properties + SetPropsFromRect(GetLogicRect()); + + // start listening + OObjectBase::StartListening(); + } + else + SdrUnoObj::NbcMove( rSize ); +} + + +void OUnoObject::NbcResize(const Point& rRef, const Fraction& xFract, const Fraction& yFract) +{ + SdrUnoObj::NbcResize( rRef, xFract, yFract ); + + // stop listening + OObjectBase::EndListening(); + + // set geometry properties + SetPropsFromRect(GetLogicRect()); + + // start listening + OObjectBase::StartListening(); +} + +void OUnoObject::NbcSetLogicRect(const tools::Rectangle& rRect) +{ + SdrUnoObj::NbcSetLogicRect(rRect); + // stop listening + OObjectBase::EndListening(); + + // set geometry properties + SetPropsFromRect(rRect); + + // start listening + OObjectBase::StartListening(); +} + +bool OUnoObject::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd) +{ + const bool bResult(SdrUnoObj::EndCreate(rStat, eCmd)); + + if(bResult) + { + // tdf#118730 remember if this object was created interactively (due to ::EndCreate being called) + m_bSetDefaultLabel = true; + + // set geometry properties + SetPropsFromRect(GetLogicRect()); + } + + return bResult; +} + +OUString OUnoObject::GetDefaultName(const OUnoObject* _pObj) +{ + OUString aDefaultName = "HERE WE HAVE TO INSERT OUR NAME!"; + if ( _pObj->supportsService( SERVICE_FIXEDTEXT ) ) + { + aDefaultName = RID_STR_CLASS_FIXEDTEXT; + } + else if ( _pObj->supportsService( SERVICE_FIXEDLINE ) ) + { + aDefaultName = RID_STR_CLASS_FIXEDLINE; + } + else if ( _pObj->supportsService( SERVICE_IMAGECONTROL ) ) + { + aDefaultName = RID_STR_CLASS_IMAGECONTROL; + } + else if ( _pObj->supportsService( SERVICE_FORMATTEDFIELD ) ) + { + aDefaultName = RID_STR_CLASS_FORMATTEDFIELD; + } + + return aDefaultName; +} + +void OUnoObject::_propertyChange( const beans::PropertyChangeEvent& evt ) +{ + OObjectBase::_propertyChange(evt); + if (!isListening()) + return; + + if ( evt.PropertyName == PROPERTY_CHARCOLOR ) + { + Reference<XPropertySet> xControlModel(GetUnoControlModel(),uno::UNO_QUERY); + if ( xControlModel.is() ) + { + OObjectBase::EndListening(); + try + { + xControlModel->setPropertyValue(PROPERTY_TEXTCOLOR,evt.NewValue); + } + catch(uno::Exception&) + { + } + OObjectBase::StartListening(); + } + } + else if ( evt.PropertyName == PROPERTY_NAME ) + { + Reference<XPropertySet> xControlModel(GetUnoControlModel(),uno::UNO_QUERY); + if ( xControlModel.is() && xControlModel->getPropertySetInfo()->hasPropertyByName(PROPERTY_NAME) ) + { + // get old name + OUString aOldName; + evt.OldValue >>= aOldName; + + // get new name + OUString aNewName; + evt.NewValue >>= aNewName; + + if ( aNewName != aOldName ) + { + // set old name property + OObjectBase::EndListening(); + if ( m_xMediator.is() ) + m_xMediator->stopListening(); + try + { + xControlModel->setPropertyValue( PROPERTY_NAME, evt.NewValue ); + } + catch(uno::Exception&) + { + } + if ( m_xMediator.is() ) + m_xMediator->startListening(); + OObjectBase::StartListening(); + } + } + } +} + +void OUnoObject::CreateMediator(bool _bReverse) +{ + if ( m_xMediator.is() ) + return; + + // tdf#118730 Directly do things formerly done in + // OUnoObject::impl_setReportComponent_nothrow here + if(!m_xReportComponent.is()) + { + OReportModel& rRptModel(static_cast< OReportModel& >(getSdrModelFromSdrObject())); + OXUndoEnvironment::OUndoEnvLock aLock( rRptModel.GetUndoEnv() ); + m_xReportComponent.set(getUnoShape(),uno::UNO_QUERY); + + impl_initializeModel_nothrow(); + } + + if(m_xReportComponent.is() && m_bSetDefaultLabel) + { + // tdf#118730 Directly do things formerly done in + // OUnoObject::EndCreate here + // tdf#119067 ...but *only* if result of interactive + // creation in Report DesignView + m_bSetDefaultLabel = false; + + try + { + if ( supportsService( SERVICE_FIXEDTEXT ) ) + { + m_xReportComponent->setPropertyValue( + PROPERTY_LABEL, + uno::Any(GetDefaultName(this))); + } + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("reportdesign"); + } + } + + if(!m_xMediator.is() && m_xReportComponent.is()) + { + Reference<XPropertySet> xControlModel(GetUnoControlModel(),uno::UNO_QUERY); + + if(xControlModel.is()) + { + m_xMediator = new OPropertyMediator( + m_xReportComponent, + xControlModel, + TPropertyNamePair(getPropertyNameMap(GetObjIdentifier())), + _bReverse); + } + } + + OObjectBase::StartListening(); +} + +uno::Reference< beans::XPropertySet> OUnoObject::getAwtComponent() +{ + return Reference<XPropertySet>(GetUnoControlModel(),uno::UNO_QUERY); +} + + +uno::Reference< drawing::XShape > OUnoObject::getUnoShape() +{ + return OObjectBase::getUnoShapeOf( *this ); +} + +void OUnoObject::setUnoShape( const uno::Reference< drawing::XShape >& rxUnoShape ) +{ + SdrUnoObj::setUnoShape( rxUnoShape ); + releaseUnoShape(); +} + +OUnoObject* OUnoObject::CloneSdrObject(SdrModel& rTargetModel) const +{ + return new OUnoObject(rTargetModel, *this); +} + +// OOle2Obj +OOle2Obj::OOle2Obj( + SdrModel& rSdrModel, + const uno::Reference< report::XReportComponent>& _xComponent, + SdrObjKind _nType) +: SdrOle2Obj(rSdrModel) + ,OObjectBase(_xComponent) + ,m_nType(_nType) + ,m_bOnlyOnce(true) +{ + setUnoShape( uno::Reference< drawing::XShape >( _xComponent, uno::UNO_QUERY_THROW ) ); + m_bIsListening = true; +} + +OOle2Obj::OOle2Obj( + SdrModel& rSdrModel, + const OUString& _sComponentName, + SdrObjKind _nType) +: SdrOle2Obj(rSdrModel) + ,OObjectBase(_sComponentName) + ,m_nType(_nType) + ,m_bOnlyOnce(true) +{ + m_bIsListening = true; +} + +static uno::Reference< chart2::data::XDatabaseDataProvider > lcl_getDataProvider(const uno::Reference < embed::XEmbeddedObject >& _xObj); + +OOle2Obj::OOle2Obj(SdrModel& rSdrModel, OOle2Obj const & rSource) +: SdrOle2Obj(rSdrModel, rSource) + ,OObjectBase(rSource.getServiceName()) + ,m_nType(rSource.m_nType) + ,m_bOnlyOnce(rSource.m_bOnlyOnce) +{ + m_bIsListening = true; + + OReportModel& rRptModel(static_cast< OReportModel& >(getSdrModelFromSdrObject())); + svt::EmbeddedObjectRef::TryRunningState( GetObjRef() ); + impl_createDataProvider_nothrow(rRptModel.getReportDefinition()); + + uno::Reference< chart2::data::XDatabaseDataProvider > xSource( lcl_getDataProvider(rSource.GetObjRef()) ); + uno::Reference< chart2::data::XDatabaseDataProvider > xDest( lcl_getDataProvider(GetObjRef()) ); + if ( xSource.is() && xDest.is() ) + comphelper::copyProperties(xSource, xDest); + + initializeChart(rRptModel.getReportDefinition()); +} + +OOle2Obj::~OOle2Obj() +{ +} + +SdrObjKind OOle2Obj::GetObjIdentifier() const +{ + return m_nType; +} + +SdrInventor OOle2Obj::GetObjInventor() const +{ + return SdrInventor::ReportDesign; +} + +SdrPage* OOle2Obj::GetImplPage() const +{ + return getSdrPageFromSdrObject(); +} + +void OOle2Obj::NbcMove( const Size& rSize ) +{ + + if ( m_bIsListening ) + { + // stop listening + OObjectBase::EndListening(); + + bool bPositionFixed = false; + Size aUndoSize(0,0); + if ( m_xReportComponent.is() ) + { + bool bUndoMode = false; + OReportModel& rRptModel(static_cast< OReportModel& >(getSdrModelFromSdrObject())); + + if (rRptModel.GetUndoEnv().IsUndoMode()) + { + // if we are locked from outside, then we must not handle wrong moves, we are in UNDO mode + bUndoMode = true; + } + OXUndoEnvironment::OUndoEnvLock aLock(rRptModel.GetUndoEnv()); + + // LLA: why there exists getPositionX and getPositionY and NOT getPosition() which return a Point? + int nNewX = m_xReportComponent->getPositionX() + rSize.Width(); + // can this hinder us to set components outside the area? + // if (nNewX < 0) + // { + // nNewX = 0; + // } + m_xReportComponent->setPositionX(nNewX); + int nNewY = m_xReportComponent->getPositionY() + rSize.Height(); + if (nNewY < 0 && !bUndoMode) + { + aUndoSize.setHeight( abs(nNewY) ); + bPositionFixed = true; + nNewY = 0; + } + m_xReportComponent->setPositionY(nNewY); + } + if (bPositionFixed) + { + getSdrModelFromSdrObject().AddUndo(getSdrModelFromSdrObject().GetSdrUndoFactory().CreateUndoMoveObject(*this, aUndoSize)); + } + // set geometry properties + SetPropsFromRect(GetLogicRect()); + + // start listening + OObjectBase::StartListening(); + } + else + SdrOle2Obj::NbcMove( rSize ); +} + + +void OOle2Obj::NbcResize(const Point& rRef, const Fraction& xFract, const Fraction& yFract) +{ + SdrOle2Obj::NbcResize( rRef, xFract, yFract ); + + // stop listening + OObjectBase::EndListening(); + + // set geometry properties + SetPropsFromRect(GetLogicRect()); + + // start listening + OObjectBase::StartListening(); +} + +void OOle2Obj::NbcSetLogicRect(const tools::Rectangle& rRect) +{ + SdrOle2Obj::NbcSetLogicRect(rRect); + // stop listening + OObjectBase::EndListening(); + + // set geometry properties + SetPropsFromRect(rRect); + + // start listening + OObjectBase::StartListening(); +} + + +bool OOle2Obj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd) +{ + bool bResult = SdrOle2Obj::EndCreate(rStat, eCmd); + if ( bResult ) + { + OReportModel& rRptModel(static_cast< OReportModel& >(getSdrModelFromSdrObject())); + OXUndoEnvironment::OUndoEnvLock aLock(rRptModel.GetUndoEnv()); + + if ( !m_xReportComponent.is() ) + m_xReportComponent.set(getUnoShape(),uno::UNO_QUERY); + + // set geometry properties + SetPropsFromRect(GetLogicRect()); + } + + return bResult; +} + +uno::Reference< beans::XPropertySet> OOle2Obj::getAwtComponent() +{ + return m_xReportComponent; +} + + +uno::Reference< drawing::XShape > OOle2Obj::getUnoShape() +{ + uno::Reference< drawing::XShape> xShape = OObjectBase::getUnoShapeOf( *this ); + if ( !m_xReportComponent.is() ) + { + OReportModel& rRptModel(static_cast< OReportModel& >(getSdrModelFromSdrObject())); + OXUndoEnvironment::OUndoEnvLock aLock(rRptModel.GetUndoEnv()); + m_xReportComponent.set(xShape,uno::UNO_QUERY); + } + return xShape; +} + +void OOle2Obj::setUnoShape( const uno::Reference< drawing::XShape >& rxUnoShape ) +{ + SdrOle2Obj::setUnoShape( rxUnoShape ); + releaseUnoShape(); + m_xReportComponent.clear(); +} + + +static uno::Reference< chart2::data::XDatabaseDataProvider > lcl_getDataProvider(const uno::Reference < embed::XEmbeddedObject >& _xObj) +{ + uno::Reference< chart2::data::XDatabaseDataProvider > xSource; + uno::Reference< embed::XComponentSupplier > xCompSupp(_xObj); + if( xCompSupp.is()) + { + uno::Reference< chart2::XChartDocument> xChartDoc( xCompSupp->getComponent(), uno::UNO_QUERY ); + if ( xChartDoc.is() ) + { + xSource.set(xChartDoc->getDataProvider(),uno::UNO_QUERY); + } + } + return xSource; +} + +// Clone() should make a complete copy of the object. +OOle2Obj* OOle2Obj::CloneSdrObject(SdrModel& rTargetModel) const +{ + return new OOle2Obj(rTargetModel, *this); +} + +void OOle2Obj::impl_createDataProvider_nothrow(const uno::Reference< frame::XModel>& _xModel) +{ + try + { + uno::Reference < embed::XEmbeddedObject > xObj = GetObjRef(); + uno::Reference< chart2::data::XDataReceiver > xReceiver; + uno::Reference< embed::XComponentSupplier > xCompSupp( xObj ); + if( xCompSupp.is()) + xReceiver.set( xCompSupp->getComponent(), uno::UNO_QUERY ); + OSL_ASSERT( xReceiver.is()); + if( xReceiver.is() ) + { + uno::Reference< lang::XMultiServiceFactory> xFac(_xModel,uno::UNO_QUERY); + uno::Reference< chart2::data::XDatabaseDataProvider > xDataProvider( xFac->createInstance("com.sun.star.chart2.data.DataProvider"),uno::UNO_QUERY); + xReceiver->attachDataProvider( xDataProvider ); + } + } + catch(const uno::Exception &) + { + } +} + +void OOle2Obj::initializeOle() +{ + if ( !m_bOnlyOnce ) + return; + + m_bOnlyOnce = false; + uno::Reference < embed::XEmbeddedObject > xObj = GetObjRef(); + OReportModel& rRptModel(static_cast< OReportModel& >(getSdrModelFromSdrObject())); + rRptModel.GetUndoEnv().AddElement(lcl_getDataProvider(xObj)); + + uno::Reference< embed::XComponentSupplier > xCompSupp( xObj ); + if( xCompSupp.is() ) + { + uno::Reference< beans::XPropertySet > xChartProps( xCompSupp->getComponent(), uno::UNO_QUERY ); + if ( xChartProps.is() ) + xChartProps->setPropertyValue("NullDate", + uno::Any(util::DateTime(0,0,0,0,30,12,1899,false))); + } +} + +void OOle2Obj::initializeChart( const uno::Reference< frame::XModel>& _xModel) +{ + uno::Reference < embed::XEmbeddedObject > xObj = GetObjRef(); + uno::Reference< chart2::data::XDataReceiver > xReceiver; + uno::Reference< embed::XComponentSupplier > xCompSupp( xObj ); + if( xCompSupp.is()) + xReceiver.set( xCompSupp->getComponent(), uno::UNO_QUERY ); + OSL_ASSERT( xReceiver.is()); + if( !xReceiver.is() ) + return; + + // lock the model to suppress any internal updates + uno::Reference< frame::XModel > xChartModel( xReceiver, uno::UNO_QUERY ); + if( xChartModel.is() ) + xChartModel->lockControllers(); + + if ( !lcl_getDataProvider(xObj).is() ) + impl_createDataProvider_nothrow(_xModel); + + OReportModel& rRptModel(static_cast< OReportModel& >(getSdrModelFromSdrObject())); + rRptModel.GetUndoEnv().AddElement(lcl_getDataProvider(xObj)); + + ::comphelper::NamedValueCollection aArgs; + aArgs.put( "CellRangeRepresentation", uno::Any( OUString( "all" ) ) ); + aArgs.put( "HasCategories", uno::Any( true ) ); + aArgs.put( "FirstCellAsLabel", uno::Any( true ) ); + aArgs.put( "DataRowSource", uno::Any( chart::ChartDataRowSource_COLUMNS ) ); + xReceiver->setArguments( aArgs.getPropertyValues() ); + + if( xChartModel.is() ) + xChartModel->unlockControllers(); +} + +uno::Reference< style::XStyle> getUsedStyle(const uno::Reference< report::XReportDefinition>& _xReport) +{ + uno::Reference<container::XNameAccess> xStyles = _xReport->getStyleFamilies(); + uno::Reference<container::XNameAccess> xPageStyles(xStyles->getByName("PageStyles"),uno::UNO_QUERY); + + uno::Reference< style::XStyle> xReturn; + const uno::Sequence< OUString> aSeq = xPageStyles->getElementNames(); + for(const OUString& rName : aSeq) + { + uno::Reference< style::XStyle> xStyle(xPageStyles->getByName(rName),uno::UNO_QUERY); + if ( xStyle->isInUse() ) + { + xReturn = xStyle; + break; + } + } + return xReturn; +} + + +} // rptui + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/reportdesign/source/core/sdr/RptObjectListener.cxx b/reportdesign/source/core/sdr/RptObjectListener.cxx new file mode 100644 index 000000000..0cc6a42b2 --- /dev/null +++ b/reportdesign/source/core/sdr/RptObjectListener.cxx @@ -0,0 +1,69 @@ +/* -*- 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 <RptObjectListener.hxx> +#include <RptObject.hxx> + +namespace rptui +{ + +// OObjectListener + + +OObjectListener::OObjectListener(OObjectBase* _pObject) + :m_pObject(_pObject) +{ +} + + +OObjectListener::~OObjectListener() +{ +} + +// XEventListener + + +void SAL_CALL OObjectListener::disposing( const css::lang::EventObject& ) +{ +} + +// XPropertyChangeListener + + +void SAL_CALL OObjectListener::propertyChange( const css::beans::PropertyChangeEvent& evt ) +{ + m_pObject->_propertyChange( evt ); +} + + +// DlgEdHint + + +DlgEdHint::DlgEdHint(DlgEdHintKind eHint) + : eHintKind(eHint) +{ +} + + +DlgEdHint::~DlgEdHint() +{ +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/reportdesign/source/core/sdr/RptPage.cxx b/reportdesign/source/core/sdr/RptPage.cxx new file mode 100644 index 000000000..1ad1cb8e1 --- /dev/null +++ b/reportdesign/source/core/sdr/RptPage.cxx @@ -0,0 +1,192 @@ +/* -*- 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 <RptPage.hxx> +#include <RptModel.hxx> +#include <Section.hxx> +#include <RptObject.hxx> +#include <ReportDrawPage.hxx> + +namespace rptui +{ +using namespace ::com::sun::star; + +OReportPage::OReportPage( + OReportModel& _rModel, + const uno::Reference< report::XSection >& _xSection) +: SdrPage(_rModel, false/*bMasterPage*/) + ,rModel(_rModel) + ,m_xSection(_xSection) + ,m_bSpecialInsertMode(false) +{ +} + +OReportPage::~OReportPage() +{ +} + +rtl::Reference<SdrPage> OReportPage::CloneSdrPage(SdrModel& rTargetModel) const +{ + OReportModel& rOReportModel(static_cast< OReportModel& >(rTargetModel)); + rtl::Reference<OReportPage> pClonedOReportPage( + new OReportPage( + rOReportModel, + m_xSection)); + pClonedOReportPage->SdrPage::lateInit(*this); + return pClonedOReportPage; +} + + +size_t OReportPage::getIndexOf(const uno::Reference< report::XReportComponent >& _xObject) +{ + const size_t nCount = GetObjCount(); + size_t i = 0; + for (; i < nCount; ++i) + { + OObjectBase* pObj = dynamic_cast<OObjectBase*>(GetObj(i)); + OSL_ENSURE(pObj,"Invalid object found!"); + if ( pObj && pObj->getReportComponent() == _xObject ) + { + break; + } + } + return i; +} + +void OReportPage::removeSdrObject(const uno::Reference< report::XReportComponent >& _xObject) +{ + size_t nPos = getIndexOf(_xObject); + if ( nPos < GetObjCount() ) + { + OObjectBase* pBase = dynamic_cast<OObjectBase*>(GetObj(nPos)); + OSL_ENSURE(pBase,"Why is this not an OObjectBase?"); + if ( pBase ) + pBase->EndListening(); + RemoveObject(nPos); + } +} + +SdrObject* OReportPage::RemoveObject(size_t nObjNum) +{ + SdrObject* pObj = SdrPage::RemoveObject(nObjNum); + if (getSpecialMode()) + { + return pObj; + } + + // this code is evil, but what else shall I do + reportdesign::OSection* pSection = comphelper::getFromUnoTunnel<reportdesign::OSection>(m_xSection); + uno::Reference< drawing::XShape> xShape(pObj->getUnoShape(),uno::UNO_QUERY); + pSection->notifyElementRemoved(xShape); + if (dynamic_cast< const OUnoObject *>( pObj ) != nullptr) + { + OUnoObject& rUnoObj = dynamic_cast<OUnoObject&>(*pObj); + uno::Reference< container::XChild> xChild(rUnoObj.GetUnoControlModel(),uno::UNO_QUERY); + if ( xChild.is() ) + xChild->setParent(nullptr); + } + return pObj; +} + +void OReportPage::insertObject(const uno::Reference< report::XReportComponent >& _xObject) +{ + OSL_ENSURE(_xObject.is(),"Object is not valid to create a SdrObject!"); + if ( !_xObject.is() ) + return; + size_t nPos = getIndexOf(_xObject); + if ( nPos < GetObjCount() ) + return; // Object already in list + + OObjectBase* pObject = dynamic_cast< OObjectBase* >(SdrObject::getSdrObjectFromXShape( _xObject )); + OSL_ENSURE( pObject, "OReportPage::insertObject: no implementation object found for the given shape/component!" ); + if ( pObject ) + pObject->StartListening(); +} + + +uno::Reference< uno::XInterface > OReportPage::createUnoPage() +{ + return static_cast<cppu::OWeakObject*>( new reportdesign::OReportDrawPage(this,m_xSection) ); +} + +void OReportPage::removeTempObject(SdrObject const *_pToRemoveObj) +{ + if (_pToRemoveObj) + { + for (size_t i=0; i<GetObjCount(); ++i) + { + SdrObject *aObj = GetObj(i); + if (aObj && aObj == _pToRemoveObj) + { + (void) RemoveObject(i); + break; + } + } + } +} + +void OReportPage::resetSpecialMode() +{ + const bool bChanged = rModel.IsChanged(); + + for (const auto& pTemporaryObject : m_aTemporaryObjectList) + { + removeTempObject(pTemporaryObject); + } + m_aTemporaryObjectList.clear(); + rModel.SetChanged(bChanged); + + m_bSpecialInsertMode = false; +} + +void OReportPage::NbcInsertObject(SdrObject* pObj, size_t nPos) +{ + SdrPage::NbcInsertObject(pObj, nPos); + + OUnoObject* pUnoObj = dynamic_cast< OUnoObject* >( pObj ); + if (getSpecialMode()) + { + m_aTemporaryObjectList.push_back(pObj); + return; + } + + if ( pUnoObj ) + { + pUnoObj->CreateMediator(); + uno::Reference< container::XChild> xChild(pUnoObj->GetUnoControlModel(),uno::UNO_QUERY); + if ( xChild.is() && !xChild->getParent().is() ) + xChild->setParent(m_xSection); + } + + // this code is evil, but what else shall I do + reportdesign::OSection* pSection = comphelper::getFromUnoTunnel<reportdesign::OSection>(m_xSection); + uno::Reference< drawing::XShape> xShape(pObj->getUnoShape(),uno::UNO_QUERY); + pSection->notifyElementAdded(xShape); + + // now that the shape is inserted into its structures, we can allow the OObjectBase + // to release the reference to it + OObjectBase* pObjectBase = dynamic_cast< OObjectBase* >( pObj ); + OSL_ENSURE( pObjectBase, "OReportPage::NbcInsertObject: what is being inserted here?" ); + if ( pObjectBase ) + pObjectBase->releaseUnoShape(); +} + +} // rptui + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/reportdesign/source/core/sdr/UndoActions.cxx b/reportdesign/source/core/sdr/UndoActions.cxx new file mode 100644 index 000000000..78d59e541 --- /dev/null +++ b/reportdesign/source/core/sdr/UndoActions.cxx @@ -0,0 +1,407 @@ +/* -*- 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 <UndoActions.hxx> +#include <UndoEnv.hxx> +#include <core_resource.hxx> +#include <strings.hrc> +#include <RptModel.hxx> + +#include <com/sun/star/container/XChild.hpp> + +#include <comphelper/types.hxx> +#include <tools/diagnose_ex.h> +#include <utility> +#include <dbaccess/dbsubcomponentcontroller.hxx> +#include <svx/unoshape.hxx> + +namespace rptui +{ + using namespace ::com::sun::star; + using namespace uno; + using namespace lang; + using namespace script; + using namespace beans; + using namespace awt; + using namespace util; + using namespace container; + using namespace report; + +::std::function<uno::Reference<report::XSection>(OGroupHelper *)> OGroupHelper::getMemberFunction(const Reference< XSection >& _xSection) +{ + ::std::function<uno::Reference<report::XSection>(OGroupHelper *)> pMemFunSection = ::std::mem_fn(&OGroupHelper::getFooter); + uno::Reference< report::XGroup> xGroup = _xSection->getGroup(); + if ( xGroup->getHeaderOn() && xGroup->getHeader() == _xSection ) + pMemFunSection = ::std::mem_fn(&OGroupHelper::getHeader); + return pMemFunSection; +} + +::std::function<uno::Reference<report::XSection>(OReportHelper *)> OReportHelper::getMemberFunction(const Reference< XSection >& _xSection) +{ + uno::Reference< report::XReportDefinition> xReportDefinition(_xSection->getReportDefinition()); + ::std::function<uno::Reference<report::XSection>(OReportHelper *)> pMemFunSection = ::std::mem_fn(&OReportHelper::getReportFooter); + if ( xReportDefinition->getReportHeaderOn() && xReportDefinition->getReportHeader() == _xSection ) + pMemFunSection = ::std::mem_fn(&OReportHelper::getReportHeader); + else if ( xReportDefinition->getPageHeaderOn() && xReportDefinition->getPageHeader() == _xSection ) + pMemFunSection = ::std::mem_fn(&OReportHelper::getPageHeader); + else if ( xReportDefinition->getPageFooterOn() && xReportDefinition->getPageFooter() == _xSection ) + pMemFunSection = ::std::mem_fn(&OReportHelper::getPageFooter); + else if ( xReportDefinition->getDetail() == _xSection ) + pMemFunSection = ::std::mem_fn(&OReportHelper::getDetail); + return pMemFunSection; +} + + +OCommentUndoAction::OCommentUndoAction(SdrModel& _rMod, TranslateId pCommentID) + :SdrUndoAction(_rMod) +{ + m_pController = static_cast< OReportModel& >( _rMod ).getController(); + if (pCommentID) + m_strComment = RptResId(pCommentID); +} +OCommentUndoAction::~OCommentUndoAction() +{ +} + +void OCommentUndoAction::Undo() +{ +} + +void OCommentUndoAction::Redo() +{ +} + +OUndoContainerAction::OUndoContainerAction(SdrModel& _rMod + ,Action _eAction + ,const uno::Reference< container::XIndexContainer >& rContainer + ,const Reference< XInterface > & xElem + ,TranslateId pCommentId) + :OCommentUndoAction(_rMod, pCommentId) + ,m_xElement(xElem) + ,m_xContainer(rContainer) + ,m_eAction( _eAction ) +{ + // normalize + if ( m_eAction == Removed ) + // we now own the element + m_xOwnElement = m_xElement; +} + +OUndoContainerAction::~OUndoContainerAction() +{ + // if we own the object... + Reference< XComponent > xComp( m_xOwnElement, UNO_QUERY ); + if ( !xComp.is() ) + return; + + // and the object does not have a parent + Reference< XChild > xChild( m_xOwnElement, UNO_QUERY ); + if ( !xChild.is() || xChild->getParent().is() ) + return; + + OXUndoEnvironment& rEnv = static_cast< OReportModel& >( rMod ).GetUndoEnv(); + rEnv.RemoveElement( m_xOwnElement ); + +#if OSL_DEBUG_LEVEL > 0 + SvxShape* pShape = comphelper::getFromUnoTunnel<SvxShape>( xChild ); + SdrObject* pObject = pShape ? pShape->GetSdrObject() : nullptr; + OSL_ENSURE( pObject == nullptr || (pShape->HasSdrObjectOwnership() && !pObject->IsInserted()), + "OUndoContainerAction::~OUndoContainerAction: inconsistency in the shape/object ownership!" ); +#endif + // -> dispose it + try + { + comphelper::disposeComponent( xComp ); + } + catch ( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("reportdesign"); + } +} + +void OUndoContainerAction::implReInsert( ) +{ + if ( m_xContainer.is() ) + { + // insert the element + m_xContainer->insertByIndex( m_xContainer->getCount(),uno::Any(m_xElement) ); + } + // we don't own the object anymore + m_xOwnElement = nullptr; +} + + +void OUndoContainerAction::implReRemove( ) +{ + OXUndoEnvironment& rEnv = static_cast< OReportModel& >( rMod ).GetUndoEnv(); + try + { + OXUndoEnvironment::OUndoEnvLock aLock(rEnv); + if ( m_xContainer.is() ) + { + const sal_Int32 nCount = m_xContainer->getCount(); + for (sal_Int32 i = 0; i < nCount; ++i) + { + uno::Reference< uno::XInterface> xObj(m_xContainer->getByIndex(i),uno::UNO_QUERY); + if ( xObj == m_xElement ) + { + m_xContainer->removeByIndex( i ); + break; + } + } + } + } + catch(uno::Exception&){} + // from now on, we own this object + m_xOwnElement = m_xElement; +} + + +void OUndoContainerAction::Undo() +{ + if ( !m_xElement.is() ) + return; + + // prevents that an undo action will be created for elementInserted + try + { + switch ( m_eAction ) + { + case Inserted: + implReRemove(); + break; + + case Removed: + implReInsert(); + break; + default: + OSL_FAIL("Illegal case value"); + break; + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "reportdesign", "OUndoContainerAction::Undo" ); + } +} + + +void OUndoContainerAction::Redo() +{ + if ( !m_xElement.is() ) + return; + + try + { + switch ( m_eAction ) + { + case Inserted: + implReInsert(); + break; + + case Removed: + implReRemove(); + break; + default: + OSL_FAIL("Illegal case value"); + break; + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "reportdesign", "OUndoContainerAction::Redo" ); + } +} + +OUndoGroupSectionAction::OUndoGroupSectionAction( + SdrModel& _rMod, Action _eAction, + ::std::function<uno::Reference<report::XSection>(OGroupHelper*)> _pMemberFunction, + const uno::Reference<report::XGroup>& _xGroup, const Reference<XInterface>& xElem, + TranslateId pCommentId) + : OUndoContainerAction(_rMod, _eAction, nullptr, xElem, pCommentId) + , m_aGroupHelper(_xGroup) + , m_pMemberFunction(std::move(_pMemberFunction)) +{ +} + +void OUndoGroupSectionAction::implReInsert( ) +{ + OXUndoEnvironment& rEnv = static_cast< OReportModel& >( rMod ).GetUndoEnv(); + try + { + OXUndoEnvironment::OUndoEnvLock aLock(rEnv); + uno::Reference< report::XSection> xSection = m_pMemberFunction(&m_aGroupHelper); + if ( xSection.is() ) + xSection->add(uno::Reference< drawing::XShape>(m_xElement,uno::UNO_QUERY)); + } + catch(uno::Exception&){} + + // we don't own the object anymore + m_xOwnElement = nullptr; +} + + +void OUndoGroupSectionAction::implReRemove( ) +{ + OXUndoEnvironment& rEnv = static_cast< OReportModel& >( rMod ).GetUndoEnv(); + try + { + OXUndoEnvironment::OUndoEnvLock aLock(rEnv); + uno::Reference< report::XSection> xSection = m_pMemberFunction(&m_aGroupHelper); + if ( xSection.is() ) + xSection->remove(uno::Reference< drawing::XShape>(m_xElement,uno::UNO_QUERY)); + } + catch(uno::Exception&){} + + // from now on, we own this object + m_xOwnElement = m_xElement; +} + +OUndoReportSectionAction::OUndoReportSectionAction( + SdrModel& _rMod, Action _eAction, + ::std::function<uno::Reference<report::XSection>(OReportHelper*)> _pMemberFunction, + const uno::Reference<report::XReportDefinition>& _xReport, const Reference<XInterface>& xElem, + TranslateId pCommentId) + : OUndoContainerAction(_rMod, _eAction, nullptr, xElem, pCommentId) + , m_aReportHelper(_xReport) + , m_pMemberFunction(std::move(_pMemberFunction)) +{ +} + +void OUndoReportSectionAction::implReInsert( ) +{ + OXUndoEnvironment& rEnv = static_cast< OReportModel& >( rMod ).GetUndoEnv(); + try + { + OXUndoEnvironment::OUndoEnvLock aLock(rEnv); + uno::Reference< report::XSection> xSection = m_pMemberFunction(&m_aReportHelper); + if ( xSection.is() ) + { + uno::Reference< drawing::XShape> xShape(m_xElement,uno::UNO_QUERY_THROW); + awt::Point aPos = xShape->getPosition(); + awt::Size aSize = xShape->getSize(); + xSection->add(xShape); + xShape->setPosition( aPos ); + xShape->setSize( aSize ); + } + } + catch(uno::Exception&){} + // we don't own the object anymore + m_xOwnElement = nullptr; +} + + +void OUndoReportSectionAction::implReRemove( ) +{ + OXUndoEnvironment& rEnv = static_cast< OReportModel& >( rMod ).GetUndoEnv(); + try + { + OXUndoEnvironment::OUndoEnvLock aLock(rEnv); + uno::Reference< report::XSection> xSection = m_pMemberFunction(&m_aReportHelper); + if ( xSection.is() ) + xSection->remove(uno::Reference< drawing::XShape>(m_xElement,uno::UNO_QUERY)); + } + catch(uno::Exception&){} + // from now on, we own this object + m_xOwnElement = m_xElement; +} + +ORptUndoPropertyAction::ORptUndoPropertyAction(SdrModel& rNewMod, const PropertyChangeEvent& evt) + :OCommentUndoAction(rNewMod,{}) + ,m_xObj(evt.Source, UNO_QUERY) + ,m_aPropertyName(evt.PropertyName) + ,m_aNewValue(evt.NewValue) + ,m_aOldValue(evt.OldValue) +{ +} + +void ORptUndoPropertyAction::Undo() +{ + setProperty(true); +} + + +void ORptUndoPropertyAction::Redo() +{ + setProperty(false); +} + +Reference< XPropertySet> ORptUndoPropertyAction::getObject() +{ + return m_xObj; +} + +void ORptUndoPropertyAction::setProperty(bool _bOld) +{ + Reference< XPropertySet> xObj = getObject(); + + if (xObj.is() ) + { + try + { + xObj->setPropertyValue( m_aPropertyName, _bOld ? m_aOldValue : m_aNewValue ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "reportdesign", "ORptUndoPropertyAction::Redo" ); + } + } +} + +OUString ORptUndoPropertyAction::GetComment() const +{ + OUString aStr( RptResId(RID_STR_UNDO_PROPERTY) ); + + return aStr.replaceFirst("#", m_aPropertyName); +} + +OUndoPropertyGroupSectionAction::OUndoPropertyGroupSectionAction( + SdrModel& _rMod, const PropertyChangeEvent& evt, + ::std::function<uno::Reference<report::XSection>(OGroupHelper*)> _pMemberFunction, + const uno::Reference<report::XGroup>& _xGroup) + : ORptUndoPropertyAction(_rMod, evt) + , m_aGroupHelper(_xGroup) + , m_pMemberFunction(std::move(_pMemberFunction)) +{ +} + +Reference< XPropertySet> OUndoPropertyGroupSectionAction::getObject() +{ + return m_pMemberFunction(&m_aGroupHelper); +} + +OUndoPropertyReportSectionAction::OUndoPropertyReportSectionAction( + SdrModel& _rMod, const PropertyChangeEvent& evt, + ::std::function<uno::Reference<report::XSection>(OReportHelper*)> _pMemberFunction, + const uno::Reference<report::XReportDefinition>& _xReport) + : ORptUndoPropertyAction(_rMod, evt) + , m_aReportHelper(_xReport) + , m_pMemberFunction(std::move(_pMemberFunction)) +{ +} + +Reference< XPropertySet> OUndoPropertyReportSectionAction::getObject() +{ + return m_pMemberFunction(&m_aReportHelper); +} + +} // rptui + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/reportdesign/source/core/sdr/UndoEnv.cxx b/reportdesign/source/core/sdr/UndoEnv.cxx new file mode 100644 index 000000000..2585d4a20 --- /dev/null +++ b/reportdesign/source/core/sdr/UndoEnv.cxx @@ -0,0 +1,619 @@ +/* -*- 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 <UndoActions.hxx> +#include <UndoEnv.hxx> +#include "formatnormalizer.hxx" +#include <conditionupdater.hxx> +#include <RptPage.hxx> +#include <strings.hrc> +#include <RptModel.hxx> + +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/beans/theIntrospection.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/util/XModifyBroadcaster.hpp> +#include <com/sun/star/beans/XIntrospectionAccess.hpp> +#include <com/sun/star/beans/XIntrospection.hpp> + +#include <svl/hint.hxx> +#include <tools/debug.hxx> +#include <tools/diagnose_ex.h> +#include <vcl/svapp.hxx> +#include <dbaccess/dbsubcomponentcontroller.hxx> +#include <osl/mutex.hxx> + +#include <unordered_map> + +namespace rptui +{ + using namespace ::com::sun::star; + using namespace uno; + using namespace lang; + using namespace script; + using namespace beans; + using namespace awt; + using namespace util; + using namespace container; + using namespace report; + +namespace { + +struct PropertyInfo +{ + bool bIsReadonlyOrTransient; + + explicit PropertyInfo( const bool i_bIsTransientOrReadOnly ) + :bIsReadonlyOrTransient( i_bIsTransientOrReadOnly ) + { + } +}; + +} + +typedef std::unordered_map< OUString, PropertyInfo > PropertiesInfo; + +namespace { + +struct ObjectInfo +{ + PropertiesInfo aProperties; + Reference< XPropertySet > xPropertyIntrospection; + + ObjectInfo() + { + } +}; + +} + +typedef ::std::map< Reference< XPropertySet >, ObjectInfo > PropertySetInfoCache; + + +class OXUndoEnvironmentImpl +{ +public: + OReportModel& m_rModel; + PropertySetInfoCache m_aPropertySetCache; + FormatNormalizer m_aFormatNormalizer; + ConditionUpdater m_aConditionUpdater; + ::osl::Mutex m_aMutex; + ::std::vector< uno::Reference< container::XChild> > m_aSections; + Reference< XIntrospection > m_xIntrospection; + oslInterlockedCount m_nLocks; + bool m_bReadOnly; + bool m_bIsUndo; + + explicit OXUndoEnvironmentImpl(OReportModel& _rModel); + OXUndoEnvironmentImpl(const OXUndoEnvironmentImpl&) = delete; + OXUndoEnvironmentImpl& operator=(const OXUndoEnvironmentImpl&) = delete; +}; + +OXUndoEnvironmentImpl::OXUndoEnvironmentImpl(OReportModel& _rModel) : m_rModel(_rModel) + ,m_aFormatNormalizer( _rModel ) + ,m_nLocks(0) + ,m_bReadOnly(false) + ,m_bIsUndo(false) +{ +} + + +OXUndoEnvironment::OXUndoEnvironment(OReportModel& _rModel) + :m_pImpl(new OXUndoEnvironmentImpl(_rModel) ) +{ + StartListening(m_pImpl->m_rModel); +} + + +OXUndoEnvironment::~OXUndoEnvironment() +{ +} + +void OXUndoEnvironment::Lock() +{ + OSL_ENSURE(m_refCount,"Illegal call to dead object!"); + osl_atomic_increment( &m_pImpl->m_nLocks ); +} +void OXUndoEnvironment::UnLock() +{ + OSL_ENSURE(m_refCount,"Illegal call to dead object!"); + + osl_atomic_decrement( &m_pImpl->m_nLocks ); +} +bool OXUndoEnvironment::IsLocked() const { return m_pImpl->m_nLocks != 0; } + +void OXUndoEnvironment::RemoveSection(OReportPage const * _pPage) +{ + if ( _pPage ) + { + Reference< XInterface > xSection(_pPage->getSection()); + if ( xSection.is() ) + RemoveElement( xSection ); + } +} + +void OXUndoEnvironment::Clear(const Accessor& /*_r*/) +{ + OUndoEnvLock aLock(*this); + + m_pImpl->m_aPropertySetCache.clear(); + + sal_uInt16 nCount = m_pImpl->m_rModel.GetPageCount(); + sal_uInt16 i; + for (i = 0; i < nCount; i++) + { + OReportPage* pPage = dynamic_cast<OReportPage*>( m_pImpl->m_rModel.GetPage(i) ); + RemoveSection(pPage); + } + + nCount = m_pImpl->m_rModel.GetMasterPageCount(); + for (i = 0; i < nCount; i++) + { + OReportPage* pPage = dynamic_cast<OReportPage*>( m_pImpl->m_rModel.GetMasterPage(i) ); + RemoveSection(pPage); + } + + m_pImpl->m_aSections.clear(); + + if (IsListening(m_pImpl->m_rModel)) + EndListening(m_pImpl->m_rModel); +} + + +void OXUndoEnvironment::ModeChanged() +{ + m_pImpl->m_bReadOnly = !m_pImpl->m_bReadOnly; + + if (!m_pImpl->m_bReadOnly) + StartListening(m_pImpl->m_rModel); + else + EndListening(m_pImpl->m_rModel); +} + + +void OXUndoEnvironment::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint ) +{ + if (rHint.GetId() == SfxHintId::ModeChanged ) + ModeChanged(); +} + +// XEventListener + +void SAL_CALL OXUndoEnvironment::disposing(const EventObject& e) +{ + // check if it's an object we have cached information about + Reference< XPropertySet > xSourceSet(e.Source, UNO_QUERY); + if ( xSourceSet.is() ) + { + uno::Reference< report::XSection> xSection(xSourceSet,uno::UNO_QUERY); + if ( xSection.is() ) + RemoveSection(xSection); + else + RemoveElement(xSourceSet); + } +} + +// XPropertyChangeListener + +void SAL_CALL OXUndoEnvironment::propertyChange( const PropertyChangeEvent& _rEvent ) +{ + + ::osl::ClearableMutexGuard aGuard( m_pImpl->m_aMutex ); + + if ( IsLocked() ) + return; + + Reference< XPropertySet > xSet( _rEvent.Source, UNO_QUERY ); + if (!xSet.is()) + return; + + dbaui::DBSubComponentController* pController = m_pImpl->m_rModel.getController(); + if ( !pController ) + return; + + // no Undo for transient and readonly props. + // let's see if we know something about the set + PropertySetInfoCache::iterator objectPos = m_pImpl->m_aPropertySetCache.find(xSet); + if (objectPos == m_pImpl->m_aPropertySetCache.end()) + { + objectPos = m_pImpl->m_aPropertySetCache.emplace( xSet, ObjectInfo() ).first; + DBG_ASSERT(objectPos != m_pImpl->m_aPropertySetCache.end(), "OXUndoEnvironment::propertyChange : just inserted it... why it's not there?"); + } + if ( objectPos == m_pImpl->m_aPropertySetCache.end() ) + return; + + // now we have access to the cached info about the set + // let's see what we know about the property + ObjectInfo& rObjectInfo = objectPos->second; + PropertiesInfo::const_iterator aPropertyPos = rObjectInfo.aProperties.find( _rEvent.PropertyName ); + if ( aPropertyPos == rObjectInfo.aProperties.end() ) + { // nothing 'til now... have to change this... + // the attributes + Reference< XPropertySetInfo > xPSI( xSet->getPropertySetInfo(), UNO_SET_THROW ); + sal_Int32 nPropertyAttributes = 0; + try + { + if ( xPSI->hasPropertyByName( _rEvent.PropertyName ) ) + { + nPropertyAttributes = xPSI->getPropertyByName( _rEvent.PropertyName ).Attributes; + } + else + { + // it's perfectly valid for a component to notify a change in a property which it doesn't have - as long + // as it has an attribute with this name + if ( !rObjectInfo.xPropertyIntrospection.is() ) + { + if ( !m_pImpl->m_xIntrospection.is() ) + { + m_pImpl->m_xIntrospection = theIntrospection::get( m_pImpl->m_rModel.getController()->getORB() ); + } + Reference< XIntrospectionAccess > xIntrospection( + m_pImpl->m_xIntrospection->inspect( Any( _rEvent.Source ) ), + UNO_SET_THROW + ); + rObjectInfo.xPropertyIntrospection.set( xIntrospection->queryAdapter( cppu::UnoType<XPropertySet>::get() ), UNO_QUERY_THROW ); + } + if ( rObjectInfo.xPropertyIntrospection.is() ) + { + xPSI.set( rObjectInfo.xPropertyIntrospection->getPropertySetInfo(), UNO_SET_THROW ); + nPropertyAttributes = xPSI->getPropertyByName( _rEvent.PropertyName ).Attributes; + } + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("reportdesign"); + } + const bool bTransReadOnly = + ( ( nPropertyAttributes & PropertyAttribute::READONLY ) != 0 ) + || ( ( nPropertyAttributes & PropertyAttribute::TRANSIENT ) != 0 ); + + // insert the new entry + aPropertyPos = rObjectInfo.aProperties.emplace( + _rEvent.PropertyName, + PropertyInfo( bTransReadOnly ) + ).first; + DBG_ASSERT(aPropertyPos != rObjectInfo.aProperties.end(), "OXUndoEnvironment::propertyChange : just inserted it ... why it's not there ?"); + } + + implSetModified(); + + // now we have access to the cached info about the property affected + // and are able to decide whether or not we need an undo action + + // no UNDO for transient/readonly properties + if ( aPropertyPos->second.bIsReadonlyOrTransient ) + return; + + // give components with sub responsibilities a chance + m_pImpl->m_aFormatNormalizer.notifyPropertyChange( _rEvent ); + m_pImpl->m_aConditionUpdater.notifyPropertyChange( _rEvent ); + + aGuard.clear(); + // TODO: this is a potential race condition: two threads here could in theory + // add their undo actions out-of-order + + SolarMutexGuard aSolarGuard; + std::unique_ptr<ORptUndoPropertyAction> pUndo; + try + { + uno::Reference< report::XSection> xSection( xSet, uno::UNO_QUERY ); + if ( xSection.is() ) + { + uno::Reference< report::XGroup> xGroup = xSection->getGroup(); + if ( xGroup.is() ) + pUndo.reset(new OUndoPropertyGroupSectionAction( m_pImpl->m_rModel, _rEvent, OGroupHelper::getMemberFunction( xSection ), xGroup )); + else + pUndo.reset(new OUndoPropertyReportSectionAction( m_pImpl->m_rModel, _rEvent, OReportHelper::getMemberFunction( xSection ), xSection->getReportDefinition() )); + } + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("reportdesign"); + } + + if ( pUndo == nullptr ) + pUndo.reset(new ORptUndoPropertyAction( m_pImpl->m_rModel, _rEvent )); + + m_pImpl->m_rModel.GetSdrUndoManager()->AddUndoAction( std::move(pUndo) ); + pController->InvalidateAll(); +} + +::std::vector< uno::Reference< container::XChild> >::const_iterator OXUndoEnvironment::getSection(const Reference<container::XChild>& _xContainer) const +{ + ::std::vector< uno::Reference< container::XChild> >::const_iterator aFind = m_pImpl->m_aSections.end(); + if ( _xContainer.is() ) + { + aFind = ::std::find(m_pImpl->m_aSections.begin(),m_pImpl->m_aSections.end(),_xContainer); + + if ( aFind == m_pImpl->m_aSections.end() ) + { + Reference<container::XChild> xParent(_xContainer->getParent(),uno::UNO_QUERY); + aFind = getSection(xParent); + } + } + return aFind; +} +// XContainerListener + +void SAL_CALL OXUndoEnvironment::elementInserted(const ContainerEvent& evt) +{ + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_pImpl->m_aMutex ); + + // new listener object + Reference< uno::XInterface > xIface( evt.Element, UNO_QUERY ); + if ( !IsLocked() ) + { + Reference< report::XReportComponent > xReportComponent( xIface, UNO_QUERY ); + if ( xReportComponent.is() ) + { + Reference< report::XSection > xContainer(evt.Source,uno::UNO_QUERY); + + ::std::vector< uno::Reference< container::XChild> >::const_iterator aFind = getSection(xContainer); + + if ( aFind != m_pImpl->m_aSections.end() ) + { + OUndoEnvLock aLock(*this); + try + { + OReportPage* pPage = m_pImpl->m_rModel.getPage(uno::Reference< report::XSection>(*aFind,uno::UNO_QUERY)); + OSL_ENSURE(pPage,"No page could be found for section!"); + if ( pPage ) + pPage->insertObject(xReportComponent); + } + catch(uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("reportdesign"); + } + + } + } + else + { + uno::Reference< report::XFunctions> xContainer(evt.Source,uno::UNO_QUERY); + if ( xContainer.is() ) + { + m_pImpl->m_rModel.GetSdrUndoManager()->AddUndoAction( + std::make_unique<OUndoContainerAction>( m_pImpl->m_rModel, rptui::Inserted, xContainer.get(), + xIface, RID_STR_UNDO_ADDFUNCTION ) ); + } + } + } + + AddElement(xIface); + + implSetModified(); +} + + +void OXUndoEnvironment::implSetModified() +{ + m_pImpl->m_rModel.SetModified( true ); +} + + +void SAL_CALL OXUndoEnvironment::elementReplaced(const ContainerEvent& evt) +{ + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_pImpl->m_aMutex ); + + Reference< XInterface > xIface(evt.ReplacedElement,uno::UNO_QUERY); + OSL_ENSURE(xIface.is(), "OXUndoEnvironment::elementReplaced: invalid container notification!"); + RemoveElement(xIface); + + xIface.set(evt.Element,uno::UNO_QUERY); + AddElement(xIface); + + implSetModified(); +} + + +void SAL_CALL OXUndoEnvironment::elementRemoved(const ContainerEvent& evt) +{ + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_pImpl->m_aMutex ); + + Reference< uno::XInterface > xIface( evt.Element, UNO_QUERY ); + if ( !IsLocked() ) + { + Reference< report::XSection > xContainer(evt.Source,uno::UNO_QUERY); + ::std::vector< uno::Reference< container::XChild> >::const_iterator aFind = getSection(xContainer); + + Reference< report::XReportComponent > xReportComponent( xIface, UNO_QUERY ); + if ( aFind != m_pImpl->m_aSections.end() && xReportComponent.is() ) + { + OXUndoEnvironment::OUndoEnvLock aLock(*this); + try + { + OReportPage* pPage = m_pImpl->m_rModel.getPage(uno::Reference< report::XSection >( *aFind, uno::UNO_QUERY_THROW ) ); + OSL_ENSURE( pPage, "OXUndoEnvironment::elementRemoved: no page for the section!" ); + if ( pPage ) + pPage->removeSdrObject(xReportComponent); + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("reportdesign"); + } + } + else + { + uno::Reference< report::XFunctions> xFunctions(evt.Source,uno::UNO_QUERY); + if ( xFunctions.is() ) + { + m_pImpl->m_rModel.GetSdrUndoManager()->AddUndoAction( std::make_unique<OUndoContainerAction>( + m_pImpl->m_rModel, rptui::Removed, xFunctions.get(), xIface, RID_STR_UNDO_ADDFUNCTION ) ); + } + } + } + + if ( xIface.is() ) + RemoveElement(xIface); + + implSetModified(); +} + + +void SAL_CALL OXUndoEnvironment::modified( const EventObject& /*aEvent*/ ) +{ + implSetModified(); +} + + +void OXUndoEnvironment::AddSection(const Reference< report::XSection > & _xSection) +{ + OUndoEnvLock aLock(*this); + try + { + uno::Reference<container::XChild> xChild = _xSection; + m_pImpl->m_aSections.push_back(xChild); + Reference< XInterface > xInt(_xSection); + AddElement(xInt); + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("reportdesign"); + } +} + + +void OXUndoEnvironment::RemoveSection(const Reference< report::XSection > & _xSection) +{ + OUndoEnvLock aLock(*this); + try + { + uno::Reference<container::XChild> xChild(_xSection); + m_pImpl->m_aSections.erase(::std::remove(m_pImpl->m_aSections.begin(),m_pImpl->m_aSections.end(), + xChild), m_pImpl->m_aSections.end()); + Reference< XInterface > xInt(_xSection); + RemoveElement(xInt); + } + catch(uno::Exception&){} +} + + +void OXUndoEnvironment::switchListening( const Reference< XIndexAccess >& _rxContainer, bool _bStartListening ) +{ + OSL_PRECOND( _rxContainer.is(), "OXUndoEnvironment::switchListening: invalid container!" ); + if ( !_rxContainer.is() ) + return; + + try + { + // also handle all children of this element + Reference< XInterface > xInterface; + sal_Int32 nCount = _rxContainer->getCount(); + for(sal_Int32 i = 0;i != nCount;++i) + { + xInterface.set(_rxContainer->getByIndex( i ),uno::UNO_QUERY); + if ( _bStartListening ) + AddElement( xInterface ); + else + RemoveElement( xInterface ); + } + + // be notified of any changes in the container elements + Reference< XContainer > xSimpleContainer( _rxContainer, UNO_QUERY ); + if ( xSimpleContainer.is() ) + { + if ( _bStartListening ) + xSimpleContainer->addContainerListener( this ); + else + xSimpleContainer->removeContainerListener( this ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("reportdesign"); + } +} + + +void OXUndoEnvironment::switchListening( const Reference< XInterface >& _rxObject, bool _bStartListening ) +{ + OSL_PRECOND( _rxObject.is(), "OXUndoEnvironment::switchListening: how should I listen at a NULL object?" ); + + try + { + if ( !m_pImpl->m_bReadOnly ) + { + Reference< XPropertySet > xProps( _rxObject, UNO_QUERY ); + if ( xProps.is() ) + { + if ( _bStartListening ) + xProps->addPropertyChangeListener( OUString(), this ); + else + xProps->removePropertyChangeListener( OUString(), this ); + } + } + + Reference< XModifyBroadcaster > xBroadcaster( _rxObject, UNO_QUERY ); + if ( xBroadcaster.is() ) + { + if ( _bStartListening ) + xBroadcaster->addModifyListener( this ); + else + xBroadcaster->removeModifyListener( this ); + } + } + catch( const Exception& ) + { + } +} + + +void OXUndoEnvironment::AddElement(const Reference< XInterface >& _rxElement ) +{ + if ( !IsLocked() ) + m_pImpl->m_aFormatNormalizer.notifyElementInserted( _rxElement ); + + // if it's a container, start listening at all elements + Reference< XIndexAccess > xContainer( _rxElement, UNO_QUERY ); + if ( xContainer.is() ) + switchListening( xContainer, true ); + + switchListening( _rxElement, true ); +} + + +void OXUndoEnvironment::RemoveElement(const Reference< XInterface >& _rxElement) +{ + uno::Reference<beans::XPropertySet> xProp(_rxElement,uno::UNO_QUERY); + if (!m_pImpl->m_aPropertySetCache.empty()) + m_pImpl->m_aPropertySetCache.erase(xProp); + switchListening( _rxElement, false ); + + Reference< XIndexAccess > xContainer( _rxElement, UNO_QUERY ); + if ( xContainer.is() ) + switchListening( xContainer, false ); +} + +void OXUndoEnvironment::SetUndoMode(bool _bUndo) +{ + m_pImpl->m_bIsUndo = _bUndo; +} + +bool OXUndoEnvironment::IsUndoMode() const +{ + return m_pImpl->m_bIsUndo; +} + +} // rptui + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/reportdesign/source/core/sdr/formatnormalizer.cxx b/reportdesign/source/core/sdr/formatnormalizer.cxx new file mode 100644 index 000000000..ae576bc40 --- /dev/null +++ b/reportdesign/source/core/sdr/formatnormalizer.cxx @@ -0,0 +1,258 @@ +/* -*- 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 "formatnormalizer.hxx" +#include <RptModel.hxx> + +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdb/XParametersSupplier.hpp> +#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp> +#include <com/sun/star/util/XNumberFormatTypes.hpp> + +#include <dbaccess/dbsubcomponentcontroller.hxx> +#include <unotools/syslocale.hxx> +#include <connectivity/statementcomposer.hxx> +#include <connectivity/dbtools.hxx> +#include <tools/diagnose_ex.h> +#include <i18nlangtag/languagetag.hxx> + + +namespace rptui +{ + + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::report::XFormattedField; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::sdb::XSingleSelectQueryComposer; + using ::com::sun::star::sdbcx::XColumnsSupplier; + using ::com::sun::star::container::XIndexAccess; + using ::com::sun::star::beans::XPropertySet; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::sdb::XParametersSupplier; + using ::com::sun::star::sdbc::SQLException; + using ::com::sun::star::util::XNumberFormatsSupplier; + using ::com::sun::star::util::XNumberFormatTypes; + + + //= FormatNormalizer + + + FormatNormalizer::FormatNormalizer( const OReportModel& _rModel ) + :m_rModel( _rModel ) + ,m_bFieldListDirty( true ) + { + } + + + FormatNormalizer::~FormatNormalizer() + { + } + + + void FormatNormalizer::notifyPropertyChange( const css::beans::PropertyChangeEvent& _rEvent ) + { + if ( !impl_lateInit() ) + return; + + if ( ( _rEvent.Source == m_xReportDefinition ) && m_xReportDefinition.is() ) + { + impl_onDefinitionPropertyChange( _rEvent.PropertyName ); + return; + } + + Reference< XFormattedField > xFormatted( _rEvent.Source, UNO_QUERY ); + if ( xFormatted.is() ) + impl_onFormattedProperttyChange( xFormatted, _rEvent.PropertyName ); + } + + + void FormatNormalizer::notifyElementInserted( const css::uno::Reference< css::uno::XInterface >& _rxElement ) + { + if ( !impl_lateInit() ) + return; + + Reference< XFormattedField > xFormatted( _rxElement, UNO_QUERY ); + if ( !xFormatted.is() ) + return; + + impl_adjustFormatToDataFieldType_nothrow( xFormatted ); + } + + + bool FormatNormalizer::impl_lateInit() + { + if ( m_xReportDefinition.is() ) + return true; + + m_xReportDefinition = m_rModel.getReportDefinition(); + return m_xReportDefinition.is(); + } + + + void FormatNormalizer::impl_onDefinitionPropertyChange( std::u16string_view _rChangedPropName ) + { + if ( _rChangedPropName != u"Command" && _rChangedPropName != u"CommandType" && _rChangedPropName != u"EscapeProcessing" ) + // nothing we're interested in + return; + m_bFieldListDirty = true; + } + + + void FormatNormalizer::impl_onFormattedProperttyChange( const Reference< XFormattedField >& _rxFormatted, std::u16string_view _rChangedPropName ) + { + if ( _rChangedPropName != u"DataField" ) + // nothing we're interested in + return; + + impl_adjustFormatToDataFieldType_nothrow( _rxFormatted ); + } + + + namespace + { + void lcl_collectFields_throw( const Reference< XIndexAccess >& _rxColumns, FormatNormalizer::FieldList& _inout_rFields ) + { + try + { + sal_Int32 nCount( _rxColumns->getCount() ); + _inout_rFields.reserve( _inout_rFields.size() + static_cast<size_t>(nCount) ); + + Reference< XPropertySet > xColumn; + FormatNormalizer::Field aField; + + for ( sal_Int32 i=0; i<nCount; ++i ) + { + xColumn.set( _rxColumns->getByIndex( i ), UNO_QUERY_THROW ); + OSL_VERIFY( xColumn->getPropertyValue("Name") >>= aField.sName ); + OSL_VERIFY( xColumn->getPropertyValue("Type") >>= aField.nDataType ); + OSL_VERIFY( xColumn->getPropertyValue("Scale") >>= aField.nScale ); + OSL_VERIFY( xColumn->getPropertyValue("IsCurrency") >>= aField.bIsCurrency ); + _inout_rFields.push_back( aField ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("reportdesign"); + } + } + } + + + bool FormatNormalizer::impl_ensureUpToDateFieldList_nothrow() + { + if ( !m_bFieldListDirty ) + return true; + m_aFields.resize( 0 ); + + OSL_PRECOND( m_xReportDefinition.is(), "FormatNormalizer::impl_ensureUpToDateFieldList_nothrow: no report definition!" ); + if ( !m_xReportDefinition.is() ) + return false; + + ::dbaui::DBSubComponentController* pController( m_rModel.getController() ); + OSL_ENSURE( pController, "FormatNormalizer::impl_ensureUpToDateFieldList_nothrow: no controller? how can *this* happen?!" ); + if ( !pController ) + return false; + + try + { + ::dbtools::StatementComposer aComposer( pController->getConnection(), m_xReportDefinition->getCommand(), + m_xReportDefinition->getCommandType(), m_xReportDefinition->getEscapeProcessing() ); + + Reference< XSingleSelectQueryComposer > xComposer( aComposer.getComposer() ); + if ( !xComposer.is() ) + return false; + + + Reference< XColumnsSupplier > xSuppCols( xComposer, UNO_QUERY_THROW ); + Reference< XIndexAccess > xColumns( xSuppCols->getColumns(), UNO_QUERY_THROW ); + lcl_collectFields_throw( xColumns, m_aFields ); + + Reference< XParametersSupplier > xSuppParams( xComposer, UNO_QUERY_THROW ); + Reference< XIndexAccess > xParams( xSuppParams->getParameters(), css::uno::UNO_SET_THROW ); + lcl_collectFields_throw( xParams, m_aFields ); + } + catch( const SQLException& ) + { + // silence it. This might happen for instance when the user sets a non-existent table, + // or things like this + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("reportdesign"); + } + + m_bFieldListDirty = false; + return true; + } + + + void FormatNormalizer::impl_adjustFormatToDataFieldType_nothrow( const Reference< XFormattedField >& _rxFormatted ) + { + if ( !impl_ensureUpToDateFieldList_nothrow() ) + // unable to obtain a recent field list + return; + + try + { + sal_Int32 nFormatKey = _rxFormatted->getFormatKey(); + if ( nFormatKey != 0 ) + // it's not the "standard numeric" format -> not interested in + return; + + OUString sDataField( _rxFormatted->getDataField() ); + static const OUStringLiteral sFieldPrefix( u"field:[" ); + if ( sDataField.indexOf( sFieldPrefix ) != 0 ) + // not bound to a table field + // TODO: we might also do this kind of thing for functions and expressions ... + return; + if ( !sDataField.endsWith("]") ) + { + // last character is not the closing brace + OSL_FAIL( "FormatNormalizer::impl_adjustFormatToDataFieldType_nothrow: suspicious data field value!" ); + return; + } + sDataField = sDataField.copy( sFieldPrefix.getLength(), sDataField.getLength() - sFieldPrefix.getLength() - 1 ); + + FieldList::const_iterator field = std::find_if(m_aFields.begin(), m_aFields.end(), + [&sDataField](const Field& rField) { return rField.sName == sDataField; }); + if ( field == m_aFields.end() ) + // unknown field + return; + + Reference< XNumberFormatsSupplier > xSuppNumFmts( _rxFormatted->getFormatsSupplier(), css::uno::UNO_SET_THROW ); + Reference< XNumberFormatTypes > xNumFmtTypes( xSuppNumFmts->getNumberFormats(), UNO_QUERY_THROW ); + + nFormatKey = ::dbtools::getDefaultNumberFormat( field->nDataType, field->nScale, field->bIsCurrency, xNumFmtTypes, + SvtSysLocale().GetLanguageTag().getLocale() ); + _rxFormatted->setFormatKey( nFormatKey ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("reportdesign"); + } + } + + +} // namespace rptui + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/reportdesign/source/core/sdr/formatnormalizer.hxx b/reportdesign/source/core/sdr/formatnormalizer.hxx new file mode 100644 index 000000000..0ed30df3e --- /dev/null +++ b/reportdesign/source/core/sdr/formatnormalizer.hxx @@ -0,0 +1,86 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_REPORTDESIGN_SOURCE_CORE_SDR_FORMATNORMALIZER_HXX +#define INCLUDED_REPORTDESIGN_SOURCE_CORE_SDR_FORMATNORMALIZER_HXX + +#include <com/sun/star/report/XReportDefinition.hpp> +#include <com/sun/star/beans/PropertyChangeEvent.hpp> +#include <com/sun/star/report/XFormattedField.hpp> + +#include <vector> + + +namespace rptui +{ + + + class OReportModel; + + //= FormatNormalizer + + class FormatNormalizer + { + public: + struct Field + { + OUString sName; + sal_Int32 nDataType; + sal_Int32 nScale; + bool bIsCurrency; + + Field() : sName(), nDataType( 0 ), nScale( 0 ), bIsCurrency( false ) { } + }; + typedef ::std::vector< Field > FieldList; + + private: + const OReportModel& m_rModel; + css::uno::Reference< css::report::XReportDefinition > m_xReportDefinition; + + /// is our field list dirty? + FieldList m_aFields; + bool m_bFieldListDirty; + + public: + explicit FormatNormalizer( const OReportModel& _rModel ); + ~FormatNormalizer(); + FormatNormalizer(const FormatNormalizer&) = delete; + FormatNormalizer& operator=(const FormatNormalizer&) = delete; + + void notifyPropertyChange( const css::beans::PropertyChangeEvent& _rEvent ); + void notifyElementInserted( const css::uno::Reference< css::uno::XInterface >& _rxElement ); + + private: + bool impl_lateInit(); + + void impl_onDefinitionPropertyChange( std::u16string_view _rChangedPropName ); + void impl_onFormattedProperttyChange( const css::uno::Reference< css::report::XFormattedField >& _rxFormatted, std::u16string_view _rChangedPropName ); + + bool impl_ensureUpToDateFieldList_nothrow(); + + void impl_adjustFormatToDataFieldType_nothrow( const css::uno::Reference< css::report::XFormattedField >& _rxFormatted ); + }; + + +} // namespace rptui + + +#endif // INCLUDED_REPORTDESIGN_SOURCE_CORE_SDR_FORMATNORMALIZER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |