diff options
Diffstat (limited to 'sc/source/ui/vba')
130 files changed, 29089 insertions, 0 deletions
diff --git a/sc/source/ui/vba/excelvbahelper.cxx b/sc/source/ui/vba/excelvbahelper.cxx new file mode 100644 index 000000000..317b06454 --- /dev/null +++ b/sc/source/ui/vba/excelvbahelper.cxx @@ -0,0 +1,399 @@ +/* -*- 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 "excelvbahelper.hxx" + +#include <basic/basmgr.hxx> +#include <comphelper/processfactory.hxx> +#include <vbahelper/vbahelper.hxx> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/sheet/XSheetCellRange.hpp> +#include <com/sun/star/sheet/GlobalSheetSettings.hpp> +#include <com/sun/star/sheet/XUnnamedDatabaseRanges.hpp> +#include <com/sun/star/sheet/XSpreadsheet.hpp> +#include <com/sun/star/sheet/XDatabaseRange.hpp> + +#include <document.hxx> +#include <docuno.hxx> +#include <tabvwsh.hxx> +#include <transobj.hxx> +#include <cellsuno.hxx> +#include <gridwin.hxx> + +#include <com/sun/star/script/vba/VBAEventId.hpp> +#include <com/sun/star/script/vba/XVBACompatibility.hpp> +#include <com/sun/star/script/vba/XVBAEventProcessor.hpp> +#include <com/sun/star/script/vba/XVBAModuleInfo.hpp> +#include <com/sun/star/script/ModuleInfo.hpp> +#include <com/sun/star/script/ModuleType.hpp> + +using namespace ::com::sun::star; +using namespace ::ooo::vba; + +namespace ooo::vba::excel { + +uno::Reference< sheet::XUnnamedDatabaseRanges > +GetUnnamedDataBaseRanges( const ScDocShell* pShell ) +{ + uno::Reference< frame::XModel > xModel; + if ( pShell ) + xModel.set( pShell->GetModel(), uno::UNO_SET_THROW ); + uno::Reference< beans::XPropertySet > xModelProps( xModel, uno::UNO_QUERY_THROW ); + uno::Reference< sheet::XUnnamedDatabaseRanges > xUnnamedDBRanges( xModelProps->getPropertyValue("UnnamedDatabaseRanges"), uno::UNO_QUERY_THROW ); + return xUnnamedDBRanges; +} + +// returns the XDatabaseRange for the autofilter on sheet (nSheet) +// also populates sName with the name of range +uno::Reference< sheet::XDatabaseRange > +GetAutoFiltRange( const ScDocShell* pShell, sal_Int16 nSheet ) +{ + uno::Reference< sheet::XUnnamedDatabaseRanges > xUnnamedDBRanges( GetUnnamedDataBaseRanges( pShell ), uno::UNO_SET_THROW ); + uno::Reference< sheet::XDatabaseRange > xDataBaseRange; + if (xUnnamedDBRanges->hasByTable( nSheet ) ) + { + uno::Reference< sheet::XDatabaseRange > xDBRange( xUnnamedDBRanges->getByTable( nSheet ) , uno::UNO_QUERY_THROW ); + bool bHasAuto = false; + uno::Reference< beans::XPropertySet > xProps( xDBRange, uno::UNO_QUERY_THROW ); + xProps->getPropertyValue("AutoFilter") >>= bHasAuto; + if ( bHasAuto ) + { + xDataBaseRange=xDBRange; + } + } + return xDataBaseRange; +} + +ScDocShell* GetDocShellFromRange( const uno::Reference< uno::XInterface >& xRange ) +{ + ScCellRangesBase* pScCellRangesBase = comphelper::getFromUnoTunnel<ScCellRangesBase>( xRange ); + if ( !pScCellRangesBase ) + { + throw uno::RuntimeException("Failed to access underlying doc shell uno range object" ); + } + return pScCellRangesBase->GetDocShell(); +} + +uno::Reference< XHelperInterface > +getUnoSheetModuleObj( const uno::Reference< table::XCellRange >& xRange ) +{ + uno::Reference< sheet::XSheetCellRange > xSheetRange( xRange, uno::UNO_QUERY_THROW ); + uno::Reference< sheet::XSpreadsheet > xSheet( xSheetRange->getSpreadsheet(), uno::UNO_SET_THROW ); + return getUnoSheetModuleObj( xSheet ); +} + +void implSetZoom( const uno::Reference< frame::XModel >& xModel, sal_Int16 nZoom, std::vector< SCTAB >& nTabs ) +{ + ScTabViewShell* pViewSh = excel::getBestViewShell( xModel ); + Fraction aFract( nZoom, 100 ); + pViewSh->GetViewData().SetZoom( aFract, aFract, nTabs ); + pViewSh->RefreshZoom(); +} + +namespace { + +class PasteCellsWarningReseter +{ +private: + bool bInitialWarningState; + /// @throws uno::RuntimeException + static uno::Reference< sheet::XGlobalSheetSettings > const & getGlobalSheetSettings() + { + static uno::Reference< sheet::XGlobalSheetSettings > xProps = sheet::GlobalSheetSettings::create( comphelper::getProcessComponentContext() ); + return xProps; + } + + /// @throws uno::RuntimeException + static bool getReplaceCellsWarning() + { + return getGlobalSheetSettings()->getReplaceCellsWarning(); + } + + /// @throws uno::RuntimeException + static void setReplaceCellsWarning( bool bState ) + { + getGlobalSheetSettings()->setReplaceCellsWarning( bState ); + } +public: + /// @throws uno::RuntimeException + PasteCellsWarningReseter() + { + bInitialWarningState = getReplaceCellsWarning(); + if ( bInitialWarningState ) + setReplaceCellsWarning( false ); + } + ~PasteCellsWarningReseter() + { + if ( bInitialWarningState ) + { + // don't allow dtor to throw + try + { + setReplaceCellsWarning( true ); + } + catch ( uno::Exception& /*e*/ ){} + } + } +}; + +} + +void +implnPaste( const uno::Reference< frame::XModel>& xModel ) +{ + PasteCellsWarningReseter resetWarningBox; + ScTabViewShell* pViewShell = getBestViewShell( xModel ); + if ( pViewShell ) + { + pViewShell->PasteFromSystem(); + pViewShell->CellContentChanged(); + } +} + +void +implnCopy( const uno::Reference< frame::XModel>& xModel ) +{ + ScTabViewShell* pViewShell = getBestViewShell( xModel ); + ScDocShell* pDocShell = getDocShell( xModel ); + if ( !(pViewShell && pDocShell) ) + return; + + pViewShell->CopyToClip(nullptr,false,false,true); + + // mark the copied transfer object so it is used in ScVbaRange::Insert + uno::Reference<datatransfer::XTransferable2> xTransferable(ScTabViewShell::GetClipData(pViewShell->GetViewData().GetActiveWin())); + ScTransferObj* pClipObj = ScTransferObj::GetOwnClipboard(xTransferable); + if (pClipObj) + { + pClipObj->SetUseInApi( true ); + pDocShell->SetClipData(xTransferable); + } +} + +void +implnCut( const uno::Reference< frame::XModel>& xModel ) +{ + ScTabViewShell* pViewShell = getBestViewShell( xModel ); + ScDocShell* pDocShell = getDocShell( xModel ); + if ( !(pViewShell && pDocShell) ) + return; + + pViewShell->CutToClip(); + + // mark the copied transfer object so it is used in ScVbaRange::Insert + uno::Reference<datatransfer::XTransferable2> xTransferable(ScTabViewShell::GetClipData(pViewShell->GetViewData().GetActiveWin())); + ScTransferObj* pClipObj = ScTransferObj::GetOwnClipboard(xTransferable); + if (pClipObj) + { + pClipObj->SetUseInApi( true ); + pDocShell->SetClipData(xTransferable); + } +} + +void implnPasteSpecial( const uno::Reference< frame::XModel>& xModel, InsertDeleteFlags nFlags, ScPasteFunc nFunction, bool bSkipEmpty, bool bTranspose) +{ + PasteCellsWarningReseter resetWarningBox; + + ScTabViewShell* pTabViewShell = getBestViewShell(xModel); + if (!pTabViewShell) + return; + + ScDocShell* pDocShell = getDocShell(xModel); + if (!pDocShell) + return; + + ScViewData& rView = pTabViewShell->GetViewData(); + vcl::Window* pWin = rView.GetActiveWin(); + if (!pWin) + return; + + const ScTransferObj* pOwnClip = ScTransferObj::GetOwnClipboard(ScTabViewShell::GetClipData(pWin)); + if (pOwnClip) + { + pTabViewShell->PasteFromClip(nFlags, pOwnClip->GetDocument(), + nFunction, bSkipEmpty, bTranspose, false, + INS_NONE, InsertDeleteFlags::NONE, true); + + pTabViewShell->CellContentChanged(); + } +} + +ScDocShell* +getDocShell( const css::uno::Reference< css::frame::XModel>& xModel ) +{ + uno::Reference< uno::XInterface > xIf( xModel, uno::UNO_QUERY_THROW ); + ScModelObj* pModel = dynamic_cast< ScModelObj* >( xIf.get() ); + ScDocShell* pDocShell = nullptr; + if ( pModel ) + pDocShell = static_cast<ScDocShell*>(pModel->GetEmbeddedObject()); + return pDocShell; + +} + +ScTabViewShell* +getBestViewShell( const css::uno::Reference< css::frame::XModel>& xModel ) +{ + ScDocShell* pDocShell = getDocShell( xModel ); + if ( pDocShell ) + return pDocShell->GetBestViewShell(); + return nullptr; +} + +ScTabViewShell* +getCurrentBestViewShell( const uno::Reference< uno::XComponentContext >& xContext ) +{ + uno::Reference< frame::XModel > xModel = getCurrentExcelDoc( xContext ); + return getBestViewShell( xModel ); +} + +SfxViewFrame* +getViewFrame( const uno::Reference< frame::XModel >& xModel ) +{ + ScTabViewShell* pViewShell = getBestViewShell( xModel ); + if ( pViewShell ) + return pViewShell->GetViewFrame(); + return nullptr; +} + +uno::Reference< XHelperInterface > +getUnoSheetModuleObj( const uno::Reference< sheet::XSpreadsheet >& xSheet ) +{ + uno::Reference< beans::XPropertySet > xProps( xSheet, uno::UNO_QUERY_THROW ); + OUString sCodeName; + xProps->getPropertyValue("CodeName") >>= sCodeName; + // #TODO #FIXME ideally we should 'throw' here if we don't get a valid parent, but... it is possible + // to create a module ( and use 'Option VBASupport 1' ) for a calc document, in this scenario there + // are *NO* special document module objects ( of course being able to switch between vba/non vba mode at + // the document in the future could fix this, especially IF the switching of the vba mode takes care to + // create the special document module objects if they don't exist. + return getUnoDocModule( sCodeName, GetDocShellFromRange( xSheet ) ); +} + +uno::Reference< XHelperInterface > +getUnoSheetModuleObj( const uno::Reference< sheet::XSheetCellRangeContainer >& xRanges ) +{ + uno::Reference< container::XEnumerationAccess > xEnumAccess( xRanges, uno::UNO_QUERY_THROW ); + uno::Reference< container::XEnumeration > xEnum = xEnumAccess->createEnumeration(); + uno::Reference< table::XCellRange > xRange( xEnum->nextElement(), uno::UNO_QUERY_THROW ); + return getUnoSheetModuleObj( xRange ); +} + +uno::Reference< XHelperInterface > +getUnoSheetModuleObj( const uno::Reference< table::XCell >& xCell ) +{ + uno::Reference< sheet::XSheetCellRange > xSheetRange( xCell, uno::UNO_QUERY_THROW ); + uno::Reference< sheet::XSpreadsheet > xSheet( xSheetRange->getSpreadsheet(), uno::UNO_SET_THROW ); + return getUnoSheetModuleObj( xSheet ); +} + +uno::Reference< XHelperInterface > +getUnoSheetModuleObj( const uno::Reference< frame::XModel >& xModel, SCTAB nTab ) +{ + uno::Reference< sheet::XSpreadsheetDocument > xDoc( xModel, uno::UNO_QUERY_THROW ); + uno::Reference< container::XIndexAccess > xSheets( xDoc->getSheets(), uno::UNO_QUERY_THROW ); + uno::Reference< sheet::XSpreadsheet > xSheet( xSheets->getByIndex( nTab ), uno::UNO_QUERY_THROW ); + return getUnoSheetModuleObj( xSheet ); +} + +void setUpDocumentModules( const uno::Reference< sheet::XSpreadsheetDocument >& xDoc ) +{ + uno::Reference< frame::XModel > xModel( xDoc, uno::UNO_QUERY ); + ScDocShell* pShell = excel::getDocShell( xModel ); + if ( !pShell ) + return; + + OUString aPrjName( "Standard" ); + pShell->GetBasicManager()->SetName( aPrjName ); + + /* Set library container to VBA compatibility mode. This will create + the VBA Globals object and store it in the Basic manager of the + document. */ + uno::Reference<script::XLibraryContainer> xLibContainer = pShell->GetBasicContainer(); + uno::Reference<script::vba::XVBACompatibility> xVBACompat( xLibContainer, uno::UNO_QUERY_THROW ); + xVBACompat->setVBACompatibilityMode( true ); + + if( xLibContainer.is() ) + { + if( !xLibContainer->hasByName( aPrjName ) ) + xLibContainer->createLibrary( aPrjName ); + uno::Any aLibAny = xLibContainer->getByName( aPrjName ); + uno::Reference< container::XNameContainer > xLib; + aLibAny >>= xLib; + if( xLib.is() ) + { + uno::Reference< script::vba::XVBAModuleInfo > xVBAModuleInfo( xLib, uno::UNO_QUERY_THROW ); + uno::Reference< lang::XMultiServiceFactory> xSF( pShell->GetModel(), uno::UNO_QUERY_THROW); + uno::Reference< container::XNameAccess > xVBACodeNamedObjectAccess( xSF->createInstance("ooo.vba.VBAObjectModuleObjectProvider"), uno::UNO_QUERY_THROW ); + // set up the module info for the workbook and sheets in the newly created + // spreadsheet + ScDocument& rDoc = pShell->GetDocument(); + OUString sCodeName = rDoc.GetCodeName(); + if ( sCodeName.isEmpty() ) + { + sCodeName = "ThisWorkbook"; + rDoc.SetCodeName( sCodeName ); + } + + std::vector< OUString > sDocModuleNames { sCodeName }; + + for ( SCTAB index = 0; index < rDoc.GetTableCount(); index++) + { + OUString aName; + rDoc.GetCodeName( index, aName ); + sDocModuleNames.push_back( aName ); + } + + for ( const auto& rName : sDocModuleNames ) + { + script::ModuleInfo sModuleInfo; + + uno::Any aName= xVBACodeNamedObjectAccess->getByName( rName ); + sModuleInfo.ModuleObject.set( aName, uno::UNO_QUERY ); + sModuleInfo.ModuleType = script::ModuleType::DOCUMENT; + xVBAModuleInfo->insertModuleInfo( rName, sModuleInfo ); + if( xLib->hasByName( rName ) ) + xLib->replaceByName( rName, uno::Any( OUString( "Option VBASupport 1\n") ) ); + else + xLib->insertByName( rName, uno::Any( OUString( "Option VBASupport 1\n" ) ) ); + } + } + } + + /* Trigger the Workbook_Open event, event processor will register + itself as listener for specific events. */ + try + { + uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents( pShell->GetDocument().GetVbaEventProcessor(), uno::UNO_SET_THROW ); + uno::Sequence< uno::Any > aArgs; + xVbaEvents->processVbaEvent( script::vba::VBAEventId::WORKBOOK_OPEN, aArgs ); + } + catch( uno::Exception& ) + { + } +} + +SfxItemSet* +ScVbaCellRangeAccess::GetDataSet( ScCellRangesBase* pRangeObj ) +{ + return pRangeObj ? pRangeObj->GetCurrentDataSet( true ) : nullptr; +} + +} // namespace ooo::vba::excel + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/excelvbahelper.hxx b/sc/source/ui/vba/excelvbahelper.hxx new file mode 100644 index 000000000..0b72481e3 --- /dev/null +++ b/sc/source/ui/vba/excelvbahelper.hxx @@ -0,0 +1,97 @@ +/* -*- 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 . + */ +#pragma once + +#include <sal/config.h> + +#include <comphelper/servicehelper.hxx> + +#include <vector> +#include <global.hxx> + +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::uno { class XComponentContext; } + +namespace com::sun::star::sheet { class XDatabaseRange; } +namespace com::sun::star::sheet { class XUnnamedDatabaseRanges; } +namespace com::sun::star::table { class XCell; } +namespace com::sun::star::table { class XCellRange; } +namespace com::sun::star::sheet { class XSheetCellRangeContainer; } +namespace com::sun::star::sheet { class XSpreadsheet; } +namespace com::sun::star::sheet { class XSpreadsheetDocument; } +namespace ooo::vba { class XHelperInterface; } + +class ScCellRangesBase; +class ScTabViewShell; +class SfxViewFrame; + +namespace ooo::vba::excel { + +// nTabs empty means apply zoom to all sheets +void implSetZoom( const css::uno::Reference< css::frame::XModel >& xModel, sal_Int16 nZoom, std::vector< SCTAB >& nTabs ); +void implnCopy( const css::uno::Reference< css::frame::XModel>& xModel ); +void implnPaste ( const css::uno::Reference< css::frame::XModel>& xModel ); +void implnCut( const css::uno::Reference< css::frame::XModel>& xModel ); +void implnPasteSpecial( const css::uno::Reference< css::frame::XModel>& xModel, InsertDeleteFlags nFlags, ScPasteFunc nFunction, bool bSkipEmpty, bool bTranspose); +ScTabViewShell* getBestViewShell( const css::uno::Reference< css::frame::XModel>& xModel ) ; +ScDocShell* getDocShell( const css::uno::Reference< css::frame::XModel>& xModel ) ; +ScTabViewShell* getCurrentBestViewShell( const css::uno::Reference< css::uno::XComponentContext >& xContext ); +SfxViewFrame* getViewFrame( const css::uno::Reference< css::frame::XModel >& xModel ); + +/// @throws css::uno::RuntimeException +css::uno::Reference< css::sheet::XUnnamedDatabaseRanges > GetUnnamedDataBaseRanges( const ScDocShell* pShell ); + +/// @throws css::uno::RuntimeException +css::uno::Reference< css::sheet::XDatabaseRange > GetAutoFiltRange( const ScDocShell* pShell, sal_Int16 nSheet ); +/// @throws css::uno::RuntimeException +css::uno::Reference< ooo::vba::XHelperInterface > getUnoSheetModuleObj( const css::uno::Reference< css::sheet::XSpreadsheet >& xSheet ); +/// @throws css::uno::RuntimeException +css::uno::Reference< ooo::vba::XHelperInterface > getUnoSheetModuleObj( const css::uno::Reference< css::sheet::XSheetCellRangeContainer >& xRanges ); +/// @throws css::uno::RuntimeException +css::uno::Reference< ooo::vba::XHelperInterface > getUnoSheetModuleObj( const css::uno::Reference< css::table::XCellRange >& xRange ); +/// @throws css::uno::RuntimeException +css::uno::Reference< ooo::vba::XHelperInterface > getUnoSheetModuleObj( const css::uno::Reference< css::table::XCell >& xCell ); +/// @throws css::uno::RuntimeException +css::uno::Reference< ooo::vba::XHelperInterface > getUnoSheetModuleObj( const css::uno::Reference< css::frame::XModel >& xModel, SCTAB nTab ); + +/// @throws css::uno::RuntimeException +ScDocShell* GetDocShellFromRange( const css::uno::Reference< css::uno::XInterface >& xRange ); +void setUpDocumentModules( const css::uno::Reference< css::sheet::XSpreadsheetDocument >& xDoc ); + +class ScVbaCellRangeAccess +{ +public: + static SfxItemSet* GetDataSet( ScCellRangesBase* pRangeObj ); +}; + +// Extracts an implementation object (via XUnoTunnel) from a UNO object. +// Will throw if unsuccessful. +/// @throws css::uno::RuntimeException +template < typename ImplObject > + ImplObject* getImplFromDocModuleWrapper( const css::uno::Reference< css::uno::XInterface >& rxWrapperIf ) + { + ImplObject* pObj = comphelper::getFromUnoTunnel<ImplObject>(rxWrapperIf); + if ( !pObj ) + throw css::uno::RuntimeException("Internal error, can't extract implementation object", rxWrapperIf ); + return pObj; + } + +} // namespace ooo::vba::excel + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/helperdecl.hxx b/sc/source/ui/vba/helperdecl.hxx new file mode 100644 index 000000000..b1163047e --- /dev/null +++ b/sc/source/ui/vba/helperdecl.hxx @@ -0,0 +1,47 @@ +/* -*- 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 . + */ + +#pragma once + +#include <comphelper/servicedecl.hxx> + +namespace comphelper::service_decl { +template <typename ImplT_, typename WithArgsT = with_args<false> > +struct vba_service_class_ : public serviceimpl_base< detail::OwnServiceImpl<ImplT_>, WithArgsT > +{ + typedef serviceimpl_base< detail::OwnServiceImpl<ImplT_>, WithArgsT > baseT; + /** Default ctor. Implementation class without args, expecting + component context as single argument. + */ + vba_service_class_() : baseT() {} + template <typename PostProcessFuncT> + /** Ctor to pass a post processing function/functor. + + @tpl PostProcessDefaultT let your compiler deduce this + @param postProcessFunc function/functor that gets the yet unacquired + ImplT_ pointer returning a + uno::Reference<uno::XInterface> + */ + explicit vba_service_class_( PostProcessFuncT const& postProcessFunc ) : baseT( postProcessFunc ) {} +}; + +} // namespace service_decl +} // namespace comphelper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaapplication.cxx b/sc/source/ui/vba/vbaapplication.cxx new file mode 100644 index 000000000..2fda7fa86 --- /dev/null +++ b/sc/source/ui/vba/vbaapplication.cxx @@ -0,0 +1,1566 @@ +/* -*- 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 <com/sun/star/frame/XDesktop.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/script/BasicErrorException.hpp> +#include <com/sun/star/sheet/XCalculatable.hpp> +#include <com/sun/star/sheet/XCellRangeAddressable.hpp> +#include <com/sun/star/sheet/XNamedRanges.hpp> +#include <com/sun/star/sheet/XSpreadsheetView.hpp> +#include <com/sun/star/task/XStatusIndicatorSupplier.hpp> +#include <com/sun/star/task/XStatusIndicator.hpp> +#include <com/sun/star/util/PathSettings.hpp> +#include <com/sun/star/view/XSelectionSupplier.hpp> +#include <ooo/vba/XCommandBars.hpp> +#include <ooo/vba/excel/XApplicationOutgoing.hpp> +#include <ooo/vba/excel/XlCalculation.hpp> +#include <ooo/vba/excel/XlMousePointer.hpp> +#include <ooo/vba/office/MsoShapeType.hpp> +#include <ooo/vba/office/MsoAutoShapeType.hpp> +#include <ooo/vba/office/MsoFileDialogType.hpp> + +#include "vbaapplication.hxx" +#include "vbaworkbooks.hxx" +#include "vbaworkbook.hxx" +#include "vbarange.hxx" +#include "vbawsfunction.hxx" +#include "vbadialogs.hxx" +#include "vbawindow.hxx" +#include "vbawindows.hxx" +#include "vbamenubars.hxx" +#include <tabvwsh.hxx> +#include <gridwin.hxx> +#include "vbanames.hxx" +#include <vbahelper/vbashape.hxx> +#include "vbatextboxshape.hxx" +#include "vbaovalshape.hxx" +#include "vbalineshape.hxx" +#include "vbaassistant.hxx" +#include <sc.hrc> +#include <macromgr.hxx> +#include "vbafiledialog.hxx" +#include "vbafiledialogitems.hxx" + +#include <osl/file.hxx> + +#include <sfx2/bindings.hxx> +#include <sfx2/request.hxx> +#include <sfx2/app.hxx> +#include <vcl/svapp.hxx> + +#include <tools/diagnose_ex.h> + +#include <basic/sbx.hxx> +#include <basic/sbstar.hxx> +#include <basic/sbuno.hxx> +#include <basic/sbmeth.hxx> +#include <basic/sberrors.hxx> +#include <comphelper/sequence.hxx> + +#include <convuno.hxx> +#include <cellsuno.hxx> +#include <unonames.hxx> +#include <docsh.hxx> +#include "excelvbahelper.hxx" +#include <basic/sbxobj.hxx> + +#include <viewutil.hxx> +#include <docoptio.hxx> +#include <scmod.hxx> +#include <scdll.hxx> + +#include <list> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::UNO_QUERY_THROW; +using ::com::sun::star::uno::UNO_QUERY; + +/** Global application settings shared by all open workbooks. */ +struct ScVbaAppSettings +{ + bool mbDisplayAlerts; + bool mbEnableEvents; + bool mbExcel4Menus; + bool mbDisplayNoteIndicator; + bool mbShowWindowsInTaskbar; + bool mbEnableCancelKey; + explicit ScVbaAppSettings(); +}; + +ScVbaAppSettings::ScVbaAppSettings() : + mbDisplayAlerts( true ), + mbEnableEvents( true ), + mbExcel4Menus( false ), + mbDisplayNoteIndicator( true ), + mbShowWindowsInTaskbar( true ), + mbEnableCancelKey( false ) +{ +} + +namespace { + +ScVbaAppSettings& ScVbaStaticAppSettings() +{ + static ScVbaAppSettings SINGLETON; + return SINGLETON; +} + +class ScVbaApplicationOutgoingConnectionPoint : public cppu::WeakImplHelper<XConnectionPoint> +{ +private: + ScVbaApplication* mpApp; + +public: + ScVbaApplicationOutgoingConnectionPoint( ScVbaApplication* pApp ); + + // XConnectionPoint + sal_uInt32 SAL_CALL Advise(const uno::Reference< XSink >& Sink ) override; + void SAL_CALL Unadvise( sal_uInt32 Cookie ) override; +}; + +} + +sal_uInt32 +ScVbaApplication::AddSink( const uno::Reference< XSink >& xSink ) +{ + { + SolarMutexGuard aGuard; + ScDLL::Init(); + } + // No harm in potentially calling this several times + SC_MOD()->RegisterAutomationApplicationEventsCaller( uno::Reference< XSinkCaller >(this) ); + mvSinks.push_back(xSink); + return mvSinks.size(); +} + +void +ScVbaApplication::RemoveSink( sal_uInt32 nNumber ) +{ + if (nNumber < 1 || nNumber > mvSinks.size()) + return; + + mvSinks[nNumber-1] = uno::Reference< XSink >(); +} + +ScVbaApplication::ScVbaApplication( const uno::Reference<uno::XComponentContext >& xContext ) : + ScVbaApplication_BASE( xContext ), + mrAppSettings( ScVbaStaticAppSettings() ), + m_nDialogType(0) +{ +} + +ScVbaApplication::~ScVbaApplication() +{ +} + +/*static*/ bool ScVbaApplication::getDocumentEventsEnabled() +{ + return ScVbaStaticAppSettings().mbEnableEvents; +} + +OUString SAL_CALL +ScVbaApplication::getExactName( const OUString& aApproximateName ) +{ + uno::Reference< beans::XExactName > xWSF( new ScVbaWSFunction( this, mxContext ) ); + return xWSF->getExactName( aApproximateName ); +} + +uno::Reference< beans::XIntrospectionAccess > SAL_CALL +ScVbaApplication::getIntrospection() +{ + uno::Reference< script::XInvocation > xWSF( new ScVbaWSFunction( this, mxContext ) ); + return xWSF->getIntrospection(); +} + +uno::Any SAL_CALL +ScVbaApplication::invoke( const OUString& FunctionName, const uno::Sequence< uno::Any >& Params, uno::Sequence< sal_Int16 >& OutParamIndex, uno::Sequence< uno::Any >& OutParam) +{ + /* When calling the functions directly at the Application object, no runtime + errors are thrown, but the error is inserted into the return value. */ + uno::Any aAny; + try + { + uno::Reference< script::XInvocation > xWSF( new ScVbaWSFunction( this, mxContext ) ); + aAny = xWSF->invoke( FunctionName, Params, OutParamIndex, OutParam ); + } + catch (const uno::Exception&) + { + aAny <<= script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), 1000, OUString() ); + } + return aAny; +} + +void SAL_CALL +ScVbaApplication::setValue( const OUString& PropertyName, const uno::Any& Value ) +{ + uno::Reference< script::XInvocation > xWSF( new ScVbaWSFunction( this, mxContext ) ); + xWSF->setValue( PropertyName, Value ); +} + +uno::Any SAL_CALL +ScVbaApplication::getValue( const OUString& PropertyName ) +{ + uno::Reference< script::XInvocation > xWSF( new ScVbaWSFunction( this, mxContext ) ); + return xWSF->getValue( PropertyName ); +} + +sal_Bool SAL_CALL +ScVbaApplication::hasMethod( const OUString& Name ) +{ + uno::Reference< script::XInvocation > xWSF( new ScVbaWSFunction( this, mxContext ) ); + return xWSF->hasMethod( Name ); +} + +sal_Bool SAL_CALL +ScVbaApplication::hasProperty( const OUString& Name ) +{ + uno::Reference< script::XInvocation > xWSF( new ScVbaWSFunction( this, mxContext ) ); + return xWSF->hasProperty( Name ); +} + +uno::Reference< excel::XWorkbook > +ScVbaApplication::getActiveWorkbook() +{ + uno::Reference< frame::XModel > xModel( getCurrentExcelDoc( mxContext ), uno::UNO_SET_THROW ); + uno::Reference< excel::XWorkbook > xWorkbook( getVBADocument( xModel ), uno::UNO_QUERY ); + if( xWorkbook.is() ) return xWorkbook; + // #i116936# getVBADocument() may return null in documents without global VBA mode enabled + return new ScVbaWorkbook( this, mxContext, xModel ); +} + +uno::Reference< excel::XWorkbook > SAL_CALL +ScVbaApplication::getThisWorkbook() +{ + uno::Reference< frame::XModel > xModel( getThisExcelDoc( mxContext ), uno::UNO_SET_THROW ); + uno::Reference< excel::XWorkbook > xWorkbook( getVBADocument( xModel ), uno::UNO_QUERY ); + if( xWorkbook.is() ) return xWorkbook; + // #i116936# getVBADocument() may return null in documents without global VBA mode enabled + return new ScVbaWorkbook( this, mxContext, xModel ); +} + +uno::Reference< XAssistant > SAL_CALL +ScVbaApplication::getAssistant() +{ + return uno::Reference< XAssistant >( new ScVbaAssistant( this, mxContext ) ); +} + +uno::Any SAL_CALL +ScVbaApplication::getSelection() +{ + uno::Reference< frame::XModel > xModel( getCurrentDocument() ); + + Reference< view::XSelectionSupplier > xSelSupp( xModel->getCurrentController(), UNO_QUERY_THROW ); + Reference< beans::XPropertySet > xPropSet( xSelSupp, UNO_QUERY_THROW ); + OUString aPropName( SC_UNO_FILTERED_RANGE_SELECTION ); + uno::Any aOldVal = xPropSet->getPropertyValue( aPropName ); + uno::Any any; + any <<= false; + xPropSet->setPropertyValue( aPropName, any ); + uno::Reference<uno::XInterface> aSelection(xSelSupp->getSelection(), uno::UNO_QUERY); + xPropSet->setPropertyValue( aPropName, aOldVal ); + + if (!aSelection.is()) + { + throw uno::RuntimeException( "failed to obtain current selection" ); + } + + uno::Reference< lang::XServiceInfo > xServiceInfo( aSelection, uno::UNO_QUERY_THROW ); + OUString sImplementationName = xServiceInfo->getImplementationName(); + + if( sImplementationName.equalsIgnoreAsciiCase("com.sun.star.drawing.SvxShapeCollection") ) + { + uno::Reference< drawing::XShapes > xShapes( aSelection, uno::UNO_QUERY_THROW ); + uno::Reference< container::XIndexAccess > xIndexAccess( xShapes, uno::UNO_QUERY_THROW ); + uno::Reference< drawing::XShape > xShape( xIndexAccess->getByIndex(0), uno::UNO_QUERY_THROW ); + // if ScVbaShape::getType( xShape ) == office::MsoShapeType::msoAutoShape + // and the uno object implements the com.sun.star.drawing.Text service + // return a textboxshape object + sal_Int32 nType = ScVbaShape::getType( xShape ); + if ( nType == office::MsoShapeType::msoAutoShape ) + { + // TODO Oval with text box + if( ScVbaShape::getAutoShapeType( xShape ) == office::MsoAutoShapeType::msoShapeOval ) + { + return uno::Any( uno::Reference< msforms::XOval >(new ScVbaOvalShape( mxContext, xShape, xShapes, xModel ) ) ); + } + + + uno::Reference< lang::XServiceInfo > xShapeServiceInfo( xShape, uno::UNO_QUERY_THROW ); + if ( xShapeServiceInfo->supportsService("com.sun.star.drawing.Text") ) + { + return uno::Any( uno::Reference< msforms::XTextBoxShape >( + new ScVbaTextBoxShape( mxContext, xShape, xShapes, xModel ) ) ); + } + } + else if ( nType == office::MsoShapeType::msoLine ) + { + return uno::Any( uno::Reference< msforms::XLine >( new ScVbaLineShape( + mxContext, xShape, xShapes, xModel ) ) ); + } + return uno::Any( uno::Reference< msforms::XShape >(new ScVbaShape( this, mxContext, xShape, xShapes, xModel, ScVbaShape::getType( xShape ) ) ) ); + } + else if( xServiceInfo->supportsService("com.sun.star.sheet.SheetCellRange") || + xServiceInfo->supportsService("com.sun.star.sheet.SheetCellRanges") ) + { + uno::Reference< table::XCellRange > xRange( aSelection, ::uno::UNO_QUERY); + if ( !xRange.is() ) + { + uno::Reference< sheet::XSheetCellRangeContainer > xRanges( aSelection, ::uno::UNO_QUERY); + if ( xRanges.is() ) + return uno::Any( uno::Reference< excel::XRange >( new ScVbaRange( excel::getUnoSheetModuleObj( xRanges ), mxContext, xRanges ) ) ); + + } + return uno::Any( uno::Reference< excel::XRange >(new ScVbaRange( excel::getUnoSheetModuleObj( xRange ), mxContext, xRange ) ) ); + } + else + { + throw uno::RuntimeException( sImplementationName + " not supported" ); + } +} + +uno::Reference< excel::XRange > +ScVbaApplication::getActiveCell() +{ + uno::Reference< sheet::XSpreadsheetView > xView( getCurrentDocument()->getCurrentController(), uno::UNO_QUERY_THROW ); + uno::Reference< table::XCellRange > xRange( xView->getActiveSheet(), ::uno::UNO_QUERY_THROW); + ScTabViewShell* pViewShell = excel::getCurrentBestViewShell(mxContext); + if ( !pViewShell ) + throw uno::RuntimeException("No ViewShell available" ); + ScViewData& rTabView = pViewShell->GetViewData(); + + sal_Int32 nCursorX = rTabView.GetCurX(); + sal_Int32 nCursorY = rTabView.GetCurY(); + + // #i117392# excel::getUnoSheetModuleObj() may return null in documents without global VBA mode enabled + return new ScVbaRange( excel::getUnoSheetModuleObj( xRange ), mxContext, xRange->getCellRangeByPosition( nCursorX, nCursorY, nCursorX, nCursorY ) ); +} + +uno::Any SAL_CALL +ScVbaApplication::GetOpenFilename(const uno::Any& /*aFileFilter*/, const uno::Any& /*aFilterIndex*/, const uno::Any& aTitle, const uno::Any& /*aButtonText*/, const uno::Any& aMultiSelect) +{ + // TODO - take all parameters into account + uno::Reference<excel::XFileDialog> xDialog(new ScVbaFileDialog(this, mxContext, office::MsoFileDialogType::msoFileDialogFilePicker)); + xDialog->setTitle(aTitle); + xDialog->setAllowMultiSelect(aMultiSelect); + + bool bMultiSelect = false; + aMultiSelect >>= bMultiSelect; + + if (xDialog->Show() == 0) + { + // return FALSE when canceled + return uno::Any(false); + } + + uno::Reference<excel::XFileDialogSelectedItems> xItems = xDialog->getSelectedItems(); + auto* pItems = dynamic_cast<ScVbaFileDialogSelectedItems*>(xItems.get()); + + // Check, if the implementation of XFileDialogSelectedItems is what we expect + if (!pItems) + throw uno::RuntimeException("Unexpected XFileDialogSelectedItems implementation"); + + auto const & rItemVector = pItems->getItems(); + + if (!bMultiSelect) // only 1 selection allowed - return path + { + OUString aPath; + if (!rItemVector.empty()) + aPath = rItemVector.at(0); + return uno::Any(aPath); + } + else + { + // convert to sequence + return uno::Any(comphelper::containerToSequence(rItemVector)); + } +} + +uno::Any SAL_CALL +ScVbaApplication::International( sal_Int32 /*Index*/ ) +{ + // complete stub for now + // #TODO flesh out some of the Indices we could handle + uno::Any aRet; + return aRet; +} + +uno::Any SAL_CALL +ScVbaApplication::FileDialog( const uno::Any& DialogType ) +{ + sal_Int32 nType = 0; + DialogType >>= nType; + + if( !m_xFileDialog || nType != m_nDialogType ) + { + m_nDialogType = nType; + m_xFileDialog = uno::Reference<excel::XFileDialog> ( new ScVbaFileDialog( this, mxContext, nType )); + } + return uno::Any( m_xFileDialog ); +} + +uno::Any SAL_CALL +ScVbaApplication::Workbooks( const uno::Any& aIndex ) +{ + uno::Reference< XCollection > xWorkBooks( new ScVbaWorkbooks( this, mxContext ) ); + if ( aIndex.getValueTypeClass() == uno::TypeClass_VOID ) + { + // void then somebody did Workbooks.something in vba + return uno::Any( xWorkBooks ); + } + + return xWorkBooks->Item( aIndex, uno::Any() ); +} + +uno::Any SAL_CALL +ScVbaApplication::Worksheets( const uno::Any& aIndex ) +{ + uno::Reference< excel::XWorkbook > xWorkbook( getActiveWorkbook(), uno::UNO_SET_THROW ); + return xWorkbook->Worksheets( aIndex ); +} + +uno::Any SAL_CALL +ScVbaApplication::WorksheetFunction( ) +{ + return uno::Any( uno::Reference< script::XInvocation >( new ScVbaWSFunction( this, mxContext ) ) ); +} + +uno::Any SAL_CALL +ScVbaApplication::Evaluate( const OUString& Name ) +{ + // #TODO Evaluate allows other things to be evaluated, e.g. functions + // I think ( like SIN(3) etc. ) need to investigate that + // named Ranges also? e.g. [MyRange] if so need a list of named ranges + uno::Any aVoid; + return uno::Any( getActiveWorkbook()->getActiveSheet()->Range( uno::Any( Name ), aVoid ) ); +} + +uno::Any +ScVbaApplication::Dialogs( const uno::Any &aIndex ) +{ + uno::Reference< excel::XDialogs > xDialogs( new ScVbaDialogs( uno::Reference< XHelperInterface >( this ), mxContext, getCurrentDocument() ) ); + if( !aIndex.hasValue() ) + return uno::Any( xDialogs ); + return xDialogs->Item( aIndex ); +} + +uno::Reference< excel::XWindow > SAL_CALL +ScVbaApplication::getActiveWindow() +{ + uno::Reference< frame::XModel > xModel = getCurrentDocument(); + uno::Reference< frame::XController > xController( xModel->getCurrentController(), uno::UNO_SET_THROW ); + uno::Reference< XHelperInterface > xParent( getActiveWorkbook(), uno::UNO_QUERY_THROW ); + uno::Reference< excel::XWindow > xWin( new ScVbaWindow( xParent, mxContext, xModel, xController ) ); + return xWin; +} + +uno::Any SAL_CALL +ScVbaApplication::getCutCopyMode() +{ + //# FIXME TODO, implementation + uno::Any result; + result <<= false; + return result; +} + +void SAL_CALL +ScVbaApplication::setCutCopyMode( const uno::Any& /* _cutcopymode */ ) +{ + //# FIXME TODO, implementation +} + +uno::Any SAL_CALL +ScVbaApplication::getStatusBar() +{ + return uno::Any( !getDisplayStatusBar() ); +} + +css::uno::Any SAL_CALL ScVbaApplication::getWindowState() +{ + return getActiveWindow()->getWindowState(); +} + +void SAL_CALL ScVbaApplication::setWindowState(const css::uno::Any& rWindowState) +{ + getActiveWindow()->setWindowState(rWindowState); +} + +void SAL_CALL +ScVbaApplication::setStatusBar( const uno::Any& _statusbar ) +{ + OUString sText; + bool bDefault = false; + uno::Reference< frame::XModel > xModel( getCurrentDocument(), uno::UNO_SET_THROW ); + uno::Reference< task::XStatusIndicatorSupplier > xStatusIndicatorSupplier( xModel->getCurrentController(), uno::UNO_QUERY_THROW ); + uno::Reference< task::XStatusIndicator > xStatusIndicator( xStatusIndicatorSupplier->getStatusIndicator(), uno::UNO_SET_THROW ); + if( _statusbar >>= sText ) + { + setDisplayStatusBar( true ); + if ( !sText.isEmpty() ) + xStatusIndicator->start( sText, 100 ); + else + xStatusIndicator->end(); // restore normal state for empty text + } + else if( _statusbar >>= bDefault ) + { + if( !bDefault ) + { + xStatusIndicator->end(); + setDisplayStatusBar( true ); + } + } + else + throw uno::RuntimeException("Invalid parameter. It should be a string or False" ); +} + +::sal_Int32 SAL_CALL +ScVbaApplication::getCalculation() +{ + // TODO: in Excel, this is an application-wide setting + uno::Reference<sheet::XCalculatable> xCalc(getCurrentDocument(), uno::UNO_QUERY_THROW); + if(xCalc->isAutomaticCalculationEnabled()) + return excel::XlCalculation::xlCalculationAutomatic; + else + return excel::XlCalculation::xlCalculationManual; +} + +void SAL_CALL +ScVbaApplication::setCalculation( ::sal_Int32 _calculation ) +{ + // TODO: in Excel, this is an application-wide setting + uno::Reference< sheet::XCalculatable > xCalc(getCurrentDocument(), uno::UNO_QUERY_THROW); + switch(_calculation) + { + case excel::XlCalculation::xlCalculationManual: + xCalc->enableAutomaticCalculation(false); + break; + case excel::XlCalculation::xlCalculationAutomatic: + case excel::XlCalculation::xlCalculationSemiautomatic: + xCalc->enableAutomaticCalculation(true); + break; + } +} + +uno::Any SAL_CALL +ScVbaApplication::Windows( const uno::Any& aIndex ) +{ + uno::Reference< excel::XWindows > xWindows( new ScVbaWindows( this, mxContext ) ); + if ( aIndex.getValueTypeClass() == uno::TypeClass_VOID ) + return uno::Any( xWindows ); + return xWindows->Item( aIndex, uno::Any() ); +} +void SAL_CALL +ScVbaApplication::wait( double time ) +{ + StarBASIC* pBasic = SfxApplication::GetBasic(); + SbxArrayRef aArgs = new SbxArray; + SbxVariableRef aRef = new SbxVariable; + aRef->PutDouble( time ); + aArgs->Put(aRef.get(), 1); + SbMethod* pMeth = static_cast<SbMethod*>(pBasic->GetRtl()->Find( "WaitUntil", SbxClassType::Method )); + + if ( pMeth ) + { + pMeth->SetParameters( aArgs.get() ); + SbxVariableRef refTemp = pMeth; + // forces a broadcast + SbxVariableRef pNew = new SbxMethod( *static_cast<SbxMethod*>(pMeth)); + } +} + +uno::Any SAL_CALL +ScVbaApplication::Range( const uno::Any& Cell1, const uno::Any& Cell2 ) +{ + uno::Reference< excel::XRange > xVbRange = ScVbaRange::ApplicationRange( mxContext, Cell1, Cell2 ); + return uno::Any( xVbRange ); +} + +uno::Any SAL_CALL +ScVbaApplication::Names( const css::uno::Any& aIndex ) +{ + uno::Reference< frame::XModel > xModel( getCurrentDocument(), uno::UNO_SET_THROW ); + uno::Reference< beans::XPropertySet > xPropertySet( xModel, uno::UNO_QUERY_THROW ); + uno::Reference< sheet::XNamedRanges > xNamedRanges( xPropertySet->getPropertyValue( + "NamedRanges" ), uno::UNO_QUERY_THROW ); + + css::uno::Reference< excel::XNames > xNames ( new ScVbaNames( this , mxContext , xNamedRanges , xModel ) ); + if ( aIndex.getValueTypeClass() == uno::TypeClass_VOID ) + { + return uno::Any( xNames ); + } + return xNames->Item( aIndex, uno::Any() ); +} + +uno::Reference< excel::XWorksheet > SAL_CALL +ScVbaApplication::getActiveSheet() +{ + uno::Reference< excel::XWorksheet > result; + uno::Reference< excel::XWorkbook > xWorkbook = getActiveWorkbook(); + if ( xWorkbook.is() ) + { + uno::Reference< excel::XWorksheet > xWorksheet = + xWorkbook->getActiveSheet(); + if ( xWorksheet.is() ) + { + result = xWorksheet; + } + } + + if ( !result.is() ) + { + // Fixme - check if this is reasonable/desired behavior + throw uno::RuntimeException("No activeSheet available" ); + } + return result; + +} + +/******************************************************************************* + * In msdn: + * Reference Optional Variant. The destination. Can be a Range + * object, a string that contains a cell reference in R1C1-style notation, + * or a string that contains a Visual Basic procedure name. + * Scroll Optional Variant. True to scroll, False to not scroll through + * the window. The default is False. + * Parser is split to three parts, Range, R1C1 string and procedure name. + * by test excel, it seems Scroll no effect. ??? +*******************************************************************************/ +void SAL_CALL +ScVbaApplication::GoTo( const uno::Any& Reference, const uno::Any& Scroll ) +{ + //test Scroll is a boolean + bool bScroll = false; + //R1C1-style string or a string of procedure name. + + if( Scroll.hasValue() ) + { + bool aScroll = false; + if( !(Scroll >>= aScroll) ) + throw uno::RuntimeException("second parameter should be boolean" ); + + bScroll = aScroll; + + } + + OUString sRangeName; + if( Reference >>= sRangeName ) + { + uno::Reference< frame::XModel > xModel( getCurrentDocument(), uno::UNO_SET_THROW ); + uno::Reference< sheet::XSpreadsheetView > xSpreadsheet( + xModel->getCurrentController(), uno::UNO_QUERY_THROW ); + + ScTabViewShell* pShell = excel::getCurrentBestViewShell( mxContext ); + ScGridWindow* gridWindow = static_cast<ScGridWindow*>(pShell->GetWindow()); + try + { + uno::Reference< excel::XRange > xVbaSheetRange = ScVbaRange::getRangeObjectForName( + mxContext, sRangeName, excel::getDocShell( xModel ), formula::FormulaGrammar::CONV_XL_R1C1 ); + + if( bScroll ) + { + xVbaSheetRange->Select(); + uno::Reference< excel::XWindow > xWindow = getActiveWindow(); + ScSplitPos eWhich = pShell->GetViewData().GetActivePart(); + sal_Int32 nValueX = pShell->GetViewData().GetPosX(WhichH(eWhich)); + sal_Int32 nValueY = pShell->GetViewData().GetPosY(WhichV(eWhich)); + xWindow->SmallScroll( uno::Any( static_cast<sal_Int16>(xVbaSheetRange->getRow() - 1) ), + uno::Any( static_cast<sal_Int16>(nValueY) ), + uno::Any( static_cast<sal_Int16>(xVbaSheetRange->getColumn() - 1) ), + uno::Any( static_cast<sal_Int16>(nValueX) ) ); + gridWindow->GrabFocus(); + } + else + { + xVbaSheetRange->Select(); + gridWindow->GrabFocus(); + } + } + catch (const uno::RuntimeException&) + { + //maybe this should be a procedure name + //TODO for procedure name + //browse::XBrowseNodeFactory is a singleton. OUString( "/singletons/com.sun.star.script.browse.theBrowseNodeFactory") + //and the createView( browse::BrowseNodeFactoryViewTypes::MACROSELECTOR ) to get a root browse::XBrowseNode. + //for query XInvocation interface. + //but how to directly get the XInvocation? + throw uno::RuntimeException("invalid reference for range name, it should be procedure name" ); + } + return; + } + uno::Reference< excel::XRange > xRange; + if( Reference >>= xRange ) + { + uno::Reference< excel::XRange > xVbaRange( Reference, uno::UNO_QUERY ); + ScTabViewShell* pShell = excel::getCurrentBestViewShell( mxContext ); + ScGridWindow* gridWindow = static_cast<ScGridWindow*>(pShell->GetWindow()); + if ( xVbaRange.is() ) + { + //TODO bScroll should be used. At this time, it does not have effect + if( bScroll ) + { + xVbaRange->Select(); + uno::Reference< excel::XWindow > xWindow = getActiveWindow(); + ScSplitPos eWhich = pShell->GetViewData().GetActivePart(); + sal_Int32 nValueX = pShell->GetViewData().GetPosX(WhichH(eWhich)); + sal_Int32 nValueY = pShell->GetViewData().GetPosY(WhichV(eWhich)); + xWindow->SmallScroll( uno::Any( static_cast<sal_Int16>(xVbaRange->getRow() - 1) ), + uno::Any( static_cast<sal_Int16>(nValueY) ), + uno::Any( static_cast<sal_Int16>(xVbaRange->getColumn() - 1) ), + uno::Any( static_cast<sal_Int16>(nValueX) ) ); + gridWindow->GrabFocus(); + } + else + { + xVbaRange->Select(); + gridWindow->GrabFocus(); + } + } + return; + } + throw uno::RuntimeException("invalid reference or name" ); +} + +sal_Int32 SAL_CALL +ScVbaApplication::getCursor() +{ + PointerStyle nPointerStyle = getPointerStyle(getCurrentDocument()); + + switch( nPointerStyle ) + { + case PointerStyle::Arrow: + return excel::XlMousePointer::xlNorthwestArrow; + case PointerStyle::Null: + return excel::XlMousePointer::xlDefault; + case PointerStyle::Wait: + return excel::XlMousePointer::xlWait; + case PointerStyle::Text: + return excel::XlMousePointer::xlIBeam; + default: + return excel::XlMousePointer::xlDefault; + } +} + +void SAL_CALL +ScVbaApplication::setCursor( sal_Int32 _cursor ) +{ + try + { + uno::Reference< frame::XModel > xModel( getCurrentDocument(), uno::UNO_SET_THROW ); + switch( _cursor ) + { + case excel::XlMousePointer::xlNorthwestArrow: + { + setCursorHelper( xModel, PointerStyle::Arrow, false ); + break; + } + case excel::XlMousePointer::xlWait: + case excel::XlMousePointer::xlIBeam: + { + PointerStyle nPointer( static_cast< PointerStyle >( _cursor ) ); + //It will set the edit window, toobar and statusbar's mouse pointer. + setCursorHelper( xModel, nPointer, true ); + break; + } + case excel::XlMousePointer::xlDefault: + { + setCursorHelper( xModel, PointerStyle::Null, false ); + break; + } + default: + throw uno::RuntimeException("Unknown value for Cursor pointer" ); + // TODO: isn't this a flaw in the API? It should be allowed to throw an + // IllegalArgumentException, or so + } + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("sc.ui"); + } +} + +// #TODO perhaps we should switch the return type depending of the filter +// type, e.g. return Calc for Calc and Excel if it's an imported doc +OUString SAL_CALL +ScVbaApplication::getName() +{ + return "Microsoft Excel"; +} + +// #TODO #FIXME get/setDisplayAlerts are just stub impl +// here just the status of the switch is set +// the function that throws an error message needs to +// evaluate this switch in order to know whether it has to disable the +// error message thrown by OpenOffice + +void SAL_CALL +ScVbaApplication::setDisplayAlerts(sal_Bool displayAlerts) +{ + mrAppSettings.mbDisplayAlerts = displayAlerts; +} + +sal_Bool SAL_CALL +ScVbaApplication::getDisplayAlerts() +{ + return mrAppSettings.mbDisplayAlerts; +} + +void SAL_CALL +ScVbaApplication::setEnableEvents(sal_Bool bEnable) +{ + mrAppSettings.mbEnableEvents = bEnable; +} + +sal_Bool SAL_CALL +ScVbaApplication::getEnableEvents() +{ + return mrAppSettings.mbEnableEvents; +} + +void SAL_CALL +ScVbaApplication::setEnableCancelKey(sal_Bool bEnable) +{ + // Stub, does nothing + mrAppSettings.mbEnableCancelKey = bEnable; +} + +sal_Bool SAL_CALL +ScVbaApplication::getEnableCancelKey() +{ + return mrAppSettings.mbEnableCancelKey; +} + +sal_Bool SAL_CALL +ScVbaApplication::getDisplayFullScreen() +{ + SfxViewShell* pShell = excel::getCurrentBestViewShell( mxContext ); + if ( pShell ) + return ScViewUtil::IsFullScreen( *pShell ); + return false; +} + +void SAL_CALL +ScVbaApplication::setDisplayFullScreen( sal_Bool bSet ) +{ + // #FIXME calling ScViewUtil::SetFullScreen( *pShell, bSet ); + // directly results in a strange crash, using dispatch instead + if ( bSet != getDisplayFullScreen() ) + dispatchRequests( getCurrentDocument(), ".uno:FullScreen" ); +} + +sal_Bool SAL_CALL +ScVbaApplication::getDisplayScrollBars() +{ + ScTabViewShell* pShell = excel::getCurrentBestViewShell( mxContext ); + if ( pShell ) + { + return ( pShell->GetViewData().IsHScrollMode() && pShell->GetViewData().IsVScrollMode() ); + } + return true; +} + +void SAL_CALL +ScVbaApplication::setDisplayScrollBars( sal_Bool bSet ) +{ + // use uno here as it does all he repainting etc. magic + uno::Reference< sheet::XSpreadsheetView > xView( getCurrentDocument()->getCurrentController(), uno::UNO_QUERY_THROW ); + uno::Reference< beans::XPropertySet > xProps( xView, uno::UNO_QUERY ); + xProps->setPropertyValue("HasVerticalScrollBar", uno::Any( bSet ) ); + xProps->setPropertyValue("HasHorizontalScrollBar", uno::Any( bSet ) ); +} + +sal_Bool SAL_CALL +ScVbaApplication::getDisplayExcel4Menus() +{ + return mrAppSettings.mbExcel4Menus; +} + +void SAL_CALL +ScVbaApplication::setDisplayExcel4Menus( sal_Bool bSet ) +{ + mrAppSettings.mbExcel4Menus = bSet; +} + +sal_Bool SAL_CALL +ScVbaApplication::getDisplayNoteIndicator() +{ + return mrAppSettings.mbDisplayNoteIndicator; +} + +void SAL_CALL +ScVbaApplication::setDisplayNoteIndicator( sal_Bool bSet ) +{ + mrAppSettings.mbDisplayNoteIndicator = bSet; +} + +sal_Bool SAL_CALL +ScVbaApplication::getShowWindowsInTaskbar() +{ + return mrAppSettings.mbShowWindowsInTaskbar; +} + +void SAL_CALL +ScVbaApplication::setShowWindowsInTaskbar( sal_Bool bSet ) +{ + mrAppSettings.mbShowWindowsInTaskbar = bSet; +} + +sal_Bool SAL_CALL +ScVbaApplication::getIteration() +{ + return SC_MOD()->GetDocOptions().IsIter(); +} + +void SAL_CALL +ScVbaApplication::setIteration( sal_Bool bSet ) +{ + uno::Reference< lang::XMultiComponentFactory > xSMgr( + mxContext->getServiceManager(), uno::UNO_SET_THROW ); + + uno::Reference< frame::XDesktop > xDesktop + (xSMgr->createInstanceWithContext( "com.sun.star.frame.Desktop" , mxContext), uno::UNO_QUERY_THROW ); + uno::Reference< container::XEnumeration > xComponents = xDesktop->getComponents()->createEnumeration(); + while ( xComponents->hasMoreElements() ) + { + uno::Reference< lang::XServiceInfo > xServiceInfo( xComponents->nextElement(), uno::UNO_QUERY ); + if ( xServiceInfo.is() && xServiceInfo->supportsService( "com.sun.star.sheet.SpreadsheetDocument" ) ) + { + uno::Reference< beans::XPropertySet > xProps( xServiceInfo, uno::UNO_QUERY ); + if ( xProps.is() ) + xProps->setPropertyValue( SC_UNO_ITERENABLED, uno::Any( bSet ) ); + } + } + ScDocOptions aOpts( SC_MOD()->GetDocOptions() ); + aOpts.SetIter( bSet ); + SC_MOD()->SetDocOptions( aOpts ); +} + +void SAL_CALL +ScVbaApplication::Calculate() +{ + uno::Reference< frame::XModel > xModel( getCurrentDocument(), uno::UNO_SET_THROW ); + uno::Reference< sheet::XCalculatable > xCalculatable( getCurrentDocument(), uno::UNO_QUERY_THROW ); + xCalculatable->calculateAll(); +} + +/// @throws uno::RuntimeException +static uno::Reference< util::XPathSettings > const & lcl_getPathSettingsService( const uno::Reference< uno::XComponentContext >& xContext ) +{ + static uno::Reference< util::XPathSettings > xPathSettings( util::PathSettings::create( xContext ) ); + return xPathSettings; +} + +OUString ScVbaApplication::getOfficePath( const OUString& _sPathType ) +{ + OUString sRetPath; + const uno::Reference< util::XPathSettings >& xProps = lcl_getPathSettingsService( mxContext ); + try + { + OUString sUrl; + xProps->getPropertyValue( _sPathType ) >>= sUrl; + + // if it's a list of paths then use the last one + sal_Int32 nIndex = sUrl.lastIndexOf( ';' ) ; + if ( nIndex > 0 ) + sUrl = sUrl.copy( nIndex + 1 ); + ::osl::File::getSystemPathFromFileURL( sUrl, sRetPath ); + } + catch (const uno::Exception&) + { + DebugHelper::runtimeexception(ERRCODE_BASIC_METHOD_FAILED); + } + return sRetPath; +} + +void SAL_CALL +ScVbaApplication::setDefaultFilePath( const OUString& DefaultFilePath ) +{ + const uno::Reference< util::XPathSettings >& xProps = lcl_getPathSettingsService( mxContext ); + OUString aURL; + osl::FileBase::getFileURLFromSystemPath( DefaultFilePath, aURL ); + xProps->setWork( aURL ); +} + +OUString SAL_CALL +ScVbaApplication::getDefaultFilePath() +{ + return getOfficePath( "Work"); +} + +OUString SAL_CALL +ScVbaApplication::getLibraryPath() +{ + return getOfficePath( "Basic"); +} + +OUString SAL_CALL +ScVbaApplication::getTemplatesPath() +{ + return getOfficePath( "Template"); +} + +OUString SAL_CALL +ScVbaApplication::getPathSeparator() +{ + return OUString( sal_Unicode(SAL_PATHDELIMITER) ); +} + +OUString SAL_CALL +ScVbaApplication::getOperatingSystem() +{ + // TODO Solution should contain the version number of the operating system + // too. +#if defined(_WIN32) + return "Windows"; +#elif defined(MACOSX) + return "Macintosh"; +#elif defined(UNX) + // M. Office is not available on Unix systems, so it is not documented. + return "Unix"; +#else + return OUString("Unknown"); +#endif +} + +// Helpers for Intersect and Union + +namespace { + +typedef ::std::list< ScRange > ListOfScRange; + +/** Appends all ranges of a VBA Range object in the passed Any to the list of ranges. + + @throws script::BasicErrorException + @throws uno::RuntimeException +*/ +void lclAddToListOfScRange( ListOfScRange& rList, const uno::Any& rArg ) +{ + if( !rArg.hasValue() ) + return; + + uno::Reference< excel::XRange > xRange( rArg, uno::UNO_QUERY_THROW ); + uno::Reference< XCollection > xCol( xRange->Areas( uno::Any() ), uno::UNO_QUERY_THROW ); + for( sal_Int32 nIdx = 1, nCount = xCol->getCount(); nIdx <= nCount; ++nIdx ) + { + uno::Reference< excel::XRange > xAreaRange( xCol->Item( uno::Any( nIdx ), uno::Any() ), uno::UNO_QUERY_THROW ); + uno::Reference< sheet::XCellRangeAddressable > xAddressable( xAreaRange->getCellRange(), uno::UNO_QUERY_THROW ); + ScRange aScRange; + ScUnoConversion::FillScRange( aScRange, xAddressable->getRangeAddress() ); + rList.push_back( aScRange ); + } +} + +/** Returns true, if the passed ranges can be expressed by a single range. The + new range will be contained in r1 then, the range r2 can be removed. */ +bool lclTryJoin( ScRange& r1, const ScRange& r2 ) +{ + // 1) r2 is completely inside r1 + if( r1.Contains( r2 ) ) + return true; + + // 2) r1 is completely inside r2 + if( r2.Contains( r1 ) ) + { + r1 = r2; + return true; + } + + SCCOL n1L = r1.aStart.Col(); + SCCOL n1R = r1.aEnd.Col(); + SCROW n1T = r1.aStart.Row(); + SCROW n1B = r1.aEnd.Row(); + SCCOL n2L = r2.aStart.Col(); + SCCOL n2R = r2.aEnd.Col(); + SCROW n2T = r2.aStart.Row(); + SCROW n2B = r2.aEnd.Row(); + + // 3) r1 and r2 have equal upper and lower border + if( (n1T == n2T) && (n1B == n2B) ) + { + // check that r1 overlaps or touches r2 + if( ((n1L < n2L) && (n2L - 1 <= n1R)) || ((n2L < n1L) && (n1L - 1 <= n2R)) ) + { + r1.aStart.SetCol( ::std::min( n1L, n2L ) ); + r1.aEnd.SetCol( ::std::max( n1R, n2R ) ); + return true; + } + return false; + } + + // 4) r1 and r2 have equal left and right border + if( (n1L == n2L) && (n1R == n2R) ) + { + // check that r1 overlaps or touches r2 + if( ((n1T < n2T) && (n2T + 1 <= n1B)) || ((n2T < n1T) && (n1T + 1 <= n2B)) ) + { + r1.aStart.SetRow( ::std::min( n1T, n2T ) ); + r1.aEnd.SetRow( ::std::max( n1B, n2B ) ); + return true; + } + return false; + } + + // 5) cannot join these ranges + return false; +} + +/** Strips out ranges that are contained by other ranges, joins ranges that can be joined + together (aligned borders, e.g. A4:D10 and B4:E10 would be combined to A4:E10. */ +void lclJoinRanges( ListOfScRange& rList ) +{ + ListOfScRange::iterator aOuterIt = rList.begin(); + while( aOuterIt != rList.end() ) + { + bool bAnyErased = false; // true = any range erased from rList + ListOfScRange::iterator aInnerIt = rList.begin(); + while( aInnerIt != rList.end() ) + { + bool bInnerErased = false; // true = aInnerIt erased from rList + // do not compare a range with itself + if( (aOuterIt != aInnerIt) && lclTryJoin( *aOuterIt, *aInnerIt ) ) + { + // aOuterIt points to joined range, aInnerIt will be removed + aInnerIt = rList.erase( aInnerIt ); + bInnerErased = bAnyErased = true; + } + /* If aInnerIt has been erased from rList, it already points to + the next element (return value of list::erase()). */ + if( !bInnerErased ) + ++aInnerIt; + } + // if any range has been erased, repeat outer loop with the same range + if( !bAnyErased ) + ++aOuterIt; + } +} + +/** Intersects the passed list with all ranges of a VBA Range object in the passed Any. + + @throws script::BasicErrorException + @throws uno::RuntimeException +*/ +void lclIntersectRanges( ListOfScRange& rList, const uno::Any& rArg ) +{ + // extract the ranges from the passed argument, will throw on invalid data + ListOfScRange aList2; + lclAddToListOfScRange( aList2, rArg ); + // do nothing, if the passed list is already empty + if( rList.empty() || aList2.empty() ) + return; + + // save original list in a local + ListOfScRange aList1; + aList1.swap( rList ); + // join ranges from passed argument + lclJoinRanges( aList2 ); + // calculate intersection of the ranges in both lists + for( const auto& rOuterItem : aList1 ) + { + for( const auto& rInnerItem : aList2 ) + { + if( rOuterItem.Intersects( rInnerItem ) ) + { + ScRange aIsectRange( + std::max( rOuterItem.aStart.Col(), rInnerItem.aStart.Col() ), + std::max( rOuterItem.aStart.Row(), rInnerItem.aStart.Row() ), + std::max( rOuterItem.aStart.Tab(), rInnerItem.aStart.Tab() ), + std::min( rOuterItem.aEnd.Col(), rInnerItem.aEnd.Col() ), + std::min( rOuterItem.aEnd.Row(), rInnerItem.aEnd.Row() ), + std::min( rOuterItem.aEnd.Tab(), rInnerItem.aEnd.Tab() ) ); + rList.push_back( aIsectRange ); + } + } + } + // again, join the result ranges + lclJoinRanges( rList ); +} + +/** Creates a VBA Range object from the passed list of ranges. + + @throws uno::RuntimeException +*/ +uno::Reference< excel::XRange > lclCreateVbaRange( + const uno::Reference< uno::XComponentContext >& rxContext, + const uno::Reference< frame::XModel >& rxModel, + const ListOfScRange& rList ) +{ + ScDocShell* pDocShell = excel::getDocShell( rxModel ); + if( !pDocShell ) throw uno::RuntimeException(); + + ScRangeList aCellRanges; + for( const auto& rItem : rList ) + aCellRanges.push_back( rItem ); + + if( aCellRanges.size() == 1 ) + { + uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( pDocShell, aCellRanges.front() ) ); + return new ScVbaRange( excel::getUnoSheetModuleObj( xRange ), rxContext, xRange ); + } + if( aCellRanges.size() > 1 ) + { + uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( pDocShell, aCellRanges ) ); + return new ScVbaRange( excel::getUnoSheetModuleObj( xRanges ), rxContext, xRanges ); + } + return nullptr; +} + +} // namespace + +uno::Reference< excel::XRange > SAL_CALL ScVbaApplication::Intersect( + const uno::Reference< excel::XRange >& rArg1, const uno::Reference< excel::XRange >& rArg2, + const uno::Any& rArg3, const uno::Any& rArg4, const uno::Any& rArg5, const uno::Any& rArg6, + const uno::Any& rArg7, const uno::Any& rArg8, const uno::Any& rArg9, const uno::Any& rArg10, + const uno::Any& rArg11, const uno::Any& rArg12, const uno::Any& rArg13, const uno::Any& rArg14, + const uno::Any& rArg15, const uno::Any& rArg16, const uno::Any& rArg17, const uno::Any& rArg18, + const uno::Any& rArg19, const uno::Any& rArg20, const uno::Any& rArg21, const uno::Any& rArg22, + const uno::Any& rArg23, const uno::Any& rArg24, const uno::Any& rArg25, const uno::Any& rArg26, + const uno::Any& rArg27, const uno::Any& rArg28, const uno::Any& rArg29, const uno::Any& rArg30 ) +{ + if( !rArg1.is() || !rArg2.is() ) + DebugHelper::basicexception( ERRCODE_BASIC_BAD_PARAMETER, {} ); + + // initialize the result list with 1st parameter, join its ranges together + ListOfScRange aList; + lclAddToListOfScRange( aList, uno::Any( rArg1 ) ); + lclJoinRanges( aList ); + + // process all other parameters, this updates the list with intersection + lclIntersectRanges( aList, uno::Any( rArg2 ) ); + lclIntersectRanges( aList, rArg3 ); + lclIntersectRanges( aList, rArg4 ); + lclIntersectRanges( aList, rArg5 ); + lclIntersectRanges( aList, rArg6 ); + lclIntersectRanges( aList, rArg7 ); + lclIntersectRanges( aList, rArg8 ); + lclIntersectRanges( aList, rArg9 ); + lclIntersectRanges( aList, rArg10 ); + lclIntersectRanges( aList, rArg11 ); + lclIntersectRanges( aList, rArg12 ); + lclIntersectRanges( aList, rArg13 ); + lclIntersectRanges( aList, rArg14 ); + lclIntersectRanges( aList, rArg15 ); + lclIntersectRanges( aList, rArg16 ); + lclIntersectRanges( aList, rArg17 ); + lclIntersectRanges( aList, rArg18 ); + lclIntersectRanges( aList, rArg19 ); + lclIntersectRanges( aList, rArg20 ); + lclIntersectRanges( aList, rArg21 ); + lclIntersectRanges( aList, rArg22 ); + lclIntersectRanges( aList, rArg23 ); + lclIntersectRanges( aList, rArg24 ); + lclIntersectRanges( aList, rArg25 ); + lclIntersectRanges( aList, rArg26 ); + lclIntersectRanges( aList, rArg27 ); + lclIntersectRanges( aList, rArg28 ); + lclIntersectRanges( aList, rArg29 ); + lclIntersectRanges( aList, rArg30 ); + + // create the VBA Range object + return lclCreateVbaRange( mxContext, getCurrentDocument(), aList ); +} + +uno::Reference< excel::XRange > SAL_CALL ScVbaApplication::Union( + const uno::Reference< excel::XRange >& rArg1, const uno::Reference< excel::XRange >& rArg2, + const uno::Any& rArg3, const uno::Any& rArg4, const uno::Any& rArg5, const uno::Any& rArg6, + const uno::Any& rArg7, const uno::Any& rArg8, const uno::Any& rArg9, const uno::Any& rArg10, + const uno::Any& rArg11, const uno::Any& rArg12, const uno::Any& rArg13, const uno::Any& rArg14, + const uno::Any& rArg15, const uno::Any& rArg16, const uno::Any& rArg17, const uno::Any& rArg18, + const uno::Any& rArg19, const uno::Any& rArg20, const uno::Any& rArg21, const uno::Any& rArg22, + const uno::Any& rArg23, const uno::Any& rArg24, const uno::Any& rArg25, const uno::Any& rArg26, + const uno::Any& rArg27, const uno::Any& rArg28, const uno::Any& rArg29, const uno::Any& rArg30 ) +{ + if( !rArg1.is() || !rArg2.is() ) + DebugHelper::basicexception( ERRCODE_BASIC_BAD_PARAMETER, {} ); + + ListOfScRange aList; + lclAddToListOfScRange( aList, uno::Any( rArg1 ) ); + lclAddToListOfScRange( aList, uno::Any( rArg2 ) ); + lclAddToListOfScRange( aList, rArg3 ); + lclAddToListOfScRange( aList, rArg4 ); + lclAddToListOfScRange( aList, rArg5 ); + lclAddToListOfScRange( aList, rArg6 ); + lclAddToListOfScRange( aList, rArg7 ); + lclAddToListOfScRange( aList, rArg8 ); + lclAddToListOfScRange( aList, rArg9 ); + lclAddToListOfScRange( aList, rArg10 ); + lclAddToListOfScRange( aList, rArg11 ); + lclAddToListOfScRange( aList, rArg12 ); + lclAddToListOfScRange( aList, rArg13 ); + lclAddToListOfScRange( aList, rArg14 ); + lclAddToListOfScRange( aList, rArg15 ); + lclAddToListOfScRange( aList, rArg16 ); + lclAddToListOfScRange( aList, rArg17 ); + lclAddToListOfScRange( aList, rArg18 ); + lclAddToListOfScRange( aList, rArg19 ); + lclAddToListOfScRange( aList, rArg20 ); + lclAddToListOfScRange( aList, rArg21 ); + lclAddToListOfScRange( aList, rArg22 ); + lclAddToListOfScRange( aList, rArg23 ); + lclAddToListOfScRange( aList, rArg24 ); + lclAddToListOfScRange( aList, rArg25 ); + lclAddToListOfScRange( aList, rArg26 ); + lclAddToListOfScRange( aList, rArg27 ); + lclAddToListOfScRange( aList, rArg28 ); + lclAddToListOfScRange( aList, rArg29 ); + lclAddToListOfScRange( aList, rArg30 ); + + // simply join together all ranges as much as possible, strip out covered ranges etc. + lclJoinRanges( aList ); + + // create the VBA Range object + return lclCreateVbaRange( mxContext, getCurrentDocument(), aList ); +} + +double +ScVbaApplication::InchesToPoints( double Inches ) +{ + double result = Inches * 72.0; + return result; +} + +void +ScVbaApplication::Volatile( const uno::Any& aVolatile ) +{ + bool bVolatile = true; + aVolatile >>= bVolatile; + SbMethod* pMeth = StarBASIC::GetActiveMethod(); + if ( pMeth ) + { + uno::Reference< frame::XModel > xModel( getCurrentDocument() ); + ScDocument& rDoc = excel::getDocShell( xModel )->GetDocument(); + rDoc.GetMacroManager()->SetUserFuncVolatile( pMeth->GetName(), bVolatile); + } + +// this is bound to break when loading the document +} + +sal_Bool SAL_CALL +ScVbaApplication::getDisplayFormulaBar() +{ + bool bRes = false; + ScTabViewShell* pViewShell = excel::getCurrentBestViewShell( mxContext ); + if ( pViewShell ) + { + SfxBoolItem sfxFormBar( FID_TOGGLEINPUTLINE); + SfxAllItemSet reqList( SfxGetpApp()->GetPool() ); + reqList.Put( sfxFormBar ); + + pViewShell->GetState( reqList ); + if ( const SfxBoolItem *pItem = reqList.GetItemIfSet( FID_TOGGLEINPUTLINE, false ) ) + bRes = pItem->GetValue(); + } + return bRes; +} + +void SAL_CALL +ScVbaApplication::setDisplayFormulaBar( sal_Bool _displayformulabar ) +{ + ScTabViewShell* pViewShell = excel::getCurrentBestViewShell( mxContext ); + if ( pViewShell && ( _displayformulabar != getDisplayFormulaBar() ) ) + { + SfxAllItemSet reqList( SfxGetpApp()->GetPool() ); + SfxRequest aReq( FID_TOGGLEINPUTLINE, SfxCallMode::SLOT, reqList ); + pViewShell->Execute( aReq ); + } +} + +uno::Any SAL_CALL +ScVbaApplication::Caller( const uno::Any& /*aIndex*/ ) +{ + StarBASIC* pBasic = SfxApplication::GetBasic(); + SbMethod* pMeth = static_cast<SbMethod*>(pBasic->GetRtl()->Find( "FuncCaller", SbxClassType::Method )); + uno::Any aRet; + if ( pMeth ) + { + SbxVariableRef refTemp = pMeth; + // forces a broadcast + SbxVariableRef pNew = new SbxMethod( *static_cast<SbxMethod*>(pMeth)); + aRet = sbxToUnoValue( pNew.get() ); + } + return aRet; +} + +uno::Reference< frame::XModel > +ScVbaApplication::getCurrentDocument() +{ + return getCurrentExcelDoc(mxContext); +} + +uno::Any SAL_CALL +ScVbaApplication::MenuBars( const uno::Any& aIndex ) +{ + uno::Reference< XCommandBars > xCommandBars( CommandBars( uno::Any() ), uno::UNO_QUERY_THROW ); + uno::Reference< XCollection > xMenuBars( new ScVbaMenuBars( this, mxContext, xCommandBars ) ); + if ( aIndex.hasValue() ) + { + return xMenuBars->Item( aIndex, uno::Any() ); + } + + return uno::Any( xMenuBars ); +} + +uno::Any SAL_CALL +ScVbaApplication::Rows( const uno::Any& aIndex ) +{ + uno::Reference< excel::XWorksheet > xWorksheet = getActiveSheet(); + if ( xWorksheet.is() ) + return uno::Any( xWorksheet->Rows( aIndex ) ); + return uno::Any(); +} + +void SAL_CALL ScVbaApplication::OnKey( const OUString& Key, const uno::Any& Procedure ) +{ + try + { + // Perhaps we can catch some excel specific + // related behaviour here + VbaApplicationBase::OnKey( Key, Procedure ); + } + catch( container::NoSuchElementException& ) + { + // #TODO special handling for unhandled + // bindings + } +} + +void SAL_CALL ScVbaApplication::setScreenUpdating(sal_Bool bUpdate) +{ + VbaApplicationBase::setScreenUpdating( bUpdate ); + + uno::Reference< frame::XModel > xModel( getCurrentExcelDoc( mxContext ), uno::UNO_SET_THROW ); + ScDocShell* pDocShell = excel::getDocShell( xModel ); + ScDocument& rDoc = pDocShell->GetDocument(); + + if( bUpdate ) + { + // Since setting ScreenUpdating from user code might be unpaired, avoid calling function, + // that asserts correct lock/unlock order and number, when not locked. + if(rDoc.IsAdjustHeightLocked()) + rDoc.UnlockAdjustHeight(); + if( !rDoc.IsAdjustHeightLocked() ) + pDocShell->UpdateAllRowHeights(); + } + else + { + rDoc.LockAdjustHeight(); + } +} + +void SAL_CALL ScVbaApplication::Undo() +{ + uno::Reference< frame::XModel > xModel( getThisExcelDoc( mxContext ), uno::UNO_SET_THROW ); + + ScTabViewShell* pViewShell = excel::getBestViewShell( xModel ); + if ( pViewShell ) + dispatchExecute( pViewShell, SID_UNDO ); +} + +// XInterfaceWithIID + +OUString SAL_CALL +ScVbaApplication::getIID() +{ + return "{82154425-0FBF-11d4-8313-005004526AB4}"; +} + +// XConnectable + +OUString SAL_CALL +ScVbaApplication::GetIIDForClassItselfNotCoclass() +{ + return "{82154426-0FBF-11D4-8313-005004526AB4}"; +} + +TypeAndIID SAL_CALL +ScVbaApplication::GetConnectionPoint() +{ + TypeAndIID aResult = + { excel::XApplicationOutgoing::static_type(), + "{82154427-0FBF-11D4-8313-005004526AB4}" + }; + + return aResult; +} + +uno::Reference<XConnectionPoint> SAL_CALL +ScVbaApplication::FindConnectionPoint() +{ + uno::Reference<XConnectionPoint> xCP(new ScVbaApplicationOutgoingConnectionPoint(this)); + return xCP; +} + +// XSinkCaller + +void SAL_CALL +ScVbaApplication::CallSinks( const OUString& Method, uno::Sequence< uno::Any >& Arguments ) +{ + for (auto& i : mvSinks) + { + if (i.is()) + i->Call(Method, Arguments); + } +} + +OUString +ScVbaApplication::getServiceImplName() +{ + return "ScVbaApplication"; +} + +uno::Sequence< OUString > +ScVbaApplication::getServiceNames() +{ + static uno::Sequence< OUString > aServiceNames + { + "ooo.vba.excel.Application" + }; + return aServiceNames; +} + + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +Calc_ScVbaApplication_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& ) +{ + return cppu::acquire(new ScVbaApplication(context)); +} + + +// ScVbaApplicationOutgoingConnectionPoint + +ScVbaApplicationOutgoingConnectionPoint::ScVbaApplicationOutgoingConnectionPoint( ScVbaApplication* pApp ) : + mpApp(pApp) +{ +} + +// XConnectionPoint +sal_uInt32 SAL_CALL +ScVbaApplicationOutgoingConnectionPoint::Advise( const uno::Reference< XSink >& Sink ) +{ + return mpApp->AddSink(Sink); +} + +void SAL_CALL +ScVbaApplicationOutgoingConnectionPoint::Unadvise( sal_uInt32 Cookie ) +{ + mpApp->RemoveSink( Cookie ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaapplication.hxx b/sc/source/ui/vba/vbaapplication.hxx new file mode 100644 index 000000000..db9c91cdd --- /dev/null +++ b/sc/source/ui/vba/vbaapplication.hxx @@ -0,0 +1,168 @@ +/* -*- 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 . + */ +#pragma once + +#include <vector> + +#include <ooo/vba/XSinkCaller.hpp> +#include <ooo/vba/excel/XApplication.hpp> + +#include <vbahelper/vbaapplicationbase.hxx> +#include <cppuhelper/implbase.hxx> + +namespace com::sun::star::uno { class XComponentContext; } +namespace ooo::vba { class XSink; } +namespace ooo::vba::excel { class XFileDialog; } + +typedef cppu::ImplInheritanceHelper< VbaApplicationBase, ov::excel::XApplication, ov::XSinkCaller > ScVbaApplication_BASE; + +struct ScVbaAppSettings; + +class ScVbaApplication : public ScVbaApplication_BASE +{ +private: + // note: member variables moved to struct "ScVbaAppSettings", see cxx file, to be shared by all application instances + ScVbaAppSettings& mrAppSettings; + + // must be stored in order to get result paths from the same instance + css::uno::Reference< ov::excel::XFileDialog > m_xFileDialog; + sal_Int32 m_nDialogType; + + /// @throws css::uno::RuntimeException + OUString getOfficePath( const OUString& sPath ); + + std::vector<css::uno::Reference< ooo::vba::XSink >> mvSinks; + +protected: + virtual css::uno::Reference< css::frame::XModel > getCurrentDocument() override; + +public: + explicit ScVbaApplication( const css::uno::Reference< css::uno::XComponentContext >& m_xContext ); + virtual ~ScVbaApplication() override; + + /** Returns true, if VBA document events are enabled. */ + static bool getDocumentEventsEnabled(); + + sal_uInt32 AddSink( const css::uno::Reference< ooo::vba::XSink >& xSink ); + void RemoveSink( sal_uInt32 nNumber ); + + // XExactName + virtual OUString SAL_CALL getExactName( const OUString& aApproximateName ) override; + + // XInvocation + virtual css::uno::Reference< css::beans::XIntrospectionAccess > SAL_CALL getIntrospection() override; + virtual css::uno::Any SAL_CALL invoke(const OUString& FunctionName, const css::uno::Sequence< css::uno::Any >& Params, css::uno::Sequence< sal_Int16 >& OutParamIndex, css::uno::Sequence< css::uno::Any >& OutParam) override; + virtual void SAL_CALL setValue(const OUString& PropertyName, const css::uno::Any& Value) override; + virtual css::uno::Any SAL_CALL getValue(const OUString& PropertyName) override; + virtual sal_Bool SAL_CALL hasMethod(const OUString& Name) override; + virtual sal_Bool SAL_CALL hasProperty(const OUString& Name) override; + + // XApplication + virtual void SAL_CALL setDefaultFilePath( const OUString& DefaultFilePath ) override; + virtual OUString SAL_CALL getDefaultFilePath() override; + virtual OUString SAL_CALL getPathSeparator() override; + virtual OUString SAL_CALL getLibraryPath() override; + virtual OUString SAL_CALL getTemplatesPath() override; + virtual OUString SAL_CALL getOperatingSystem() override; + + virtual OUString SAL_CALL getName() override; + virtual sal_Bool SAL_CALL getDisplayAlerts() override; + virtual void SAL_CALL setDisplayAlerts( sal_Bool displayAlerts ) override; + virtual ::sal_Int32 SAL_CALL getCalculation() override; + virtual void SAL_CALL setCalculation( ::sal_Int32 _calculation ) override; + virtual css::uno::Any SAL_CALL getSelection() override; + virtual css::uno::Reference< ov::excel::XWorkbook > SAL_CALL getActiveWorkbook() override; + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL getActiveCell() override; + virtual css::uno::Reference< ov::excel::XWindow > SAL_CALL getActiveWindow() override; + virtual css::uno::Reference< ov::excel::XWorksheet > SAL_CALL getActiveSheet() override; + virtual sal_Bool SAL_CALL getDisplayFormulaBar() override; + virtual void SAL_CALL setDisplayFormulaBar(sal_Bool _displayformulabar) override; + + virtual css::uno::Reference< ov::XAssistant > SAL_CALL getAssistant() override; + virtual css::uno::Reference< ov::excel::XWorkbook > SAL_CALL getThisWorkbook() override; + + virtual css::uno::Any SAL_CALL GetOpenFilename(const css::uno::Any& FileFilter, const css::uno::Any& FilterIndex, const css::uno::Any& Title, const css::uno::Any& ButtonText, const css::uno::Any& MultiSelect) override; + virtual css::uno::Any SAL_CALL International( sal_Int32 Index ) override; + virtual css::uno::Any SAL_CALL FileDialog( const css::uno::Any& DialogType ) override; + virtual css::uno::Any SAL_CALL Workbooks( const css::uno::Any& aIndex ) override; + virtual css::uno::Any SAL_CALL Worksheets( const css::uno::Any& aIndex ) override; + virtual css::uno::Any SAL_CALL WorksheetFunction( ) override; + virtual css::uno::Any SAL_CALL Evaluate( const OUString& Name ) override; + virtual css::uno::Any SAL_CALL Dialogs( const css::uno::Any& DialogIndex ) override; + virtual css::uno::Any SAL_CALL getCutCopyMode() override; + virtual void SAL_CALL setCutCopyMode( const css::uno::Any& _cutcopymode ) override; + virtual css::uno::Any SAL_CALL getStatusBar() override; + virtual void SAL_CALL setStatusBar( const css::uno::Any& _statusbar ) override; + virtual css::uno::Any SAL_CALL getWindowState() override; + virtual void SAL_CALL setWindowState(const css::uno::Any& rWindowState) override; + virtual ::sal_Int32 SAL_CALL getCursor() override; + virtual void SAL_CALL setCursor( ::sal_Int32 _cursor ) override; + virtual void SAL_CALL OnKey( const OUString& Key, const css::uno::Any& Procedure ) override; + virtual void SAL_CALL setScreenUpdating( sal_Bool bUpdate ) override; + virtual sal_Bool SAL_CALL getEnableEvents() override; + virtual void SAL_CALL setEnableEvents( sal_Bool bEnable ) override; + virtual sal_Bool SAL_CALL getEnableCancelKey() override; + virtual void SAL_CALL setEnableCancelKey( sal_Bool bEnable ) override; + + virtual sal_Bool SAL_CALL getDisplayFullScreen() override; + virtual void SAL_CALL setDisplayFullScreen( sal_Bool bSet ) override; + virtual sal_Bool SAL_CALL getDisplayScrollBars() override; + virtual void SAL_CALL setDisplayScrollBars( sal_Bool bSet ) override; + virtual sal_Bool SAL_CALL getDisplayExcel4Menus() override; + virtual void SAL_CALL setDisplayExcel4Menus( sal_Bool bSet ) override; + + virtual sal_Bool SAL_CALL getDisplayNoteIndicator() override; + virtual void SAL_CALL setDisplayNoteIndicator( sal_Bool bSet ) override; + virtual sal_Bool SAL_CALL getShowWindowsInTaskbar() override; + virtual void SAL_CALL setShowWindowsInTaskbar( sal_Bool bSet ) override; + virtual sal_Bool SAL_CALL getIteration() override; + virtual void SAL_CALL setIteration( sal_Bool bSet ) override; + + virtual css::uno::Any SAL_CALL Windows( const css::uno::Any& aIndex ) override; + virtual void SAL_CALL wait( double time ) override; + virtual css::uno::Any SAL_CALL Range( const css::uno::Any& Cell1, const css::uno::Any& Cell2 ) override; + virtual css::uno::Any SAL_CALL Names( const css::uno::Any& aIndex ) override; + virtual void SAL_CALL GoTo( const css::uno::Any& Reference, const css::uno::Any& Scroll ) override; + virtual void SAL_CALL Calculate() override; + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Intersect( const css::uno::Reference< ov::excel::XRange >& Arg1, const css::uno::Reference< ov::excel::XRange >& Arg2, const css::uno::Any& Arg3, const css::uno::Any& Arg4, const css::uno::Any& Arg5, const css::uno::Any& Arg6, const css::uno::Any& Arg7, const css::uno::Any& Arg8, const css::uno::Any& Arg9, const css::uno::Any& Arg10, const css::uno::Any& Arg11, const css::uno::Any& Arg12, const css::uno::Any& Arg13, const css::uno::Any& Arg14, const css::uno::Any& Arg15, const css::uno::Any& Arg16, const css::uno::Any& Arg17, const css::uno::Any& Arg18, const css::uno::Any& Arg19, const css::uno::Any& Arg20, const css::uno::Any& Arg21, const css::uno::Any& Arg22, const css::uno::Any& Arg23, const css::uno::Any& Arg24, const css::uno::Any& Arg25, const css::uno::Any& Arg26, const css::uno::Any& Arg27, const css::uno::Any& Arg28, const css::uno::Any& Arg29, const css::uno::Any& Arg30 ) override; + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Union( const css::uno::Reference< ov::excel::XRange >& Arg1, const css::uno::Reference< ov::excel::XRange >& Arg2, const css::uno::Any& Arg3, const css::uno::Any& Arg4, const css::uno::Any& Arg5, const css::uno::Any& Arg6, const css::uno::Any& Arg7, const css::uno::Any& Arg8, const css::uno::Any& Arg9, const css::uno::Any& Arg10, const css::uno::Any& Arg11, const css::uno::Any& Arg12, const css::uno::Any& Arg13, const css::uno::Any& Arg14, const css::uno::Any& Arg15, const css::uno::Any& Arg16, const css::uno::Any& Arg17, const css::uno::Any& Arg18, const css::uno::Any& Arg19, const css::uno::Any& Arg20, const css::uno::Any& Arg21, const css::uno::Any& Arg22, const css::uno::Any& Arg23, const css::uno::Any& Arg24, const css::uno::Any& Arg25, const css::uno::Any& Arg26, const css::uno::Any& Arg27, const css::uno::Any& Arg28, const css::uno::Any& Arg29, const css::uno::Any& Arg30 ) override; + virtual double SAL_CALL InchesToPoints( double InchesToPoints ) override; + virtual void SAL_CALL Volatile( const css::uno::Any& Volatile ) override; + virtual css::uno::Any SAL_CALL MenuBars( const css::uno::Any& aIndex ) override; + virtual css::uno::Any SAL_CALL Rows( const css::uno::Any& aIndex ) override; + virtual css::uno::Any SAL_CALL Caller( const css::uno::Any& aIndex ) override; + virtual void SAL_CALL Undo() override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; + + // XInterfaceWithIID + virtual OUString SAL_CALL getIID() override; + + // XConnectable + virtual OUString SAL_CALL GetIIDForClassItselfNotCoclass() override; + virtual ov::TypeAndIID SAL_CALL GetConnectionPoint() override; + virtual css::uno::Reference<ov::XConnectionPoint> SAL_CALL FindConnectionPoint() override; + + // XSinkCaller + virtual void SAL_CALL CallSinks( const OUString& Method, css::uno::Sequence< css::uno::Any >& Arguments ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaassistant.cxx b/sc/source/ui/vba/vbaassistant.cxx new file mode 100644 index 000000000..ea13fbcd6 --- /dev/null +++ b/sc/source/ui/vba/vbaassistant.cxx @@ -0,0 +1,116 @@ +/* -*- 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 <ooo/vba/office/MsoAnimationType.hpp> + +#include"vbaassistant.hxx" + +using namespace com::sun::star; +using namespace ooo::vba; + +using namespace ooo::vba::office::MsoAnimationType; + +constexpr OUStringLiteral g_sName = u"Clippit"; + +ScVbaAssistant::ScVbaAssistant( const uno::Reference< XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext ): ScVbaAssistantImpl_BASE(rParent, rContext) +{ + m_bIsVisible = false; + m_nPointsLeft = 795; + m_nPointsTop = 248; + m_nAnimation = msoAnimationIdle; +} + +ScVbaAssistant::~ScVbaAssistant() +{ +} + +sal_Bool SAL_CALL ScVbaAssistant::getVisible() +{ + return m_bIsVisible; +} + +void SAL_CALL ScVbaAssistant::setVisible( sal_Bool bVisible ) +{ + m_bIsVisible = bVisible; +} + +sal_Bool SAL_CALL ScVbaAssistant::getOn() +{ + return false; +} + +void SAL_CALL ScVbaAssistant::setOn( sal_Bool bOn ) +{ + setVisible( bOn ); +} + +::sal_Int32 SAL_CALL +ScVbaAssistant::getTop() +{ + return m_nPointsTop; +} +void SAL_CALL +ScVbaAssistant::setTop( ::sal_Int32 _top ) +{ + m_nPointsTop = _top; +} +::sal_Int32 SAL_CALL +ScVbaAssistant::getLeft() +{ + return m_nPointsLeft; +} +void SAL_CALL +ScVbaAssistant::setLeft( ::sal_Int32 _left ) +{ + m_nPointsLeft = _left; +} +::sal_Int32 SAL_CALL +ScVbaAssistant::getAnimation() +{ + return m_nAnimation; +} +void SAL_CALL +ScVbaAssistant::setAnimation( ::sal_Int32 _animation ) +{ + m_nAnimation = _animation; +} + +OUString SAL_CALL +ScVbaAssistant::Name( ) +{ + return g_sName; +} + +OUString +ScVbaAssistant::getServiceImplName() +{ + return "ScVbaAssistant"; +} + +uno::Sequence< OUString > +ScVbaAssistant::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.Assistant" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaassistant.hxx b/sc/source/ui/vba/vbaassistant.hxx new file mode 100644 index 000000000..674e64445 --- /dev/null +++ b/sc/source/ui/vba/vbaassistant.hxx @@ -0,0 +1,57 @@ +/* -*- 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 . + */ +#pragma once + +#include <cppuhelper/implbase.hxx> +#include <ooo/vba/XAssistant.hpp> + +#include <vbahelper/vbahelperinterface.hxx> + +typedef ::cppu::WeakImplHelper< ov::XAssistant > Assistant; +typedef InheritedHelperInterfaceImpl< Assistant > ScVbaAssistantImpl_BASE; + +class ScVbaAssistant : public ScVbaAssistantImpl_BASE +{ +private: + bool m_bIsVisible; + sal_Int32 m_nPointsLeft; + sal_Int32 m_nPointsTop; + sal_Int32 m_nAnimation; +public: + ScVbaAssistant( const css::uno::Reference< ov::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext ); + virtual ~ScVbaAssistant() override; + // XAssistant + virtual sal_Bool SAL_CALL getOn() override; + virtual void SAL_CALL setOn( sal_Bool _on ) override; + virtual sal_Bool SAL_CALL getVisible() override; + virtual void SAL_CALL setVisible( sal_Bool _visible ) override; + virtual ::sal_Int32 SAL_CALL getTop() override; + virtual void SAL_CALL setTop( ::sal_Int32 _top ) override; + virtual ::sal_Int32 SAL_CALL getLeft() override; + virtual void SAL_CALL setLeft( ::sal_Int32 _left ) override; + virtual ::sal_Int32 SAL_CALL getAnimation() override; + virtual void SAL_CALL setAnimation( ::sal_Int32 _animation ) override; + + virtual OUString SAL_CALL Name( ) override; + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaaxes.cxx b/sc/source/ui/vba/vbaaxes.cxx new file mode 100644 index 000000000..c295158b7 --- /dev/null +++ b/sc/source/ui/vba/vbaaxes.cxx @@ -0,0 +1,211 @@ +/* -*- 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 "vbaaxes.hxx" +#include "vbaaxis.hxx" +#include "vbachart.hxx" +#include <basic/sberrors.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/script/BasicErrorException.hpp> +#include <ooo/vba/excel/XlAxisType.hpp> +#include <ooo/vba/excel/XlAxisGroup.hpp> +#include <ooo/vba/excel/XAxis.hpp> + +using namespace ::com::sun::star; +using namespace ::ooo::vba; +using namespace ::ooo::vba::excel::XlAxisType; +using namespace ::ooo::vba::excel::XlAxisGroup; + +// each 'Item' in the Axes collection is indexed via 2 indexes, group and type. +// We need to 'flatten' this into a single index in order to be able to wrap +// iteration over the set of Axis(s) in a XIndexAccess implementation + +typedef ::std::pair<sal_Int32, sal_Int32 > AxesCoordinate; // type and group combination + +namespace { + +class EnumWrapper : public EnumerationHelper_BASE +{ + uno::Reference<container::XIndexAccess > m_xIndexAccess; + sal_Int32 nIndex; +public: + explicit EnumWrapper( const uno::Reference< container::XIndexAccess >& xIndexAccess ) : m_xIndexAccess( xIndexAccess ), nIndex( 0 ) {} + virtual sal_Bool SAL_CALL hasMoreElements( ) override + { + return ( nIndex < m_xIndexAccess->getCount() ); + } + + virtual uno::Any SAL_CALL nextElement( ) override + { + if ( nIndex < m_xIndexAccess->getCount() ) + return m_xIndexAccess->getByIndex( nIndex++ ); + throw container::NoSuchElementException(); + } +}; + +} + +uno::Reference< excel::XAxis > +ScVbaAxes::createAxis( const uno::Reference< excel::XChart >& xChart, const uno::Reference< uno::XComponentContext >& xContext, sal_Int32 nType, sal_Int32 nAxisGroup ) +{ + ScVbaChart* pChart = static_cast< ScVbaChart* >( xChart.get() ); + if ( !pChart ) + throw uno::RuntimeException("Object failure, can't access chart implementation" ); + + uno::Reference< beans::XPropertySet > xAxisPropertySet; + if ((nType == xlCategory) || (nType == xlSeriesAxis) || (nType == xlValue)) + { + if ((nAxisGroup != xlPrimary) && (nAxisGroup != xlSecondary)) + DebugHelper::runtimeexception(ERRCODE_BASIC_METHOD_FAILED); + xAxisPropertySet.set( pChart->getAxisPropertySet(nType, nAxisGroup), uno::UNO_SET_THROW ); + } + else + DebugHelper::runtimeexception(ERRCODE_BASIC_METHOD_FAILED); + uno::Reference< XHelperInterface > xParent( xChart, uno::UNO_QUERY_THROW ); + return new ScVbaAxis( xParent, xContext, xAxisPropertySet, nType, nAxisGroup); +} + +namespace { + +class AxisIndexWrapper : public ::cppu::WeakImplHelper< container::XIndexAccess > +{ + // if necessary for better performance we could change this into a map and cache the + // indices -> Axis, currently we create a new Axis object + // on each getByIndex + uno::Reference< uno::XComponentContext > mxContext; + std::vector< AxesCoordinate > mCoordinates; + uno::Reference< excel::XChart > mxChart; +public: + AxisIndexWrapper( const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< excel::XChart >& xChart ) : mxContext( xContext ), mxChart( xChart ) + { + if ( !mxChart.is() ) + return; + + ScVbaChart* pChart = static_cast< ScVbaChart* >( mxChart.get() ); + // primary + bool bBool = false; + uno::Reference< beans::XPropertySet > xDiagramPropertySet( pChart->xDiagramPropertySet() ); + if ( ( xDiagramPropertySet->getPropertyValue("HasXAxis") >>= bBool ) && bBool ) + mCoordinates.emplace_back( xlPrimary, xlCategory ); + if ( ( xDiagramPropertySet->getPropertyValue("HasYAxis") >>= bBool ) && bBool ) + mCoordinates.emplace_back( xlPrimary, xlSeriesAxis ); + + if ( pChart->is3D() ) + mCoordinates.emplace_back( xlPrimary, xlValue ); + + // secondary + if ( ( xDiagramPropertySet->getPropertyValue("HasSecondaryXAxis") >>= bBool ) && bBool ) + mCoordinates.emplace_back( xlSecondary, xlCategory ); + if ( ( xDiagramPropertySet->getPropertyValue("HasSecondaryYAxis") >>= bBool ) && bBool ) + mCoordinates.emplace_back( xlSecondary, xlSeriesAxis ); + + } + virtual ::sal_Int32 SAL_CALL getCount() override { return mCoordinates.size(); } + virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override + { + try + { + AxesCoordinate dIndexes = mCoordinates[ Index ]; + return uno::Any( ScVbaAxes::createAxis( mxChart, mxContext, dIndexes.second, dIndexes.first ) ); + } + catch (const css::script::BasicErrorException&) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetException( + "Error Getting Index!", + static_cast < OWeakObject * > ( this ), + anyEx ); + } + } + // XElementAccess + virtual uno::Type SAL_CALL getElementType() override + { + return cppu::UnoType<excel::XAxis>::get(); + } + virtual sal_Bool SAL_CALL hasElements( ) override + { + return ( !mCoordinates.empty() ); + } +}; + +uno::Reference< container::XIndexAccess > createIndexWrapper( const uno::Reference< excel::XChart >& xChart, const uno::Reference< uno::XComponentContext >& xContext ) +{ + return new AxisIndexWrapper( xContext, xChart ); +} + +} + +// #FIXME The collection semantics will never work as this object is not yet initialised correctly +ScVbaAxes::ScVbaAxes( const uno::Reference< XHelperInterface >& xParent,const uno::Reference< uno::XComponentContext > & xContext, const uno::Reference< excel::XChart >& xChart ) : ScVbaAxes_BASE( xParent, xContext, createIndexWrapper( xChart, xContext )), moChartParent( xChart ) +{ +} + +uno::Type SAL_CALL +ScVbaAxes::getElementType() +{ + return cppu::UnoType<excel::XAxes>::get(); +} + +uno::Reference< container::XEnumeration > SAL_CALL +ScVbaAxes::createEnumeration() +{ + return new EnumWrapper( m_xIndexAccess ); +} + +uno::Any SAL_CALL +ScVbaAxes::Item( const css::uno::Any& _nType, const css::uno::Any& _oAxisGroup) +{ + // #TODO map the possible index combinations to a container::XIndexAccess wrapper impl + // using a vector of valid std::pair maybe? + // body helper api port bits + sal_Int32 nAxisGroup = xlPrimary; + sal_Int32 nType = -1; + if ( !_nType.hasValue() || !( _nType >>= nType ) ) + throw uno::RuntimeException("Axes::Item Failed to extract type" ); + + if ( _oAxisGroup.hasValue() ) + _oAxisGroup >>= nAxisGroup ; + + return uno::Any( createAxis( moChartParent, mxContext, nType, nAxisGroup ) ); +} + +uno::Any +ScVbaAxes::createCollectionObject(const css::uno::Any& aSource) +{ + return aSource; // pass through ( it's already an XAxis object +} + +OUString +ScVbaAxes::getServiceImplName() +{ + return "ScVbaAxes"; +} + +uno::Sequence< OUString > +ScVbaAxes::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.Axes" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaaxes.hxx b/sc/source/ui/vba/vbaaxes.hxx new file mode 100644 index 000000000..cb7c48a7f --- /dev/null +++ b/sc/source/ui/vba/vbaaxes.hxx @@ -0,0 +1,47 @@ +/* -*- 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 . + */ +#pragma once + +#include <ooo/vba/excel/XAxes.hpp> +#include <vbahelper/vbacollectionimpl.hxx> + +namespace ooo::vba::excel { class XAxis; } +namespace ooo::vba::excel { class XChart; } + +typedef CollTestImplHelper< ov::excel::XAxes > ScVbaAxes_BASE; +class ScVbaAxes : public ScVbaAxes_BASE +{ + css::uno::Reference< ov::excel::XChart > moChartParent; // not the true parent I guess +public: + ScVbaAxes( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< ov::excel::XChart >& xChart ); + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + // XCollection + virtual css::uno::Any SAL_CALL Item( const css::uno::Any& aIndex, const css::uno::Any& aIndex2 ) override; + virtual css::uno::Any createCollectionObject(const css::uno::Any&) override; + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; + /// @throws css::uno::RuntimeException + /// @throws css::script::BasicErrorException + static css::uno::Reference< ov::excel::XAxis > createAxis( const css::uno::Reference< ov::excel::XChart >& xChart, const css::uno::Reference< css::uno::XComponentContext >& xContext, sal_Int32 nType, sal_Int32 nAxisGroup ); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaaxis.cxx b/sc/source/ui/vba/vbaaxis.cxx new file mode 100644 index 000000000..c34649fa5 --- /dev/null +++ b/sc/source/ui/vba/vbaaxis.cxx @@ -0,0 +1,656 @@ +/* -*- 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 "vbaaxis.hxx" +#include <ooo/vba/excel/XlAxisCrosses.hpp> +#include <ooo/vba/excel/XlAxisType.hpp> +#include <ooo/vba/excel/XlScaleType.hpp> +#include "vbaaxistitle.hxx" +#include "vbachart.hxx" +using namespace ::com::sun::star; +using namespace ::ooo::vba; +using namespace ::ooo::vba::excel::XlAxisCrosses; +using namespace ::ooo::vba::excel::XlAxisType; +using namespace ::ooo::vba::excel::XlScaleType; + +constexpr OUStringLiteral ORIGIN(u"Origin"); +constexpr OUStringLiteral AUTOORIGIN(u"AutoOrigin"); +constexpr OUStringLiteral VBA_MIN(u"Max"); +constexpr OUStringLiteral VBA_MAX(u"Min"); +ScVbaChart* +ScVbaAxis::getChartPtr() +{ + ScVbaChart* pChart = static_cast< ScVbaChart* >( moChartParent.get() ); + if ( !pChart ) + throw uno::RuntimeException("Can't access parent chart impl" ); + return pChart; +} + +bool +ScVbaAxis::isValueAxis() +{ + if ( getType() == xlCategory ) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } + return true; +} + +ScVbaAxis::ScVbaAxis( const uno::Reference< XHelperInterface >& xParent,const uno::Reference< uno::XComponentContext > & xContext, const uno::Reference< beans::XPropertySet >& _xPropertySet, sal_Int32 _nType, sal_Int32 _nGroup ) : ScVbaAxis_BASE( xParent, xContext ), mxPropertySet( _xPropertySet ), mnType( _nType ), mnGroup( _nGroup ), bCrossesAreCustomized( false ) +{ + oShapeHelper.reset( new ShapeHelper( uno::Reference< drawing::XShape >( mxPropertySet, uno::UNO_QUERY ) ) ); + moChartParent.set( xParent, uno::UNO_QUERY_THROW ); + setType(_nType); + setCrosses(xlAxisCrossesAutomatic); +} + +void SAL_CALL +ScVbaAxis::Delete( ) +{ + uno::Reference< lang::XComponent > xComponent( mxPropertySet, uno::UNO_QUERY_THROW ); + xComponent->dispose(); +} + + uno::Reference< ::ooo::vba::excel::XAxisTitle > SAL_CALL +ScVbaAxis::getAxisTitle( ) +{ + uno::Reference< excel::XAxisTitle > xAxisTitle; + try + { + ScVbaChart* pChart = getChartPtr(); + + if (getHasTitle() ) + { + int nType = getType(); + switch(nType) + { + case xlCategory: + xAxisTitle = new ScVbaAxisTitle(this, mxContext, pChart->xAxisXSupplier->getXAxisTitle()); + break; + case xlSeriesAxis: + xAxisTitle = new ScVbaAxisTitle(this, mxContext, pChart->xAxisZSupplier->getZAxisTitle()); + break; + default: // xlValue: + xAxisTitle = new ScVbaAxisTitle(this, mxContext, pChart->xAxisYSupplier->getYAxisTitle()); + break; + } + } + } + catch (const uno::Exception& e) + { + DebugHelper::basicexception(e); + } + return xAxisTitle; + +} + +void SAL_CALL +ScVbaAxis::setDisplayUnit( ::sal_Int32 /*DisplayUnit*/ ) +{ + DebugHelper::basicexception(ERRCODE_BASIC_NOT_IMPLEMENTED, {}); +} + +::sal_Int32 SAL_CALL +ScVbaAxis::getDisplayUnit( ) +{ + DebugHelper::basicexception(ERRCODE_BASIC_NOT_IMPLEMENTED, {}); + return -1; +} + +void SAL_CALL +ScVbaAxis::setCrosses( ::sal_Int32 _nCrosses ) +{ + try + { + double fNum = 0.0; + switch (_nCrosses) + { + case xlAxisCrossesAutomatic: //Microsoft Excel sets the axis crossing point. + mxPropertySet->setPropertyValue(AUTOORIGIN, uno::Any( true ) ); + bCrossesAreCustomized = false; + return; + case xlAxisCrossesMinimum: // The axis crosses at the minimum value. + mxPropertySet->getPropertyValue(VBA_MIN) >>= fNum; + setCrossesAt( fNum ); + bCrossesAreCustomized = false; + break; + case xlAxisCrossesMaximum: // The axis crosses at the maximum value. + mxPropertySet->getPropertyValue(VBA_MAX) >>= fNum; + setCrossesAt(fNum); + bCrossesAreCustomized = false; + break; + default: //xlAxisCrossesCustom + bCrossesAreCustomized = true; + break; + } + mxPropertySet->setPropertyValue(AUTOORIGIN, uno::Any(false) ); + } + catch (const uno::Exception&) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } +} +::sal_Int32 SAL_CALL +ScVbaAxis::getCrosses( ) +{ + sal_Int32 nCrosses = xlAxisCrossesCustom; + try + { + bool bisAutoOrigin = false; + mxPropertySet->getPropertyValue(AUTOORIGIN) >>= bisAutoOrigin; + if (bisAutoOrigin) + nCrosses = xlAxisCrossesAutomatic; + else + { + if (bCrossesAreCustomized) + nCrosses = xlAxisCrossesCustom; + else + { + double forigin = 0.0; + mxPropertySet->getPropertyValue(ORIGIN) >>= forigin; + double fmin = 0.0; + mxPropertySet->getPropertyValue(VBA_MIN) >>= fmin; + if (forigin == fmin) + nCrosses = xlAxisCrossesMinimum; + else + nCrosses = xlAxisCrossesMaximum; + } + } + } + catch (uno::Exception& ) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} ); + } + return nCrosses; +} + + void SAL_CALL +ScVbaAxis::setCrossesAt( double _fCrossesAt ) +{ + try + { + setMaximumScaleIsAuto( false ); + setMinimumScaleIsAuto( false ); + mxPropertySet->setPropertyValue(ORIGIN, uno::Any(_fCrossesAt)); + } + catch (const uno::Exception& e) + { + DebugHelper::basicexception(e); + } +} + + double SAL_CALL +ScVbaAxis::getCrossesAt( ) +{ + double fCrosses = 0.0; + try + { + mxPropertySet->getPropertyValue(ORIGIN) >>= fCrosses; + } + catch (uno::Exception& ) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } + return fCrosses; +} + +void SAL_CALL +ScVbaAxis::setType( ::sal_Int32 _nType ) +{ + mnType = _nType; +} + +::sal_Int32 SAL_CALL +ScVbaAxis::getType( ) +{ + return mnType; +} + +void SAL_CALL +ScVbaAxis::setHasTitle( sal_Bool _bHasTitle ) +{ + try + { + ScVbaChart* pChart = getChartPtr(); + sal_Int32 nType = getType(); + switch(nType) + { + case xlCategory: + pChart->mxDiagramPropertySet->setPropertyValue("HasXAxisTitle", uno::Any(_bHasTitle)); + break; + case xlSeriesAxis: + pChart->mxDiagramPropertySet->setPropertyValue("HasZAxisTitle", uno::Any(_bHasTitle)); + break; + default: // xlValue: + pChart->mxDiagramPropertySet->setPropertyValue("HasYAxisTitle", uno::Any(_bHasTitle)); + } + + } + catch (const uno::Exception& e) + { + DebugHelper::basicexception(e); + } +} + + sal_Bool SAL_CALL +ScVbaAxis::getHasTitle( ) +{ + bool bHasTitle = false; + try + { + ScVbaChart* pChart = getChartPtr(); + int nType = getType(); + switch(nType) + { + case xlCategory: + pChart->mxDiagramPropertySet->getPropertyValue("HasXAxisTitle") >>= bHasTitle; + break; + case xlSeriesAxis: + pChart->mxDiagramPropertySet->getPropertyValue("HasZAxisTitle") >>= bHasTitle; + break; + default: // xlValue: + pChart->mxDiagramPropertySet->getPropertyValue("HasYAxisTitle") >>= bHasTitle; + } + } + catch (const uno::Exception& e) + { + DebugHelper::basicexception(e); + } + return bHasTitle; +} + +void SAL_CALL +ScVbaAxis::setMinorUnit( double _fMinorUnit ) +{ + try + { + if (isValueAxis()) + mxPropertySet->setPropertyValue("StepHelp", uno::Any(_fMinorUnit)); + } + catch (uno::Exception& ) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } +} + +double SAL_CALL +ScVbaAxis::getMinorUnit( ) +{ + double fMinor = 1.0; + try + { + if (isValueAxis()) + mxPropertySet->getPropertyValue("StepHelp") >>= fMinor; + } + catch (uno::Exception& ) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } + return fMinor; +} + +void SAL_CALL +ScVbaAxis::setMinorUnitIsAuto( sal_Bool _bMinorUnitIsAuto ) +{ + try + { + if (isValueAxis()) + mxPropertySet->setPropertyValue("AutoStepHelp", uno::Any(_bMinorUnitIsAuto)); + } + catch (uno::Exception& ) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} ); + } +} + + sal_Bool SAL_CALL +ScVbaAxis::getMinorUnitIsAuto( ) +{ + bool bIsAuto = false; + try + { + if (isValueAxis()) + { + mxPropertySet->getPropertyValue("AutoStepHelp") >>= bIsAuto; + } + } + catch (const uno::Exception&) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } + return bIsAuto; +} + +void SAL_CALL +ScVbaAxis::setReversePlotOrder( sal_Bool /*ReversePlotOrder*/ ) +{ + DebugHelper::basicexception(ERRCODE_BASIC_NOT_IMPLEMENTED, {}); +} + +sal_Bool SAL_CALL +ScVbaAxis::getReversePlotOrder( ) +{ + DebugHelper::basicexception(ERRCODE_BASIC_NOT_IMPLEMENTED, {}); + return false; +} + +void SAL_CALL +ScVbaAxis::setMajorUnit( double _fMajorUnit ) +{ + try + { + if (isValueAxis()) + { + mxPropertySet->setPropertyValue("StepMain", uno::Any(_fMajorUnit)); + } + } + catch (const uno::Exception&) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } +} + +double SAL_CALL +ScVbaAxis::getMajorUnit( ) +{ + double fMax = 1.0; + try + { + if (isValueAxis()) + mxPropertySet->getPropertyValue("StepMain") >>= fMax; + } + catch (const uno::Exception&) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} ); + } + return fMax; +} + +void SAL_CALL +ScVbaAxis::setMajorUnitIsAuto( sal_Bool _bMajorUnitIsAuto ) +{ + try + { + if (isValueAxis()) + { + mxPropertySet->setPropertyValue("AutoStepMain", uno::Any( _bMajorUnitIsAuto )); + } + } + catch (const uno::Exception&) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } +} + +sal_Bool SAL_CALL +ScVbaAxis::getMajorUnitIsAuto( ) +{ + bool bIsAuto = false; + try + { + if (isValueAxis()) + { + mxPropertySet->getPropertyValue("AutoStepMain") >>= bIsAuto; + } + } + catch (const uno::Exception&) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } + return bIsAuto; +} + +void SAL_CALL +ScVbaAxis::setMaximumScale( double _fMaximumScale ) +{ + try + { + if ( isValueAxis() ) + { + mxPropertySet->setPropertyValue("Max", uno::Any(_fMaximumScale)); + } + } + catch (const uno::Exception&) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } +} + +double SAL_CALL +ScVbaAxis::getMaximumScale( ) +{ + double fMax = 1.0; + try + { + if (isValueAxis()) + { + mxPropertySet->getPropertyValue("Max") >>= fMax; + } + } + catch (const uno::Exception&) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } + return fMax; + +} + +void SAL_CALL +ScVbaAxis::setMaximumScaleIsAuto( sal_Bool _bMaximumScaleIsAuto ) +{ + try + { + if ( isValueAxis() ) + mxPropertySet->setPropertyValue("AutoMax", uno::Any( _bMaximumScaleIsAuto )); + + } + catch (const uno::Exception&) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } +} + +sal_Bool SAL_CALL +ScVbaAxis::getMaximumScaleIsAuto( ) +{ + bool bIsAuto = false; + try + { + if (isValueAxis()) + mxPropertySet->getPropertyValue("AutoMax") >>= bIsAuto; + } + catch (const uno::Exception&) + { + DebugHelper::basicexception( ERRCODE_BASIC_METHOD_FAILED, {} ); + } + return bIsAuto; +} + +void SAL_CALL +ScVbaAxis::setMinimumScale( double _fMinimumScale ) +{ + try + { + if (isValueAxis()) + mxPropertySet->setPropertyValue("Min", uno::Any( _fMinimumScale ) ); + } + catch ( uno::Exception& ) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} ); + } +} + +double SAL_CALL +ScVbaAxis::getMinimumScale( ) +{ + double fMin = 0.0; + try + { + if (isValueAxis()) + mxPropertySet->getPropertyValue("Min") >>= fMin; + } + catch (const uno::Exception& e) + { + DebugHelper::basicexception(e); + } + return fMin; +} + +void SAL_CALL +ScVbaAxis::setMinimumScaleIsAuto( sal_Bool _bMinimumScaleIsAuto ) +{ + try + { + if (isValueAxis()) + { + mxPropertySet->setPropertyValue("AutoMin", uno::Any(_bMinimumScaleIsAuto)); + } + } + catch (const uno::Exception&) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } +} + +sal_Bool SAL_CALL +ScVbaAxis::getMinimumScaleIsAuto( ) +{ + bool bIsAuto = false; + try + { + if (isValueAxis()) + { + mxPropertySet->getPropertyValue("AutoMin") >>= bIsAuto; + } + } + catch (const uno::Exception&) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } + return bIsAuto; +} + +::sal_Int32 SAL_CALL +ScVbaAxis::getAxisGroup( ) +{ + return mnGroup; +} + +void SAL_CALL +ScVbaAxis::setScaleType( ::sal_Int32 _nScaleType ) +{ + try + { + if (isValueAxis()) + { + switch (_nScaleType) + { + case xlScaleLinear: + mxPropertySet->setPropertyValue("Logarithmic", uno::Any( false ) ); + break; + case xlScaleLogarithmic: + mxPropertySet->setPropertyValue("Logarithmic", uno::Any( true ) ); + break; + default: + // According to MS the parameter is ignored and no Error is thrown + break; + } + } + } + catch (const uno::Exception&) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } +} + +::sal_Int32 SAL_CALL +ScVbaAxis::getScaleType( ) +{ + sal_Int32 nScaleType = xlScaleLinear; + try + { + if (isValueAxis()) + { + bool bisLogarithmic = false; + mxPropertySet->getPropertyValue( "Logarithmic" ) >>= bisLogarithmic; + if (bisLogarithmic) + nScaleType = xlScaleLogarithmic; + else + nScaleType = xlScaleLinear; + } + } + catch (const uno::Exception&) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } + return nScaleType; +} + +double SAL_CALL +ScVbaAxis::getHeight( ) +{ + return oShapeHelper->getHeight(); +} + +void SAL_CALL ScVbaAxis::setHeight( double height ) +{ + oShapeHelper->setHeight( height ); +} +double SAL_CALL ScVbaAxis::getWidth( ) +{ + return oShapeHelper->getWidth( ); +} +void SAL_CALL ScVbaAxis::setWidth( double width ) +{ + oShapeHelper->setWidth( width ); +} +double SAL_CALL ScVbaAxis::getTop( ) +{ + return oShapeHelper->getTop( ); +} +void SAL_CALL ScVbaAxis::setTop( double top ) +{ + oShapeHelper->setTop( top ); +} +double SAL_CALL ScVbaAxis::getLeft( ) +{ + return oShapeHelper->getLeft( ); +} +void SAL_CALL ScVbaAxis::setLeft( double left ) +{ + oShapeHelper->setLeft( left ); +} + +OUString +ScVbaAxis::getServiceImplName() +{ + return "ScVbaAxis"; +} + +uno::Sequence< OUString > +ScVbaAxis::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.Axis" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaaxis.hxx b/sc/source/ui/vba/vbaaxis.hxx new file mode 100644 index 000000000..6636fb617 --- /dev/null +++ b/sc/source/ui/vba/vbaaxis.hxx @@ -0,0 +1,90 @@ +/* -*- 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 . + */ +#pragma once +#include <com/sun/star/beans/XPropertySet.hpp> +#include <ooo/vba/excel/XAxis.hpp> +#include <ooo/vba/excel/XChart.hpp> +#include <vbahelper/vbahelperinterface.hxx> +#include <memory> +typedef InheritedHelperInterfaceWeakImpl< ov::excel::XAxis > ScVbaAxis_BASE; +class ScVbaChart; +class ScVbaAxis : public ScVbaAxis_BASE +{ + css::uno::Reference< ov::excel::XChart > moChartParent; + css::uno::Reference< css::beans::XPropertySet > mxPropertySet; + sal_Int32 mnType; + sal_Int32 mnGroup; + bool bCrossesAreCustomized; + /// @throws css::uno::RuntimeException + ScVbaChart* getChartPtr(); + /// @throws css::script::BasicErrorException + bool isValueAxis(); + std::unique_ptr<ov::ShapeHelper> oShapeHelper; + +public: + ScVbaAxis( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::beans::XPropertySet >& _xPropertySet, sal_Int32 _nType, sal_Int32 _nGroup ); + // Methods + virtual void SAL_CALL Delete( ) override; + virtual css::uno::Reference< ::ooo::vba::excel::XAxisTitle > SAL_CALL getAxisTitle( ) override; + virtual void SAL_CALL setDisplayUnit( ::sal_Int32 DisplayUnit ) override; + virtual ::sal_Int32 SAL_CALL getDisplayUnit( ) override; + virtual void SAL_CALL setCrosses( ::sal_Int32 Crosses ) override; + virtual ::sal_Int32 SAL_CALL getCrosses( ) override; + virtual void SAL_CALL setCrossesAt( double CrossesAt ) override; + virtual double SAL_CALL getCrossesAt( ) override; + virtual void SAL_CALL setType( ::sal_Int32 Type ) override; + virtual ::sal_Int32 SAL_CALL getType( ) override; + virtual void SAL_CALL setHasTitle( sal_Bool HasTitle ) override; + virtual sal_Bool SAL_CALL getHasTitle( ) override; + virtual void SAL_CALL setMinorUnit( double MinorUnit ) override; + virtual double SAL_CALL getMinorUnit( ) override; + virtual void SAL_CALL setMinorUnitIsAuto( sal_Bool MinorUnitIsAuto ) override; + virtual sal_Bool SAL_CALL getMinorUnitIsAuto( ) override; + virtual void SAL_CALL setReversePlotOrder( sal_Bool ReversePlotOrder ) override; + virtual sal_Bool SAL_CALL getReversePlotOrder( ) override; + virtual void SAL_CALL setMajorUnit( double MajorUnit ) override; + virtual double SAL_CALL getMajorUnit( ) override; + virtual void SAL_CALL setMajorUnitIsAuto( sal_Bool MajorUnitIsAuto ) override; + virtual sal_Bool SAL_CALL getMajorUnitIsAuto( ) override; + virtual void SAL_CALL setMaximumScale( double MaximumScale ) override; + virtual double SAL_CALL getMaximumScale( ) override; + virtual void SAL_CALL setMaximumScaleIsAuto( sal_Bool MaximumScaleIsAuto ) override; + virtual sal_Bool SAL_CALL getMaximumScaleIsAuto( ) override; + virtual void SAL_CALL setMinimumScale( double MinimumScale ) override; + virtual double SAL_CALL getMinimumScale( ) override; + virtual void SAL_CALL setMinimumScaleIsAuto( sal_Bool MinimumScaleIsAuto ) override; + virtual sal_Bool SAL_CALL getMinimumScaleIsAuto( ) override; + virtual ::sal_Int32 SAL_CALL getAxisGroup( ) override; + virtual void SAL_CALL setScaleType( ::sal_Int32 ScaleType ) override; + virtual ::sal_Int32 SAL_CALL getScaleType( ) override; + virtual double SAL_CALL getHeight( ) override; + virtual void SAL_CALL setHeight( double height ) override; + virtual double SAL_CALL getWidth( ) override; + virtual void SAL_CALL setWidth( double width ) override; + virtual double SAL_CALL getTop( ) override; + virtual void SAL_CALL setTop( double top ) override; + virtual double SAL_CALL getLeft( ) override; + virtual void SAL_CALL setLeft( double left ) override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaaxistitle.cxx b/sc/source/ui/vba/vbaaxistitle.cxx new file mode 100644 index 000000000..5336ef7a7 --- /dev/null +++ b/sc/source/ui/vba/vbaaxistitle.cxx @@ -0,0 +1,44 @@ +/* -*- 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 "vbaaxistitle.hxx" +#include <comphelper/sequence.hxx> + +using namespace ::com::sun::star; +using namespace ::ooo::vba; + +ScVbaAxisTitle::ScVbaAxisTitle( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< drawing::XShape >& _xTitleShape ) : AxisTitleBase( xParent, xContext, _xTitleShape ) +{ +} + +OUString +ScVbaAxisTitle::getServiceImplName() +{ + return "ScVbaAxisTitle"; +} + +uno::Sequence< OUString > +ScVbaAxisTitle::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames = comphelper::concatSequences( + AxisTitleBase::getServiceNames(), + uno::Sequence<OUString> { "ooo.vba.excel.AxisTitle" } ); + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaaxistitle.hxx b/sc/source/ui/vba/vbaaxistitle.hxx new file mode 100644 index 000000000..9226a58a3 --- /dev/null +++ b/sc/source/ui/vba/vbaaxistitle.hxx @@ -0,0 +1,36 @@ +/* -*- 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 . + */ +#pragma once + +#include "vbatitle.hxx" +#include <cppuhelper/implbase.hxx> +#include <ooo/vba/excel/XAxisTitle.hpp> + +typedef TitleImpl< cppu::WeakImplHelper< ov::excel::XAxisTitle > > AxisTitleBase; + +class ScVbaAxisTitle : public AxisTitleBase +{ +public: + ScVbaAxisTitle( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Reference< css::drawing::XShape >& _xTitleShape ); + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaborders.cxx b/sc/source/ui/vba/vbaborders.cxx new file mode 100644 index 000000000..22434f971 --- /dev/null +++ b/sc/source/ui/vba/vbaborders.cxx @@ -0,0 +1,591 @@ +/* -*- 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 "vbaborders.hxx" + +#include <sal/macros.h> +#include <cppuhelper/implbase.hxx> +#include <ooo/vba/excel/XlBordersIndex.hpp> +#include <ooo/vba/excel/XlBorderWeight.hpp> +#include <ooo/vba/excel/XlLineStyle.hpp> +#include <ooo/vba/excel/XlColorIndex.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/table/TableBorder.hpp> +#include <com/sun/star/table/XCellRange.hpp> +#include <com/sun/star/table/XColumnRowRange.hpp> + +#include "vbapalette.hxx" + +using namespace ::com::sun::star; +using namespace ::ooo::vba; +using namespace ::ooo::vba::excel; + +typedef ::cppu::WeakImplHelper<container::XIndexAccess > RangeBorders_Base; +typedef InheritedHelperInterfaceWeakImpl<excel::XBorder > ScVbaBorder_Base; + +// #TODO sort these indexes to match the order in which Excel iterates over the +// borders, the enumeration will match the order in this list +const sal_Int16 supportedIndexTable[] = { XlBordersIndex::xlEdgeLeft, XlBordersIndex::xlEdgeTop, XlBordersIndex::xlEdgeBottom, XlBordersIndex::xlEdgeRight, XlBordersIndex::xlDiagonalDown, XlBordersIndex::xlDiagonalUp, XlBordersIndex::xlInsideVertical, XlBordersIndex::xlInsideHorizontal }; + +constexpr OUStringLiteral sTableBorder = u"TableBorder"; + +// Equiv widths in 1/100 mm +const sal_Int32 OOLineThin = 26; +const sal_Int32 OOLineMedium = 88; +const sal_Int32 OOLineThick = 141; +const sal_Int32 OOLineHairline = 2; + +namespace { + +class ScVbaBorder : public ScVbaBorder_Base +{ +private: + uno::Reference< beans::XPropertySet > m_xProps; + sal_Int32 m_LineType; + ScVbaPalette m_Palette; + void setBorderLine( const table::BorderLine& rBorderLine ) + { + table::TableBorder aTableBorder; + m_xProps->getPropertyValue( sTableBorder ) >>= aTableBorder; + + switch ( m_LineType ) + { + case XlBordersIndex::xlEdgeLeft: + aTableBorder.IsLeftLineValid = true; + aTableBorder.LeftLine= rBorderLine; + break; + case XlBordersIndex::xlEdgeTop: + aTableBorder.IsTopLineValid = true; + aTableBorder.TopLine = rBorderLine; + break; + + case XlBordersIndex::xlEdgeBottom: + aTableBorder.IsBottomLineValid = true; + aTableBorder.BottomLine = rBorderLine; + break; + case XlBordersIndex::xlEdgeRight: + aTableBorder.IsRightLineValid = true; + aTableBorder.RightLine = rBorderLine; + break; + case XlBordersIndex::xlInsideVertical: + aTableBorder.IsVerticalLineValid = true; + aTableBorder.VerticalLine = rBorderLine; + break; + case XlBordersIndex::xlInsideHorizontal: + aTableBorder.IsHorizontalLineValid = true; + aTableBorder.HorizontalLine = rBorderLine; + break; + case XlBordersIndex::xlDiagonalDown: + case XlBordersIndex::xlDiagonalUp: + // #TODO have to ignore at the moment, would be + // nice to investigate what we can do here + break; + default: + return; + } + m_xProps->setPropertyValue( sTableBorder, uno::Any(aTableBorder) ); + } + + bool getBorderLine( table::BorderLine& rBorderLine ) + { + table::TableBorder aTableBorder; + m_xProps->getPropertyValue( sTableBorder ) >>= aTableBorder; + switch ( m_LineType ) + { + case XlBordersIndex::xlEdgeLeft: + if ( aTableBorder.IsLeftLineValid ) + rBorderLine = aTableBorder.LeftLine; + break; + case XlBordersIndex::xlEdgeTop: + if ( aTableBorder.IsTopLineValid ) + rBorderLine = aTableBorder.TopLine; + break; + + case XlBordersIndex::xlEdgeBottom: + if ( aTableBorder.IsBottomLineValid ) + rBorderLine = aTableBorder.BottomLine; + break; + case XlBordersIndex::xlEdgeRight: + if ( aTableBorder.IsRightLineValid ) + rBorderLine = aTableBorder.RightLine; + break; + case XlBordersIndex::xlInsideVertical: + if ( aTableBorder.IsVerticalLineValid ) + rBorderLine = aTableBorder.VerticalLine; + break; + case XlBordersIndex::xlInsideHorizontal: + if ( aTableBorder.IsHorizontalLineValid ) + rBorderLine = aTableBorder.HorizontalLine; + break; + + case XlBordersIndex::xlDiagonalDown: + case XlBordersIndex::xlDiagonalUp: + // #TODO have to ignore at the moment, would be + // nice to investigate what we can do here + break; + default: + return false; + } + return true; + } + +protected: + virtual OUString getServiceImplName() override + { + return "ScVbaBorder"; + } + virtual css::uno::Sequence<OUString> getServiceNames() override + { + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.Border" + }; + return aServiceNames; + } +public: + ScVbaBorder( const uno::Reference< beans::XPropertySet > & xProps, const uno::Reference< uno::XComponentContext >& xContext, sal_Int32 lineType, const ScVbaPalette& rPalette) : ScVbaBorder_Base( uno::Reference< XHelperInterface >( xProps, uno::UNO_QUERY ), xContext ), m_xProps( xProps ), m_LineType( lineType ), m_Palette( rPalette ) {} + + // XBorder + uno::Any SAL_CALL getColor() override + { + table::BorderLine aBorderLine; + if ( getBorderLine( aBorderLine ) ) + return uno::Any( OORGBToXLRGB( Color(ColorTransparency, aBorderLine.Color) ) ); + throw uno::RuntimeException("No Implementation available" ); + } + void SAL_CALL setColor( const uno::Any& _color ) override + { + sal_Int32 nColor = 0; + _color >>= nColor; + table::BorderLine aBorderLine; + if ( !getBorderLine( aBorderLine ) ) + throw uno::RuntimeException("No Implementation available" ); + + aBorderLine.Color = XLRGBToOORGB( nColor ); + setBorderLine( aBorderLine ); + + } + + uno::Any SAL_CALL getColorIndex() override + { + sal_Int32 nColor = 0; + XLRGBToOORGB( getColor() ) >>= nColor; + uno::Reference< container::XIndexAccess > xIndex = m_Palette.getPalette(); + sal_Int32 nElems = xIndex->getCount(); + sal_Int32 nIndex = -1; + for ( sal_Int32 count=0; count<nElems; ++count ) + { + sal_Int32 nPaletteColor = 0; + xIndex->getByIndex( count ) >>= nPaletteColor; + if ( nPaletteColor == nColor ) + { + nIndex = count + 1; + break; + } + } + return uno::Any(nIndex); + } + + void SAL_CALL setColorIndex( const uno::Any& _colorindex ) override + { + sal_Int32 nColor = 0; + _colorindex >>= nColor; + if ( !nColor || nColor == XlColorIndex::xlColorIndexAutomatic ) + nColor = 1; + setColor( OORGBToXLRGB( m_Palette.getPalette()->getByIndex( --nColor ) ) ); + } + uno::Any SAL_CALL getWeight() override + { + table::BorderLine aBorderLine; + if ( getBorderLine( aBorderLine ) ) + { + switch ( aBorderLine.OuterLineWidth ) + { + case 0: // Thin = default OO thickness + case OOLineThin: + return uno::Any( XlBorderWeight::xlThin ); + case OOLineMedium: + return uno::Any( XlBorderWeight::xlMedium ); + case OOLineThick: + return uno::Any( XlBorderWeight::xlThick ); + case OOLineHairline: + return uno::Any( XlBorderWeight::xlHairline ); + default: + break; + } + } + throw uno::RuntimeException("Method failed" ); + } + void SAL_CALL setWeight( const uno::Any& _weight ) override + { + sal_Int32 nWeight = 0; + _weight >>= nWeight; + table::BorderLine aBorderLine; + if ( !getBorderLine( aBorderLine ) ) + throw uno::RuntimeException("Method failed" ); + + switch ( nWeight ) + { + case XlBorderWeight::xlThin: + aBorderLine.OuterLineWidth = OOLineThin; + break; + case XlBorderWeight::xlMedium: + aBorderLine.OuterLineWidth = OOLineMedium; + break; + case XlBorderWeight::xlThick: + aBorderLine.OuterLineWidth = OOLineThick; + break; + case XlBorderWeight::xlHairline: + aBorderLine.OuterLineWidth = OOLineHairline; + break; + default: + throw uno::RuntimeException("Bad param" ); + } + setBorderLine( aBorderLine ); + + } + + void SAL_CALL setTintAndShade( const uno::Any& /*rAny*/ ) override + { + // TODO implement + } + uno::Any SAL_CALL getTintAndShade() override + { + // TODO implement + return uno::Any(static_cast<double>(0)); + } + + uno::Any SAL_CALL getLineStyle() override + { + // always return xlContinuous; + return uno::Any( XlLineStyle::xlContinuous ); + } + void SAL_CALL setLineStyle( const uno::Any& _linestyle ) override + { + // Urk no choice but to silently ignore we don't support this attribute + // #TODO would be nice to support the excel line styles + sal_Int32 nLineStyle = 0; + _linestyle >>= nLineStyle; + table::BorderLine aBorderLine; + if ( !getBorderLine( aBorderLine ) ) + throw uno::RuntimeException("Method failed" ); + + switch ( nLineStyle ) + { + case XlLineStyle::xlContinuous: + case XlLineStyle::xlDash: + case XlLineStyle::xlDashDot: + case XlLineStyle::xlDashDotDot: + case XlLineStyle::xlDot: + case XlLineStyle::xlDouble: + case XlLineStyle::xlLineStyleNone: + case XlLineStyle::xlSlantDashDot: + break; + default: + throw uno::RuntimeException("Bad param" ); + } + setBorderLine( aBorderLine ); + + } +}; + +class RangeBorders : public RangeBorders_Base +{ +private: + uno::Reference< table::XCellRange > m_xRange; + uno::Reference< uno::XComponentContext > m_xContext; + ScVbaPalette m_Palette; + sal_Int32 getTableIndex( sal_Int32 nConst ) + { + // okay return position of the index in the table + sal_Int32 nIndexes = getCount(); + sal_Int32 realIndex = 0; + const sal_Int16* pTableEntry = supportedIndexTable; + for ( ; realIndex < nIndexes; ++realIndex, ++pTableEntry ) + { + if ( *pTableEntry == nConst ) + return realIndex; + } + return getCount(); // error condition + } +public: + RangeBorders( const uno::Reference< table::XCellRange >& xRange, const uno::Reference< uno::XComponentContext > & xContext, const ScVbaPalette& rPalette ) : m_xRange( xRange ), m_xContext( xContext ), m_Palette( rPalette ) + { + } + // XIndexAccess + virtual ::sal_Int32 SAL_CALL getCount( ) override + { + return SAL_N_ELEMENTS( supportedIndexTable ); + } + virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override + { + + sal_Int32 nIndex = getTableIndex( Index ); + if ( nIndex >= 0 && nIndex < getCount() ) + { + uno::Reference< beans::XPropertySet > xProps( m_xRange, uno::UNO_QUERY_THROW ); + return uno::Any( uno::Reference< excel::XBorder >( new ScVbaBorder( xProps, m_xContext, supportedIndexTable[ nIndex ], m_Palette )) ); + } + throw lang::IndexOutOfBoundsException(); + } + virtual uno::Type SAL_CALL getElementType( ) override + { + return cppu::UnoType<excel::XBorder>::get(); + } + virtual sal_Bool SAL_CALL hasElements( ) override + { + return true; + } +}; + +} + +static uno::Reference< container::XIndexAccess > +rangeToBorderIndexAccess( const uno::Reference< table::XCellRange >& xRange, const uno::Reference< uno::XComponentContext > & xContext, const ScVbaPalette& rPalette ) +{ + return new RangeBorders( xRange, xContext, rPalette ); +} + +namespace { + +class RangeBorderEnumWrapper : public EnumerationHelper_BASE +{ + uno::Reference<container::XIndexAccess > m_xIndexAccess; + sal_Int32 nIndex; +public: + explicit RangeBorderEnumWrapper( const uno::Reference< container::XIndexAccess >& xIndexAccess ) : m_xIndexAccess( xIndexAccess ), nIndex( 0 ) {} + virtual sal_Bool SAL_CALL hasMoreElements( ) override + { + return ( nIndex < m_xIndexAccess->getCount() ); + } + + virtual uno::Any SAL_CALL nextElement( ) override + { + if ( nIndex < m_xIndexAccess->getCount() ) + return m_xIndexAccess->getByIndex( nIndex++ ); + throw container::NoSuchElementException(); + } +}; + +} + +ScVbaBorders::ScVbaBorders( const uno::Reference< XHelperInterface >& xParent, + const uno::Reference< uno::XComponentContext > & xContext, + const uno::Reference< table::XCellRange >& xRange, + const ScVbaPalette& rPalette ) + : ScVbaBorders_BASE( xParent, xContext, rangeToBorderIndexAccess( xRange ,xContext, rPalette ) ), bRangeIsSingleCell( false ) +{ + uno::Reference< table::XColumnRowRange > xColumnRowRange(xRange, uno::UNO_QUERY_THROW ); + if ( xColumnRowRange->getRows()->getCount() == 1 && xColumnRowRange->getColumns()->getCount() == 1 ) + bRangeIsSingleCell = true; + m_xProps.set( xRange, uno::UNO_QUERY_THROW ); +} + +uno::Reference< container::XEnumeration > +ScVbaBorders::createEnumeration() +{ + return new RangeBorderEnumWrapper( m_xIndexAccess ); +} + +uno::Any +ScVbaBorders::createCollectionObject( const css::uno::Any& aSource ) +{ + return aSource; // it's already a Border object +} + +uno::Type +ScVbaBorders::getElementType() +{ + return cppu::UnoType<excel::XBorders>::get(); +} + +uno::Any +ScVbaBorders::getItemByIntIndex( const sal_Int32 nIndex ) +{ + return createCollectionObject( m_xIndexAccess->getByIndex( nIndex ) ); +} + +uno::Any SAL_CALL ScVbaBorders::getColor() +{ + sal_Int32 count = getCount(); + uno::Any color; + for( sal_Int32 i = 0; i < count ; i++ ) + { + if( XlBordersIndex::xlDiagonalDown != supportedIndexTable[i] && XlBordersIndex::xlDiagonalUp != supportedIndexTable[i] ) + { + uno::Reference< XBorder > xBorder( getItemByIntIndex( supportedIndexTable[i] ), uno::UNO_QUERY_THROW ); + if( color.hasValue() ) + { + if( color != xBorder->getColor() ) + return uno::Any( uno::Reference< uno::XInterface >() ); + } + else + color = xBorder->getColor(); + } + } + return color; +} +void SAL_CALL ScVbaBorders::setColor( const uno::Any& _color ) +{ + sal_Int32 count = getCount(); + for( sal_Int32 i = 0; i < count ; i++ ) + { + uno::Reference< XBorder > xBorder( getItemByIntIndex( supportedIndexTable[i] ), uno::UNO_QUERY_THROW ); + xBorder->setColor( _color ); + } +} +uno::Any SAL_CALL ScVbaBorders::getColorIndex() +{ + sal_Int32 count = getCount(); + uno::Any nColorIndex; + for( sal_Int32 i = 0; i < count ; i++ ) + { + if( XlBordersIndex::xlDiagonalDown != supportedIndexTable[i] && XlBordersIndex::xlDiagonalUp != supportedIndexTable[i] ) + { + uno::Reference< XBorder > xBorder( getItemByIntIndex( supportedIndexTable[i] ), uno::UNO_QUERY_THROW ); + if( nColorIndex.hasValue() ) + { + if( nColorIndex != xBorder->getColorIndex() ) + return uno::Any( uno::Reference< uno::XInterface >() ); + } + else + nColorIndex = xBorder->getColorIndex(); + } + } + return nColorIndex; +} +void SAL_CALL ScVbaBorders::setColorIndex( const uno::Any& _colorindex ) +{ + sal_Int32 count = getCount(); + for( sal_Int32 i = 0; i < count ; i++ ) + { + uno::Reference< XBorder > xBorder( getItemByIntIndex( supportedIndexTable[i] ), uno::UNO_QUERY_THROW ); + xBorder->setColorIndex( _colorindex ); + } +} + +static bool +lcl_areAllLineWidthsSame( const table::TableBorder& maTableBorder, bool bIsCell ) +{ + + bool bRes = false; + if (bIsCell) + { + bRes = ((maTableBorder.TopLine.OuterLineWidth == maTableBorder.BottomLine.OuterLineWidth) && +(maTableBorder.TopLine.OuterLineWidth == maTableBorder.LeftLine.OuterLineWidth) && +(maTableBorder.TopLine.OuterLineWidth == maTableBorder.RightLine.OuterLineWidth)); + } + else + { + bRes = ((maTableBorder.TopLine.OuterLineWidth == maTableBorder.BottomLine.OuterLineWidth) && +(maTableBorder.TopLine.OuterLineWidth == maTableBorder.LeftLine.OuterLineWidth) && +(maTableBorder.TopLine.OuterLineWidth == maTableBorder.HorizontalLine.OuterLineWidth) && +(maTableBorder.TopLine.OuterLineWidth == maTableBorder.VerticalLine.OuterLineWidth) && +(maTableBorder.TopLine.OuterLineWidth == maTableBorder.RightLine.OuterLineWidth)); + } + return bRes; +} + +uno::Any SAL_CALL ScVbaBorders::getLineStyle() +{ + table::TableBorder aTableBorder; + m_xProps->getPropertyValue( sTableBorder ) >>= aTableBorder; + + sal_Int32 aLinestyle = XlLineStyle::xlLineStyleNone; + + if ( lcl_areAllLineWidthsSame( aTableBorder, bRangeIsSingleCell )) + { + if (aTableBorder.TopLine.LineDistance != 0) + { + aLinestyle = XlLineStyle::xlDouble; + } + else if ( aTableBorder.TopLine.OuterLineWidth != 0 ) + { + aLinestyle = XlLineStyle::xlContinuous; + } + } + return uno::Any( aLinestyle ); +} +void SAL_CALL ScVbaBorders::setLineStyle( const uno::Any& _linestyle ) +{ + sal_Int32 count = getCount(); + for( sal_Int32 i = 0; i < count ; i++ ) + { + uno::Reference< XBorder > xBorder( getItemByIntIndex( supportedIndexTable[i] ), uno::UNO_QUERY_THROW ); + xBorder->setLineStyle( _linestyle ); + } +} +uno::Any SAL_CALL ScVbaBorders::getWeight() +{ + sal_Int32 count = getCount(); + uno::Any weight; + for( sal_Int32 i = 0; i < count ; i++ ) + { + if( XlBordersIndex::xlDiagonalDown != supportedIndexTable[i] && XlBordersIndex::xlDiagonalUp != supportedIndexTable[i] ) + { + uno::Reference< XBorder > xBorder( getItemByIntIndex( supportedIndexTable[i] ), uno::UNO_QUERY_THROW ); + if( weight.hasValue() ) + { + if( weight != xBorder->getWeight() ) + return uno::Any( uno::Reference< uno::XInterface >() ); + } + else + weight = xBorder->getWeight(); + } + } + return weight; +} + +uno::Any SAL_CALL ScVbaBorders::getTintAndShade() +{ + // TODO implement + return uno::Any(static_cast<double>(0)); +} + +void SAL_CALL ScVbaBorders::setTintAndShade(const uno::Any& /*rAny*/) +{ + // TODO implement +} + +void SAL_CALL ScVbaBorders::setWeight( const uno::Any& _weight ) +{ + sal_Int32 count = getCount(); + for( sal_Int32 i = 0; i < count ; i++ ) + { + uno::Reference< XBorder > xBorder( getItemByIntIndex( supportedIndexTable[i] ), uno::UNO_QUERY_THROW ); + xBorder->setWeight( _weight ); + } +} + +OUString +ScVbaBorders::getServiceImplName() +{ + return "ScVbaBorders"; +} + +uno::Sequence< OUString > +ScVbaBorders::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.Borders" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaborders.hxx b/sc/source/ui/vba/vbaborders.hxx new file mode 100644 index 000000000..6d3621101 --- /dev/null +++ b/sc/source/ui/vba/vbaborders.hxx @@ -0,0 +1,67 @@ +/* -*- 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 . + */ +#pragma once + +#include <ooo/vba/excel/XBorders.hpp> + +#include <vbahelper/vbacollectionimpl.hxx> + +namespace com::sun::star::beans { class XPropertySet; } +namespace com::sun::star::uno { class XComponentContext; } +namespace com::sun::star::table { class XCellRange; } + +typedef CollTestImplHelper< ov::excel::XBorders > ScVbaBorders_BASE; +class ScVbaPalette; +class ScVbaBorders : public ScVbaBorders_BASE +{ + // XEnumerationAccess + virtual css::uno::Any getItemByIntIndex( const sal_Int32 nIndex ) override; + bool bRangeIsSingleCell; + css::uno::Reference< css::beans::XPropertySet > m_xProps; +public: + ScVbaBorders( const css::uno::Reference< ov::XHelperInterface >& xParent, + const css::uno::Reference< css::uno::XComponentContext > & xContext, + const css::uno::Reference< css::table::XCellRange >& xRange, + const ScVbaPalette& rPalette ); + + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + + // XBorders + + // ScVbaCollectionBaseImpl + virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override; + + virtual css::uno::Any SAL_CALL getColor() override; + virtual void SAL_CALL setColor( const css::uno::Any& _color ) override; + virtual css::uno::Any SAL_CALL getColorIndex() override; + virtual void SAL_CALL setColorIndex( const css::uno::Any& _colorindex ) override; + virtual css::uno::Any SAL_CALL getLineStyle() override; + virtual void SAL_CALL setLineStyle( const css::uno::Any& _linestyle ) override; + virtual css::uno::Any SAL_CALL getWeight() override; + virtual void SAL_CALL setWeight( const css::uno::Any& ) override; + virtual css::uno::Any SAL_CALL getTintAndShade() override; + virtual void SAL_CALL setTintAndShade( const css::uno::Any& ) override; + // xxxxBASE + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbacharacters.cxx b/sc/source/ui/vba/vbacharacters.cxx new file mode 100644 index 000000000..3fd00b207 --- /dev/null +++ b/sc/source/ui/vba/vbacharacters.cxx @@ -0,0 +1,134 @@ +/* -*- 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 "vbacharacters.hxx" + +#include "vbafont.hxx" + +#include <com/sun/star/beans/XPropertySet.hpp> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +ScVbaCharacters::ScVbaCharacters( const uno::Reference< XHelperInterface >& xParent, + const uno::Reference< uno::XComponentContext >& xContext, + const ScVbaPalette& dPalette, + const uno::Reference< text::XSimpleText>& xRange, + const css::uno::Any& Start, + const css::uno::Any& Length, + bool Replace ) + : ScVbaCharacters_BASE( xParent, xContext ), + m_xSimpleText(xRange), m_aPalette( dPalette), bReplace( Replace ) +{ + sal_Int16 nLength(-1); + sal_Int16 nStart(1); + Start >>= nStart; + if ( nStart < 1 ) + nStart = 1; // silently correct user error ( as ms ) + nStart--; // OOo is 0 based + Length >>=nLength; + uno::Reference< text::XTextCursor > xTextCursor( m_xSimpleText->createTextCursor(), uno::UNO_SET_THROW ); + xTextCursor->collapseToStart(); + if ( nStart ) + { + if ( ( nStart + 1 ) > m_xSimpleText->getString().getLength() ) + //nStart = m_xSimpleText->getString().getLength(); + xTextCursor->gotoEnd( false ); + xTextCursor->goRight( nStart, false ); + } + if ( nLength < 0 ) // expand to end + xTextCursor->gotoEnd( true ); + else + xTextCursor->goRight( nLength, true ); + m_xTextRange.set( xTextCursor, uno::UNO_QUERY_THROW ); + +} + +OUString SAL_CALL +ScVbaCharacters::getCaption() +{ + return m_xTextRange->getString(); +} +void SAL_CALL +ScVbaCharacters::setCaption( const OUString& _caption ) +{ + m_xTextRange->setString( _caption ); + +} + +::sal_Int32 SAL_CALL +ScVbaCharacters::getCount() +{ + return getCaption().getLength(); +} + +OUString SAL_CALL +ScVbaCharacters::getText() +{ + return getCaption(); +} +void SAL_CALL +ScVbaCharacters::setText( const OUString& _text ) +{ + setCaption( _text ); +} +uno::Reference< excel::XFont > SAL_CALL +ScVbaCharacters::getFont() +{ + uno::Reference< beans::XPropertySet > xProps( m_xTextRange, uno::UNO_QUERY_THROW ); + return uno::Reference< excel::XFont >( new ScVbaFont( this, mxContext, m_aPalette, xProps ) ); +} +void SAL_CALL +ScVbaCharacters::setFont( const uno::Reference< excel::XFont >& /*_font*/ ) +{ + // #TODO #FIXME needs implementation, or can't be done? + throw uno::RuntimeException("Not Implemented" ); +} + +// Methods +void SAL_CALL +ScVbaCharacters::Insert( const OUString& rString ) +{ + m_xSimpleText->insertString( m_xTextRange, rString, bReplace ); +} + +void SAL_CALL +ScVbaCharacters::Delete( ) +{ + // #FIXME #TODO is this a bit suspect? I wonder should the contents + // of the cell be deleted from the parent ( range ) + m_xSimpleText->setString(OUString()); +} + +OUString +ScVbaCharacters::getServiceImplName() +{ + return "ScVbaCharacters"; +} + +uno::Sequence< OUString > +ScVbaCharacters::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.Characters" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbacharacters.hxx b/sc/source/ui/vba/vbacharacters.hxx new file mode 100644 index 000000000..1d9c3c82f --- /dev/null +++ b/sc/source/ui/vba/vbacharacters.hxx @@ -0,0 +1,61 @@ +/* -*- 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 . + */ +#pragma once + +#include <ooo/vba/excel/XCharacters.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/text/XSimpleText.hpp> + +#include <vbahelper/vbahelperinterface.hxx> +#include "vbapalette.hxx" +typedef InheritedHelperInterfaceWeakImpl< ov::excel::XCharacters > ScVbaCharacters_BASE; + +class ScVbaCharacters : public ScVbaCharacters_BASE +{ +private: + css::uno::Reference< css::text::XTextRange > m_xTextRange; + css::uno::Reference< css::text::XSimpleText > m_xSimpleText; + ScVbaPalette m_aPalette; + // Add because of MSO has different behavior. + bool bReplace; +public: + /// @throws css::lang::IllegalArgumentException + /// @throws css::uno::RuntimeException + ScVbaCharacters( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext, const ScVbaPalette& dPalette, const css::uno::Reference< css::text::XSimpleText >& xRange, const css::uno::Any& Start, const css::uno::Any& Length, bool bReplace = false ); + + // Attributes + virtual OUString SAL_CALL getCaption() override; + virtual void SAL_CALL setCaption( const OUString& _caption ) override; + virtual ::sal_Int32 SAL_CALL getCount() override; + virtual OUString SAL_CALL getText() override; + virtual void SAL_CALL setText( const OUString& _text ) override; + virtual css::uno::Reference< ov::excel::XFont > SAL_CALL getFont() override; + virtual void SAL_CALL setFont( const css::uno::Reference< ov::excel::XFont >& _font ) override; + + // Methods + virtual void SAL_CALL Insert( const OUString& String ) override; + virtual void SAL_CALL Delete( ) override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbachart.cxx b/sc/source/ui/vba/vbachart.cxx new file mode 100644 index 000000000..5d9cd56a8 --- /dev/null +++ b/sc/source/ui/vba/vbachart.cxx @@ -0,0 +1,1056 @@ +/* -*- 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 "vbachart.hxx" +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/sheet/XCellRangeAddressable.hpp> +#include <com/sun/star/chart/XAxisXSupplier.hpp> +#include <com/sun/star/chart/XAxisYSupplier.hpp> +#include <com/sun/star/chart/XAxisZSupplier.hpp> +#include <com/sun/star/chart/XTwoAxisXSupplier.hpp> +#include <com/sun/star/chart/XTwoAxisYSupplier.hpp> +#include <com/sun/star/chart/XChartDataArray.hpp> +#include <com/sun/star/chart/ChartSymbolType.hpp> +#include <com/sun/star/chart/ChartSolidType.hpp> +#include <com/sun/star/chart/ChartDataRowSource.hpp> +#include <ooo/vba/excel/XlChartType.hpp> +#include <ooo/vba/excel/XlRowCol.hpp> +#include <ooo/vba/excel/XlAxisType.hpp> +#include <ooo/vba/excel/XlAxisGroup.hpp> + +#include <basic/sberrors.hxx> +#include "vbachartobject.hxx" +#include "vbarange.hxx" +#include "vbacharttitle.hxx" +#include "vbaaxes.hxx" +#include <document.hxx> + +using namespace ::com::sun::star; +using namespace ::ooo::vba; +using namespace ::ooo::vba::excel::XlChartType; +using namespace ::ooo::vba::excel::XlRowCol; +using namespace ::ooo::vba::excel::XlAxisType; +using namespace ::ooo::vba::excel::XlAxisGroup; + +constexpr OUStringLiteral CHART_NAME(u"Name"); +// #TODO move this constant to vbaseries.[ch]xx ( when it exists ) +constexpr OUStringLiteral DEFAULTSERIESPREFIX(u"Series"); +constexpr OUStringLiteral DATAROWSOURCE(u"DataRowSource"); +constexpr OUStringLiteral UPDOWN(u"UpDown"); +constexpr OUStringLiteral VOLUME(u"Volume"); +constexpr OUStringLiteral LINES(u"Lines"); +constexpr OUStringLiteral SPLINETYPE(u"SplineType"); +constexpr OUStringLiteral SYMBOLTYPE(u"SymbolType"); +constexpr OUStringLiteral DEEP(u"Deep"); +constexpr OUStringLiteral SOLIDTYPE(u"SolidType"); +constexpr OUStringLiteral VERTICAL(u"Vertical"); +constexpr OUStringLiteral PERCENT(u"Percent"); +constexpr OUStringLiteral STACKED(u"Stacked"); +constexpr OUStringLiteral DIM3D(u"Dim3D"); +constexpr OUStringLiteral HASMAINTITLE(u"HasMainTitle"); +constexpr OUStringLiteral HASLEGEND(u"HasLegend"); + +ScVbaChart::ScVbaChart( const css::uno::Reference< ov::XHelperInterface >& _xParent, const css::uno::Reference< css::uno::XComponentContext >& _xContext, const css::uno::Reference< css::lang::XComponent >& _xChartComponent, const css::uno::Reference< css::table::XTableChart >& _xTableChart ) : ChartImpl_BASE( _xParent, _xContext ), mxTableChart( _xTableChart ) +{ + mxChartDocument.set( _xChartComponent, uno::UNO_QUERY_THROW ) ; + // #TODO is it possible that the XPropertySet interface is not set + // code in setPlotBy seems to indicate that this is possible? but + // additionally there is no check in most of the places where it is used + // ( and therefore could possibly be NULL ) + // I'm going to let it throw for the moment ( npower ) + mxDiagramPropertySet.set( mxChartDocument->getDiagram(), uno::UNO_QUERY_THROW ); + mxChartPropertySet.set( _xChartComponent, uno::UNO_QUERY_THROW ) ; +} + +OUString SAL_CALL +ScVbaChart::getName() +{ + OUString sName; + uno::Reference< beans::XPropertySet > xProps( mxChartDocument, uno::UNO_QUERY_THROW ); + try + { + xProps->getPropertyValue( CHART_NAME ) >>= sName; + } + catch( const uno::Exception & ) // swallow exceptions + { + } + return sName; +} + +uno::Any SAL_CALL +ScVbaChart::SeriesCollection(const uno::Any&) +{ + return uno::Any(); +} + +::sal_Int32 SAL_CALL +ScVbaChart::getChartType() +{ + sal_Int32 nChartType = -1; + try + { + OUString sDiagramType = mxChartDocument->getDiagram()->getDiagramType(); + if ( sDiagramType == "com.sun.star.chart.AreaDiagram" ) + { + if (is3D()) + { + nChartType = getStackedType(xl3DAreaStacked, xl3DAreaStacked100, xl3DArea); + } + else + { + nChartType = getStackedType(xlAreaStacked, xlAreaStacked100, xlArea); + } + } + else if ( sDiagramType == "com.sun.star.chart.PieDiagram" ) + { + if (is3D()) + nChartType = xl3DPie; + else + nChartType = xlPie; /*TODO XlChartType xlPieExploded, XlChartType xlPieOfPie */ + } + else if ( sDiagramType == "com.sun.star.chart.BarDiagram" ) + { + sal_Int32 nSolidType = chart::ChartSolidType::RECTANGULAR_SOLID; + if (mxDiagramPropertySet->getPropertySetInfo()->hasPropertyByName(SOLIDTYPE)) + { //in 2D diagrams 'SolidType' may not be set + if (is3D()) + mxDiagramPropertySet->getPropertyValue(SOLIDTYPE) >>= nSolidType; + } + switch (nSolidType) + { + case chart::ChartSolidType::CONE: + nChartType = getSolidType(xlConeCol, xlConeColStacked, xlConeColStacked100, xlConeColClustered, xlConeBarStacked, xlConeBarStacked100, xlConeBarClustered); + break; + case chart::ChartSolidType::CYLINDER: + nChartType = getSolidType(xlCylinderCol, xlCylinderColStacked, xlCylinderColStacked100, xlCylinderColClustered, xlCylinderBarStacked, xlCylinderBarStacked100, xlCylinderBarClustered); + break; + case chart::ChartSolidType::PYRAMID: + nChartType = getSolidType(xlPyramidCol, xlPyramidColStacked, xlPyramidColStacked100, xlPyramidColClustered, xlPyramidBarStacked, xlPyramidBarStacked100, xlPyramidBarClustered); + break; + default: // RECTANGULAR_SOLID + if (is3D()) + { + nChartType = getSolidType(xl3DColumn, xl3DColumnStacked, xl3DColumnStacked100, xl3DColumnClustered, xl3DBarStacked, xl3DBarStacked100, xl3DBarClustered); + } + else + { + nChartType = getSolidType(xlColumnClustered, xlColumnStacked, xlColumnStacked100, xlColumnClustered, xlBarStacked, xlBarStacked100, xlBarClustered); + } + break; + } + } + else if ( sDiagramType == "com.sun.star.chart.StockDiagram" ) + { + bool bVolume = false; + mxDiagramPropertySet->getPropertyValue(VOLUME) >>= bVolume; + if (bVolume) + { + nChartType = getStockUpDownValue(xlStockVOHLC, xlStockVHLC); + } + else + { + nChartType = getStockUpDownValue(xlStockOHLC, xlStockHLC); + } + } + else if ( sDiagramType == "com.sun.star.chart.XYDiagram" ) + { + bool bHasLines = false; + mxDiagramPropertySet->getPropertyValue(LINES) >>= bHasLines; + sal_Int32 nSplineType = 0; + mxDiagramPropertySet->getPropertyValue(SPLINETYPE) >>= nSplineType; + if (nSplineType == 1) + { + nChartType = getMarkerType(xlXYScatterSmooth, xlXYScatterSmoothNoMarkers); + } + else if (bHasLines) + { + nChartType = getMarkerType(xlXYScatterLines, xlXYScatterLinesNoMarkers); + } + else + { + nChartType = xlXYScatter; + } + } + else if ( sDiagramType == "com.sun.star.chart.LineDiagram" ) + { + if (is3D()) + { + nChartType = xl3DLine; + } + else if (hasMarkers()) + { + nChartType = getStackedType(xlLineMarkersStacked, xlLineMarkersStacked100, xlLineMarkers); + } + else + { + nChartType = getStackedType(xlLineStacked, xlLineStacked100, xlLine); + } + } + else if ( sDiagramType == "com.sun.star.chart.DonutDiagram" ) + { + nChartType = xlDoughnut; // TODO DoughnutExploded ?? + } + else if ( sDiagramType == "com.sun.star.chart.NetDiagram" ) + { + nChartType = getMarkerType(xlRadarMarkers, xlRadar); + } + } + catch ( const uno::Exception& ) + { + throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() ); + } + return nChartType; +} + +void SAL_CALL +ScVbaChart::setChartType( ::sal_Int32 _nChartType ) +{ + try + { + switch (_nChartType) + { + case xlColumnClustered: + case xlColumnStacked: + case xlColumnStacked100: + case xl3DColumnClustered: + case xl3DColumnStacked: + case xl3DColumnStacked100: + case xl3DColumn: + case xlBarClustered: + case xlBarStacked: + case xlBarStacked100: + case xl3DBarClustered: + case xl3DBarStacked: + case xl3DBarStacked100: + case xlConeColClustered: + case xlConeColStacked: + case xlConeColStacked100: + case xlConeBarClustered: + case xlConeBarStacked: + case xlConeBarStacked100: + case xlConeCol: + case xlPyramidColClustered: + case xlPyramidColStacked: + case xlPyramidColStacked100: + case xlPyramidBarClustered: + case xlPyramidBarStacked: + case xlPyramidBarStacked100: + case xlPyramidCol: + case xlCylinderColClustered: + case xlCylinderColStacked: + case xlCylinderColStacked100: + case xlCylinderBarClustered: + case xlCylinderBarStacked: + case xlCylinderBarStacked100: + case xlCylinderCol: + case xlSurface: // not possible + case xlSurfaceWireframe: + case xlSurfaceTopView: + case xlSurfaceTopViewWireframe: + setDiagram( "com.sun.star.chart.BarDiagram"); + break; + case xlLine: + case xl3DLine: + case xlLineStacked: + case xlLineStacked100: + case xlLineMarkers: + case xlLineMarkersStacked: + case xlLineMarkersStacked100: + setDiagram( "com.sun.star.chart.LineDiagram"); + break; + case xl3DArea: + case xlArea: + case xlAreaStacked: + case xlAreaStacked100: + case xl3DAreaStacked: + case xl3DAreaStacked100: + setDiagram( "com.sun.star.chart.AreaDiagram" ); + break; + case xlDoughnut: + case xlDoughnutExploded: + setDiagram( "com.sun.star.chart.DonutDiagram" ); + break; + case xlStockHLC: + case xlStockOHLC: + case xlStockVHLC: + case xlStockVOHLC: + setDiagram( "com.sun.star.chart.StockDiagram"); + mxDiagramPropertySet->setPropertyValue( UPDOWN, uno::Any((_nChartType == xlStockOHLC) || (_nChartType == xlStockVOHLC))); + mxDiagramPropertySet->setPropertyValue( VOLUME, uno::Any((_nChartType == xlStockVHLC) || (_nChartType == xlStockVOHLC))); + break; + + case xlPieOfPie: // not possible + case xlPieExploded: // SegmentOffset on ChartDataPointProperties -> get from XDiagram //How does Excel do this? + case xl3DPieExploded: + case xl3DPie: + case xlPie: + case xlBarOfPie: // not possible (Zoom pie) + setDiagram( "com.sun.star.chart.PieDiagram"); + break; + + case xlRadar: + case xlRadarMarkers: + case xlRadarFilled: + setDiagram( "com.sun.star.chart.NetDiagram"); + break; + case xlXYScatter: + case xlBubble: // not possible + case xlBubble3DEffect: // not possible + case xlXYScatterLines: + case xlXYScatterLinesNoMarkers: + case xlXYScatterSmooth: + case xlXYScatterSmoothNoMarkers: + setDiagram( "com.sun.star.chart.XYDiagram"); + switch(_nChartType) + { + case xlXYScatter: + case xlBubble: // not possible + case xlBubble3DEffect: // not possible + mxDiagramPropertySet->setPropertyValue(LINES, uno::Any( false )); + break; + case xlXYScatterLines: + case xlXYScatterLinesNoMarkers: + mxDiagramPropertySet->setPropertyValue(LINES, uno::Any( true )); + break; + case xlXYScatterSmooth: + case xlXYScatterSmoothNoMarkers: + mxDiagramPropertySet->setPropertyValue(SPLINETYPE, uno::Any( sal_Int32(1))); + break; + default: + break; + } + break; + default: + throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_CONVERSION), OUString() ); + } + + switch (_nChartType) + { + case xlLineMarkers: + case xlLineMarkersStacked: + case xlLineMarkersStacked100: + case xlRadarMarkers: + case xlXYScatterLines: + case xlXYScatterSmooth: + case xlXYScatter: + case xlBubble: // not possible + case xlBubble3DEffect: // not possible + mxDiagramPropertySet->setPropertyValue(SYMBOLTYPE, uno::Any( chart::ChartSymbolType::AUTO)); + break; + default: + if (mxDiagramPropertySet->getPropertySetInfo()->hasPropertyByName(SYMBOLTYPE)) + { + mxDiagramPropertySet->setPropertyValue(SYMBOLTYPE, uno::Any(chart::ChartSymbolType::NONE)); + } + break; + } + + switch (_nChartType) + { + case xlConeCol: + case xlPyramidCol: + case xlCylinderCol: + case xl3DColumn: + case xlSurface: // not possible + case xlSurfaceWireframe: + case xlSurfaceTopView: + case xlSurfaceTopViewWireframe: + mxDiagramPropertySet->setPropertyValue(DEEP,uno::Any( true )); + break; + default: + if (mxDiagramPropertySet->getPropertySetInfo()->hasPropertyByName(DEEP)) + { + mxDiagramPropertySet->setPropertyValue(DEEP, uno::Any( false)); + } + break; + } + + switch (_nChartType) + { + case xlConeColClustered: + case xlConeColStacked: + case xlConeColStacked100: + case xlConeBarClustered: + case xlConeBarStacked: + case xlConeBarStacked100: + case xlConeCol: + mxDiagramPropertySet->setPropertyValue(SOLIDTYPE, uno::Any(chart::ChartSolidType::CONE)); + break; + case xlPyramidColClustered: + case xlPyramidColStacked: + case xlPyramidColStacked100: + case xlPyramidBarClustered: + case xlPyramidBarStacked: + case xlPyramidBarStacked100: + case xlPyramidCol: + mxDiagramPropertySet->setPropertyValue(SOLIDTYPE, uno::Any(chart::ChartSolidType::PYRAMID)); + break; + case xlCylinderColClustered: + case xlCylinderColStacked: + case xlCylinderColStacked100: + case xlCylinderBarClustered: + case xlCylinderBarStacked: + case xlCylinderBarStacked100: + case xlCylinderCol: + mxDiagramPropertySet->setPropertyValue(SOLIDTYPE, uno::Any(chart::ChartSolidType::CYLINDER)); + break; + default: + if (mxDiagramPropertySet->getPropertySetInfo()->hasPropertyByName(SOLIDTYPE)) + { + mxDiagramPropertySet->setPropertyValue(SOLIDTYPE, uno::Any(chart::ChartSolidType::RECTANGULAR_SOLID)); + } + break; + } + + switch ( _nChartType) + { + case xlConeCol: + case xlConeColClustered: + case xlConeColStacked: + case xlConeColStacked100: + case xlPyramidColClustered: + case xlPyramidColStacked: + case xlPyramidColStacked100: + case xlCylinderColClustered: + case xlCylinderColStacked: + case xlCylinderColStacked100: + case xlColumnClustered: + case xlColumnStacked: + case xlColumnStacked100: + case xl3DColumnClustered: + case xl3DColumnStacked: + case xl3DColumnStacked100: + case xlSurface: // not possible + case xlSurfaceWireframe: + case xlSurfaceTopView: + case xlSurfaceTopViewWireframe: + mxDiagramPropertySet->setPropertyValue(VERTICAL, uno::Any( true)); + break; + default: + if (mxDiagramPropertySet->getPropertySetInfo()->hasPropertyByName(VERTICAL)) + { + mxDiagramPropertySet->setPropertyValue(VERTICAL, uno::Any(false)); + } + break; + } + + switch (_nChartType) + { + case xlColumnStacked: + case xl3DColumnStacked: + case xlBarStacked: + case xl3DBarStacked: + case xlLineStacked: + case xlLineMarkersStacked: + case xlAreaStacked: + case xl3DAreaStacked: + case xlCylinderColStacked: + case xlCylinderBarStacked: + case xlConeColStacked: + case xlConeBarStacked: + case xlPyramidColStacked: + case xlPyramidBarStacked: + mxDiagramPropertySet->setPropertyValue(PERCENT, uno::Any( false )); + mxDiagramPropertySet->setPropertyValue(STACKED, uno::Any( true )); + break; + case xlPyramidColStacked100: + case xlPyramidBarStacked100: + case xlConeColStacked100: + case xlConeBarStacked100: + case xlCylinderBarStacked100: + case xlCylinderColStacked100: + case xl3DAreaStacked100: + case xlLineMarkersStacked100: + case xlAreaStacked100: + case xlLineStacked100: + case xl3DBarStacked100: + case xlBarStacked100: + case xl3DColumnStacked100: + case xlColumnStacked100: + mxDiagramPropertySet->setPropertyValue(STACKED, uno::Any( true)); + mxDiagramPropertySet->setPropertyValue(PERCENT, uno::Any( true )); + break; + default: + mxDiagramPropertySet->setPropertyValue(PERCENT, uno::Any( false)); + mxDiagramPropertySet->setPropertyValue(STACKED, uno::Any( false)); + break; + } + switch (_nChartType) + { + case xl3DArea: + case xl3DAreaStacked: + case xl3DAreaStacked100: + case xl3DBarClustered: + case xl3DBarStacked: + case xl3DBarStacked100: + case xl3DColumn: + case xl3DColumnClustered: + case xl3DColumnStacked: + case xl3DColumnStacked100: + case xl3DLine: + case xl3DPie: + case xl3DPieExploded: + case xlConeColClustered: + case xlConeColStacked: + case xlConeColStacked100: + case xlConeBarClustered: + case xlConeBarStacked: + case xlConeBarStacked100: + case xlConeCol: + case xlPyramidColClustered: + case xlPyramidColStacked: + case xlPyramidColStacked100: + case xlPyramidBarClustered: + case xlPyramidBarStacked: + case xlPyramidBarStacked100: + case xlPyramidCol: + case xlCylinderColClustered: + case xlCylinderColStacked: + case xlCylinderColStacked100: + case xlCylinderBarClustered: + case xlCylinderBarStacked: + case xlCylinderBarStacked100: + case xlCylinderCol: + mxDiagramPropertySet->setPropertyValue(DIM3D, uno::Any( true)); + break; + default: + if (mxDiagramPropertySet->getPropertySetInfo()->hasPropertyByName(DIM3D)) + { + mxDiagramPropertySet->setPropertyValue(DIM3D, uno::Any( false)); + } + break; + } + } + catch ( const uno::Exception& ) + { + throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() ); + } +} + +void SAL_CALL +ScVbaChart::Activate() +{ + // #TODO how are Chart sheets handled ( I know we don't even consider + // them in the worksheets/sheets collections ), but...??? + // note: in vba for excel the parent of a Chart sheet is a workbook, + // e.g. 'ThisWorkbook' + uno::Reference< XHelperInterface > xParent( getParent() ); + ScVbaChartObject* pChartObj = static_cast< ScVbaChartObject* >( xParent.get() ); + if ( !pChartObj ) + throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), "no ChartObject as parent" ); + + pChartObj->Activate(); + +} + +void SAL_CALL +ScVbaChart::setSourceData( const css::uno::Reference< ::ooo::vba::excel::XRange >& _xCalcRange, const css::uno::Any& _aPlotBy ) +{ + try + { + table::CellRangeAddress aSingleRangeAddress; + + uno::Reference< sheet::XCellRangeAddressable > xAddressable( _xCalcRange->getCellRange(), uno::UNO_QUERY_THROW ); + aSingleRangeAddress = xAddressable->getRangeAddress(); + + mxTableChart->setRanges({ aSingleRangeAddress } ); + + bool bsetRowHeaders = false; + bool bsetColumnHeaders = false; + + ScVbaRange* pRange = static_cast< ScVbaRange* >( _xCalcRange.get() ); + if ( pRange ) + { + ScDocument& rDoc = pRange->getScDocument(); + bsetRowHeaders = rDoc.HasRowHeader( static_cast< SCCOL >( aSingleRangeAddress.StartColumn ), static_cast< SCROW >( aSingleRangeAddress.StartRow ), static_cast< SCCOL >( aSingleRangeAddress.EndColumn ), static_cast< SCROW >( aSingleRangeAddress.EndRow ), static_cast< SCTAB >( aSingleRangeAddress.Sheet ) ); + bsetColumnHeaders = rDoc.HasColHeader( static_cast< SCCOL >( aSingleRangeAddress.StartColumn ), static_cast< SCROW >( aSingleRangeAddress.StartRow ), static_cast< SCCOL >( aSingleRangeAddress.EndColumn ), static_cast< SCROW >( aSingleRangeAddress.EndRow ), static_cast< SCTAB >( aSingleRangeAddress.Sheet )); + } + mxTableChart->setHasRowHeaders(bsetRowHeaders); + mxTableChart->setHasColumnHeaders(bsetColumnHeaders); + + if ((!bsetColumnHeaders) || (!bsetRowHeaders)) + { + uno::Reference< chart::XChartDataArray > xChartDataArray( mxChartDocument->getData(), uno::UNO_QUERY_THROW ); + if (!bsetColumnHeaders) + { + xChartDataArray->setColumnDescriptions( getDefaultSeriesDescriptions(xChartDataArray->getColumnDescriptions().getLength() )); + } + if (!bsetRowHeaders) + { + xChartDataArray->setRowDescriptions(getDefaultSeriesDescriptions(xChartDataArray->getRowDescriptions().getLength() )); + } + } + + if ( _aPlotBy.hasValue() ) + { + sal_Int32 nVal = 0; + _aPlotBy >>= nVal; + setPlotBy( nVal ); + } + else + { + sal_Int32 nRows = aSingleRangeAddress.EndRow - aSingleRangeAddress.StartRow; + sal_Int32 nCols = aSingleRangeAddress.EndColumn - aSingleRangeAddress.StartColumn; + // AutoDetect emulation + if ( nRows > nCols ) + setPlotBy( xlColumns ); + else if ( nRows <= nCols ) + setPlotBy( xlRows ); + } + } + catch (const uno::Exception&) + { + throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() ); + } +} + +uno::Sequence< OUString > +ScVbaChart::getDefaultSeriesDescriptions( sal_Int32 _nCount ) +{ + uno::Sequence< OUString > sDescriptions ( _nCount ); + std::generate_n(sDescriptions.getArray(), _nCount, + [i = 1]() mutable -> OUString { return DEFAULTSERIESPREFIX + OUString::number(i++); }); + return sDescriptions; +} + +void +ScVbaChart::setDefaultChartType() +{ + setChartType( xlColumnClustered ); +} + +void +ScVbaChart::setPlotBy( ::sal_Int32 _nPlotBy ) +{ + try + { + if ( !mxDiagramPropertySet.is() ) + setDefaultChartType(); + switch (_nPlotBy) + { + case xlRows: + mxDiagramPropertySet->setPropertyValue( DATAROWSOURCE, uno::Any( chart::ChartDataRowSource_ROWS ) ); + break; + case xlColumns: + mxDiagramPropertySet->setPropertyValue( DATAROWSOURCE, uno::Any( chart::ChartDataRowSource_COLUMNS) ); + break; + default: + throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() ); + } + } + catch (const uno::Exception&) + { + throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() ); + } +} + +::sal_Int32 SAL_CALL +ScVbaChart::getPlotBy( ) +{ + try + { + chart::ChartDataRowSource aChartDataRowSource; + mxDiagramPropertySet->getPropertyValue(DATAROWSOURCE) >>= aChartDataRowSource; + if (aChartDataRowSource == chart::ChartDataRowSource_COLUMNS) + { + return xlColumns; + } + else + { + return xlRows; + } + } + catch (const uno::Exception&) + { + throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() ); + } +} + +void +ScVbaChart::setDiagram( const OUString& _sDiagramType ) +{ + try + { + uno::Reference< lang::XMultiServiceFactory > xMSF( mxChartDocument, uno::UNO_QUERY_THROW ); + uno::Reference< chart::XDiagram > xDiagram( xMSF->createInstance( _sDiagramType ), uno::UNO_QUERY_THROW ); + mxChartDocument->setDiagram( xDiagram ); + mxDiagramPropertySet.set( xDiagram, uno::UNO_QUERY_THROW ); + } + catch ( const uno::Exception& ) + { + throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() ); + } +} + +// #TODO find out why we have Location/getLocation? there is afaik no +// Location property, just a Location function for the Chart object +sal_Int32 SAL_CALL +ScVbaChart::Location() +{ + return getLocation(); +} + +sal_Int32 SAL_CALL +ScVbaChart::getLocation() +{ + return -1; +} + +void SAL_CALL +ScVbaChart::setLocation( ::sal_Int32 /*where*/, const css::uno::Any& /*Name*/ ) +{ + // Helper api just stubs out the code <shrug> + // #TODO come back and make sense out of this +// String sheetName = null; +// +// if ((name != null) && name instanceof String) { +// sheetName = (String) name; +// } +// XSpreadsheetDocument xShDoc = (XSpreadsheetDocument) UnoRuntime.queryInterface( XSpreadsheetDocument.class,getXModel() ); +// com.sun.star.sheet.XSpreadsheets xSheets = xShDoc.Sheets(); +// +// switch (where) { +// case ClLocationType.clLocationAsObject_value: //{ +// +// if (sheetName == null) { +// DebugHelper.writeInfo("Can't embed in Chart without knowing SheetName"); +// return; +// } +// +// try { +// Any any = (Any) xSheets.getByName(sheetName); +// chartSheet = (XSpreadsheet) any.getObject(); +// +// // chartSheet = (XSpreadsheet) xSheets.getByName( sheetName ); +// } catch (NoSuchElementException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// +// return; +// } catch (WrappedTargetException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// +// return; +// } catch (java.lang.Exception e) { +// e.printStackTrace(); +// } +// +// XTableChartsSupplier xTCS = (XTableChartsSupplier) UnoRuntime.queryInterface( XTableChartsSupplier.class, chartSheet); +// XTableCharts xTableCharts = xTCS.getCharts(); +// XIndexAccess xIA = (XIndexAccess) UnoRuntime.queryInterface( XIndexAccess.class, xTableCharts); +// int numCharts = xIA.getCount(); +// chartName = "Chart " + (numCharts + 1); +// +// //} +// break; +// +// case ClLocationType.clLocationAsNewSheet_value: +// case ClLocationType.clLocationAutomatic_value:default: //{ +// chartName = "Chart 1"; // Since it's a new sheet, it's the first on it... +// +// XIndexAccess xSheetIA = (XIndexAccess) UnoRuntime.queryInterface( XIndexAccess.class, xSheets); +// +// short newSheetNum = (short) (xSheetIA.getCount() + 1); +// +// if (sheetName == null){ +// sheetName = "ChartSheet " + newSheetNum; // Why not? +// } +// // DPK TODO : Probably should use Sheets to create this! +// xSheets.insertNewByName(sheetName, newSheetNum); +// +// try { +// chartSheet = +// (XSpreadsheet) xSheets.getByName(sheetName); +// } catch (NoSuchElementException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// +// return; +// } catch (WrappedTargetException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// +// return; +// } +// +// //} +// break; +// } +// +// // Last thing should be a call to createChartForReal(), one of them +// // should succeed. +// createChartForReal(); + +} + +sal_Bool SAL_CALL +ScVbaChart::getHasTitle( ) +{ + bool bHasTitle = false; + try + { + mxChartPropertySet->getPropertyValue(HASMAINTITLE) >>= bHasTitle; + } + catch (const uno::Exception&) + { + throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() ); + } + return bHasTitle; +} + +void SAL_CALL +ScVbaChart::setHasTitle( sal_Bool bTitle ) +{ + try + { + mxChartPropertySet->setPropertyValue(HASMAINTITLE, uno::Any( bTitle )); + } + catch (const uno::Exception&) + { + throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() ); + } + +} + +sal_Bool SAL_CALL +ScVbaChart::getHasLegend( ) +{ + bool bHasLegend = false; + try + { + mxChartPropertySet->getPropertyValue(HASLEGEND) >>= bHasLegend; + } + catch (const uno::Exception&) + { + throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() ); + } + return bHasLegend; +} + +void SAL_CALL +ScVbaChart::setHasLegend( sal_Bool bLegend ) +{ + try + { + mxChartPropertySet->setPropertyValue(HASLEGEND, uno::Any(bLegend)); + } + catch (const uno::Exception&) + { + throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() ); + } +} + +uno::Reference< excel::XChartTitle > SAL_CALL +ScVbaChart::getChartTitle( ) +{ + uno::Reference< drawing::XShape > xTitleShape = mxChartDocument->getTitle(); + // #TODO check parent + return new ScVbaChartTitle(this, mxContext, xTitleShape); +} + +uno::Any SAL_CALL +ScVbaChart::Axes( const uno::Any& Type, const uno::Any& AxisGroup ) +{ + // mmm chart probably is the parent, #TODO check parent + uno::Reference< excel::XAxes > xAxes = new ScVbaAxes( this, mxContext, this ); + if ( !Type.hasValue() ) + return uno::Any( xAxes ); + return xAxes->Item( Type, AxisGroup ); +} +bool +ScVbaChart::is3D() +{ + // #TODO perhaps provide limited Debughelper functionality + bool is3d = false; + mxDiagramPropertySet->getPropertyValue(DIM3D) >>= is3d; + return is3d; +} + +sal_Int32 +ScVbaChart::getStackedType( sal_Int32 _nStacked, sal_Int32 _n100PercentStacked, sal_Int32 _nUnStacked ) +{ + // #TODO perhaps provide limited Debughelper functionality + if (isStacked()) + { + if (is100PercentStacked()) + return _n100PercentStacked; + else + return _nStacked; + } + else + return _nUnStacked; +} + +bool +ScVbaChart::isStacked() +{ + // #TODO perhaps provide limited Debughelper functionality + bool bStacked = false; + mxDiagramPropertySet->getPropertyValue(STACKED) >>= bStacked; + return bStacked; +} + +bool +ScVbaChart::is100PercentStacked() +{ + // #TODO perhaps provide limited Debughelper functionality + bool b100Percent = false; + mxDiagramPropertySet->getPropertyValue(PERCENT) >>= b100Percent; + return b100Percent; +} + +sal_Int32 +ScVbaChart::getSolidType(sal_Int32 _nDeep, sal_Int32 _nVertiStacked, sal_Int32 _nVerti100PercentStacked, sal_Int32 _nVertiUnStacked, sal_Int32 _nHoriStacked, sal_Int32 _nHori100PercentStacked, sal_Int32 _nHoriUnStacked) +{ + try + { + bool bIsVertical = true; + mxDiagramPropertySet->getPropertyValue(VERTICAL) >>= bIsVertical; + bool bIsDeep = false; + mxDiagramPropertySet->getPropertyValue(DEEP) >>= bIsDeep; + + if (bIsDeep) + { + return _nDeep; + } + else + { + if (bIsVertical) + { + return getStackedType(_nVertiStacked, _nVerti100PercentStacked, _nVertiUnStacked); + } + else + { + return getStackedType(_nHoriStacked, _nHori100PercentStacked, _nHoriUnStacked); + } + } + } + catch (const uno::Exception&) + { + throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() ); + } +} + +sal_Int32 +ScVbaChart::getStockUpDownValue(sal_Int32 _nUpDown, sal_Int32 _nNotUpDown) +{ + try + { + bool bUpDown = false; + mxDiagramPropertySet->getPropertyValue(UPDOWN) >>= bUpDown; + if (bUpDown) + { + return _nUpDown; + } + else + { + return _nNotUpDown; + } + } + catch (const uno::Exception&) + { + throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() ); + } +} + +bool +ScVbaChart::hasMarkers() +{ + bool bHasMarkers = false; + try + { + sal_Int32 nSymbol=0; + mxDiagramPropertySet->getPropertyValue(SYMBOLTYPE) >>= nSymbol; + bHasMarkers = nSymbol != chart::ChartSymbolType::NONE; + } + catch (const uno::Exception&) + { + throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() ); + } + return bHasMarkers; +} + +sal_Int32 +ScVbaChart::getMarkerType(sal_Int32 _nWithMarkers, sal_Int32 _nWithoutMarkers) +{ + if (hasMarkers()) + return _nWithMarkers; + return _nWithoutMarkers; +} + +void +ScVbaChart::assignDiagramAttributes() +{ + xAxisXSupplier.set( mxDiagramPropertySet, uno::UNO_QUERY_THROW ); + xAxisYSupplier.set( mxDiagramPropertySet, uno::UNO_QUERY_THROW ); + xAxisZSupplier.set( mxDiagramPropertySet, uno::UNO_QUERY_THROW ); + xTwoAxisXSupplier.set( mxDiagramPropertySet, uno::UNO_QUERY_THROW ); + xTwoAxisYSupplier.set( mxDiagramPropertySet, uno::UNO_QUERY_THROW ); +} + +uno::Reference< beans::XPropertySet > +ScVbaChart::getAxisPropertySet(sal_Int32 _nAxisType, sal_Int32 _nAxisGroup) +{ + assignDiagramAttributes(); + uno::Reference< beans::XPropertySet > xAxisProps; + switch(_nAxisType) + { + case xlCategory: + if (_nAxisGroup == xlPrimary) + { + xAxisProps = xAxisXSupplier->getXAxis(); + } + else if (_nAxisGroup == xlSecondary) + { + xAxisProps = xTwoAxisXSupplier->getSecondaryXAxis(); + } + break; + case xlSeriesAxis: + xAxisProps = xAxisZSupplier->getZAxis(); + break; + case xlValue: + if (_nAxisGroup == xlPrimary) + xAxisProps = xAxisYSupplier->getYAxis(); + else if (_nAxisGroup == xlSecondary) + xAxisProps = xTwoAxisYSupplier->getSecondaryYAxis(); + break; + default: + return xAxisProps; + } + return xAxisProps; +} + +OUString +ScVbaChart::getServiceImplName() +{ + return "ScVbaChart"; +} + +uno::Sequence< OUString > +ScVbaChart::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.Chart" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbachart.hxx b/sc/source/ui/vba/vbachart.hxx new file mode 100644 index 000000000..eedf13b9f --- /dev/null +++ b/sc/source/ui/vba/vbachart.hxx @@ -0,0 +1,103 @@ +/* -*- 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 . + */ + +#pragma once + +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/table/XTableChart.hpp> +#include <com/sun/star/chart/XChartDocument.hpp> +#include <com/sun/star/chart/XAxisXSupplier.hpp> +#include <com/sun/star/chart/XAxisYSupplier.hpp> +#include <com/sun/star/chart/XAxisZSupplier.hpp> +#include <com/sun/star/chart/XTwoAxisXSupplier.hpp> +#include <com/sun/star/chart/XTwoAxisYSupplier.hpp> +#include <ooo/vba/excel/XChart.hpp> +#include <vbahelper/vbahelperinterface.hxx> + +typedef InheritedHelperInterfaceWeakImpl<ov::excel::XChart > ChartImpl_BASE; + +class ScVbaChart : public ChartImpl_BASE +{ +friend class ScVbaAxis; + + css::uno::Reference< css::chart::XChartDocument > mxChartDocument; + css::uno::Reference< css::table::XTableChart > mxTableChart; + css::uno::Reference< css::beans::XPropertySet > mxDiagramPropertySet; + css::uno::Reference< css::beans::XPropertySet > mxChartPropertySet; + css::uno::Reference< css::chart::XAxisXSupplier > xAxisXSupplier; + css::uno::Reference< css::chart::XAxisYSupplier> xAxisYSupplier; + css::uno::Reference< css::chart::XAxisZSupplier > xAxisZSupplier; + css::uno::Reference< css::chart::XTwoAxisXSupplier > xTwoAxisXSupplier; + css::uno::Reference< css::chart::XTwoAxisYSupplier > xTwoAxisYSupplier; + + static css::uno::Sequence< OUString > getDefaultSeriesDescriptions( sal_Int32 nCount ); + /// @throws css::script::BasicErrorException + void setDefaultChartType() ; + /// @throws css::script::BasicErrorException + void setDiagram( const OUString& _sDiagramType); + /// @throws css::uno::RuntimeException + bool isStacked(); + /// @throws css::uno::RuntimeException + bool is100PercentStacked(); + /// @throws css::uno::RuntimeException + sal_Int32 getStackedType( sal_Int32 _nStacked, sal_Int32 _n100PercentStacked, sal_Int32 _nUnStacked ); + /// @throws css::script::BasicErrorException + sal_Int32 getSolidType(sal_Int32 _nDeep, sal_Int32 _nVertiStacked, sal_Int32 _nVerti100PercentStacked, sal_Int32 _nVertiUnStacked, sal_Int32 _nHoriStacked, sal_Int32 _nHori100PercentStacked, sal_Int32 _nHoriUnStacked); + /// @throws css::script::BasicErrorException + sal_Int32 getStockUpDownValue(sal_Int32 _nUpDown, sal_Int32 _nNotUpDown); + /// @throws css::script::BasicErrorException + bool hasMarkers(); + /// @throws css::script::BasicErrorException + sal_Int32 getMarkerType(sal_Int32 _nWithMarkers, sal_Int32 _nWithoutMarkers); + void assignDiagramAttributes(); +public: + ScVbaChart( const css::uno::Reference< ov::XHelperInterface >& _xParent, const css::uno::Reference< css::uno::XComponentContext >& _xContext, const css::uno::Reference< css::lang::XComponent >& _xChartComponent, const css::uno::Reference< css::table::XTableChart >& _xTableChart ); + + // Non-interface + const css::uno::Reference< css::beans::XPropertySet >& xDiagramPropertySet() const { return mxDiagramPropertySet; } + /// @throws css::uno::RuntimeException + bool is3D(); + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + css::uno::Reference< css::beans::XPropertySet > getAxisPropertySet(sal_Int32 _nAxisType, sal_Int32 _nAxisGroup); + // Methods + virtual OUString SAL_CALL getName() override; + virtual css::uno::Any SAL_CALL SeriesCollection(const css::uno::Any&) override; + virtual ::sal_Int32 SAL_CALL getChartType() override; + virtual void SAL_CALL setChartType( ::sal_Int32 _charttype ) override; + virtual void SAL_CALL Activate( ) override; + virtual void SAL_CALL setSourceData( const css::uno::Reference< ::ooo::vba::excel::XRange >& range, const css::uno::Any& PlotBy ) override; + virtual ::sal_Int32 SAL_CALL Location( ) override; + virtual ::sal_Int32 SAL_CALL getLocation( ) override; + virtual void SAL_CALL setLocation( ::sal_Int32 where, const css::uno::Any& Name ) override; + virtual sal_Bool SAL_CALL getHasTitle( ) override; + virtual void SAL_CALL setHasTitle( sal_Bool bTitle ) override; + virtual sal_Bool SAL_CALL getHasLegend( ) override; + virtual void SAL_CALL setHasLegend( sal_Bool bLegend ) override; + virtual void SAL_CALL setPlotBy( ::sal_Int32 xlRowCol ) override; + virtual ::sal_Int32 SAL_CALL getPlotBy( ) override; + virtual css::uno::Reference< ov::excel::XChartTitle > SAL_CALL getChartTitle( ) override; + virtual css::uno::Any SAL_CALL Axes( const css::uno::Any& Type, const css::uno::Any& AxisGroup ) override; + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbachartobject.cxx b/sc/source/ui/vba/vbachartobject.cxx new file mode 100644 index 000000000..5246a9040 --- /dev/null +++ b/sc/source/ui/vba/vbachartobject.cxx @@ -0,0 +1,147 @@ +/* -*- 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 "vbachart.hxx" +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/document/XEmbeddedObjectSupplier.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/script/BasicErrorException.hpp> +#include <com/sun/star/view/XSelectionSupplier.hpp> +#include <basic/sberrors.hxx> +#include "vbachartobject.hxx" +#include "vbachartobjects.hxx" + +using namespace ::com::sun::star; +using namespace ::ooo::vba; + +constexpr OUStringLiteral PERSIST_NAME(u"PersistName"); + +ScVbaChartObject::ScVbaChartObject( const css::uno::Reference< ov::XHelperInterface >& _xParent, const css::uno::Reference< css::uno::XComponentContext >& _xContext, const css::uno::Reference< css::table::XTableChart >& _xTableChart, const css::uno::Reference< css::drawing::XDrawPageSupplier >& _xDrawPageSupplier ) : ChartObjectImpl_BASE( _xParent, _xContext ), xTableChart( _xTableChart ), xDrawPageSupplier( _xDrawPageSupplier ) +{ + xDrawPage = xDrawPageSupplier->getDrawPage(); + xEmbeddedObjectSupplier.set( xTableChart, uno::UNO_QUERY_THROW ); + xNamed.set( xTableChart, uno::UNO_QUERY_THROW ); + sPersistName = getPersistName(); + xShape = setShape(); + setName(sPersistName); + oShapeHelper.reset(new ShapeHelper(xShape)); +} + +OUString const & ScVbaChartObject::getPersistName() +{ + if ( sPersistName.isEmpty() ) + sPersistName = xNamed->getName(); + return sPersistName; +} + +uno::Reference< drawing::XShape > +ScVbaChartObject::setShape() +{ + try + { + sal_Int32 nItems = xDrawPage->getCount(); + for (int i = 0; i < nItems; i++) + { + xShape.set( xDrawPage->getByIndex(i), uno::UNO_QUERY_THROW ); + if (xShape->getShapeType() == "com.sun.star.drawing.OLE2Shape") + { + uno::Reference< beans::XPropertySet > xShapePropertySet(xShape, uno::UNO_QUERY_THROW ); + OUString sName; + xShapePropertySet->getPropertyValue(PERSIST_NAME ) >>=sName; + if ( sName == sPersistName ) + { + xNamedShape.set( xShape, uno::UNO_QUERY_THROW ); + return xShape; + } + } + } + } + catch (uno::Exception& ) + { + throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() ); + } + return nullptr; +} + +void SAL_CALL +ScVbaChartObject::setName( const OUString& sName ) +{ + xNamedShape->setName(sName); +} + +OUString SAL_CALL +ScVbaChartObject::getName() +{ + return xNamedShape->getName(); +} + +void SAL_CALL +ScVbaChartObject::Delete() +{ + // parent of this object is sheet + uno::Reference< excel::XWorksheet > xParent( getParent(), uno::UNO_QUERY_THROW ); + uno::Reference< excel::XChartObjects > xColl( xParent->ChartObjects( uno::Any() ), uno::UNO_QUERY_THROW ); + ScVbaChartObjects* pChartObjectsImpl = static_cast< ScVbaChartObjects* >( xColl.get() ); + if (!pChartObjectsImpl) + throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), "Parent is not ChartObjects" ); + + pChartObjectsImpl->removeByName( getPersistName() ); + +} + +void +ScVbaChartObject::Activate() +{ + try + { + // #TODO #FIXME should be ThisWorkbook or equivalent, or in + // fact probably the chart object should be created with + // the XModel owner + //uno::Reference< view::XSelectionSupplier > xSelectionSupplier( getXModel().getCurrentController()); + uno::Reference< view::XSelectionSupplier > xSelectionSupplier( getCurrentExcelDoc(mxContext)->getCurrentController(), uno::UNO_QUERY_THROW ); + xSelectionSupplier->select(uno::Any(xShape)); + } + catch (uno::Exception& ) + { + throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), "ChartObject Activate internal error" ); + } +} + +uno::Reference< excel::XChart > SAL_CALL +ScVbaChartObject::getChart() +{ + return new ScVbaChart( this, mxContext, xEmbeddedObjectSupplier->getEmbeddedObject(), xTableChart ); +} + +OUString +ScVbaChartObject::getServiceImplName() +{ + return "ScVbaChartObject"; +} + +uno::Sequence< OUString > +ScVbaChartObject::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.ChartObject" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbachartobject.hxx b/sc/source/ui/vba/vbachartobject.hxx new file mode 100644 index 000000000..85a014052 --- /dev/null +++ b/sc/source/ui/vba/vbachartobject.hxx @@ -0,0 +1,61 @@ +/* -*- 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 . + */ + +#pragma once + +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/table/XTableChart.hpp> +#include <com/sun/star/drawing/XDrawPageSupplier.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/document/XEmbeddedObjectSupplier.hpp> +#include <ooo/vba/excel/XChartObject.hpp> +#include <vbahelper/vbahelperinterface.hxx> +#include <memory> + +typedef InheritedHelperInterfaceWeakImpl<ov::excel::XChartObject > ChartObjectImpl_BASE; + +class ScVbaChartObject : public ChartObjectImpl_BASE +{ + + css::uno::Reference< css::table::XTableChart > xTableChart; + css::uno::Reference< css::document::XEmbeddedObjectSupplier > xEmbeddedObjectSupplier; + css::uno::Reference< css::drawing::XDrawPageSupplier > xDrawPageSupplier; + css::uno::Reference< css::drawing::XDrawPage > xDrawPage; + css::uno::Reference< css::drawing::XShape > xShape; + css::uno::Reference< css::container::XNamed > xNamed; + OUString sPersistName; + std::unique_ptr<ov::ShapeHelper> oShapeHelper; + css::uno::Reference< css::container::XNamed > xNamedShape; + OUString const & getPersistName(); + /// @throws css::script::BasicErrorException + css::uno::Reference< css::drawing::XShape > setShape(); +public: + ScVbaChartObject( const css::uno::Reference< ov::XHelperInterface >& _xParent, const css::uno::Reference< css::uno::XComponentContext >& _xContext, const css::uno::Reference< css::table::XTableChart >& _xTableChart, const css::uno::Reference< css::drawing::XDrawPageSupplier >& _xDrawPageSupplier ); + virtual OUString SAL_CALL getName() override; + virtual void SAL_CALL setName( const OUString& sName ) override; + virtual css::uno::Reference< ov::excel::XChart > SAL_CALL getChart() override; + virtual void SAL_CALL Delete() override; + /// @throws css::script::BasicErrorException + void Activate(); + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbachartobjects.cxx b/sc/source/ui/vba/vbachartobjects.cxx new file mode 100644 index 000000000..674c92511 --- /dev/null +++ b/sc/source/ui/vba/vbachartobjects.cxx @@ -0,0 +1,206 @@ +/* -*- 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 <com/sun/star/table/XTableChartsSupplier.hpp> +#include <com/sun/star/table/XTableChart.hpp> +#include <com/sun/star/script/BasicErrorException.hpp> +#include <com/sun/star/sheet/XSpreadsheetDocument.hpp> +#include <ooo/vba/excel/XlChartType.hpp> + +#include "vbachartobjects.hxx" +#include "vbachartobject.hxx" +#include <docsh.hxx> +#include <cellsuno.hxx> + +#include <string_view> +#include <vector> +#include <basic/sberrors.hxx> +#include <comphelper/sequence.hxx> +#include <tools/diagnose_ex.h> + +using namespace ::com::sun::star; +using namespace ::ooo::vba; + +namespace { + +class ChartObjectEnumerationImpl : public EnumerationHelperImpl +{ + uno::Reference< drawing::XDrawPageSupplier > xDrawPageSupplier; + +public: + /// @throws uno::RuntimeException + ChartObjectEnumerationImpl( const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< container::XEnumeration >& xEnumeration, const uno::Reference< drawing::XDrawPageSupplier >& _xDrawPageSupplier, const uno::Reference< XHelperInterface >& _xParent ) : EnumerationHelperImpl( _xParent, xContext, xEnumeration ), xDrawPageSupplier( _xDrawPageSupplier ) {} + virtual uno::Any SAL_CALL nextElement( ) override + { + uno::Any ret; + + try + { + uno::Reference< table::XTableChart > xTableChart( m_xEnumeration->nextElement(), uno::UNO_QUERY_THROW ); + // parent Object is sheet + ret <<= uno::Reference< excel::XChartObject > ( new ScVbaChartObject( m_xParent, m_xContext, xTableChart, xDrawPageSupplier ) ); + } + catch (const lang::WrappedTargetException&) + { + throw; + } + catch (const container::NoSuchElementException&) + { + throw; + } + catch (const uno::RuntimeException&) + { + throw; + } + catch (const uno::Exception&) + { + css::uno::Any anyEx(cppu::getCaughtException()); + throw lang::WrappedTargetException( + "Error creating ScVbaChartObject!", + static_cast < OWeakObject * > ( this ), + anyEx ); + } + return ret; + } +}; + +} + +ScVbaChartObjects::ScVbaChartObjects( const css::uno::Reference< ov::XHelperInterface >& _xParent, const css::uno::Reference< css::uno::XComponentContext >& _xContext, const css::uno::Reference< css::table::XTableCharts >& _xTableCharts, const uno::Reference< drawing::XDrawPageSupplier >& _xDrawPageSupplier ) : ChartObjects_BASE(_xParent, _xContext, css::uno::Reference< css::container::XIndexAccess >( _xTableCharts, css::uno::UNO_QUERY ) ), xTableCharts( _xTableCharts ) , xDrawPageSupplier( _xDrawPageSupplier ) +{ + +} + +void +ScVbaChartObjects::removeByName(const OUString& _sChartName) +{ + xTableCharts->removeByName( _sChartName ); +} + +uno::Sequence< OUString > +ScVbaChartObjects::getChartObjectNames() const +{ + uno::Sequence< OUString > sChartNames; + try + { + // c++ hackery + uno::Reference< uno::XInterface > xIf( xDrawPageSupplier, uno::UNO_QUERY_THROW ); + ScCellRangesBase* pUno= dynamic_cast< ScCellRangesBase* >( xIf.get() ); + ScDocShell* pDocShell = nullptr; + if ( !pUno ) + throw uno::RuntimeException("Failed to obtain the impl class from the drawpage" ); + pDocShell = pUno->GetDocShell(); + if ( !pDocShell ) + throw uno::RuntimeException("Failed to obtain the docshell implclass" ); + + uno::Reference< sheet::XSpreadsheetDocument > xSpreadsheetDocument( pDocShell->GetModel(), uno::UNO_QUERY_THROW ); + uno::Reference< sheet::XSpreadsheets > xSpreadsheets = xSpreadsheetDocument->getSheets(); + std::vector< OUString > aChartNamesVector; + + const uno::Sequence< OUString > sSheetNames = xSpreadsheets->getElementNames(); + for (const auto& rSheetName : sSheetNames) + { + uno::Reference< table::XTableChartsSupplier > xLocTableChartsSupplier( xSpreadsheets->getByName(rSheetName), uno::UNO_QUERY_THROW ); + const uno::Sequence< OUString > scurchartnames = xLocTableChartsSupplier->getCharts()->getElementNames(); + aChartNamesVector.insert( aChartNamesVector.end(), scurchartnames.begin(), scurchartnames.end() ); + } + sChartNames = comphelper::containerToSequence( aChartNamesVector ); + } + catch (uno::Exception& ) + { + throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() ); + } + return sChartNames; +} + +// XChartObjects +uno::Any SAL_CALL +ScVbaChartObjects::Add( double _nX, double _nY, double _nWidth, double _nHeight ) +{ + try + { + uno::Sequence< table::CellRangeAddress > aCellRangeAddress( 1 ); + awt::Rectangle aRectangle; + aRectangle.X = Millimeter::getInHundredthsOfOneMillimeter(_nX); + aRectangle.Y = Millimeter::getInHundredthsOfOneMillimeter(_nY); + aRectangle.Width = Millimeter::getInHundredthsOfOneMillimeter(_nWidth); + aRectangle.Height = Millimeter::getInHundredthsOfOneMillimeter(_nHeight); + // Note the space at the end of the stem ("Chart "). In ChartSheets only "Chart" is the stem + OUString sPersistChartName = ContainerUtilities::getUniqueName( getChartObjectNames(), "Chart " , std::u16string_view(), 1); + xTableCharts->addNewByName(sPersistChartName, aRectangle, aCellRangeAddress, true, false ); + uno::Reference< excel::XChartObject > xChartObject( getItemByStringIndex( sPersistChartName ), uno::UNO_QUERY_THROW ); + xChartObject->getChart()->setChartType(excel::XlChartType::xlColumnClustered); + return uno::Any( xChartObject ); + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("sc"); + } + return aNULL(); +} +void SAL_CALL ScVbaChartObjects::Delete( ) +{ + const uno::Sequence< OUString > sChartNames = xTableCharts->getElementNames(); + for (const auto& rChartName : sChartNames) + removeByName(rChartName); +} + +// XEnumerationAccess + +uno::Reference< container::XEnumeration > +ScVbaChartObjects::createEnumeration() +{ + css::uno::Reference< container::XEnumerationAccess > xEnumAccess( xTableCharts, uno::UNO_QUERY_THROW ); + return new ChartObjectEnumerationImpl( mxContext, xEnumAccess->createEnumeration(), xDrawPageSupplier, getParent() /* sheet */); +} + +// XElementAccess + +uno::Type +ScVbaChartObjects::getElementType() +{ + return cppu::UnoType<excel::XChartObject>::get(); +} + +// ScVbaCollectionBaseImpl +uno::Any +ScVbaChartObjects::createCollectionObject( const css::uno::Any& aSource ) +{ + uno::Reference< table::XTableChart > xTableChart( aSource, uno::UNO_QUERY_THROW ); + // correct parent object is sheet + return uno::Any( uno::Reference< excel::XChartObject > ( new ScVbaChartObject( getParent(), mxContext, xTableChart, xDrawPageSupplier ) ) ); +} + +OUString +ScVbaChartObjects::getServiceImplName() +{ + return "ScVbaChartObjects"; +} + +css::uno::Sequence<OUString> +ScVbaChartObjects::getServiceNames() +{ + static uno::Sequence< OUString > const sNames + { + "ooo.vba.excel.ChartObjects" + }; + return sNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbachartobjects.hxx b/sc/source/ui/vba/vbachartobjects.hxx new file mode 100644 index 000000000..ce116e734 --- /dev/null +++ b/sc/source/ui/vba/vbachartobjects.hxx @@ -0,0 +1,60 @@ +/* -*- 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 . + */ + +#pragma once + +#include <ooo/vba/excel/XChartObjects.hpp> +#include <vbahelper/vbacollectionimpl.hxx> + +namespace com::sun::star::container { class XEnumeration; } +namespace com::sun::star::drawing { class XDrawPageSupplier; } +namespace com::sun::star::table { class XTableCharts; } +namespace com::sun::star::uno { class XComponentContext; } + +typedef CollTestImplHelper< ov::excel::XChartObjects > ChartObjects_BASE; + +class ScVbaChartObjects : public ChartObjects_BASE +{ + + css::uno::Reference< css::table::XTableCharts > xTableCharts; + css::uno::Reference< css::drawing::XDrawPageSupplier > xDrawPageSupplier; + // method associated with populating the hashmap ( I'm not convinced this is necessary ) + //css::uno::Reference< ov::excel::XChartObject > putByPersistName( const rtl:::OUString& _sPersistChartName ); +public: + ScVbaChartObjects( const css::uno::Reference< ov::XHelperInterface >& _xParent, const css::uno::Reference< css::uno::XComponentContext >& _xContext, const css::uno::Reference< css::table::XTableCharts >& _xTableCharts, const css::uno::Reference< css::drawing::XDrawPageSupplier >& _xDrawPageSupplier ); + + /// @throws css::script::BasicErrorException + css::uno::Sequence< OUString > getChartObjectNames() const; + void removeByName(const OUString& _sChartName); + + // XChartObjects + virtual css::uno::Any SAL_CALL Add( double Left, double Top, double Width, double Height ) override; + virtual void SAL_CALL Delete( ) override; + // XEnumerationAccess + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + // XElementAccess + virtual css::uno::Type SAL_CALL getElementType() override; + // ScVbaCollectionBaseImpl + virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override; + // ChartObjects_BASE + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbacharttitle.cxx b/sc/source/ui/vba/vbacharttitle.cxx new file mode 100644 index 000000000..2e881fd61 --- /dev/null +++ b/sc/source/ui/vba/vbacharttitle.cxx @@ -0,0 +1,44 @@ +/* -*- 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 "vbacharttitle.hxx" +#include <comphelper/sequence.hxx> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +ScVbaChartTitle::ScVbaChartTitle( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< drawing::XShape >& _xTitleShape ) : ChartTitleBase( xParent, xContext, _xTitleShape ) +{ +} + +OUString +ScVbaChartTitle::getServiceImplName() +{ + return "ScVbaChartTitle"; +} + +uno::Sequence< OUString > +ScVbaChartTitle::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames = comphelper::concatSequences( + ChartTitleBase::getServiceNames(), + uno::Sequence< OUString > { "ooo.vba.excel.Chart" } ); + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbacharttitle.hxx b/sc/source/ui/vba/vbacharttitle.hxx new file mode 100644 index 000000000..2b816357e --- /dev/null +++ b/sc/source/ui/vba/vbacharttitle.hxx @@ -0,0 +1,35 @@ +/* -*- 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 . + */ +#pragma once +#include "vbatitle.hxx" +#include <cppuhelper/implbase.hxx> +#include <ooo/vba/excel/XChartTitle.hpp> + +typedef TitleImpl< cppu::WeakImplHelper< ov::excel::XChartTitle > > ChartTitleBase; + +class ScVbaChartTitle : public ChartTitleBase +{ +public: + ScVbaChartTitle( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Reference< css::drawing::XShape >& _xTitleShape ); + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbacomment.cxx b/sc/source/ui/vba/vbacomment.cxx new file mode 100644 index 000000000..a9b1cf7c4 --- /dev/null +++ b/sc/source/ui/vba/vbacomment.cxx @@ -0,0 +1,234 @@ +/* -*- 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 "vbacomment.hxx" + +#include <com/sun/star/drawing/XDrawPageSupplier.hpp> +#include <com/sun/star/sheet/XSpreadsheet.hpp> +#include <com/sun/star/sheet/XSheetAnnotationAnchor.hpp> +#include <com/sun/star/sheet/XSheetAnnotationsSupplier.hpp> +#include <com/sun/star/sheet/XSheetAnnotationShapeSupplier.hpp> +#include <com/sun/star/sheet/XSheetCellRange.hpp> +#include <com/sun/star/sheet/XCellAddressable.hpp> +#include <com/sun/star/table/CellAddress.hpp> +#include <com/sun/star/table/XCell.hpp> +#include <com/sun/star/text/XSimpleText.hpp> +#include <com/sun/star/text/XTextCursor.hpp> +#include <com/sun/star/text/XTextRange.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <ooo/vba/office/MsoShapeType.hpp> + +#include <vbahelper/vbashape.hxx> +#include <sal/log.hxx> +#include "vbacomments.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +ScVbaComment::ScVbaComment( + const uno::Reference< XHelperInterface >& xParent, + const uno::Reference< uno::XComponentContext >& xContext, + const uno::Reference< frame::XModel >& xModel, + const uno::Reference< table::XCellRange >& xRange ) : + ScVbaComment_BASE( xParent, xContext ), + mxModel( xModel, uno::UNO_SET_THROW ), + mxRange( xRange ) +{ + if ( !xRange.is() ) + throw lang::IllegalArgumentException("range is not set ", uno::Reference< uno::XInterface >() , 1 ); + getAnnotation(); +} + +// private helper functions + +uno::Reference< sheet::XSheetAnnotation > +ScVbaComment::getAnnotation() +{ + uno::Reference< table::XCell > xCell( mxRange->getCellByPosition(0, 0), uno::UNO_SET_THROW ); + uno::Reference< sheet::XSheetAnnotationAnchor > xAnnoAnchor( xCell, uno::UNO_QUERY_THROW ); + return uno::Reference< sheet::XSheetAnnotation > ( xAnnoAnchor->getAnnotation(), uno::UNO_SET_THROW ); +} + +uno::Reference< sheet::XSheetAnnotations > +ScVbaComment::getAnnotations() const +{ + uno::Reference< sheet::XSheetCellRange > xSheetCellRange(mxRange, ::uno::UNO_QUERY_THROW ); + uno::Reference< sheet::XSpreadsheet > xSheet = xSheetCellRange->getSpreadsheet(); + uno::Reference< sheet::XSheetAnnotationsSupplier > xAnnosSupp( xSheet, uno::UNO_QUERY_THROW ); + + return uno::Reference< sheet::XSheetAnnotations > ( xAnnosSupp->getAnnotations(), uno::UNO_SET_THROW ); +} + +sal_Int32 +ScVbaComment::getAnnotationIndex() +{ + uno::Reference< sheet::XSheetAnnotations > xAnnos = getAnnotations(); + table::CellAddress aAddress = getAnnotation()->getPosition(); + + sal_Int32 aIndex = 0; + sal_Int32 aCount = xAnnos->getCount(); + + for ( ; aIndex < aCount ; aIndex++ ) + { + uno::Reference< sheet::XSheetAnnotation > xAnno( xAnnos->getByIndex( aIndex ), uno::UNO_QUERY_THROW ); + table::CellAddress aAnnoAddress = xAnno->getPosition(); + + if ( aAnnoAddress.Column == aAddress.Column && aAnnoAddress.Row == aAddress.Row && aAnnoAddress.Sheet == aAddress.Sheet ) + { + SAL_INFO("sc.ui", "terminating search, index is " << aIndex); + break; + } + } + SAL_INFO("sc.ui", "returning index is " << aIndex); + + return aIndex; +} + +uno::Reference< excel::XComment > +ScVbaComment::getCommentByIndex( sal_Int32 Index ) +{ + uno::Reference< container::XIndexAccess > xIndexAccess( getAnnotations(), uno::UNO_QUERY_THROW ); + // parent is sheet ( parent of the range which is the parent of the comment ) + uno::Reference< XCollection > xColl( new ScVbaComments( getParent()->getParent(), mxContext, mxModel, xIndexAccess ) ); + + return uno::Reference< excel::XComment > ( xColl->Item( uno::Any( Index ), uno::Any() ), uno::UNO_QUERY_THROW ); + } + +// public vba functions + +OUString SAL_CALL +ScVbaComment::getAuthor() +{ + return getAnnotation()->getAuthor(); +} + +void SAL_CALL +ScVbaComment::setAuthor( const OUString& /*_author*/ ) +{ + // #TODO #FIXME implementation needed +} + +uno::Reference< msforms::XShape > SAL_CALL +ScVbaComment::getShape() +{ + uno::Reference< sheet::XSheetAnnotationShapeSupplier > xAnnoShapeSupp( getAnnotation(), uno::UNO_QUERY_THROW ); + uno::Reference< drawing::XShape > xAnnoShape( xAnnoShapeSupp->getAnnotationShape(), uno::UNO_SET_THROW ); + uno::Reference< sheet::XSheetCellRange > xCellRange( mxRange, uno::UNO_QUERY_THROW ); + uno::Reference< drawing::XDrawPageSupplier > xDrawPageSupp( xCellRange->getSpreadsheet(), uno::UNO_QUERY_THROW ); + uno::Reference< drawing::XShapes > xShapes( xDrawPageSupp->getDrawPage(), uno::UNO_QUERY_THROW ); + return new ScVbaShape( this, mxContext, xAnnoShape, xShapes, mxModel, office::MsoShapeType::msoComment ); +} + +sal_Bool SAL_CALL +ScVbaComment::getVisible() +{ + return getAnnotation()->getIsVisible(); +} + +void SAL_CALL +ScVbaComment::setVisible( sal_Bool _visible ) +{ + getAnnotation()->setIsVisible( _visible ); +} + +void SAL_CALL +ScVbaComment::Delete() +{ + getAnnotations()->removeByIndex( getAnnotationIndex() ); +} + +uno::Reference< excel::XComment > SAL_CALL +ScVbaComment::Next() +{ + // index: uno = 0, vba = 1 + return getCommentByIndex( getAnnotationIndex() + 2 ); +} + +uno::Reference< excel::XComment > SAL_CALL +ScVbaComment::Previous() +{ + // index: uno = 0, vba = 1 + return getCommentByIndex( getAnnotationIndex() ); +} + +OUString SAL_CALL +ScVbaComment::Text( const uno::Any& aText, const uno::Any& aStart, const uno::Any& Overwrite ) +{ + OUString sText; + aText >>= sText; + + uno::Reference< text::XSimpleText > xAnnoText( getAnnotation(), uno::UNO_QUERY_THROW ); + OUString sAnnoText = xAnnoText->getString(); + + if ( aStart.hasValue() ) + { + sal_Int16 nStart = 0; + bool bOverwrite = true; + Overwrite >>= bOverwrite; + + if ( aStart >>= nStart ) + { + uno::Reference< text::XTextCursor > xTextCursor( xAnnoText->createTextCursor(), uno::UNO_SET_THROW ); + + if ( bOverwrite ) + { + xTextCursor->collapseToStart(); + xTextCursor->gotoStart( false ); + xTextCursor->goRight( nStart - 1, false ); + xTextCursor->gotoEnd( true ); + } + else + { + xTextCursor->collapseToStart(); + xTextCursor->gotoStart( false ); + xTextCursor->goRight( nStart - 1 , true ); + } + + uno::Reference< text::XTextRange > xRange( xTextCursor, uno::UNO_QUERY_THROW ); + xAnnoText->insertString( xRange, sText, bOverwrite ); + return xAnnoText->getString(); + } + throw uno::RuntimeException("ScVbaComment::Text - bad Start value " ); + } + else if ( aText.hasValue() ) + { + uno::Reference< sheet::XCellAddressable > xCellAddr(mxRange->getCellByPosition(0, 0), uno::UNO_QUERY_THROW ); + table::CellAddress aAddress = xCellAddr->getCellAddress(); + getAnnotations()->insertNew( aAddress, sText ); + } + + return sAnnoText; +} + +OUString +ScVbaComment::getServiceImplName() +{ + return "ScVbaComment"; +} + +uno::Sequence< OUString > +ScVbaComment::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.ScVbaComment" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbacomment.hxx b/sc/source/ui/vba/vbacomment.hxx new file mode 100644 index 000000000..fe801899c --- /dev/null +++ b/sc/source/ui/vba/vbacomment.hxx @@ -0,0 +1,72 @@ +/* -*- 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 . + */ +#pragma once + +#include <ooo/vba/excel/XComment.hpp> +#include <ooo/vba/msforms/XShape.hpp> +#include <com/sun/star/sheet/XSheetAnnotations.hpp> +#include <com/sun/star/sheet/XSheetAnnotation.hpp> +#include <com/sun/star/table/XCellRange.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <vbahelper/vbahelperinterface.hxx> + +typedef InheritedHelperInterfaceWeakImpl< ov::excel::XComment > ScVbaComment_BASE; + +class ScVbaComment : public ScVbaComment_BASE +{ + css::uno::Reference< css::frame::XModel > mxModel; + css::uno::Reference< css::table::XCellRange > mxRange; + +private: + /// @throws css::uno::RuntimeException + css::uno::Reference< css::sheet::XSheetAnnotation > getAnnotation(); + /// @throws css::uno::RuntimeException + css::uno::Reference< css::sheet::XSheetAnnotations > getAnnotations() const; + /// @throws css::uno::RuntimeException + sal_Int32 getAnnotationIndex(); + /// @throws css::uno::RuntimeException + css::uno::Reference< ov::excel::XComment > getCommentByIndex( sal_Int32 Index ); +public: + /// @throws css::lang::IllegalArgumentException + /// @throws css::uno::RuntimeException + ScVbaComment( + const css::uno::Reference< ov::XHelperInterface >& xParent, + const css::uno::Reference< css::uno::XComponentContext >& xContext, + const css::uno::Reference< css::frame::XModel >& xModel, + const css::uno::Reference< css::table::XCellRange >& xRange ); + + // Attributes + virtual OUString SAL_CALL getAuthor() override; + virtual void SAL_CALL setAuthor( const OUString& _author ) override; + virtual css::uno::Reference< ov::msforms::XShape > SAL_CALL getShape() override; + virtual sal_Bool SAL_CALL getVisible() override; + virtual void SAL_CALL setVisible( sal_Bool _visible ) override; + + // Methods + virtual void SAL_CALL Delete() override; + virtual css::uno::Reference< ov::excel::XComment > SAL_CALL Next() override; + virtual css::uno::Reference< ov::excel::XComment > SAL_CALL Previous() override; + virtual OUString SAL_CALL Text( const css::uno::Any& Text, const css::uno::Any& Start, const css::uno::Any& Overwrite ) override; + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbacomments.cxx b/sc/source/ui/vba/vbacomments.cxx new file mode 100644 index 000000000..470e468b7 --- /dev/null +++ b/sc/source/ui/vba/vbacomments.cxx @@ -0,0 +1,113 @@ +/* -*- 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 "vbacomments.hxx" +#include "vbacomment.hxx" + +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/sheet/XSheetAnnotation.hpp> +#include <com/sun/star/table/XCellRange.hpp> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +static uno::Any AnnotationToComment( const uno::Any& aSource, const uno::Reference< uno::XComponentContext > & xContext, const uno::Reference< frame::XModel >& xModel ) +{ + uno::Reference< sheet::XSheetAnnotation > xAnno( aSource, uno::UNO_QUERY_THROW ); + uno::Reference< container::XChild > xChild( xAnno, uno::UNO_QUERY_THROW ); + uno::Reference< table::XCellRange > xCellRange( xChild->getParent(), uno::UNO_QUERY_THROW ); + + // #FIXME needs to find the correct Parent + return uno::Any( uno::Reference< excel::XComment > ( + new ScVbaComment( uno::Reference< XHelperInterface >(), xContext, xModel, xCellRange ) ) ); +} + +namespace { + +class CommentEnumeration : public EnumerationHelperImpl +{ + css::uno::Reference< css::frame::XModel > mxModel; +public: + /// @throws uno::RuntimeException + CommentEnumeration( + const uno::Reference< XHelperInterface >& xParent, + const uno::Reference< uno::XComponentContext >& xContext, + const uno::Reference< container::XEnumeration >& xEnumeration, + const uno::Reference< frame::XModel >& xModel ) : + EnumerationHelperImpl( xParent, xContext, xEnumeration ), + mxModel( xModel, uno::UNO_SET_THROW ) + {} + + virtual uno::Any SAL_CALL nextElement() override + { + return AnnotationToComment( m_xEnumeration->nextElement(), m_xContext, mxModel ); + } + +}; + +} + +ScVbaComments::ScVbaComments( + const uno::Reference< XHelperInterface >& xParent, + const uno::Reference< uno::XComponentContext > & xContext, + const uno::Reference< frame::XModel >& xModel, + const uno::Reference< container::XIndexAccess >& xIndexAccess ) : + ScVbaComments_BASE( xParent, xContext, xIndexAccess ), + mxModel( xModel, uno::UNO_SET_THROW ) +{ +} + +// public helper functions + +uno::Reference< container::XEnumeration > +ScVbaComments::createEnumeration() +{ + uno::Reference< container::XEnumerationAccess > xEnumAccess( m_xIndexAccess, uno::UNO_QUERY_THROW ); + return new CommentEnumeration( mxParent, mxContext, xEnumAccess->createEnumeration(), mxModel ); +} + +uno::Any +ScVbaComments::createCollectionObject( const css::uno::Any& aSource ) +{ + return AnnotationToComment( aSource, mxContext, mxModel ); +} + +uno::Type +ScVbaComments::getElementType() +{ + return cppu::UnoType<excel::XComment>::get(); +} + +OUString +ScVbaComments::getServiceImplName() +{ + return "ScVbaComments"; +} + +css::uno::Sequence<OUString> +ScVbaComments::getServiceNames() +{ + static uno::Sequence< OUString > const sNames + { + "ooo.vba.excel.Comments" + }; + return sNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbacomments.hxx b/sc/source/ui/vba/vbacomments.hxx new file mode 100644 index 000000000..83a62b6e8 --- /dev/null +++ b/sc/source/ui/vba/vbacomments.hxx @@ -0,0 +1,49 @@ +/* -*- 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 . + */ +#pragma once + +#include <ooo/vba/excel/XComments.hpp> + +#include <vbahelper/vbacollectionimpl.hxx> + +typedef CollTestImplHelper< ov::excel::XComments > ScVbaComments_BASE; + +class ScVbaComments : public ScVbaComments_BASE +{ +public: + ScVbaComments( + const css::uno::Reference< ov::XHelperInterface >& xParent, + const css::uno::Reference< css::uno::XComponentContext > & xContext, + const css::uno::Reference< css::frame::XModel >& xModel, + const css::uno::Reference< css::container::XIndexAccess >& xIndexAccess ); + + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + + // ScVbaComments_BASE + virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override; + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; + +private: + css::uno::Reference< css::frame::XModel > mxModel; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbacondition.cxx b/sc/source/ui/vba/vbacondition.cxx new file mode 100644 index 000000000..c5577a7f8 --- /dev/null +++ b/sc/source/ui/vba/vbacondition.cxx @@ -0,0 +1,143 @@ +/* -*- 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 "vbacondition.hxx" +#include <ooo/vba/excel/XlFormatConditionOperator.hpp> +#include <ooo/vba/excel/XFormatCondition.hpp> +#include <com/sun/star/sheet/XCellRangeAddressable.hpp> +#include <com/sun/star/sheet/XSheetCondition.hpp> +#include <basic/sberrors.hxx> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +const sal_Int32 ISFORMULA = 98765432; + +template <typename... Ifc> +ScVbaCondition<Ifc...>::ScVbaCondition( + const uno::Reference<XHelperInterface>& xParent, + const uno::Reference<uno::XComponentContext>& xContext, + const uno::Reference<sheet::XSheetCondition>& _xSheetCondition) + : ScVbaCondition_BASE(xParent, xContext) + , mxSheetCondition(_xSheetCondition) +{ + mxAddressable.set(xParent, uno::UNO_QUERY_THROW); +} + +template <typename... Ifc> +sheet::ConditionOperator ScVbaCondition<Ifc...>::retrieveAPIOperator(const uno::Any& _aOperator) +{ + sheet::ConditionOperator aRetAPIOperator = sheet::ConditionOperator_NONE; + sal_Int32 nOperator = 0; + if (_aOperator >>= nOperator) + { + switch (nOperator) + { + case excel::XlFormatConditionOperator::xlBetween: + aRetAPIOperator = sheet::ConditionOperator_BETWEEN; + break; + case excel::XlFormatConditionOperator::xlNotBetween: + aRetAPIOperator = sheet::ConditionOperator_NOT_BETWEEN; + break; + case excel::XlFormatConditionOperator::xlEqual: + aRetAPIOperator = sheet::ConditionOperator_EQUAL; + break; + case excel::XlFormatConditionOperator::xlNotEqual: + aRetAPIOperator = sheet::ConditionOperator_NOT_EQUAL; + break; + case excel::XlFormatConditionOperator::xlGreater: + aRetAPIOperator = sheet::ConditionOperator_GREATER; + break; + case excel::XlFormatConditionOperator::xlLess: + aRetAPIOperator = sheet::ConditionOperator_LESS; + break; + case excel::XlFormatConditionOperator::xlGreaterEqual: + aRetAPIOperator = sheet::ConditionOperator_GREATER_EQUAL; + break; + case excel::XlFormatConditionOperator::xlLessEqual: + aRetAPIOperator = sheet::ConditionOperator_LESS_EQUAL; + break; + default: + aRetAPIOperator = sheet::ConditionOperator_NONE; + break; + } + } + return aRetAPIOperator; +} + +template <typename... Ifc> OUString ScVbaCondition<Ifc...>::Formula1() +{ + return mxSheetCondition->getFormula1(); +} + +template <typename... Ifc> OUString ScVbaCondition<Ifc...>::Formula2() +{ + return mxSheetCondition->getFormula2(); +} + +template <typename... Ifc> sal_Int32 ScVbaCondition<Ifc...>::Operator(bool _bIncludeFormulaValue) +{ + sal_Int32 retvalue = -1; + sheet::ConditionOperator aConditionalOperator = mxSheetCondition->getOperator(); + switch (aConditionalOperator) + { + case sheet::ConditionOperator_EQUAL: + retvalue = excel::XlFormatConditionOperator::xlEqual; + break; + case sheet::ConditionOperator_NOT_EQUAL: + retvalue = excel::XlFormatConditionOperator::xlNotEqual; + break; + case sheet::ConditionOperator_GREATER: + retvalue = excel::XlFormatConditionOperator::xlGreater; + break; + case sheet::ConditionOperator_GREATER_EQUAL: + retvalue = excel::XlFormatConditionOperator::xlGreaterEqual; + break; + case sheet::ConditionOperator_LESS: + retvalue = excel::XlFormatConditionOperator::xlLess; + break; + case sheet::ConditionOperator_LESS_EQUAL: + retvalue = excel::XlFormatConditionOperator::xlLessEqual; + break; + case sheet::ConditionOperator_BETWEEN: + retvalue = excel::XlFormatConditionOperator::xlBetween; + break; + case sheet::ConditionOperator_NOT_BETWEEN: + retvalue = excel::XlFormatConditionOperator::xlNotBetween; + break; + case sheet::ConditionOperator_FORMULA: + if (_bIncludeFormulaValue) + { + //#FIXME huh what's this all about + // from helperapi/impl/.../calc/ConditionImpl + retvalue = ISFORMULA; + break; + } + [[fallthrough]]; //TODO ??? + case sheet::ConditionOperator_NONE: + default: + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, u"Operator not supported"); + break; + } + return retvalue; +} + +template class ScVbaCondition<excel::XFormatCondition>; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbacondition.hxx b/sc/source/ui/vba/vbacondition.hxx new file mode 100644 index 000000000..78faf0d5e --- /dev/null +++ b/sc/source/ui/vba/vbacondition.hxx @@ -0,0 +1,48 @@ +/* -*- 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 . + */ +#pragma once + +#include <vbahelper/vbahelperinterface.hxx> +#include <com/sun/star/sheet/ConditionOperator.hpp> + +namespace com::sun::star::sheet { class XCellRangeAddressable; } +namespace com::sun::star::sheet { class XSheetCondition; } + +template< typename... Ifc > +class ScVbaCondition : public InheritedHelperInterfaceWeakImpl< Ifc... > +{ +typedef InheritedHelperInterfaceWeakImpl< Ifc... > ScVbaCondition_BASE; +protected: + css::uno::Reference< css::sheet::XCellRangeAddressable > mxAddressable; + css::uno::Reference< css::sheet::XSheetCondition > mxSheetCondition; +public: + ScVbaCondition( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::sheet::XSheetCondition >& _xSheetCondition ); + + /// @throws css::script::BasicErrorException + static css::sheet::ConditionOperator retrieveAPIOperator( const css::uno::Any& _aOperator); + + virtual OUString SAL_CALL Formula1( ) override; + virtual OUString SAL_CALL Formula2( ) override; + /// @throws css::script::BasicErrorException + virtual sal_Int32 Operator(bool _bIncludeFormulaValue); + virtual sal_Int32 SAL_CALL Operator() override = 0; + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbadialog.cxx b/sc/source/ui/vba/vbadialog.cxx new file mode 100644 index 000000000..5537c65a3 --- /dev/null +++ b/sc/source/ui/vba/vbadialog.cxx @@ -0,0 +1,85 @@ +/* -*- 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 <sal/config.h> + +#include <string_view> + +#include "vbadialog.hxx" + +#include <sal/macros.h> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +const std::u16string_view aStringList[]= +{ + u".uno:Open", + u".uno:FormatCellDialog", + u".uno:InsertCell", + u".uno:Print", + u".uno:PasteSpecial", + u".uno:ToolProtectionDocument", + u".uno:ColumnWidth", + u".uno:DefineName", + u".uno:ConfigureDialog", + u".uno:HyperlinkDialog", + u".uno:InsertGraphic", + u".uno:InsertObject", + u".uno:PageFormatDialog", + u".uno:DataSort", + u".uno:RowHeight", + u".uno:AutoCorrectDlg", + u".uno:ConditionalFormatDialog", + u".uno:DataConsolidate", + u".uno:CreateNames", + u".uno:FillSeries", + u".uno:Validation", + u".uno:DefineLabelRange", + u".uno:DataFilterAutoFilter", + u".uno:DataFilterSpecialFilter", + u".uno:AutoFormat" +}; + +const sal_Int32 nDialogSize = SAL_N_ELEMENTS(aStringList); + +OUString +ScVbaDialog::mapIndexToName( sal_Int32 nIndex ) +{ + if( nIndex < nDialogSize ) + return OUString(aStringList[ nIndex ]); + return OUString(); +} + +OUString +ScVbaDialog::getServiceImplName() +{ + return "ScVbaDialog"; +} + +uno::Sequence< OUString > +ScVbaDialog::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.Dialog" + }; + return aServiceNames; +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbadialog.hxx b/sc/source/ui/vba/vbadialog.hxx new file mode 100644 index 000000000..9317cbfaf --- /dev/null +++ b/sc/source/ui/vba/vbadialog.hxx @@ -0,0 +1,40 @@ +/* -*- 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 . + */ +#pragma once + +#include <cppuhelper/implbase.hxx> +#include <ooo/vba/excel/XDialog.hpp> +#include <vbahelper/vbadialogbase.hxx> + +typedef cppu::ImplInheritanceHelper< VbaDialogBase, ov::excel::XDialog > ScVbaDialog_BASE; + +class ScVbaDialog : public ScVbaDialog_BASE +{ +public: + ScVbaDialog( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::frame::XModel >& xModel, sal_Int32 nIndex ):ScVbaDialog_BASE( xParent, xContext, xModel, nIndex ) {} + + // Methods + virtual OUString mapIndexToName( sal_Int32 nIndex ) override; + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbadialogs.cxx b/sc/source/ui/vba/vbadialogs.cxx new file mode 100644 index 000000000..9264728a2 --- /dev/null +++ b/sc/source/ui/vba/vbadialogs.cxx @@ -0,0 +1,51 @@ +/* -*- 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 <ooo/vba/excel/XDialog.hpp> +#include "vbadialogs.hxx" +#include "vbadialog.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +uno::Any +ScVbaDialogs::Item( const uno::Any &aItem ) +{ + sal_Int32 nIndex = 0; + aItem >>= nIndex; + uno::Reference< excel::XDialog > aDialog( new ScVbaDialog( uno::Reference< XHelperInterface >( Application(),uno::UNO_QUERY_THROW ), mxContext, m_xModel, nIndex ) ); + return uno::Any( aDialog ); +} + +OUString +ScVbaDialogs::getServiceImplName() +{ + return "ScVbaDialogs"; +} + +uno::Sequence< OUString > +ScVbaDialogs::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.Dialogs" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbadialogs.hxx b/sc/source/ui/vba/vbadialogs.hxx new file mode 100644 index 000000000..97cbbda04 --- /dev/null +++ b/sc/source/ui/vba/vbadialogs.hxx @@ -0,0 +1,43 @@ +/* -*- 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 . + */ +#pragma once + +#include <ooo/vba/excel/XDialogs.hpp> +#include <vbahelper/vbadialogsbase.hxx> +#include <cppuhelper/implbase.hxx> + +namespace ooo::vba { class XHelperInterface; } +namespace com::sun::star::uno { class XComponentContext; } + +typedef cppu::ImplInheritanceHelper< VbaDialogsBase, ov::excel::XDialogs > ScVbaDialogs_BASE; + +class ScVbaDialogs : public ScVbaDialogs_BASE +{ +public: + ScVbaDialogs( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > &xContext, const css::uno::Reference< css::frame::XModel >& xModel ): ScVbaDialogs_BASE( xParent, xContext, xModel ) {} + + // XCollection + virtual css::uno::Any SAL_CALL Item( const css::uno::Any& Index ) override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaeventshelper.cxx b/sc/source/ui/vba/vbaeventshelper.cxx new file mode 100644 index 000000000..bd00fdcac --- /dev/null +++ b/sc/source/ui/vba/vbaeventshelper.cxx @@ -0,0 +1,898 @@ +/* -*- 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 "vbaeventshelper.hxx" +#include "excelvbahelper.hxx" + +#include <com/sun/star/awt/XTopWindow.hpp> +#include <com/sun/star/awt/XTopWindowListener.hpp> +#include <com/sun/star/awt/XWindowListener.hpp> +#include <com/sun/star/frame/XBorderResizeListener.hpp> +#include <com/sun/star/frame/XControllerBorder.hpp> +#include <com/sun/star/script/ModuleType.hpp> +#include <com/sun/star/script/vba/VBAEventId.hpp> +#include <com/sun/star/sheet/XCellRangeAddressable.hpp> +#include <com/sun/star/sheet/XSheetCellRangeContainer.hpp> +#include <com/sun/star/table/XCellRange.hpp> +#include <com/sun/star/util/XChangesListener.hpp> +#include <com/sun/star/util/XChangesNotifier.hpp> + +#include <cppuhelper/implbase.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <unotools/eventcfg.hxx> +#include <vcl/event.hxx> +#include <vcl/svapp.hxx> +#include <vcl/window.hxx> +#include <vbahelper/vbaaccesshelper.hxx> + +#include <docsh.hxx> +#include <document.hxx> +#include <cellsuno.hxx> +#include <convuno.hxx> +#include "vbaapplication.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::script::vba::VBAEventId; +using namespace ::ooo::vba; + +namespace { + +/** Extracts a sheet index from the specified element of the passed sequence. + The element may be an integer, a Calc range or ranges object, or a VBA Range object. + + @throws lang::IllegalArgumentException + @throws uno::RuntimeException +*/ +SCTAB lclGetTabFromArgs( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) +{ + VbaEventsHelperBase::checkArgument( rArgs, nIndex ); + + // first try to extract a sheet index + sal_Int32 nTab = -1; + if( rArgs[ nIndex ] >>= nTab ) + { + if( (nTab < 0) || (nTab > MAXTAB) ) + throw lang::IllegalArgumentException(); + return static_cast< SCTAB >( nTab ); + } + + // try VBA Range object + uno::Reference< excel::XRange > xVbaRange = getXSomethingFromArgs< excel::XRange >( rArgs, nIndex ); + if( xVbaRange.is() ) + { + uno::Reference< XHelperInterface > xVbaHelper( xVbaRange, uno::UNO_QUERY_THROW ); + // TODO: in the future, the parent may be an excel::XChart (chart sheet) -> will there be a common base interface? + uno::Reference< excel::XWorksheet > xVbaSheet( xVbaHelper->getParent(), uno::UNO_QUERY_THROW ); + // VBA sheet index is 1-based + return static_cast< SCTAB >( xVbaSheet->getIndex() - 1 ); + } + + // try single UNO range object + uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable = getXSomethingFromArgs< sheet::XCellRangeAddressable >( rArgs, nIndex ); + if( xCellRangeAddressable.is() ) + return xCellRangeAddressable->getRangeAddress().Sheet; + + // at last, try UNO range list + uno::Reference< sheet::XSheetCellRangeContainer > xRanges = getXSomethingFromArgs< sheet::XSheetCellRangeContainer >( rArgs, nIndex ); + if( xRanges.is() ) + { + uno::Sequence< table::CellRangeAddress > aRangeAddresses = xRanges->getRangeAddresses(); + if( aRangeAddresses.hasElements() ) + return aRangeAddresses[ 0 ].Sheet; + } + + throw lang::IllegalArgumentException(); +} + +/** Returns the AWT container window of the passed controller. */ +uno::Reference< awt::XWindow > lclGetWindowForController( const uno::Reference< frame::XController >& rxController ) +{ + if( rxController.is() ) try + { + uno::Reference< frame::XFrame > xFrame( rxController->getFrame(), uno::UNO_SET_THROW ); + return xFrame->getContainerWindow(); + } + catch( uno::Exception& ) + { + } + return nullptr; +} + +} // namespace + +// This class is to process Workbook window related event +class ScVbaEventListener : public ::cppu::WeakImplHelper< awt::XTopWindowListener, + awt::XWindowListener, + frame::XBorderResizeListener, + util::XChangesListener > +{ +public: + ScVbaEventListener( ScVbaEventsHelper& rVbaEvents, const uno::Reference< frame::XModel >& rxModel, ScDocShell* pDocShell ); + + /** Starts listening to the passed document controller. */ + void startControllerListening( const uno::Reference< frame::XController >& rxController ); + /** Stops listening to the passed document controller. */ + void stopControllerListening( const uno::Reference< frame::XController >& rxController ); + + // XTopWindowListener + virtual void SAL_CALL windowOpened( const lang::EventObject& rEvent ) override; + virtual void SAL_CALL windowClosing( const lang::EventObject& rEvent ) override; + virtual void SAL_CALL windowClosed( const lang::EventObject& rEvent ) override; + virtual void SAL_CALL windowMinimized( const lang::EventObject& rEvent ) override; + virtual void SAL_CALL windowNormalized( const lang::EventObject& rEvent ) override; + virtual void SAL_CALL windowActivated( const lang::EventObject& rEvent ) override; + virtual void SAL_CALL windowDeactivated( const lang::EventObject& rEvent ) override; + + // XWindowListener + virtual void SAL_CALL windowResized( const awt::WindowEvent& rEvent ) override; + virtual void SAL_CALL windowMoved( const awt::WindowEvent& rEvent ) override; + virtual void SAL_CALL windowShown( const lang::EventObject& rEvent ) override; + virtual void SAL_CALL windowHidden( const lang::EventObject& rEvent ) override; + + // XBorderResizeListener + virtual void SAL_CALL borderWidthsChanged( const uno::Reference< uno::XInterface >& rSource, const frame::BorderWidths& aNewSize ) override; + + // XChangesListener + virtual void SAL_CALL changesOccurred( const util::ChangesEvent& rEvent ) override; + + // XEventListener + virtual void SAL_CALL disposing( const lang::EventObject& rEvent ) override; + +private: + /** Starts listening to the document model. */ + void startModelListening(); + /** Stops listening to the document model. */ + void stopModelListening(); + + /** Returns the controller for the passed VCL window. */ + uno::Reference< frame::XController > getControllerForWindow( vcl::Window* pWindow ) const; + + /** Calls the Workbook_Window[Activate|Deactivate] event handler. */ + void processWindowActivateEvent( vcl::Window* pWindow, bool bActivate ); + /** Posts a Workbook_WindowResize user event. */ + void postWindowResizeEvent( vcl::Window* pWindow ); + /** Callback link for Application::PostUserEvent(). */ + DECL_LINK( processWindowResizeEvent, void*, void ); + +private: + typedef ::std::map< VclPtr<vcl::Window>, uno::Reference< frame::XController > > WindowControllerMap; + + ::osl::Mutex maMutex; + ScVbaEventsHelper& mrVbaEvents; + uno::Reference< frame::XModel > mxModel; + ScDocShell* mpDocShell; + WindowControllerMap maControllers; /// Maps VCL top windows to their controllers. + std::multiset< VclPtr<vcl::Window> > m_PostedWindows; /// Keeps processWindowResizeEvent windows from being deleted between postWindowResizeEvent and processWindowResizeEvent + VclPtr<vcl::Window> mpActiveWindow; /// Currently activated window, to prevent multiple (de)activation. + bool mbWindowResized; /// True = window resize system event processed. + bool mbBorderChanged; /// True = borders changed system event processed. + bool mbDisposed; +}; + +ScVbaEventListener::ScVbaEventListener( ScVbaEventsHelper& rVbaEvents, const uno::Reference< frame::XModel >& rxModel, ScDocShell* pDocShell ) : + mrVbaEvents( rVbaEvents ), + mxModel( rxModel ), + mpDocShell( pDocShell ), + mpActiveWindow( nullptr ), + mbWindowResized( false ), + mbBorderChanged( false ), + mbDisposed( !rxModel.is() ) +{ + if( !mxModel.is() ) + return; + + startModelListening(); + try + { + uno::Reference< frame::XController > xController( mxModel->getCurrentController(), uno::UNO_SET_THROW ); + startControllerListening( xController ); + } + catch( uno::Exception& ) + { + } +} + +void ScVbaEventListener::startControllerListening( const uno::Reference< frame::XController >& rxController ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + uno::Reference< awt::XWindow > xWindow = lclGetWindowForController( rxController ); + if( xWindow.is() ) + try { xWindow->addWindowListener( this ); } catch( uno::Exception& ) {} + + uno::Reference< awt::XTopWindow > xTopWindow( xWindow, uno::UNO_QUERY ); + if( xTopWindow.is() ) + try { xTopWindow->addTopWindowListener( this ); } catch( uno::Exception& ) {} + + uno::Reference< frame::XControllerBorder > xControllerBorder( rxController, uno::UNO_QUERY ); + if( xControllerBorder.is() ) + try { xControllerBorder->addBorderResizeListener( this ); } catch( uno::Exception& ) {} + + if( VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow ) ) + { + maControllers[ pWindow ] = rxController; + } +} + +void ScVbaEventListener::stopControllerListening( const uno::Reference< frame::XController >& rxController ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + uno::Reference< awt::XWindow > xWindow = lclGetWindowForController( rxController ); + if( xWindow.is() ) + try { xWindow->removeWindowListener( this ); } catch( uno::Exception& ) {} + + uno::Reference< awt::XTopWindow > xTopWindow( xWindow, uno::UNO_QUERY ); + if( xTopWindow.is() ) + try { xTopWindow->removeTopWindowListener( this ); } catch( uno::Exception& ) {} + + uno::Reference< frame::XControllerBorder > xControllerBorder( rxController, uno::UNO_QUERY ); + if( xControllerBorder.is() ) + try { xControllerBorder->removeBorderResizeListener( this ); } catch( uno::Exception& ) {} + + if( VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow ) ) + { + maControllers.erase( pWindow ); + if( pWindow == mpActiveWindow ) + mpActiveWindow = nullptr; + } +} + +void SAL_CALL ScVbaEventListener::windowOpened( const lang::EventObject& /*rEvent*/ ) +{ +} + +void SAL_CALL ScVbaEventListener::windowClosing( const lang::EventObject& /*rEvent*/ ) +{ +} + +void SAL_CALL ScVbaEventListener::windowClosed( const lang::EventObject& /*rEvent*/ ) +{ +} + +void SAL_CALL ScVbaEventListener::windowMinimized( const lang::EventObject& /*rEvent*/ ) +{ +} + +void SAL_CALL ScVbaEventListener::windowNormalized( const lang::EventObject& /*rEvent*/ ) +{ +} + +void SAL_CALL ScVbaEventListener::windowActivated( const lang::EventObject& rEvent ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + if( mbDisposed ) + return; + + uno::Reference< awt::XWindow > xWindow( rEvent.Source, uno::UNO_QUERY ); + VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow ); + // do not fire activation event multiple time for the same window + if( pWindow && (pWindow != mpActiveWindow) ) + { + // if another window is active, fire deactivation event first + if( mpActiveWindow ) + processWindowActivateEvent( mpActiveWindow, false ); + // fire activation event for the new window + processWindowActivateEvent( pWindow, true ); + mpActiveWindow = pWindow; + } +} + +void SAL_CALL ScVbaEventListener::windowDeactivated( const lang::EventObject& rEvent ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + if( !mbDisposed ) + { + uno::Reference< awt::XWindow > xWindow( rEvent.Source, uno::UNO_QUERY ); + VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow ); + // do not fire the deactivation event, if the window is not active (prevent multiple deactivation) + if( pWindow && (pWindow == mpActiveWindow) ) + processWindowActivateEvent( pWindow, false ); + // forget pointer to the active window + mpActiveWindow = nullptr; + } +} + +void SAL_CALL ScVbaEventListener::windowResized( const awt::WindowEvent& rEvent ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + mbWindowResized = true; + if( !mbDisposed && mbBorderChanged ) + { + uno::Reference< awt::XWindow > xWindow( rEvent.Source, uno::UNO_QUERY ); + postWindowResizeEvent( VCLUnoHelper::GetWindow( xWindow ) ); + } +} + +void SAL_CALL ScVbaEventListener::windowMoved( const awt::WindowEvent& /*rEvent*/ ) +{ +} + +void SAL_CALL ScVbaEventListener::windowShown( const lang::EventObject& /*rEvent*/ ) +{ +} + +void SAL_CALL ScVbaEventListener::windowHidden( const lang::EventObject& /*rEvent*/ ) +{ +} + +void SAL_CALL ScVbaEventListener::borderWidthsChanged( const uno::Reference< uno::XInterface >& rSource, const frame::BorderWidths& /*aNewSize*/ ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + mbBorderChanged = true; + if( !mbDisposed && mbWindowResized ) + { + uno::Reference< frame::XController > xController( rSource, uno::UNO_QUERY ); + uno::Reference< awt::XWindow > xWindow = lclGetWindowForController( xController ); + postWindowResizeEvent( VCLUnoHelper::GetWindow( xWindow ) ); + } +} + +void SAL_CALL ScVbaEventListener::changesOccurred( const util::ChangesEvent& rEvent ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + sal_Int32 nCount = rEvent.Changes.getLength(); + if( mbDisposed || !mpDocShell || (nCount == 0) ) + return; + + util::ElementChange aChange = rEvent.Changes[ 0 ]; + OUString sOperation; + aChange.Accessor >>= sOperation; + if( !sOperation.equalsIgnoreAsciiCase("cell-change") ) + return; + + if( nCount == 1 ) + { + uno::Reference< table::XCellRange > xRangeObj; + aChange.ReplacedElement >>= xRangeObj; + if( xRangeObj.is() ) + { + uno::Sequence< uno::Any > aArgs{ uno::Any(xRangeObj) }; + mrVbaEvents.processVbaEventNoThrow( WORKSHEET_CHANGE, aArgs ); + } + return; + } + + ScRangeList aRangeList; + for( const util::ElementChange& rChange : rEvent.Changes ) + { + rChange.Accessor >>= sOperation; + uno::Reference< table::XCellRange > xRangeObj; + rChange.ReplacedElement >>= xRangeObj; + if( xRangeObj.is() && sOperation.equalsIgnoreAsciiCase("cell-change") ) + { + uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable( xRangeObj, uno::UNO_QUERY ); + if( xCellRangeAddressable.is() ) + { + ScRange aRange; + ScUnoConversion::FillScRange( aRange, xCellRangeAddressable->getRangeAddress() ); + aRangeList.push_back( aRange ); + } + } + } + + if (!aRangeList.empty()) + { + uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( mpDocShell, aRangeList ) ); + uno::Sequence< uno::Any > aArgs{ uno::Any(xRanges) }; + mrVbaEvents.processVbaEventNoThrow( WORKSHEET_CHANGE, aArgs ); + } +} + +void SAL_CALL ScVbaEventListener::disposing( const lang::EventObject& rEvent ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + uno::Reference< frame::XModel > xModel( rEvent.Source, uno::UNO_QUERY ); + if( xModel.is() ) + { + OSL_ENSURE( xModel.get() == mxModel.get(), "ScVbaEventListener::disposing - disposing from unknown model" ); + stopModelListening(); + mbDisposed = true; + return; + } + + uno::Reference< frame::XController > xController( rEvent.Source, uno::UNO_QUERY ); + if( xController.is() ) + { + stopControllerListening( xController ); + return; + } +} + +// private -------------------------------------------------------------------- + +void ScVbaEventListener::startModelListening() +{ + try + { + uno::Reference< util::XChangesNotifier > xChangesNotifier( mxModel, uno::UNO_QUERY_THROW ); + xChangesNotifier->addChangesListener( this ); + } + catch( uno::Exception& ) + { + } +} + +void ScVbaEventListener::stopModelListening() +{ + try + { + uno::Reference< util::XChangesNotifier > xChangesNotifier( mxModel, uno::UNO_QUERY_THROW ); + xChangesNotifier->removeChangesListener( this ); + } + catch( uno::Exception& ) + { + } +} + +uno::Reference< frame::XController > ScVbaEventListener::getControllerForWindow( vcl::Window* pWindow ) const +{ + WindowControllerMap::const_iterator aIt = maControllers.find( pWindow ); + return (aIt == maControllers.end()) ? uno::Reference< frame::XController >() : aIt->second; +} + +void ScVbaEventListener::processWindowActivateEvent( vcl::Window* pWindow, bool bActivate ) +{ + uno::Reference< frame::XController > xController = getControllerForWindow( pWindow ); + if( xController.is() ) + { + uno::Sequence< uno::Any > aArgs{ uno::Any(xController) }; + mrVbaEvents.processVbaEventNoThrow( bActivate ? WORKBOOK_WINDOWACTIVATE : WORKBOOK_WINDOWDEACTIVATE, aArgs ); + } +} + +void ScVbaEventListener::postWindowResizeEvent( vcl::Window* pWindow ) +{ + // check that the passed window is still alive (it must be registered in maControllers) + if( pWindow && (maControllers.count( pWindow ) > 0) ) + { + mbWindowResized = mbBorderChanged = false; + acquire(); // ensure we don't get deleted before the timer fires + m_PostedWindows.insert(pWindow); + Application::PostUserEvent( LINK( this, ScVbaEventListener, processWindowResizeEvent ), pWindow ); + } +} + +IMPL_LINK( ScVbaEventListener, processWindowResizeEvent, void*, p, void ) +{ + vcl::Window* pWindow = static_cast<vcl::Window*>(p); + ::osl::MutexGuard aGuard( maMutex ); + + /* Check that the passed window is still alive (it must be registered in + maControllers). While closing a document, postWindowResizeEvent() may + be called on the last window which posts a user event via + Application::PostUserEvent to call this event handler. VCL will trigger + the handler some time later. Sometimes, the window gets deleted before. + This is handled via the disposing() function which removes the window + pointer from the member maControllers. Thus, checking whether + maControllers contains pWindow ensures that the window is still alive. */ + if( !mbDisposed && pWindow && !pWindow->isDisposed() && (maControllers.count(pWindow) > 0) ) + { + // do not fire event unless all mouse buttons have been released + vcl::Window::PointerState aPointerState = pWindow->GetPointerState(); + if( (aPointerState.mnState & (MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT)) == 0 ) + { + uno::Reference< frame::XController > xController = getControllerForWindow( pWindow ); + if( xController.is() ) + { + uno::Sequence< uno::Any > aArgs{ uno::Any(xController) }; + // #163419# do not throw exceptions into application core + mrVbaEvents.processVbaEventNoThrow( WORKBOOK_WINDOWRESIZE, aArgs ); + } + } + } + { + // note: there may be multiple processWindowResizeEvent outstanding + // for pWindow, so it may have been added to m_PostedWindows multiple + // times - so this must delete exactly one of these elements! + auto const iter(m_PostedWindows.find(pWindow)); + assert(iter != m_PostedWindows.end()); + m_PostedWindows.erase(iter); + } + release(); +} + +ScVbaEventsHelper::ScVbaEventsHelper( const uno::Sequence< uno::Any >& rArgs ) : + VbaEventsHelperBase( rArgs ), + mbOpened( false ) +{ + mpDocShell = dynamic_cast< ScDocShell* >( mpShell ); // mpShell from base class + mpDoc = mpDocShell ? &mpDocShell->GetDocument() : nullptr; + + if( !mxModel.is() || !mpDocShell || !mpDoc ) + return; + + // global + auto registerAutoEvent = [this](sal_Int32 nID, const char* sName) + { registerEventHandler(nID, script::ModuleType::NORMAL, OString(OString::Concat("Auto_") + sName).getStr(), -1, uno::Any(false)); }; + registerAutoEvent(AUTO_OPEN, "Open"); + registerAutoEvent(AUTO_CLOSE, "Close"); + + // Workbook + auto registerWorkbookEvent = [this](sal_Int32 nID, const char* sName, sal_Int32 nCancelIndex) + { registerEventHandler(nID, script::ModuleType::DOCUMENT, OString(OString::Concat("Workbook_") + sName).getStr(), nCancelIndex, uno::Any(false)); }; + registerWorkbookEvent( WORKBOOK_ACTIVATE, "Activate", -1 ); + registerWorkbookEvent( WORKBOOK_DEACTIVATE, "Deactivate", -1 ); + registerWorkbookEvent( WORKBOOK_OPEN, "Open", -1 ); + registerWorkbookEvent( WORKBOOK_BEFORECLOSE, "BeforeClose", 0 ); + registerWorkbookEvent( WORKBOOK_BEFOREPRINT, "BeforePrint", 0 ); + registerWorkbookEvent( WORKBOOK_BEFORESAVE, "BeforeSave", 1 ); + registerWorkbookEvent( WORKBOOK_AFTERSAVE, "AfterSave", -1 ); + registerWorkbookEvent( WORKBOOK_NEWSHEET, "NewSheet", -1 ); + registerWorkbookEvent( WORKBOOK_WINDOWACTIVATE, "WindowActivate", -1 ); + registerWorkbookEvent( WORKBOOK_WINDOWDEACTIVATE, "WindowDeactivate", -1 ); + registerWorkbookEvent( WORKBOOK_WINDOWRESIZE, "WindowResize", -1 ); + + // Worksheet events. All events have a corresponding workbook event. + auto registerWorksheetEvent = [this](sal_Int32 nID, const char* sName, sal_Int32 nCancelIndex) + { + registerEventHandler(nID, script::ModuleType::DOCUMENT, OString(OString::Concat("Worksheet_") + sName).getStr(), + nCancelIndex, uno::Any(true)); + registerEventHandler(USERDEFINED_START + nID, script::ModuleType::DOCUMENT, + OString(OString::Concat("Workbook_Worksheet") + sName).getStr(), + ((nCancelIndex >= 0) ? (nCancelIndex + 1) : -1), uno::Any(false)); + }; + registerWorksheetEvent( WORKSHEET_ACTIVATE, "Activate", -1 ); + registerWorksheetEvent( WORKSHEET_DEACTIVATE, "Deactivate", -1 ); + registerWorksheetEvent( WORKSHEET_BEFOREDOUBLECLICK, "BeforeDoubleClick", 1 ); + registerWorksheetEvent( WORKSHEET_BEFORERIGHTCLICK, "BeforeRightClick", 1 ); + registerWorksheetEvent( WORKSHEET_CALCULATE, "Calculate", -1 ); + registerWorksheetEvent( WORKSHEET_CHANGE, "Change", -1 ); + registerWorksheetEvent( WORKSHEET_SELECTIONCHANGE, "SelectionChange", -1 ); + registerWorksheetEvent( WORKSHEET_FOLLOWHYPERLINK, "FollowHyperlink", -1 ); +} + +ScVbaEventsHelper::~ScVbaEventsHelper() +{ +} + +void SAL_CALL ScVbaEventsHelper::notifyEvent( const css::document::EventObject& rEvent ) +{ + static const uno::Sequence< uno::Any > saEmptyArgs; + if( (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::OPENDOC )) || + (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::CREATEDOC )) ) // CREATEDOC triggered e.g. during VBA Workbooks.Add + { + processVbaEventNoThrow( WORKBOOK_OPEN, saEmptyArgs ); + } + else if( rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::ACTIVATEDOC ) ) + { + processVbaEventNoThrow( WORKBOOK_ACTIVATE, saEmptyArgs ); + } + else if( rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::DEACTIVATEDOC ) ) + { + processVbaEventNoThrow( WORKBOOK_DEACTIVATE, saEmptyArgs ); + } + else if( (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVEDOCDONE )) || + (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVEASDOCDONE )) || + (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVETODOCDONE )) ) + { + uno::Sequence< uno::Any > aArgs{ uno::Any(true) }; + processVbaEventNoThrow( WORKBOOK_AFTERSAVE, aArgs ); + } + else if( (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVEDOCFAILED )) || + (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVEASDOCFAILED )) || + (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVETODOCFAILED )) ) + { + uno::Sequence< uno::Any > aArgs{ uno::Any(false) }; + processVbaEventNoThrow( WORKBOOK_AFTERSAVE, aArgs ); + } + else if( rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::CLOSEDOC ) ) + { + /* Trigger the WORKBOOK_WINDOWDEACTIVATE and WORKBOOK_DEACTIVATE + events and stop listening to the model (done in base class). */ + uno::Reference< frame::XController > xController( mxModel->getCurrentController() ); + if( xController.is() ) + { + uno::Sequence< uno::Any > aArgs{ uno::Any(xController) }; + processVbaEventNoThrow( WORKBOOK_WINDOWDEACTIVATE, aArgs ); + } + processVbaEventNoThrow( WORKBOOK_DEACTIVATE, saEmptyArgs ); + } + else if( rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::VIEWCREATED ) ) + { + uno::Reference< frame::XController > xController( mxModel->getCurrentController() ); + if( mxListener && xController.is() ) + mxListener->startControllerListening( xController ); + } + VbaEventsHelperBase::notifyEvent( rEvent ); +} + +OUString ScVbaEventsHelper::getImplementationName() +{ + return "ScVbaEventsHelper"; +} + +css::uno::Sequence<OUString> ScVbaEventsHelper::getSupportedServiceNames() +{ + return css::uno::Sequence<OUString>{ + "com.sun.star.script.vba.VBASpreadsheetEventProcessor"}; +} + +// protected ------------------------------------------------------------------ + +bool ScVbaEventsHelper::implPrepareEvent( EventQueue& rEventQueue, + const EventHandlerInfo& rInfo, const uno::Sequence< uno::Any >& rArgs ) +{ + // document and document shell are needed during event processing + if( !mpShell || !mpDoc ) + throw uno::RuntimeException(); + + /* For document events: check if events are enabled via the + Application.EnableEvents symbol (this is an Excel-only attribute). + Check this again for every event, as the event handler may change the + state of the EnableEvents symbol. Global events such as AUTO_OPEN and + AUTO_CLOSE are always enabled. */ + bool bExecuteEvent = (rInfo.mnModuleType != script::ModuleType::DOCUMENT) || ScVbaApplication::getDocumentEventsEnabled(); + + // framework and Calc fire a few events before 'OnLoad', ignore them + if( bExecuteEvent ) + bExecuteEvent = (rInfo.mnEventId == WORKBOOK_OPEN) ? !mbOpened : mbOpened; + + // special handling for some events + if( bExecuteEvent ) switch( rInfo.mnEventId ) + { + case WORKBOOK_OPEN: + { + // execute delayed Activate event too (see above) + rEventQueue.emplace_back(WORKBOOK_ACTIVATE ); + uno::Sequence< uno::Any > aArgs{ uno::Any(mxModel->getCurrentController()) }; + rEventQueue.emplace_back( WORKBOOK_WINDOWACTIVATE, aArgs ); + rEventQueue.emplace_back(AUTO_OPEN ); + // remember initial selection + maOldSelection <<= mxModel->getCurrentSelection(); + } + break; + case WORKSHEET_SELECTIONCHANGE: + // if selection is not changed, then do not fire the event + bExecuteEvent = isSelectionChanged( rArgs, 0 ); + break; + } + + if( bExecuteEvent ) + { + // add workbook event associated to a sheet event + bool bSheetEvent = false; + if( (rInfo.maUserData >>= bSheetEvent) && bSheetEvent ) + rEventQueue.emplace_back( rInfo.mnEventId + USERDEFINED_START, rArgs ); + } + + return bExecuteEvent; +} + +uno::Sequence< uno::Any > ScVbaEventsHelper::implBuildArgumentList( const EventHandlerInfo& rInfo, + const uno::Sequence< uno::Any >& rArgs ) +{ + // fill arguments for workbook events associated to sheet events according to sheet events, sheet will be added below + bool bSheetEventAsBookEvent = rInfo.mnEventId > USERDEFINED_START; + sal_Int32 nEventId = bSheetEventAsBookEvent ? (rInfo.mnEventId - USERDEFINED_START) : rInfo.mnEventId; + + uno::Sequence< uno::Any > aVbaArgs; + switch( nEventId ) + { + // *** Workbook *** + + // no arguments + case WORKBOOK_ACTIVATE: + case WORKBOOK_DEACTIVATE: + case WORKBOOK_OPEN: + break; + // 1 arg: cancel + case WORKBOOK_BEFORECLOSE: + case WORKBOOK_BEFOREPRINT: + aVbaArgs.realloc( 1 ); + // current cancel state will be inserted by caller + break; + // 2 args: saveAs, cancel + case WORKBOOK_BEFORESAVE: + checkArgumentType< bool >( rArgs, 0 ); + aVbaArgs = { rArgs[ 0 ], {} }; + // current cancel state will be inserted by caller + break; + // 1 arg: success + case WORKBOOK_AFTERSAVE: + checkArgumentType< bool >( rArgs, 0 ); + aVbaArgs = { rArgs[ 0 ] }; + break; + // 1 arg: window + case WORKBOOK_WINDOWACTIVATE: + case WORKBOOK_WINDOWDEACTIVATE: + case WORKBOOK_WINDOWRESIZE: + aVbaArgs = { createWindow( rArgs, 0 ) }; + break; + // 1 arg: worksheet + case WORKBOOK_NEWSHEET: + aVbaArgs = { createWorksheet( rArgs, 0 ) }; + break; + + // *** Worksheet *** + + // no arguments + case WORKSHEET_ACTIVATE: + case WORKSHEET_CALCULATE: + case WORKSHEET_DEACTIVATE: + break; + // 1 arg: range + case WORKSHEET_CHANGE: + case WORKSHEET_SELECTIONCHANGE: + aVbaArgs = { createRange( rArgs, 0 ) }; + break; + // 2 args: range, cancel + case WORKSHEET_BEFOREDOUBLECLICK: + case WORKSHEET_BEFORERIGHTCLICK: + aVbaArgs = { createRange( rArgs, 0 ), {} }; + // current cancel state will be inserted by caller + break; + // 1 arg: hyperlink + case WORKSHEET_FOLLOWHYPERLINK: + aVbaArgs = { createHyperlink( rArgs, 0 ) }; + break; + } + + /* For workbook events associated to sheet events, the workbook event gets + the same arguments but with a Worksheet object in front of them. */ + if( bSheetEventAsBookEvent ) + { + sal_Int32 nLength = aVbaArgs.getLength(); + uno::Sequence< uno::Any > aVbaArgs2( nLength + 1 ); + auto pVbaArgs2 = aVbaArgs2.getArray(); + *pVbaArgs2 = createWorksheet( rArgs, 0 ); + std::copy_n(std::cbegin(aVbaArgs), nLength, std::next(pVbaArgs2)); + aVbaArgs = aVbaArgs2; + } + + return aVbaArgs; +} + +void ScVbaEventsHelper::implPostProcessEvent( EventQueue& rEventQueue, + const EventHandlerInfo& rInfo, bool bCancel ) +{ + switch( rInfo.mnEventId ) + { + case WORKBOOK_OPEN: + mbOpened = true; + // register the listeners + if( !mxListener.is() ) + mxListener = new ScVbaEventListener( *this, mxModel, mpDocShell ); + break; + case WORKBOOK_BEFORECLOSE: + /* Execute Auto_Close only if not cancelled by event handler, but + before UI asks user whether to cancel closing the document. */ + if( !bCancel ) + rEventQueue.emplace_back(AUTO_CLOSE ); + break; + } +} + +OUString ScVbaEventsHelper::implGetDocumentModuleName( const EventHandlerInfo& rInfo, + const uno::Sequence< uno::Any >& rArgs ) const +{ + bool bSheetEvent = false; + rInfo.maUserData >>= bSheetEvent; + SCTAB nTab = bSheetEvent ? lclGetTabFromArgs( rArgs, 0 ) : -1; + if( bSheetEvent && (nTab < 0) ) + throw lang::IllegalArgumentException(); + + OUString aCodeName; + if( bSheetEvent ) + mpDoc->GetCodeName( nTab, aCodeName ); + else + aCodeName = mpDoc->GetCodeName(); + return aCodeName; +} + +// private -------------------------------------------------------------------- + +namespace { + +/** Compares the passed range lists representing sheet selections. Ignores + selections that refer to different sheets (returns false in this case). */ +bool lclSelectionChanged( const ScRangeList& rLeft, const ScRangeList& rRight ) +{ + // one of the range lists empty? -> return false, if both lists empty + bool bLeftEmpty = rLeft.empty(); + bool bRightEmpty = rRight.empty(); + if( bLeftEmpty || bRightEmpty ) + return !(bLeftEmpty && bRightEmpty); + + // check sheet indexes of the range lists (assuming that all ranges in a list are on the same sheet) + if (rLeft[0].aStart.Tab() != rRight[0].aStart.Tab()) + return false; + + // compare all ranges + return rLeft != rRight; +} + +} // namespace + +bool ScVbaEventsHelper::isSelectionChanged( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) +{ + uno::Reference< uno::XInterface > xOldSelection( maOldSelection, uno::UNO_QUERY ); + uno::Reference< uno::XInterface > xNewSelection = getXSomethingFromArgs< uno::XInterface >( rArgs, nIndex, false ); + ScCellRangesBase* pOldCellRanges = comphelper::getFromUnoTunnel<ScCellRangesBase>( xOldSelection ); + ScCellRangesBase* pNewCellRanges = comphelper::getFromUnoTunnel<ScCellRangesBase>( xNewSelection ); + bool bChanged = !pOldCellRanges || !pNewCellRanges || lclSelectionChanged( pOldCellRanges->GetRangeList(), pNewCellRanges->GetRangeList() ); + maOldSelection <<= xNewSelection; + return bChanged; +} + +uno::Any ScVbaEventsHelper::createWorksheet( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const +{ + // extract sheet index, will throw, if parameter is invalid + SCTAB nTab = lclGetTabFromArgs( rArgs, nIndex ); + return uno::Any( excel::getUnoSheetModuleObj( mxModel, nTab ) ); +} + +uno::Any ScVbaEventsHelper::createRange( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const +{ + // it is possible to pass an existing VBA Range object + uno::Reference< excel::XRange > xVbaRange = getXSomethingFromArgs< excel::XRange >( rArgs, nIndex ); + if( !xVbaRange.is() ) + { + uno::Reference< sheet::XSheetCellRangeContainer > xRanges = getXSomethingFromArgs< sheet::XSheetCellRangeContainer >( rArgs, nIndex ); + uno::Reference< table::XCellRange > xRange = getXSomethingFromArgs< table::XCellRange >( rArgs, nIndex ); + if ( !xRanges.is() && !xRange.is() ) + throw lang::IllegalArgumentException(); + + uno::Sequence< uno::Any > aArgs; + if ( xRanges.is() ) + { + aArgs = { uno::Any(excel::getUnoSheetModuleObj( xRanges )), uno::Any(xRanges) }; + } + else + { + aArgs = { uno::Any(excel::getUnoSheetModuleObj( xRange )), uno::Any(xRange) }; + } + xVbaRange.set( createVBAUnoAPIServiceWithArgs( mpShell, "ooo.vba.excel.Range", aArgs ), uno::UNO_QUERY_THROW ); + } + return uno::Any( xVbaRange ); +} + +uno::Any ScVbaEventsHelper::createHyperlink( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const +{ + uno::Reference< table::XCell > xCell = getXSomethingFromArgs< table::XCell >( rArgs, nIndex, false ); + uno::Sequence< uno::Any > aArgs{ uno::Any(excel::getUnoSheetModuleObj( xCell )), + uno::Any(xCell) }; + uno::Reference< uno::XInterface > xHyperlink( createVBAUnoAPIServiceWithArgs( mpShell, "ooo.vba.excel.Hyperlink", aArgs ), uno::UNO_SET_THROW ); + return uno::Any( xHyperlink ); +} + +uno::Any ScVbaEventsHelper::createWindow( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const +{ + uno::Sequence< uno::Any > aArgs{ uno::Any(getVBADocument( mxModel )), + uno::Any(mxModel), + uno::Any(getXSomethingFromArgs< frame::XController >( rArgs, nIndex, false )) }; + uno::Reference< uno::XInterface > xWindow( createVBAUnoAPIServiceWithArgs( mpShell, "ooo.vba.excel.Window", aArgs ), uno::UNO_SET_THROW ); + return uno::Any( xWindow ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +ScVbaEventsHelper_get_implementation( + css::uno::XComponentContext * /*context*/, + css::uno::Sequence<css::uno::Any> const &arguments) +{ + return cppu::acquire(new ScVbaEventsHelper(arguments)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaeventshelper.hxx b/sc/source/ui/vba/vbaeventshelper.hxx new file mode 100644 index 000000000..e5bf11ecb --- /dev/null +++ b/sc/source/ui/vba/vbaeventshelper.hxx @@ -0,0 +1,84 @@ +/* -*- 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 . + */ + +#pragma once + +#include <rtl/ref.hxx> +#include <vbahelper/vbaeventshelperbase.hxx> + +class ScDocShell; +class ScDocument; +class ScVbaEventListener; + +class ScVbaEventsHelper : public VbaEventsHelperBase +{ +public: + ScVbaEventsHelper( const css::uno::Sequence< css::uno::Any >& rArgs ); + virtual ~ScVbaEventsHelper() override; + + virtual void SAL_CALL notifyEvent( const css::document::EventObject& rEvent ) override; + + OUString SAL_CALL getImplementationName() override; + + css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + +protected: + virtual bool implPrepareEvent( EventQueue& rEventQueue, const EventHandlerInfo& rInfo, const css::uno::Sequence< css::uno::Any >& rArgs ) override; + virtual css::uno::Sequence< css::uno::Any > implBuildArgumentList( const EventHandlerInfo& rInfo, const css::uno::Sequence< css::uno::Any >& rArgs ) override; + virtual void implPostProcessEvent( EventQueue& rEventQueue, const EventHandlerInfo& rInfo, bool bCancel ) override; + virtual OUString implGetDocumentModuleName( const EventHandlerInfo& rInfo, const css::uno::Sequence< css::uno::Any >& rArgs ) const override; + +private: + /** Checks if selection has been changed compared to selection of last call. + @return true, if the selection has been changed. + @throws css::lang::IllegalArgumentException + @throws css::uno::RuntimeException + */ + bool isSelectionChanged( const css::uno::Sequence< css::uno::Any >& rArgs, sal_Int32 nIndex ); + + /** Creates a VBA Worksheet object (the argument must contain a sheet index). + @throws css::lang::IllegalArgumentException + @throws css::uno::RuntimeException + */ + css::uno::Any createWorksheet( const css::uno::Sequence< css::uno::Any >& rArgs, sal_Int32 nIndex ) const; + /** Creates a VBA Range object (the argument must contain a UNO range or UNO range list). + @throws css::lang::IllegalArgumentException + @throws css::uno::RuntimeException + */ + css::uno::Any createRange( const css::uno::Sequence< css::uno::Any >& rArgs, sal_Int32 nIndex ) const; + /** Creates a VBA Hyperlink object (the argument must contain a UNO cell). + @throws css::lang::IllegalArgumentException + @throws css::uno::RuntimeException + */ + css::uno::Any createHyperlink( const css::uno::Sequence< css::uno::Any >& rArgs, sal_Int32 nIndex ) const; + /** Creates a VBA Window object (the argument must contain a model controller). + @throws css::lang::IllegalArgumentException + @throws css::uno::RuntimeException + */ + css::uno::Any createWindow( const css::uno::Sequence< css::uno::Any >& rArgs, sal_Int32 nIndex ) const; + +private: + ::rtl::Reference< ScVbaEventListener > mxListener; + css::uno::Any maOldSelection; + ScDocShell* mpDocShell; + ScDocument* mpDoc; + bool mbOpened; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbafiledialog.cxx b/sc/source/ui/vba/vbafiledialog.cxx new file mode 100644 index 000000000..f7f31db2a --- /dev/null +++ b/sc/source/ui/vba/vbafiledialog.cxx @@ -0,0 +1,174 @@ +/* -*- 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 "vbafiledialog.hxx" +#include "vbafiledialogitems.hxx" + +#include <osl/file.hxx> + +#include <ooo/vba/office/MsoFileDialogType.hpp> + +#include <com/sun/star/ui/dialogs/FilePicker.hpp> +#include <com/sun/star/ui/dialogs/FolderPicker.hpp> +#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp> +#include <com/sun/star/ui/dialogs/TemplateDescription.hpp> + +using namespace ::com::sun::star; +using namespace ::ooo::vba; + +ScVbaFileDialog::ScVbaFileDialog( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const sal_Int32 nType ) + : ScVbaFileDialog_BASE( xParent, xContext) + , m_nType(nType) + , m_sTitle("FileDialog") + , m_bMultiSelectMode(false) +{} + +uno::Any +ScVbaFileDialog::getInitialFileName() { return uno::Any( m_sInitialFileName ); } + +void ScVbaFileDialog::setInitialFileName( const css::uno::Any& rName ) +{ + OUString sDefaultPath; + + if( rName >>= sDefaultPath ) + { + OUString sDefaultURL; + sal_Int32 eSuccess = osl::FileBase::getFileURLFromSystemPath( + sDefaultPath, sDefaultURL ) ; + if( eSuccess == osl::FileBase::RC::E_INVAL ) + m_sInitialFileName = sDefaultPath; // the user may gave it in URL form + else + m_sInitialFileName = sDefaultURL; + } +} + +css::uno::Any ScVbaFileDialog::getTitle() { return uno::Any( m_sTitle ); } + +void ScVbaFileDialog::setTitle( const css::uno::Any& rTitle ) +{ + rTitle >>= m_sTitle; +} + +uno::Any ScVbaFileDialog::getAllowMultiSelect() +{ + return uno::Any(m_bMultiSelectMode); +} + +void ScVbaFileDialog::setAllowMultiSelect(const uno::Any& rAllowMultiSelect) +{ + rAllowMultiSelect >>= m_bMultiSelectMode; +} + +uno::Reference< excel::XFileDialogSelectedItems > SAL_CALL ScVbaFileDialog::getSelectedItems() +{ + // TODO use InitialFileName when m_xItems is empty + return m_xItems; +} + +sal_Int32 ScVbaFileDialog::Show() +{ + std::vector<OUString> sSelectedPaths; + sal_Int32 nRet = -1; + + switch (m_nType) + { + case office::MsoFileDialogType::msoFileDialogOpen: + // TODO implement + break; + case office::MsoFileDialogType::msoFileDialogSaveAs: + // TODO implement + break; + case office::MsoFileDialogType::msoFileDialogFilePicker: + { + uno::Reference<ui::dialogs::XFilePicker3> xFilePicker = + ui::dialogs::FilePicker::createWithMode( + mxContext, ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE ); + + if( !m_sInitialFileName.isEmpty() ) + xFilePicker->setDisplayDirectory( m_sInitialFileName ); + + if( xFilePicker->execute() != ui::dialogs::ExecutableDialogResults::OK ) + { + nRet = 0; // cancel pressed + break; + } + + const uno::Sequence<OUString> aSelectedFiles = xFilePicker->getSelectedFiles(); + for( const auto& sURL : aSelectedFiles ) + { + OUString sPath; + osl::FileBase::getSystemPathFromFileURL(sURL, sPath); + + sSelectedPaths.push_back(sPath); + } + } + break; + case office::MsoFileDialogType::msoFileDialogFolderPicker: + { + uno::Reference< ui::dialogs::XFolderPicker2 > xFolderPicker = + ui::dialogs::FolderPicker::create(mxContext); + + if( !m_sInitialFileName.isEmpty() ) + xFolderPicker->setDisplayDirectory( m_sInitialFileName ); + + if( xFolderPicker->execute() != ui::dialogs::ExecutableDialogResults::OK ) + { + nRet = 0; // cancel pressed + break; + } + + OUString sURL = xFolderPicker->getDirectory(); + + if(!sURL.isEmpty()) + { + OUString sPath; + osl::FileBase::getSystemPathFromFileURL(sURL, sPath); + + sSelectedPaths.push_back(sPath); + } + + } + break; + default: + throw uno::RuntimeException(); + } + + m_xItems = css::uno::Reference< ov::excel::XFileDialogSelectedItems >( + new ScVbaFileDialogSelectedItems(this, mxContext, std::move(sSelectedPaths)) ); + return nRet; +} + +// XHelperInterface +OUString +ScVbaFileDialog::getServiceImplName() +{ + return "ScVbaFileDialog"; +} + +uno::Sequence<OUString> +ScVbaFileDialog::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.FileDialog" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbafiledialog.hxx b/sc/source/ui/vba/vbafiledialog.hxx new file mode 100644 index 000000000..f339e4a97 --- /dev/null +++ b/sc/source/ui/vba/vbafiledialog.hxx @@ -0,0 +1,58 @@ +/* -*- 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 . + */ +#pragma once + +#include <ooo/vba/excel/XFileDialog.hpp> +#include <vbahelper/vbahelperinterface.hxx> + +namespace com::sun::star::uno { class XComponentContext; } +namespace ooo::vba { class XHelperInterface; } +namespace ooo::vba::excel { class XFileDialogSelectedItems; } + +typedef InheritedHelperInterfaceWeakImpl< ov::excel::XFileDialog > ScVbaFileDialog_BASE; + +class ScVbaFileDialog : public ScVbaFileDialog_BASE +{ +private: + sal_Int32 m_nType; + OUString m_sTitle; + OUString m_sInitialFileName; + bool m_bMultiSelectMode; + css::uno::Reference< ov::excel::XFileDialogSelectedItems> m_xItems; +public: + ScVbaFileDialog( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext, const sal_Int32 nType); + + virtual css::uno::Any SAL_CALL getInitialFileName() override; + virtual void SAL_CALL setInitialFileName( const css::uno::Any& rName ) override; + virtual css::uno::Any SAL_CALL getTitle() override; + virtual void SAL_CALL setTitle( const css::uno::Any& rTitle ) override; + virtual css::uno::Any SAL_CALL getAllowMultiSelect() override; + virtual void SAL_CALL setAllowMultiSelect(const css::uno::Any& rAllowMultiSelect) override; + + virtual css::uno::Reference< ov::excel::XFileDialogSelectedItems > SAL_CALL getSelectedItems() override; + + virtual sal_Int32 SAL_CALL Show() override; + + //XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbafiledialogitems.cxx b/sc/source/ui/vba/vbafiledialogitems.cxx new file mode 100644 index 000000000..d34ace3c5 --- /dev/null +++ b/sc/source/ui/vba/vbafiledialogitems.cxx @@ -0,0 +1,123 @@ +/* -*- 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 <o3tl/safeint.hxx> + +#include "vbafiledialogitems.hxx" + +using namespace ::com::sun::star; +using namespace ::ooo::vba; + +namespace { + +class FileDialogItemEnumeration : public ::cppu::WeakImplHelper< container::XEnumeration > +{ + std::vector< OUString > m_sItems; + std::vector< OUString >::iterator mIt; +public: + explicit FileDialogItemEnumeration( std::vector< OUString >&& rVector ) : m_sItems( std::move(rVector) ), mIt( m_sItems.begin() ) {} + virtual sal_Bool SAL_CALL hasMoreElements() override + { + return ( mIt != m_sItems.end() ); + } + virtual uno::Any SAL_CALL nextElement() override + { + if( !hasMoreElements() ) + throw container::NoSuchElementException(); + OUString sPath = *mIt++; + return uno::Any( sPath ); + } +}; + +} + +ScVbaFileDialogSelectedItems::ScVbaFileDialogSelectedItems( + const css::uno::Reference< ov::XHelperInterface >& xParent + ,const css::uno::Reference< css::uno::XComponentContext >& xContext + ,std::vector< OUString >&& rItems) + : FileDialogSelectedItems_BASE( xParent, xContext, uno::Reference< container::XIndexAccess>() ) + , m_sItems(std::move(rItems)) {} + + +// XEnumerationAccess +uno::Type SAL_CALL +ScVbaFileDialogSelectedItems::getElementType() +{ + return cppu::UnoType<OUString>::get(); +} + +uno::Reference< container::XEnumeration > +ScVbaFileDialogSelectedItems::createEnumeration() +{ + return uno::Reference< container::XEnumeration >( new FileDialogItemEnumeration( std::vector(m_sItems) ) ); +} + +uno::Any +ScVbaFileDialogSelectedItems::createCollectionObject( const uno::Any& aSource ) +{ + sal_Int32 nPosition = -1; + if (!(aSource >>= nPosition)) + throw uno::RuntimeException("not an sal_Int32"); + if (nPosition < 0 || o3tl::make_unsigned(nPosition) >= m_sItems.size()) + throw uno::RuntimeException("out of range"); + + OUString sPath = m_sItems[nPosition]; + return uno::Any( sPath ); +} + +// Methods +uno::Any SAL_CALL +ScVbaFileDialogSelectedItems::Item( const uno::Any& aIndex, const uno::Any& /*aIndex*/ ) +{ + sal_Int32 nPosition = -1; + aIndex >>= nPosition; + + --nPosition; // vba indexing starts with 1 + + if( nPosition < 0 || nPosition >= getCount() ) + { + throw uno::RuntimeException(); + } + + return createCollectionObject( uno::Any( nPosition ) ); +} + +sal_Int32 ScVbaFileDialogSelectedItems::getCount() +{ + return m_sItems.size(); +} + +// XHelperInterface +OUString +ScVbaFileDialogSelectedItems::getServiceImplName() +{ + return "ScVbaFileDialogSelectedItems"; +} + +uno::Sequence<OUString> +ScVbaFileDialogSelectedItems::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.FileDialogSelectedItems" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbafiledialogitems.hxx b/sc/source/ui/vba/vbafiledialogitems.hxx new file mode 100644 index 000000000..5a01df010 --- /dev/null +++ b/sc/source/ui/vba/vbafiledialogitems.hxx @@ -0,0 +1,43 @@ +/* -*- 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/. + */ +#pragma once + +#include <ooo/vba/excel/XFileDialogSelectedItems.hpp> +#include <vbahelper/vbacollectionimpl.hxx> + +typedef CollTestImplHelper< ov::excel::XFileDialogSelectedItems > FileDialogSelectedItems_BASE; + +class ScVbaFileDialogSelectedItems final : public FileDialogSelectedItems_BASE +{ + const std::vector<OUString> m_sItems; +public: + std::vector<OUString> const& getItems() + { + return m_sItems; + } + + ScVbaFileDialogSelectedItems( const css::uno::Reference< ov::XHelperInterface >& xParent, + const css::uno::Reference< css::uno::XComponentContext >& xContext, + std::vector<OUString>&& sItems); + + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override; + + // Methods + virtual css::uno::Any SAL_CALL Item( const css::uno::Any& Index, const css::uno::Any& /*Index2*/ ) override; + virtual sal_Int32 SAL_CALL getCount() override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbafont.cxx b/sc/source/ui/vba/vbafont.cxx new file mode 100644 index 000000000..99afd919b --- /dev/null +++ b/sc/source/ui/vba/vbafont.cxx @@ -0,0 +1,329 @@ +/* -*- 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 <com/sun/star/awt/FontUnderline.hpp> +#include <ooo/vba/excel/XlColorIndex.hpp> +#include <ooo/vba/excel/XlUnderlineStyle.hpp> +#include <svl/itemset.hxx> +#include <o3tl/string_view.hxx> +#include "excelvbahelper.hxx" +#include "vbafont.hxx" +#include "vbapalette.hxx" +#include <scitems.hxx> +#include <cellsuno.hxx> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +ScVbaFont::ScVbaFont( + const uno::Reference< XHelperInterface >& xParent, + const uno::Reference< uno::XComponentContext >& xContext, + const ScVbaPalette& dPalette, + const uno::Reference< beans::XPropertySet >& xPropertySet, + ScCellRangeObj* pRangeObj, bool bFormControl ) : + ScVbaFont_BASE( xParent, xContext, dPalette.getPalette(), xPropertySet, bFormControl ), + mpRangeObj( pRangeObj ) +{ +} + +SfxItemSet* +ScVbaFont::GetDataSet() +{ + return mpRangeObj ? excel::ScVbaCellRangeAccess::GetDataSet( mpRangeObj ) : nullptr; +} + +ScVbaFont::~ScVbaFont() +{ +} + +uno::Any SAL_CALL +ScVbaFont::getSize() +{ + if ( GetDataSet() ) + if ( GetDataSet()->GetItemState( ATTR_FONT_HEIGHT) == SfxItemState::DONTCARE ) + return aNULL(); + return ScVbaFont_BASE::getSize(); +} + +void SAL_CALL +ScVbaFont::setColorIndex( const uno::Any& _colorindex ) +{ + if(mbFormControl) + return; + + sal_Int32 nIndex = 0; + _colorindex >>= nIndex; + // #FIXME xlColorIndexAutomatic & xlColorIndexNone are not really + // handled properly here + + if ( !nIndex || ( nIndex == excel::XlColorIndex::xlColorIndexAutomatic ) ) + { + nIndex = 1; // check default ( assume black ) + ScVbaFont_BASE::setColorIndex( uno::Any( nIndex ) ); + } + else + ScVbaFont_BASE::setColorIndex( _colorindex ); +} + +uno::Any SAL_CALL +ScVbaFont::getColorIndex() +{ + if(mbFormControl) + return uno::Any( sal_Int32(0) ); + if ( GetDataSet() ) + if ( GetDataSet()->GetItemState( ATTR_FONT_COLOR) == SfxItemState::DONTCARE ) + return aNULL(); + return ScVbaFont_BASE::getColorIndex(); +} + +void SAL_CALL +ScVbaFont::setStandardFontSize( const uno::Any& /*aValue*/ ) +{ +//XXX #TODO# #FIXME# + //mxFont->setPropertyValue("CharSize", ( uno::Any )fValue ); + throw uno::RuntimeException( + "setStandardFontSize not supported" ); +} + +uno::Any SAL_CALL +ScVbaFont::getStandardFontSize() +{ +//XXX #TODO# #FIXME# + throw uno::RuntimeException( "getStandardFontSize not supported" ); + // return uno::Any(); +} + +void SAL_CALL +ScVbaFont::setStandardFont( const uno::Any& /*aValue*/ ) +{ +//XXX #TODO# #FIXME# + throw uno::RuntimeException("setStandardFont not supported" ); +} + +uno::Any SAL_CALL +ScVbaFont::getStandardFont() +{ +//XXX #TODO# #FIXME# + throw uno::RuntimeException("getStandardFont not supported"); + // return uno::Any(); +} + +void SAL_CALL +ScVbaFont::setFontStyle( const uno::Any& aValue ) +{ + bool bBold = false; + bool bItalic = false; + + OUString aStyles; + aValue >>= aStyles; + + for (sal_Int32 nIdx{ 0 }; nIdx>=0; ) + { + const std::u16string_view aToken{ o3tl::getToken(aStyles, 0, ' ', nIdx ) }; + if (o3tl::equalsIgnoreAsciiCase(aToken, u"Bold")) + { + bBold = true; + if (bItalic) + break; + } + else if (o3tl::equalsIgnoreAsciiCase(aToken, u"Italic")) + { + bItalic = true; + if (bBold) + break; + } + } + + setBold( uno::Any( bBold ) ); + setItalic( uno::Any( bItalic ) ); +} + +uno::Any SAL_CALL +ScVbaFont::getFontStyle() +{ + OUStringBuffer aStyles; + bool bValue = false; + getBold() >>= bValue; + if( bValue ) + aStyles.append("Bold"); + + getItalic() >>= bValue; + if( bValue ) + { + if( !aStyles.isEmpty() ) + aStyles.append(" "); + aStyles.append("Italic"); + } + return uno::Any( aStyles.makeStringAndClear() ); +} + +uno::Any SAL_CALL +ScVbaFont::getBold() +{ + if ( GetDataSet() ) + if ( GetDataSet()->GetItemState( ATTR_FONT_WEIGHT) == SfxItemState::DONTCARE ) + return aNULL(); + return ScVbaFont_BASE::getBold(); +} + +void SAL_CALL +ScVbaFont::setUnderline( const uno::Any& aValue ) +{ + if(mbFormControl) + return; + + // default + sal_Int32 nValue = excel::XlUnderlineStyle::xlUnderlineStyleNone; + aValue >>= nValue; + switch ( nValue ) + { +// NOTE:: #TODO #FIMXE +// xlUnderlineStyleDoubleAccounting & xlUnderlineStyleSingleAccounting +// don't seem to be supported in Openoffice. +// The import filter converts them to single or double underlines as appropriate +// So, here at the moment we are similarly silently converting +// xlUnderlineStyleSingleAccounting to xlUnderlineStyleSingle. + + case excel::XlUnderlineStyle::xlUnderlineStyleNone: + nValue = awt::FontUnderline::NONE; + break; + case excel::XlUnderlineStyle::xlUnderlineStyleSingle: + case excel::XlUnderlineStyle::xlUnderlineStyleSingleAccounting: + nValue = awt::FontUnderline::SINGLE; + break; + case excel::XlUnderlineStyle::xlUnderlineStyleDouble: + case excel::XlUnderlineStyle::xlUnderlineStyleDoubleAccounting: + nValue = awt::FontUnderline::DOUBLE; + break; + default: + throw uno::RuntimeException("Unknown value for Underline" ); + } + + mxFont->setPropertyValue("CharUnderline", uno::Any(nValue) ); + +} + +uno::Any SAL_CALL +ScVbaFont::getUnderline() +{ + if ( GetDataSet() ) + if ( GetDataSet()->GetItemState( ATTR_FONT_UNDERLINE) == SfxItemState::DONTCARE ) + return aNULL(); + + sal_Int32 nValue = awt::FontUnderline::NONE; + + if(mbFormControl) + return uno::Any( nValue ); + + mxFont->getPropertyValue("CharUnderline") >>= nValue; + switch ( nValue ) + { + case awt::FontUnderline::DOUBLE: + nValue = excel::XlUnderlineStyle::xlUnderlineStyleDouble; + break; + case awt::FontUnderline::SINGLE: + nValue = excel::XlUnderlineStyle::xlUnderlineStyleSingle; + break; + case awt::FontUnderline::NONE: + nValue = excel::XlUnderlineStyle::xlUnderlineStyleNone; + break; + default: + throw uno::RuntimeException("Unknown value retrieved for Underline" ); + + } + return uno::Any( nValue ); +} + +uno::Any SAL_CALL +ScVbaFont::getStrikethrough() +{ + if ( GetDataSet() ) + if ( GetDataSet()->GetItemState( ATTR_FONT_CROSSEDOUT) == SfxItemState::DONTCARE ) + return aNULL(); + return ScVbaFont_BASE::getStrikethrough(); +} + +uno::Any SAL_CALL +ScVbaFont::getShadow() +{ + if ( GetDataSet() ) + if ( GetDataSet()->GetItemState( ATTR_FONT_SHADOWED) == SfxItemState::DONTCARE ) + return aNULL(); + return ScVbaFont_BASE::getShadow(); +} + +uno::Any SAL_CALL +ScVbaFont::getItalic() +{ + if ( GetDataSet() ) + if ( GetDataSet()->GetItemState( ATTR_FONT_POSTURE) == SfxItemState::DONTCARE ) + return aNULL(); + + return ScVbaFont_BASE::getItalic(); +} + +uno::Any SAL_CALL +ScVbaFont::getName() +{ + if ( GetDataSet() ) + if ( GetDataSet()->GetItemState( ATTR_FONT) == SfxItemState::DONTCARE ) + return aNULL(); + return ScVbaFont_BASE::getName(); +} +uno::Any +ScVbaFont::getColor() +{ + // #TODO #FIXME - behave like getXXX above ( wrt. GetDataSet ) + uno::Any aAny = OORGBToXLRGB( mxFont->getPropertyValue("CharColor") ); + return aAny; +} + +void SAL_CALL +ScVbaFont::setOutlineFont( const uno::Any& aValue ) +{ + if(!mbFormControl) + mxFont->setPropertyValue("CharContoured", aValue ); +} + +uno::Any SAL_CALL +ScVbaFont::getOutlineFont() +{ + if ( GetDataSet() ) + if ( GetDataSet()->GetItemState( ATTR_FONT_CONTOUR) == SfxItemState::DONTCARE ) + return aNULL(); + return mbFormControl ? uno::Any( false ) : mxFont->getPropertyValue("CharContoured"); +} + +OUString +ScVbaFont::getServiceImplName() +{ + return "ScVbaFont"; +} + +uno::Sequence< OUString > +ScVbaFont::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.Font" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbafont.hxx b/sc/source/ui/vba/vbafont.hxx new file mode 100644 index 000000000..d6a01b9a0 --- /dev/null +++ b/sc/source/ui/vba/vbafont.hxx @@ -0,0 +1,76 @@ +/* -*- 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 . + */ +#pragma once + +#include <cppuhelper/implbase.hxx> + +#include <ooo/vba/excel/XFont.hpp> +#include <vbahelper/vbafontbase.hxx> + +namespace com::sun::star::beans +{ +class XPropertySet; +} + +class ScCellRangeObj; +class SfxItemSet; +class ScVbaPalette; + +typedef cppu::ImplInheritanceHelper<VbaFontBase, ov::excel::XFont> ScVbaFont_BASE; + +class ScVbaFont : public ScVbaFont_BASE +{ + ScCellRangeObj* mpRangeObj; + SfxItemSet* GetDataSet(); + +public: + /// @throws css::uno::RuntimeException + ScVbaFont(const css::uno::Reference<ov::XHelperInterface>& xParent, + const css::uno::Reference<css::uno::XComponentContext>& xContext, + const ScVbaPalette& dPalette, + const css::uno::Reference<css::beans::XPropertySet>& xPropertySet, + ScCellRangeObj* pRangeObj = nullptr, bool bFormControl = false); + virtual ~ScVbaFont() override; // {} + + // Attributes + virtual css::uno::Any SAL_CALL getSize() override; + virtual css::uno::Any SAL_CALL getStandardFontSize() override; + virtual void SAL_CALL setStandardFontSize(const css::uno::Any& _standardfontsize) override; + virtual css::uno::Any SAL_CALL getStandardFont() override; + virtual void SAL_CALL setStandardFont(const css::uno::Any& _standardfont) override; + virtual css::uno::Any SAL_CALL getFontStyle() override; + virtual void SAL_CALL setFontStyle(const css::uno::Any& _fontstyle) override; + virtual css::uno::Any SAL_CALL getColorIndex() override; + virtual void SAL_CALL setColorIndex(const css::uno::Any& _colorindex) override; + virtual css::uno::Any SAL_CALL getBold() override; + virtual css::uno::Any SAL_CALL getUnderline() override; + virtual void SAL_CALL setUnderline(const css::uno::Any& _underline) override; + virtual css::uno::Any SAL_CALL getStrikethrough() override; + virtual css::uno::Any SAL_CALL getShadow() override; + virtual css::uno::Any SAL_CALL getItalic() override; + virtual css::uno::Any SAL_CALL getName() override; + virtual css::uno::Any SAL_CALL getColor() override; + virtual css::uno::Any SAL_CALL getOutlineFont() override; + virtual void SAL_CALL setOutlineFont(const css::uno::Any& _outlinefont) override; + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaformat.cxx b/sc/source/ui/vba/vbaformat.cxx new file mode 100644 index 000000000..a027279ae --- /dev/null +++ b/sc/source/ui/vba/vbaformat.cxx @@ -0,0 +1,814 @@ +/* -*- 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 "vbaformat.hxx" +#include <ooo/vba/excel/XFont.hpp> +#include <ooo/vba/excel/XStyle.hpp> +#include <ooo/vba/excel/XlVAlign.hpp> +#include <ooo/vba/excel/XlHAlign.hpp> +#include <ooo/vba/excel/XlOrientation.hpp> +#include <ooo/vba/excel/Constants.hpp> +#include <ooo/vba/excel/XRange.hpp> +#include <com/sun/star/table/CellVertJustify2.hpp> +#include <com/sun/star/table/CellHoriJustify.hpp> +#include <com/sun/star/table/CellOrientation.hpp> +#include <com/sun/star/table/XCellRange.hpp> +#include <com/sun/star/text/WritingMode.hpp> +#include <com/sun/star/util/CellProtection.hpp> +#include <com/sun/star/util/XNumberFormatsSupplier.hpp> +#include <com/sun/star/util/XNumberFormats.hpp> +#include <com/sun/star/util/XNumberFormatTypes.hpp> +#include <com/sun/star/frame/XModel.hpp> + +#include <basic/sberrors.hxx> +#include <rtl/math.hxx> + +#include "excelvbahelper.hxx" +#include "vbaborders.hxx" +#include "vbapalette.hxx" +#include "vbafont.hxx" +#include "vbainterior.hxx" + +#include <docsh.hxx> +#include <unonames.hxx> +#include <cellsuno.hxx> +#include <scitems.hxx> +#include <attrib.hxx> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +constexpr OUStringLiteral FORMATSTRING = u"FormatString"; +constexpr OUStringLiteral LOCALE = u"Locale"; + +template< typename... Ifc > +ScVbaFormat< Ifc... >::ScVbaFormat( const uno::Reference< XHelperInterface >& xParent, + const uno::Reference< uno::XComponentContext > & xContext, + const uno::Reference< beans::XPropertySet >& _xPropertySet, + const uno::Reference< frame::XModel >& xModel, + bool bCheckAmbiguoity ) + : ScVbaFormat_BASE( xParent, xContext ), + m_aDefaultLocale( "en", "US", OUString() ), + mxPropertySet( _xPropertySet ), + mxModel( xModel ), + mbCheckAmbiguoity( bCheckAmbiguoity ), + mbAddIndent( false ) +{ + try + { + if ( !mxModel.is() ) + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, u"XModel Interface could not be retrieved" ); + // mxServiceInfo is unused, + // mxNumberFormatsSupplier is initialized when needed in initializeNumberFormats. + } + catch (const uno::Exception& ) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} ); + } +} + +template< typename... Ifc > +void SAL_CALL +ScVbaFormat< Ifc... >::setVerticalAlignment( const uno::Any& _oAlignment) +{ + try + { + uno::Any aVal; + sal_Int32 nAlignment = 0; + if ( !(_oAlignment >>= nAlignment )) + throw uno::RuntimeException(); + switch (nAlignment) + { + case excel::XlVAlign::xlVAlignBottom : + aVal <<= table::CellVertJustify2::BOTTOM; + break; + case excel::XlVAlign::xlVAlignCenter : + aVal <<= table::CellVertJustify2::CENTER; + break; + case excel::XlVAlign::xlVAlignDistributed: + case excel::XlVAlign::xlVAlignJustify: + aVal <<= table::CellVertJustify2::STANDARD; + break; + + case excel::XlVAlign::xlVAlignTop: + aVal <<= table::CellVertJustify2::TOP; + break; + default: + aVal <<= table::CellVertJustify2::STANDARD; + break; + } + mxPropertySet->setPropertyValue( SC_UNONAME_CELLVJUS, aVal ); + } + catch (const uno::Exception&) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } +} + +template< typename... Ifc > +uno::Any SAL_CALL +ScVbaFormat< Ifc... >::getVerticalAlignment( ) +{ + uno::Any aResult = aNULL(); + try + { + if (!isAmbiguous( SC_UNONAME_CELLVJUS ) ) + { + sal_Int32 aAPIAlignment = table::CellVertJustify2::STANDARD; + mxPropertySet->getPropertyValue( SC_UNONAME_CELLVJUS ) >>= aAPIAlignment; + switch( aAPIAlignment ) + { + case table::CellVertJustify2::BOTTOM: + aResult <<= excel::XlVAlign::xlVAlignBottom; + break; + case table::CellVertJustify2::CENTER: + aResult <<= excel::XlVAlign::xlVAlignCenter; + break; + case table::CellVertJustify2::STANDARD: + aResult <<= excel::XlVAlign::xlVAlignBottom; + break; + case table::CellVertJustify2::TOP: + aResult <<= excel::XlVAlign::xlVAlignTop; + break; + default: + break; + } + } + } + catch (const uno::Exception& ) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } + return aResult; +} + +template< typename... Ifc > +void SAL_CALL +ScVbaFormat< Ifc... >::setHorizontalAlignment( const uno::Any& HorizontalAlignment ) +{ + try + { + uno::Any aVal; + sal_Int32 nAlignment = 0; + if ( !( HorizontalAlignment >>= nAlignment ) ) + throw uno::RuntimeException(); + switch ( nAlignment ) + { + case excel::XlHAlign::xlHAlignJustify: + aVal <<= table::CellHoriJustify_BLOCK; + break; + case excel::XlHAlign::xlHAlignCenter: + aVal <<= table::CellHoriJustify_CENTER; + break; + case excel::XlHAlign::xlHAlignDistributed: + aVal <<= table::CellHoriJustify_BLOCK; + break; + case excel::XlHAlign::xlHAlignLeft: + aVal <<= table::CellHoriJustify_LEFT; + break; + case excel::XlHAlign::xlHAlignRight: + aVal <<= table::CellHoriJustify_RIGHT; + break; + } + // #FIXME what about the default case above? + // shouldn't need the test below + if ( aVal.hasValue() ) + mxPropertySet->setPropertyValue( SC_UNONAME_CELLHJUS, aVal ); + } + catch (const uno::Exception& ) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} ); + } + +} + +template< typename... Ifc > +uno::Any SAL_CALL +ScVbaFormat< Ifc... >::getHorizontalAlignment( ) +{ + uno::Any NRetAlignment = aNULL(); + try + { + OUString sHoriJust( SC_UNONAME_CELLHJUS ); + if (!isAmbiguous(sHoriJust)) + { + table::CellHoriJustify aAPIAlignment = table::CellHoriJustify_BLOCK; + + if ( mxPropertySet->getPropertyValue(sHoriJust) >>= aAPIAlignment ) + { + switch( aAPIAlignment ) + { + case table::CellHoriJustify_BLOCK: + NRetAlignment <<= excel::XlHAlign::xlHAlignJustify; + break; + case table::CellHoriJustify_CENTER: + NRetAlignment <<= excel::XlHAlign::xlHAlignCenter; + break; + case table::CellHoriJustify_LEFT: + NRetAlignment <<= excel::XlHAlign::xlHAlignLeft; + break; + case table::CellHoriJustify_RIGHT: + NRetAlignment <<= excel::XlHAlign::xlHAlignRight; + break; + default: // handle those other cases with a NULL return + break; + } + } + } + } + catch (const uno::Exception& ) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} ); + } + return NRetAlignment; +} + +template< typename... Ifc > +void SAL_CALL +ScVbaFormat< Ifc... >::setOrientation( const uno::Any& _aOrientation ) +{ + try + { + sal_Int32 nOrientation = 0; + if ( !( _aOrientation >>= nOrientation ) ) + throw uno::RuntimeException(); + uno::Any aVal; + switch( nOrientation ) + { + case excel::XlOrientation::xlDownward: + aVal <<= table::CellOrientation_TOPBOTTOM; + break; + case excel::XlOrientation::xlHorizontal: + aVal <<= table::CellOrientation_STANDARD; + mxPropertySet->setPropertyValue( SC_UNONAME_ROTANG, uno::Any( sal_Int32(0) ) ); + break; + case excel::XlOrientation::xlUpward: + aVal <<= table::CellOrientation_BOTTOMTOP; + break; + case excel::XlOrientation::xlVertical: + aVal <<= table::CellOrientation_STACKED; + break; + } + // #FIXME what about the default case above? + // shouldn't need the test below + if ( aVal.hasValue() ) + mxPropertySet->setPropertyValue( SC_UNONAME_CELLORI, aVal ); + + } + catch (const uno::Exception& ) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} ); + } +} +template< typename... Ifc > +uno::Any SAL_CALL +ScVbaFormat< Ifc... >::getOrientation( ) +{ + uno::Any NRetOrientation = aNULL(); + try + { + if (!isAmbiguous(SC_UNONAME_CELLORI)) + { + table::CellOrientation aOrientation = table::CellOrientation_STANDARD; + if ( !( mxPropertySet->getPropertyValue( SC_UNONAME_CELLORI ) >>= aOrientation ) ) + throw uno::RuntimeException(); + + switch(aOrientation) + { + case table::CellOrientation_STANDARD: + NRetOrientation <<= excel::XlOrientation::xlHorizontal; + break; + case table::CellOrientation_BOTTOMTOP: + NRetOrientation <<= excel::XlOrientation::xlUpward; + break; + case table::CellOrientation_TOPBOTTOM: + NRetOrientation <<= excel::XlOrientation::xlDownward; + break; + case table::CellOrientation_STACKED: + NRetOrientation <<= excel::XlOrientation::xlVertical; + break; + default: + NRetOrientation <<= excel::XlOrientation::xlHorizontal; + } + } + } + catch (const uno::Exception& ) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } + return NRetOrientation; +} + +template< typename... Ifc > +void SAL_CALL +ScVbaFormat< Ifc... >::setWrapText( const uno::Any& _aWrapText ) +{ + try + { + mxPropertySet->setPropertyValue( SC_UNONAME_WRAP, _aWrapText); + } + catch (const uno::Exception& ) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} ); + } +} + +template< typename... Ifc > +uno::Any SAL_CALL +ScVbaFormat< Ifc... >::getWrapText( ) +{ + uno::Any aWrap = aNULL(); + try + { + OUString aPropName( SC_UNONAME_WRAP ); + if (!isAmbiguous( aPropName )) + { + aWrap = mxPropertySet->getPropertyValue(aPropName); + } + } + catch (const uno::Exception&) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} ); + } + return aWrap; +} + +template< typename... Ifc > +uno::Any SAL_CALL +ScVbaFormat< Ifc... >::Borders( const uno::Any& Index ) +{ + ScVbaPalette aPalette( excel::getDocShell( mxModel ) ); + uno::Reference< XCollection > xColl = new ScVbaBorders( thisHelperIface(), ScVbaFormat_BASE::mxContext, uno::Reference< table::XCellRange >( mxPropertySet, uno::UNO_QUERY_THROW ), aPalette ); + + if ( Index.hasValue() ) + { + return xColl->Item( Index, uno::Any() ); + } + return uno::Any( xColl ); +} + +template< typename... Ifc > +uno::Reference< excel::XFont > SAL_CALL +ScVbaFormat< Ifc... >::Font( ) +{ + ScVbaPalette aPalette( excel::getDocShell( mxModel ) ); + return new ScVbaFont( thisHelperIface(), ScVbaFormat_BASE::mxContext, aPalette, mxPropertySet ); +} + +template< typename... Ifc > +uno::Reference< excel::XInterior > SAL_CALL +ScVbaFormat< Ifc... >::Interior( ) +{ + return new ScVbaInterior( thisHelperIface(), ScVbaFormat_BASE::mxContext, mxPropertySet ); +} + +template< typename... Ifc > +uno::Any SAL_CALL +ScVbaFormat< Ifc... >::getNumberFormatLocal( ) +{ + uno::Any aRet{ OUString() }; + try + { + OUString sPropName( SC_UNO_DP_NUMBERFO ); + if (!isAmbiguous( sPropName )) + { + + initializeNumberFormats(); + + sal_Int32 nFormat = 0; + if ( ! (mxPropertySet->getPropertyValue( sPropName ) >>= nFormat ) ) + throw uno::RuntimeException(); + + OUString sFormat; + xNumberFormats->getByKey(nFormat)->getPropertyValue( FORMATSTRING ) >>= sFormat; + aRet <<= sFormat.toAsciiLowerCase(); + + } + } + catch (const uno::Exception&) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } + return aRet; + +} + +template< typename... Ifc > +void SAL_CALL +ScVbaFormat< Ifc... >::setNumberFormatLocal( const uno::Any& _oLocalFormatString ) +{ + try + { + OUString sLocalFormatString; + sal_Int32 nFormat = -1; + OUString sNumFormat( SC_UNO_DP_NUMBERFO ); + if ( !(_oLocalFormatString >>= sLocalFormatString ) + || !( mxPropertySet->getPropertyValue(sNumFormat) >>= nFormat ) ) + throw uno::RuntimeException(); + + sLocalFormatString = sLocalFormatString.toAsciiUpperCase(); + initializeNumberFormats(); + lang::Locale aRangeLocale; + xNumberFormats->getByKey(nFormat)->getPropertyValue( LOCALE ) >>= aRangeLocale; + sal_Int32 nNewFormat = xNumberFormats->queryKey(sLocalFormatString, aRangeLocale, true); + + if (nNewFormat == -1) + nNewFormat = xNumberFormats->addNew(sLocalFormatString, aRangeLocale); + mxPropertySet->setPropertyValue(sNumFormat, uno::Any( nNewFormat )); + } + catch (const uno::Exception& ) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} ); + } +} + +template< typename... Ifc > +void SAL_CALL +ScVbaFormat< Ifc... >::setNumberFormat( const uno::Any& _oFormatString ) +{ + try + { + OUString sFormatString; + if ( !( _oFormatString >>= sFormatString ) ) + throw uno::RuntimeException(); + + sFormatString = sFormatString.toAsciiUpperCase(); + + lang::Locale aDefaultLocale = m_aDefaultLocale; + initializeNumberFormats(); + sal_Int32 nFormat = xNumberFormats->queryKey(sFormatString, aDefaultLocale, true); + + if (nFormat == -1) + nFormat = xNumberFormats->addNew(sFormatString, aDefaultLocale); + + lang::Locale aRangeLocale; + xNumberFormats->getByKey(nFormat)->getPropertyValue( LOCALE ) >>= aRangeLocale; + sal_Int32 nNewFormat = xNumberFormatTypes->getFormatForLocale(nFormat, aRangeLocale); + mxPropertySet->setPropertyValue( SC_UNO_DP_NUMBERFO, uno::Any( nNewFormat)); + } + catch (const uno::Exception& ) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } + +} + +template< typename... Ifc > +void SAL_CALL +ScVbaFormat< Ifc... >::setIndentLevel( const uno::Any& _aLevel ) +{ + try + { + sal_Int32 nLevel = 0; + if ( !(_aLevel >>= nLevel ) ) + throw uno::RuntimeException(); + table::CellHoriJustify aAPIAlignment = table::CellHoriJustify_STANDARD; + + OUString sHoriJust( SC_UNONAME_CELLHJUS ); + if ( !( mxPropertySet->getPropertyValue(sHoriJust) >>= aAPIAlignment ) ) + throw uno::RuntimeException(); + if (aAPIAlignment == table::CellHoriJustify_STANDARD) + mxPropertySet->setPropertyValue( sHoriJust, uno::Any( table::CellHoriJustify_LEFT) ) ; + mxPropertySet->setPropertyValue( SC_UNONAME_PINDENT, uno::Any( sal_Int16(nLevel * 352.8) ) ); + } + catch (const uno::Exception&) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } +} + +template< typename... Ifc > +uno::Any SAL_CALL +ScVbaFormat< Ifc... >::getIndentLevel( ) +{ + uno::Any NRetIndentLevel = aNULL(); + try + { + OUString sParaIndent( SC_UNONAME_PINDENT ); + if (!isAmbiguous(sParaIndent)) + { + sal_Int16 IndentLevel = 0; + if ( mxPropertySet->getPropertyValue(sParaIndent) >>= IndentLevel ) + NRetIndentLevel <<= sal_Int32( rtl::math::round(static_cast<double>( IndentLevel ) / 352.8)); + else + NRetIndentLevel <<= sal_Int32(0); + } + } + catch (const uno::Exception&) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } + return NRetIndentLevel; +} + +template< typename... Ifc > +void SAL_CALL +ScVbaFormat< Ifc... >::setLocked( const uno::Any& _aLocked ) +{ + try + { + bool bIsLocked = false; + if ( !( _aLocked >>= bIsLocked ) ) + throw uno::RuntimeException(); + util::CellProtection aCellProtection; + OUString sCellProt( SC_UNONAME_CELLPRO ); + mxPropertySet->getPropertyValue(sCellProt) >>= aCellProtection; + aCellProtection.IsLocked = bIsLocked; + mxPropertySet->setPropertyValue(sCellProt, uno::Any( aCellProtection ) ); + } + catch (const uno::Exception&) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} ); + } +} + +template< typename... Ifc > +void SAL_CALL +ScVbaFormat< Ifc... >::setFormulaHidden( const uno::Any& FormulaHidden ) +{ + try + { + bool bIsFormulaHidden = false; + FormulaHidden >>= bIsFormulaHidden; + util::CellProtection aCellProtection; + OUString sCellProt( SC_UNONAME_CELLPRO ); + mxPropertySet->getPropertyValue(sCellProt) >>= aCellProtection; + aCellProtection.IsFormulaHidden = bIsFormulaHidden; + mxPropertySet->setPropertyValue(sCellProt,uno::Any(aCellProtection)); + } + catch (const uno::Exception&) + { + DebugHelper::basicexception( ERRCODE_BASIC_METHOD_FAILED, {} ); + } +} + +template< typename... Ifc > +uno::Any SAL_CALL +ScVbaFormat< Ifc... >::getLocked( ) +{ + uno::Any aCellProtection = aNULL(); + try + { + OUString sCellProt( SC_UNONAME_CELLPRO ); + + if (!isAmbiguous(sCellProt)) + { + SfxItemSet* pDataSet = getCurrentDataSet(); + if ( pDataSet ) + { + const ScProtectionAttr& rProtAttr = pDataSet->Get(ATTR_PROTECTION); + SfxItemState eState = pDataSet->GetItemState(ATTR_PROTECTION); + if(eState != SfxItemState::DONTCARE) + aCellProtection <<= rProtAttr.GetProtection(); + } + else // fallback to propertyset + { + util::CellProtection cellProtection; + mxPropertySet->getPropertyValue(sCellProt) >>= cellProtection; + aCellProtection <<= cellProtection.IsLocked; + } + } + } + catch (const uno::Exception&) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } + return aCellProtection; +} + +template< typename... Ifc > +uno::Any SAL_CALL +ScVbaFormat< Ifc... >::getFormulaHidden( ) +{ + uno::Any aBoolRet = aNULL(); + try + { + OUString sCellProt( SC_UNONAME_CELLPRO ); + if (!isAmbiguous(sCellProt)) + { + SfxItemSet* pDataSet = getCurrentDataSet(); + if ( pDataSet ) + { + const ScProtectionAttr& rProtAttr = pDataSet->Get(ATTR_PROTECTION); + SfxItemState eState = pDataSet->GetItemState(ATTR_PROTECTION); + if(eState != SfxItemState::DONTCARE) + aBoolRet <<= rProtAttr.GetHideFormula(); + } + else + { + util::CellProtection aCellProtection; + mxPropertySet->getPropertyValue(sCellProt) >>= aCellProtection; + aBoolRet <<= aCellProtection.IsFormulaHidden; + } + } + } + catch (const uno::Exception&) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } + return aBoolRet; +} + +template< typename... Ifc > +void SAL_CALL +ScVbaFormat< Ifc... >::setShrinkToFit( const uno::Any& ShrinkToFit ) +{ + try + { + mxPropertySet->setPropertyValue( SC_UNONAME_SHRINK_TO_FIT, ShrinkToFit); + } + catch (const uno::Exception& ) + { + DebugHelper::basicexception(ERRCODE_BASIC_NOT_IMPLEMENTED, {} ); + } + +} + +template< typename... Ifc > +uno::Any SAL_CALL +ScVbaFormat< Ifc... >::getShrinkToFit( ) +{ + uno::Any aRet = aNULL(); + try + { + OUString sShrinkToFit( SC_UNONAME_SHRINK_TO_FIT ); + if (!isAmbiguous(sShrinkToFit)) + aRet = mxPropertySet->getPropertyValue(sShrinkToFit); + } + catch (const uno::Exception& ) + { + DebugHelper::basicexception(ERRCODE_BASIC_NOT_IMPLEMENTED, {}); + } + return aRet; +} + +template< typename... Ifc > +void SAL_CALL +ScVbaFormat< Ifc... >::setReadingOrder( const uno::Any& ReadingOrder ) +{ + try + { + sal_Int32 nReadingOrder = 0; + if ( !(ReadingOrder >>= nReadingOrder )) + throw uno::RuntimeException(); + uno::Any aVal = aNULL(); + switch(nReadingOrder) + { + case excel::Constants::xlLTR: + aVal <<= sal_Int16(text::WritingMode_LR_TB); + break; + case excel::Constants::xlRTL: + aVal <<= sal_Int16(text::WritingMode_RL_TB); + break; + case excel::Constants::xlContext: + // TODO implement xlContext + // Reading order has to depend on the language of the first letter + // written. + aVal <<= sal_Int16(text::WritingMode_LR_TB); + break; + default: + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } + mxPropertySet->setPropertyValue( SC_UNONAME_WRITING, aVal ); + } + catch (const uno::Exception& ) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } + +} + +template< typename... Ifc > +uno::Any SAL_CALL +ScVbaFormat< Ifc... >::getReadingOrder( ) +{ + uno::Any NRetReadingOrder = aNULL(); + try + { + OUString sWritingMode( SC_UNONAME_WRITING ); + if (!isAmbiguous(sWritingMode)) + { + text::WritingMode aWritingMode = text::WritingMode_LR_TB; + if ( ( mxPropertySet->getPropertyValue(sWritingMode) ) >>= aWritingMode ) + switch (aWritingMode) + { + case text::WritingMode_LR_TB: + NRetReadingOrder <<= excel::Constants::xlLTR; + break; + case text::WritingMode_RL_TB: + NRetReadingOrder <<= excel::Constants::xlRTL; + break; + default: + NRetReadingOrder <<= excel::Constants::xlRTL; + } + } + } + catch (const uno::Exception& ) + { + DebugHelper::basicexception(ERRCODE_BASIC_NOT_IMPLEMENTED, {}); + } + return NRetReadingOrder; + +} + +template< typename... Ifc > +uno::Any SAL_CALL +ScVbaFormat< Ifc... >::getNumberFormat( ) +{ + uno::Any aFormat = aNULL(); + try + { + sal_Int32 nFormat = -1; + OUString sNumFormat( SC_UNO_DP_NUMBERFO ); + if (!isAmbiguous(sNumFormat) && + ( mxPropertySet->getPropertyValue(sNumFormat) >>= nFormat) ) + { + initializeNumberFormats(); + + sal_Int32 nNewFormat = xNumberFormatTypes->getFormatForLocale(nFormat, m_aDefaultLocale ); + OUString sFormat; + xNumberFormats->getByKey(nNewFormat)->getPropertyValue( FORMATSTRING ) >>= sFormat; + aFormat <<= sFormat; + } + } + catch (const uno::Exception& ) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } + return aFormat; +} + +template< typename... Ifc > +bool +ScVbaFormat< Ifc... >::isAmbiguous(const OUString& _sPropertyName) +{ + bool bResult = false; + try + { + if (mbCheckAmbiguoity) + bResult = ( getXPropertyState()->getPropertyState(_sPropertyName) == beans::PropertyState_AMBIGUOUS_VALUE ); + } + catch (const uno::Exception& ) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } + return bResult; +} + +template< typename... Ifc > +void +ScVbaFormat< Ifc... >::initializeNumberFormats() +{ + if ( !xNumberFormats.is() ) + { + mxNumberFormatsSupplier.set( mxModel, uno::UNO_QUERY_THROW ); + xNumberFormats = mxNumberFormatsSupplier->getNumberFormats(); + xNumberFormatTypes.set( xNumberFormats, uno::UNO_QUERY ); // _THROW? + } +} + +template< typename... Ifc > +uno::Reference< beans::XPropertyState > const & +ScVbaFormat< Ifc... >::getXPropertyState() +{ + if ( !xPropertyState.is() ) + xPropertyState.set( mxPropertySet, uno::UNO_QUERY_THROW ); + return xPropertyState; +} + +template< typename... Ifc > +ScCellRangesBase* +ScVbaFormat< Ifc... >::getCellRangesBase() +{ + return comphelper::getFromUnoTunnel<ScCellRangesBase>( mxPropertySet ); +} + +template< typename... Ifc > +SfxItemSet* +ScVbaFormat< Ifc... >::getCurrentDataSet() +{ + SfxItemSet* pDataSet = excel::ScVbaCellRangeAccess::GetDataSet( getCellRangesBase() ); + if ( !pDataSet ) + throw uno::RuntimeException("Can't access Itemset for XPropertySet" ); + return pDataSet; +} + +template class ScVbaFormat< excel::XStyle >; +template class ScVbaFormat< excel::XRange >; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaformat.hxx b/sc/source/ui/vba/vbaformat.hxx new file mode 100644 index 000000000..f3c6750ce --- /dev/null +++ b/sc/source/ui/vba/vbaformat.hxx @@ -0,0 +1,154 @@ +/* -*- 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 . + */ +#pragma once + +#include <com/sun/star/lang/Locale.hpp> +#include <vbahelper/vbahelperinterface.hxx> + +namespace com::sun::star::beans { class XPropertySet; } +namespace com::sun::star::beans { class XPropertyState; } +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::util { class XNumberFormats; } +namespace com::sun::star::util { class XNumberFormatsSupplier; } +namespace com::sun::star::util { class XNumberFormatTypes; } +namespace ooo::vba::excel { class XFont; } +namespace ooo::vba::excel { class XInterior; } + +class ScCellRangesBase; +class SfxItemSet; + +template< typename... Ifc > +class ScVbaFormat : public InheritedHelperInterfaceWeakImpl< Ifc... > +{ +typedef InheritedHelperInterfaceWeakImpl< Ifc... > ScVbaFormat_BASE; + css::lang::Locale m_aDefaultLocale; +protected: + css::uno::Reference< css::beans::XPropertySet > mxPropertySet; + css::uno::Reference< css::util::XNumberFormatsSupplier > mxNumberFormatsSupplier; + css::uno::Reference< css::util::XNumberFormats > xNumberFormats; + css::uno::Reference< css::util::XNumberFormatTypes > xNumberFormatTypes; + css::uno::Reference< css::frame::XModel > mxModel; + css::uno::Reference< css::beans::XPropertyState > xPropertyState; + bool mbCheckAmbiguoity; + bool mbAddIndent; + /// @throws css::script::BasicErrorException + bool isAmbiguous(const OUString& _sPropertyName); + /// @throws css::uno::RuntimeException + css::uno::Reference< css::beans::XPropertyState > const & getXPropertyState(); + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + void initializeNumberFormats(); + /// @throws css::uno::RuntimeException + SfxItemSet* getCurrentDataSet( ); +protected: + /// @throws css::uno::RuntimeException + virtual ScCellRangesBase* getCellRangesBase(); +public: + /// @throws css::script::BasicErrorException + ScVbaFormat( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::beans::XPropertySet >& _xPropertySet, const css::uno::Reference< css::frame::XModel >& xModel, bool bCheckAmbiguoity ); + virtual css::uno::Reference< ov::XHelperInterface > thisHelperIface() = 0; + /// @throws css::uno::RuntimeException + void SAL_CALL setAddIndent( const css::uno::Any& BAddIndent) { BAddIndent >>= mbAddIndent; } + /// @throws css::uno::RuntimeException + css::uno::Any SAL_CALL getAddIndent() { return css::uno::Any( mbAddIndent ); } + // Interface Methods + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + virtual css::uno::Any SAL_CALL Borders( const css::uno::Any& Index ); + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + virtual css::uno::Reference< ::ooo::vba::excel::XFont > SAL_CALL Font( ); + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + virtual css::uno::Reference< ::ooo::vba::excel::XInterior > SAL_CALL Interior( ); + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + virtual void SAL_CALL setNumberFormat( const css::uno::Any& NumberFormat ); + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + virtual css::uno::Any SAL_CALL getNumberFormat( ); + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + virtual void SAL_CALL setNumberFormatLocal( const css::uno::Any& NumberFormatLocal ); + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + virtual css::uno::Any SAL_CALL getNumberFormatLocal( ); + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + virtual void SAL_CALL setIndentLevel( const css::uno::Any& IndentLevel ); + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + virtual css::uno::Any SAL_CALL getIndentLevel( ); + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + virtual void SAL_CALL setHorizontalAlignment( const css::uno::Any& HorizontalAlignment ); + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + virtual css::uno::Any SAL_CALL getHorizontalAlignment( ); + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + virtual void SAL_CALL setVerticalAlignment( const css::uno::Any& VerticalAlignment ); + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + virtual css::uno::Any SAL_CALL getVerticalAlignment( ); + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + virtual void SAL_CALL setOrientation( const css::uno::Any& Orientation ); + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + virtual css::uno::Any SAL_CALL getOrientation( ); + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + virtual void SAL_CALL setShrinkToFit( const css::uno::Any& ShrinkToFit ); + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + virtual css::uno::Any SAL_CALL getShrinkToFit( ); + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + virtual void SAL_CALL setWrapText( const css::uno::Any& WrapText ); + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + virtual css::uno::Any SAL_CALL getWrapText( ); + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + virtual void SAL_CALL setLocked( const css::uno::Any& Locked ); + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + virtual css::uno::Any SAL_CALL getLocked( ); + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + virtual void SAL_CALL setFormulaHidden( const css::uno::Any& FormulaHidden ); + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + virtual css::uno::Any SAL_CALL getFormulaHidden( ); + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + virtual void SAL_CALL setMergeCells( const css::uno::Any& MergeCells ) = 0; + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + virtual css::uno::Any SAL_CALL getMergeCells( ) = 0; + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + virtual void SAL_CALL setReadingOrder( const css::uno::Any& ReadingOrder ); + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + virtual css::uno::Any SAL_CALL getReadingOrder( ); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaformatcondition.cxx b/sc/source/ui/vba/vbaformatcondition.cxx new file mode 100644 index 000000000..d9804399c --- /dev/null +++ b/sc/source/ui/vba/vbaformatcondition.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 "vbaformatcondition.hxx" +#include "vbaformatconditions.hxx" +#include <unonames.hxx> +#include <ooo/vba/excel/XlFormatConditionType.hpp> +#include <basic/sberrors.hxx> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +/// @throws css::script::BasicErrorException +static ScVbaFormatConditions* +lcl_getScVbaFormatConditionsPtr( const uno::Reference< excel::XFormatConditions >& xFormatConditions ) +{ + ScVbaFormatConditions* pFormatConditions = static_cast< ScVbaFormatConditions* >( xFormatConditions.get() ); + if ( !pFormatConditions ) + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} ); + return pFormatConditions; +} + +ScVbaFormatCondition::ScVbaFormatCondition( const uno::Reference< XHelperInterface >& xParent, + const uno::Reference< uno::XComponentContext > & xContext, + const uno::Reference< sheet::XSheetConditionalEntry >& _xSheetConditionalEntry, + const uno::Reference< excel::XStyle >& _xStyle, + const uno::Reference< excel::XFormatConditions >& _xFormatConditions, + const uno::Reference< css::beans::XPropertySet >& _xPropertySet ) + : ScVbaFormatCondition_BASE( xParent, xContext, + uno::Reference< sheet::XSheetCondition >( _xSheetConditionalEntry, css::uno::UNO_QUERY_THROW ) ), + moFormatConditions( _xFormatConditions ), mxStyle( _xStyle ), mxParentRangePropertySet( _xPropertySet ) +{ + mxSheetConditionalEntries = lcl_getScVbaFormatConditionsPtr( moFormatConditions )->getSheetConditionalEntries(); + + msStyleName = mxStyle->getName(); +} + +void SAL_CALL +ScVbaFormatCondition::Delete( ) +{ + ScVbaFormatConditions* pFormatConditions = lcl_getScVbaFormatConditionsPtr( moFormatConditions ); + pFormatConditions->removeFormatCondition(msStyleName, true); + notifyRange(); +} + +void SAL_CALL +ScVbaFormatCondition::Modify( ::sal_Int32 _nType, const uno::Any& _aOperator, const uno::Any& _aFormula1, const uno::Any& _aFormula2 ) +{ + try + { + ScVbaFormatConditions* pFormatConditions = lcl_getScVbaFormatConditionsPtr( moFormatConditions ); + pFormatConditions->removeFormatCondition(msStyleName, false); + pFormatConditions->Add(_nType, _aOperator, _aFormula1, _aFormula2, mxStyle); + } + catch (const uno::Exception&) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} ); + } +} + +uno::Reference< excel::XInterior > SAL_CALL +ScVbaFormatCondition::Interior( ) +{ + return mxStyle->Interior(); +} + +uno::Reference< excel::XFont > SAL_CALL +ScVbaFormatCondition::Font( ) +{ + return mxStyle->Font(); +} +uno::Any SAL_CALL +ScVbaFormatCondition::Borders( const uno::Any& Index ) +{ return mxStyle->Borders( Index ); +} + +sheet::ConditionOperator +ScVbaFormatCondition::retrieveAPIType(sal_Int32 _nVBAType, const uno::Reference< sheet::XSheetCondition >& _xSheetCondition ) +{ + sheet::ConditionOperator aAPIType = sheet::ConditionOperator_NONE; + switch (_nVBAType) + { + case excel::XlFormatConditionType::xlExpression: + aAPIType = sheet::ConditionOperator_FORMULA; + break; + case excel::XlFormatConditionType::xlCellValue: + if ( _xSheetCondition.is() && (_xSheetCondition->getOperator() == sheet::ConditionOperator_FORMULA ) ) + aAPIType = sheet::ConditionOperator_NONE; + break; + default: + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} ); + } + return aAPIType; +} + +::sal_Int32 SAL_CALL +ScVbaFormatCondition::Type( ) +{ + sal_Int32 nReturnType = 0; + if ( mxSheetCondition->getOperator() == sheet::ConditionOperator_FORMULA) + nReturnType = excel::XlFormatConditionType::xlExpression; + else + nReturnType = excel::XlFormatConditionType::xlCellValue; + return nReturnType; +} + +::sal_Int32 SAL_CALL +ScVbaFormatCondition::Operator( ) +{ + return ScVbaFormatCondition_BASE::Operator( true ); +} + +void +ScVbaFormatCondition::notifyRange() +{ + try + { + mxParentRangePropertySet->setPropertyValue(SC_UNONAME_CONDFMT, uno::Any( mxSheetConditionalEntries)); + } + catch (uno::Exception& ) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} ); + } +} + +OUString +ScVbaFormatCondition::getServiceImplName() +{ + return "ScVbaFormatCondition"; +} + +uno::Sequence< OUString > +ScVbaFormatCondition::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.FormatCondition" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaformatcondition.hxx b/sc/source/ui/vba/vbaformatcondition.hxx new file mode 100644 index 000000000..7d09a11b9 --- /dev/null +++ b/sc/source/ui/vba/vbaformatcondition.hxx @@ -0,0 +1,67 @@ +/* -*- 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 . + */ +#pragma once +#include <ooo/vba/excel/XFormatCondition.hpp> +#include <ooo/vba/excel/XFormatConditions.hpp> +#include <ooo/vba/excel/XStyle.hpp> +#include <com/sun/star/sheet/XSheetConditionalEntries.hpp> +#include <com/sun/star/sheet/XSheetConditionalEntry.hpp> +#include <com/sun/star/sheet/XSheetCondition.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include "vbacondition.hxx" + +typedef ScVbaCondition< ov::excel::XFormatCondition > ScVbaFormatCondition_BASE; +class ScVbaFormatCondition final : public ScVbaFormatCondition_BASE +{ + OUString msStyleName; + css::uno::Reference< css::sheet::XSheetConditionalEntries > mxSheetConditionalEntries; + css::uno::Reference< ov::excel::XFormatConditions> moFormatConditions; + css::uno::Reference< ov::excel::XStyle > mxStyle; + css::uno::Reference< css::beans::XPropertySet > mxParentRangePropertySet; + +public: + /// @throws css::uno::RuntimeException + /// @throws css::script::BasicErrorException + ScVbaFormatCondition( const css::uno::Reference< ov::XHelperInterface >& xParent, + const css::uno::Reference< css::uno::XComponentContext > & xContext, + const css::uno::Reference< css::sheet::XSheetConditionalEntry >& _xSheetConditionalEntry, + const css::uno::Reference< ov::excel::XStyle >&, + const css::uno::Reference< ov::excel::XFormatConditions >& _xFormatConditions, + const css::uno::Reference< css::beans::XPropertySet >& _xPropertySet ); + + /// @throws css::script::BasicErrorException + void notifyRange(); + /// @throws css::script::BasicErrorException + static css::sheet::ConditionOperator retrieveAPIType(sal_Int32 _nVBAType, const css::uno::Reference< css::sheet::XSheetCondition >& _xSheetCondition ); + + //Methods + virtual void SAL_CALL Delete( ) override; + virtual void SAL_CALL Modify( ::sal_Int32 Type, const css::uno::Any& Operator, const css::uno::Any& Formula1, const css::uno::Any& Formula2 ) override; + virtual ::sal_Int32 SAL_CALL Type( ) override; + using ScVbaFormatCondition_BASE::Operator; + virtual ::sal_Int32 SAL_CALL Operator( ) override; + virtual css::uno::Reference< ::ooo::vba::excel::XInterior > SAL_CALL Interior( ) override; + virtual css::uno::Any SAL_CALL Borders( const css::uno::Any& Index ) override; + virtual css::uno::Reference< ::ooo::vba::excel::XFont > SAL_CALL Font( ) override; + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaformatconditions.cxx b/sc/source/ui/vba/vbaformatconditions.cxx new file mode 100644 index 000000000..bbf167b3c --- /dev/null +++ b/sc/source/ui/vba/vbaformatconditions.cxx @@ -0,0 +1,289 @@ +/* -*- 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 <ooo/vba/excel/XRange.hpp> +#include <com/sun/star/sheet/XSheetConditionalEntry.hpp> +#include <basic/sberrors.hxx> +#include <comphelper/sequence.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <vector> +#include <unonames.hxx> +#include "vbaformatconditions.hxx" +#include "vbaformatcondition.hxx" +#include "vbastyles.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +void SAL_CALL +ScVbaFormatConditions::Delete( ) +{ + try + { + ScVbaStyles* pStyles = static_cast< ScVbaStyles* >( mxStyles.get() ); + if ( !pStyles ) + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} ); + sal_Int32 nCount = mxSheetConditionalEntries->getCount(); + for (sal_Int32 i = nCount - 1; i >= 0; i--) + { + uno::Reference< sheet::XSheetConditionalEntry > xSheetConditionalEntry( mxSheetConditionalEntries->getByIndex(i), uno::UNO_QUERY_THROW ); + pStyles->Delete(xSheetConditionalEntry->getStyleName()); + mxSheetConditionalEntries->removeByIndex(i); + } + notifyRange(); + } + catch (uno::Exception& ) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } +} + +uno::Type SAL_CALL +ScVbaFormatConditions::getElementType() +{ + return cppu::UnoType<excel::XFormatCondition>::get(); +} + +static uno::Any xSheetConditionToFormatCondition( const uno::Reference< XHelperInterface >& xRangeParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< excel::XStyles >& xStyles, const uno::Reference< excel::XFormatConditions >& xFormatConditions, const uno::Reference< beans::XPropertySet >& xRangeProps, const uno::Any& aObject ) +{ + uno::Reference< sheet::XSheetConditionalEntry > xSheetConditionalEntry; + aObject >>= xSheetConditionalEntry; + + uno::Reference< excel::XStyle > xStyle( xStyles->Item( uno::Any( xSheetConditionalEntry->getStyleName() ), uno::Any() ), uno::UNO_QUERY_THROW ); + uno::Reference< excel::XFormatCondition > xCondition = new ScVbaFormatCondition( xRangeParent, xContext, xSheetConditionalEntry, xStyle, xFormatConditions, xRangeProps ); + return uno::Any( xCondition ); +} + +uno::Any +ScVbaFormatConditions::createCollectionObject(const uno::Any& aObject ) +{ + return xSheetConditionToFormatCondition( uno::Reference< XHelperInterface >( mxRangeParent, uno::UNO_QUERY_THROW ), mxContext, mxStyles, this, mxParentRangePropertySet, aObject ); +} + +namespace { + +class EnumWrapper : public EnumerationHelper_BASE +{ + uno::Reference<container::XIndexAccess > m_xIndexAccess; + uno::Reference<excel::XRange > m_xParentRange; + uno::Reference<uno::XComponentContext > m_xContext; + uno::Reference<excel::XStyles > m_xStyles; + uno::Reference<excel::XFormatConditions > m_xParentCollection; + uno::Reference<beans::XPropertySet > m_xProps; + + sal_Int32 nIndex; +public: + EnumWrapper( const uno::Reference< container::XIndexAccess >& xIndexAccess, const uno::Reference<excel::XRange >& xRange, const uno::Reference<uno::XComponentContext >& xContext, const uno::Reference<excel::XStyles >& xStyles, const uno::Reference< excel::XFormatConditions >& xCollection, const uno::Reference<beans::XPropertySet >& xProps ) : m_xIndexAccess( xIndexAccess ), m_xParentRange( xRange ), m_xContext( xContext ), m_xStyles( xStyles ), m_xParentCollection( xCollection ), m_xProps( xProps ), nIndex( 0 ) {} + virtual sal_Bool SAL_CALL hasMoreElements( ) override + { + return ( nIndex < m_xIndexAccess->getCount() ); + } + + virtual uno::Any SAL_CALL nextElement( ) override + { + try + { + if ( nIndex < m_xIndexAccess->getCount() ) + return xSheetConditionToFormatCondition( uno::Reference< XHelperInterface >( m_xParentRange, uno::UNO_QUERY_THROW ), m_xContext, m_xStyles, m_xParentCollection, m_xProps, m_xIndexAccess->getByIndex( nIndex++ ) ); + } + catch (const container::NoSuchElementException&) + { + throw; + } + catch (const lang::WrappedTargetException&) + { + throw; + } + catch (const uno::RuntimeException&) + { + throw; + } + catch (const uno::Exception& e) + { + css::uno::Any a(cppu::getCaughtException()); + throw css::lang::WrappedTargetException( + "wrapped Exception " + e.Message, + css::uno::Reference<css::uno::XInterface>(), a); + } + throw container::NoSuchElementException(); + } +}; + +} + +uno::Reference< excel::XFormatCondition > SAL_CALL +ScVbaFormatConditions::Add( ::sal_Int32 _nType, const uno::Any& _aOperator, const uno::Any& _aFormula1, const uno::Any& _aFormula2 ) +{ + return Add( _nType, _aOperator, _aFormula1, _aFormula2, uno::Reference< excel::XStyle >() ); +} + +uno::Reference< excel::XFormatCondition > +ScVbaFormatConditions::Add( ::sal_Int32 _nType, const uno::Any& _aOperator, const uno::Any& _aFormula1, const uno::Any& _aFormula2, const css::uno::Reference< excel::XStyle >& _xStyle ) +{ + // #TODO + // #FIXME + // This method will NOT handle r1c1 formulas [*]and only assumes that + // the formulas are _xlA1 based ( need to hook into calc work this should + // address this ) + // [*] reason: getA1Formula method below is just a hook and just + // returns what it gets ( e.g. doesn't convert anything ) + uno::Reference< excel::XStyle > xStyle( _xStyle ); + uno::Reference< excel::XFormatCondition > xFormatCondition; + try + { + OUString sStyleName; + if ( !xStyle.is() ) + { + sStyleName = getStyleName(); + xStyle = mxStyles->Add(sStyleName, uno::Any() ); + } + else + { + sStyleName = xStyle->getName(); + } + + std::vector< beans::PropertyValue > aPropertyValueVector; + sheet::ConditionOperator aType = ScVbaFormatCondition::retrieveAPIType(_nType, uno::Reference< sheet::XSheetCondition >() ); + uno::Any aValue; + + if ( aType == sheet::ConditionOperator_FORMULA) + aValue <<= sheet::ConditionOperator_FORMULA; + else + aValue <<= ScVbaFormatCondition::retrieveAPIOperator(_aOperator); + + beans::PropertyValue aProperty( "Operator", 0, aValue, beans::PropertyState_DIRECT_VALUE ); + aPropertyValueVector.push_back( aProperty ); + + if ( _aFormula1.hasValue() ) + { + beans::PropertyValue aProp( "Formula1", 0, uno::Any( getA1Formula( _aFormula1 ) ), beans::PropertyState_DIRECT_VALUE ); + aPropertyValueVector.push_back( aProp ); + } + if ( _aFormula2.hasValue() ) + { + beans::PropertyValue aProp( "Formula2", 0, uno::Any( getA1Formula( _aFormula2 ) ), beans::PropertyState_DIRECT_VALUE ); + aPropertyValueVector.push_back( aProp ); + } + aProperty.Name = "StyleName"; + aProperty.Value <<= sStyleName; + + mxSheetConditionalEntries->addNew(comphelper::containerToSequence(aPropertyValueVector)); + for (sal_Int32 i = mxSheetConditionalEntries->getCount()-1; i >= 0; i--) + { + uno::Reference< sheet::XSheetConditionalEntry > xSheetConditionalEntry( mxSheetConditionalEntries->getByIndex(i), uno::UNO_QUERY_THROW ); + if (xSheetConditionalEntry->getStyleName() == sStyleName) + { + xFormatCondition = new ScVbaFormatCondition(uno::Reference< XHelperInterface >( mxRangeParent, uno::UNO_QUERY_THROW ), mxContext, xSheetConditionalEntry, xStyle, this, mxParentRangePropertySet); + notifyRange(); + return xFormatCondition; + } + } + } + catch (uno::Exception& ) + { + } + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} ); + return xFormatCondition; +} + +uno::Reference< container::XEnumeration > SAL_CALL +ScVbaFormatConditions::createEnumeration() +{ + return new EnumWrapper( m_xIndexAccess, mxRangeParent, mxContext, mxStyles, this, mxParentRangePropertySet ); +} + +void +ScVbaFormatConditions::notifyRange() +{ + try + { + mxParentRangePropertySet->setPropertyValue(SC_UNONAME_CONDFMT, uno::Any( mxSheetConditionalEntries )); + } + catch (uno::Exception& ) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } +} + +OUString +ScVbaFormatConditions::getA1Formula(const css::uno::Any& _aFormula) +{ + // #TODO, #FIXME hook-in proper formula conversion detection & logic + OUString sFormula; + if ( !( _aFormula >>= sFormula ) ) + DebugHelper::basicexception(ERRCODE_BASIC_BAD_PARAMETER, {} ); + return sFormula; +} + +OUString +ScVbaFormatConditions::getStyleName() +{ + ScVbaStyles* pStyles = static_cast< ScVbaStyles* >( mxStyles.get() ); + if ( !pStyles ) + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} ); + uno::Sequence< OUString > sCellStyleNames = pStyles->getStyleNames(); + return ContainerUtilities::getUniqueName(sCellStyleNames, "Excel_CondFormat", u"_"); +} + +void +ScVbaFormatConditions::removeFormatCondition( const OUString& _sStyleName, bool _bRemoveStyle) +{ + try + { + sal_Int32 nElems = mxSheetConditionalEntries->getCount(); + for (sal_Int32 i = 0; i < nElems; i++) + { + uno::Reference< sheet::XSheetConditionalEntry > xSheetConditionalEntry( mxSheetConditionalEntries->getByIndex(i), uno::UNO_QUERY_THROW ); + if (_sStyleName == xSheetConditionalEntry->getStyleName()) + { + mxSheetConditionalEntries->removeByIndex(i); + if (_bRemoveStyle) + { + ScVbaStyles* pStyles = static_cast< ScVbaStyles* >( mxStyles.get() ); + if ( !pStyles ) + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + pStyles->Delete( _sStyleName ); + } + return; + } + } + } + catch (const uno::Exception&) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } +} + +OUString +ScVbaFormatConditions::getServiceImplName() +{ + return "ScVbaFormatConditions"; +} + +uno::Sequence< OUString > +ScVbaFormatConditions::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.FormatConditions" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaformatconditions.hxx b/sc/source/ui/vba/vbaformatconditions.hxx new file mode 100644 index 000000000..fd5a7fc83 --- /dev/null +++ b/sc/source/ui/vba/vbaformatconditions.hxx @@ -0,0 +1,66 @@ +/* -*- 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 . + */ + +#pragma once + +#include <ooo/vba/excel/XFormatConditions.hpp> +#include <vbahelper/vbacollectionimpl.hxx> + +namespace com::sun::star::beans { class XPropertySet; } +namespace com::sun::star::sheet { class XSheetConditionalEntries; } +namespace ooo::vba::excel { class XRange; } +namespace ooo::vba::excel { class XStyle; } +namespace ooo::vba::excel { class XStyles; } + +// This class is used only as a target for casting, it seems, +// and no objects of this type are created as such, I think. + +class ScVbaFormatConditions: public CollTestImplHelper< ov::excel::XFormatConditions > +{ + css::uno::Reference< css::sheet::XSheetConditionalEntries > mxSheetConditionalEntries; + css::uno::Reference< ov::excel::XStyles > mxStyles; + css::uno::Reference< ov::excel::XRange > mxRangeParent; + css::uno::Reference< css::beans::XPropertySet > mxParentRangePropertySet; +public: + /// @throws css::script::BasicErrorException + void notifyRange(); + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + css::uno::Reference< ov::excel::XFormatCondition > Add( ::sal_Int32 Type, const css::uno::Any& Operator, const css::uno::Any& Formula1, const css::uno::Any& Formula2, const css::uno::Reference< ov::excel::XStyle >& _xCalcStyle ); + /// @throws css::script::BasicErrorException + static OUString getA1Formula(const css::uno::Any& _aFormula); + OUString getStyleName(); + /// @throws css::script::BasicErrorException + void removeFormatCondition( const OUString& _sStyleName, bool _bRemoveStyle); + const css::uno::Reference< css::sheet::XSheetConditionalEntries >& getSheetConditionalEntries() const { return mxSheetConditionalEntries; } + // XFormatConditions + virtual void SAL_CALL Delete( ) override; + virtual css::uno::Reference< ov::excel::XFormatCondition > SAL_CALL Add( ::sal_Int32 Type, const css::uno::Any& Operator, const css::uno::Any& Formula1, const css::uno::Any& Formula2 ) override; + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + virtual css::uno::Any createCollectionObject(const css::uno::Any&) override; + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; + + ScVbaFormatConditions() = delete; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaglobals.cxx b/sc/source/ui/vba/vbaglobals.cxx new file mode 100644 index 000000000..734553d50 --- /dev/null +++ b/sc/source/ui/vba/vbaglobals.cxx @@ -0,0 +1,265 @@ +/* -*- 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 "vbaglobals.hxx" + +#include <com/sun/star/lang/XMultiComponentFactory.hpp> +#include <comphelper/sequence.hxx> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/frame/XModel.hpp> + +#include "vbaapplication.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::ooo::vba; + +// ScVbaGlobals + +//ScVbaGlobals::ScVbaGlobals( css::uno::Reference< css::uno::XComponentContext >const& rxContext, ) : ScVbaGlobals_BASE( uno::Reference< XHelperInterface >(), rxContext ) + +ScVbaGlobals::ScVbaGlobals( uno::Sequence< uno::Any > const& aArgs, uno::Reference< uno::XComponentContext >const& rxContext ) : ScVbaGlobals_BASE( uno::Reference< XHelperInterface >(), rxContext, "ExcelDocumentContext" ) +{ + uno::Sequence< beans::PropertyValue > aInitArgs( aArgs.hasElements() ? 2 : 1 ); + auto pInitArgs = aInitArgs.getArray(); + pInitArgs[ 0 ].Name = "Application"; + pInitArgs[ 0 ].Value <<= getApplication(); + if ( aArgs.hasElements() ) + { + pInitArgs[ 1 ].Name = "ExcelDocumentContext"; + pInitArgs[ 1 ].Value <<= getXSomethingFromArgs< frame::XModel >( aArgs, 0 ); + } + init( aInitArgs ); +} + +ScVbaGlobals::~ScVbaGlobals() +{ +} + +// XGlobals + +uno::Reference<excel::XApplication > const & +ScVbaGlobals::getApplication() +{ + if ( !mxApplication.is() ) + mxApplication.set( new ScVbaApplication( mxContext) ); + return mxApplication; +} + +uno::Reference<excel::XApplication > SAL_CALL +ScVbaGlobals::getExcel() +{ + return getApplication(); +} + +uno::Reference< excel::XWorkbook > SAL_CALL +ScVbaGlobals::getActiveWorkbook() +{ + uno::Reference< excel::XWorkbook > xWorkbook( getApplication()->getActiveWorkbook(), uno::UNO_SET_THROW); + return xWorkbook; +} + +uno::Reference< excel::XWindow > SAL_CALL +ScVbaGlobals::getActiveWindow() +{ + return getApplication()->getActiveWindow(); +} + +uno::Reference< excel::XWorksheet > SAL_CALL +ScVbaGlobals::getActiveSheet() +{ + return getApplication()->getActiveSheet(); +} + +uno::Any SAL_CALL +ScVbaGlobals::WorkBooks( const uno::Any& aIndex ) +{ + return getApplication()->Workbooks(aIndex); +} + +uno::Any SAL_CALL +ScVbaGlobals::WorkSheets(const uno::Any& aIndex) +{ + return getApplication()->Worksheets( aIndex ); +} +uno::Any SAL_CALL +ScVbaGlobals::Sheets( const uno::Any& aIndex ) +{ + return WorkSheets( aIndex ); +} + +uno::Any SAL_CALL +ScVbaGlobals::Range( const uno::Any& Cell1, const uno::Any& Cell2 ) +{ + return getApplication()->Range( Cell1, Cell2 ); +} + +uno::Any SAL_CALL +ScVbaGlobals::Names( const css::uno::Any& aIndex ) +{ + return getApplication()->Names( aIndex ); +} + +uno::Reference< excel::XRange > SAL_CALL +ScVbaGlobals::getActiveCell() +{ + return getApplication()->getActiveCell(); +} + +uno::Reference< XAssistant > SAL_CALL +ScVbaGlobals::getAssistant() +{ + return getApplication()->getAssistant(); +} + +uno::Any SAL_CALL +ScVbaGlobals::getSelection() +{ + return getApplication()->getSelection(); +} + +uno::Reference< excel::XWorkbook > SAL_CALL +ScVbaGlobals::getThisWorkbook() +{ + return getApplication()->getThisWorkbook(); +} +void SAL_CALL +ScVbaGlobals::Calculate() +{ + return getApplication()->Calculate(); +} + +uno::Reference< excel::XRange > SAL_CALL +ScVbaGlobals::Cells( const uno::Any& RowIndex, const uno::Any& ColumnIndex ) +{ + return getApplication()->getActiveSheet()->Cells( RowIndex, ColumnIndex ); +} +uno::Reference< excel::XRange > SAL_CALL +ScVbaGlobals::Columns( const uno::Any& aIndex ) +{ + return getApplication()->getActiveSheet()->Columns( aIndex ); +} + +uno::Any SAL_CALL +ScVbaGlobals::CommandBars( const uno::Any& aIndex ) +{ + uno::Reference< XApplicationBase > xBase( getApplication(), uno::UNO_QUERY_THROW ); + return xBase->CommandBars( aIndex ); +} + +css::uno::Reference< ov::excel::XRange > SAL_CALL +ScVbaGlobals::Union( const css::uno::Reference< ov::excel::XRange >& Arg1, const css::uno::Reference< ov::excel::XRange >& Arg2, const css::uno::Any& Arg3, const css::uno::Any& Arg4, const css::uno::Any& Arg5, const css::uno::Any& Arg6, const css::uno::Any& Arg7, const css::uno::Any& Arg8, const css::uno::Any& Arg9, const css::uno::Any& Arg10, const css::uno::Any& Arg11, const css::uno::Any& Arg12, const css::uno::Any& Arg13, const css::uno::Any& Arg14, const css::uno::Any& Arg15, const css::uno::Any& Arg16, const css::uno::Any& Arg17, const css::uno::Any& Arg18, const css::uno::Any& Arg19, const css::uno::Any& Arg20, const css::uno::Any& Arg21, const css::uno::Any& Arg22, const css::uno::Any& Arg23, const css::uno::Any& Arg24, const css::uno::Any& Arg25, const css::uno::Any& Arg26, const css::uno::Any& Arg27, const css::uno::Any& Arg28, const css::uno::Any& Arg29, const css::uno::Any& Arg30 ) +{ + return getApplication()->Union( Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9, Arg10, Arg11, Arg12, Arg13, Arg14, Arg15, Arg16, Arg17, Arg18, Arg19, Arg20, Arg21, Arg22, Arg23, Arg24, Arg25, Arg26, Arg27, Arg28, Arg29, Arg30 ); +} +css::uno::Reference< ov::excel::XRange > SAL_CALL +ScVbaGlobals::Intersect( const css::uno::Reference< ov::excel::XRange >& Arg1, const css::uno::Reference< ov::excel::XRange >& Arg2, const css::uno::Any& Arg3, const css::uno::Any& Arg4, const css::uno::Any& Arg5, const css::uno::Any& Arg6, const css::uno::Any& Arg7, const css::uno::Any& Arg8, const css::uno::Any& Arg9, const css::uno::Any& Arg10, const css::uno::Any& Arg11, const css::uno::Any& Arg12, const css::uno::Any& Arg13, const css::uno::Any& Arg14, const css::uno::Any& Arg15, const css::uno::Any& Arg16, const css::uno::Any& Arg17, const css::uno::Any& Arg18, const css::uno::Any& Arg19, const css::uno::Any& Arg20, const css::uno::Any& Arg21, const css::uno::Any& Arg22, const css::uno::Any& Arg23, const css::uno::Any& Arg24, const css::uno::Any& Arg25, const css::uno::Any& Arg26, const css::uno::Any& Arg27, const css::uno::Any& Arg28, const css::uno::Any& Arg29, const css::uno::Any& Arg30 ) +{ + return getApplication()->Intersect( Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9, Arg10, Arg11, Arg12, Arg13, Arg14, Arg15, Arg16, Arg17, Arg18, Arg19, Arg20, Arg21, Arg22, Arg23, Arg24, Arg25, Arg26, Arg27, Arg28, Arg29, Arg30 ); +} + +uno::Any SAL_CALL +ScVbaGlobals::Evaluate( const OUString& Name ) +{ + return getApplication()->Evaluate( Name ); +} + +css::uno::Any SAL_CALL +ScVbaGlobals::WorksheetFunction( ) +{ + return getApplication()->WorksheetFunction(); +} + +uno::Any SAL_CALL +ScVbaGlobals::Windows( const uno::Any& aIndex ) +{ + return getApplication()->Windows( aIndex ); +} + +uno::Reference< excel::XRange > SAL_CALL +ScVbaGlobals::Rows( const uno::Any& aIndex ) +{ + return getApplication()->getActiveSheet()->Rows( aIndex ); + +} + +uno::Any SAL_CALL +ScVbaGlobals::getDebug() +{ + try // return empty object on error + { + uno::Reference< lang::XMultiComponentFactory > xServiceManager( mxContext->getServiceManager(), uno::UNO_SET_THROW ); + uno::Reference< uno::XInterface > xVBADebug = xServiceManager->createInstanceWithContext( + "ooo.vba.Debug", mxContext ); + return uno::Any( xVBADebug ); + } + catch( uno::Exception& ) + { + } + return uno::Any(); +} + +uno::Any SAL_CALL +ScVbaGlobals::MenuBars( const uno::Any& aIndex ) +{ + return getApplication()->MenuBars(aIndex); +} + +uno::Sequence< OUString > SAL_CALL +ScVbaGlobals::getAvailableServiceNames( ) +{ + static const uno::Sequence< OUString > serviceNames = comphelper::concatSequences( + ScVbaGlobals_BASE::getAvailableServiceNames(), + uno::Sequence< OUString > + { + "ooo.vba.excel.Range", + "ooo.vba.excel.Workbook", + "ooo.vba.excel.Window", + "ooo.vba.excel.Worksheet", + "ooo.vba.excel.Application", + "ooo.vba.excel.Hyperlink", + "com.sun.star.script.vba.VBASpreadsheetEventProcessor" + } ); + return serviceNames; +} + +OUString +ScVbaGlobals::getServiceImplName() +{ + return "ScVbaGlobals"; +} + +uno::Sequence< OUString > +ScVbaGlobals::getServiceNames() +{ + static uno::Sequence< OUString > aServiceNames + { + "ooo.vba.excel.Globals" + }; + return aServiceNames; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +ScVbaGlobals_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &arguments) +{ + return cppu::acquire(new ScVbaGlobals(arguments, context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaglobals.hxx b/sc/source/ui/vba/vbaglobals.hxx new file mode 100644 index 000000000..6f978c591 --- /dev/null +++ b/sc/source/ui/vba/vbaglobals.hxx @@ -0,0 +1,82 @@ +/* -*- 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 SC_VBA_GLOBALS +#define SC_VBA_GLOBALS + +#include <ooo/vba/excel/XGlobals.hpp> + +#include <cppuhelper/implbase.hxx> + +#include <vbahelper/vbaglobalbase.hxx> + +namespace com::sun::star::uno { class XComponentContext; } +namespace ooo::vba::excel { class XApplication; } + + +typedef ::cppu::ImplInheritanceHelper< VbaGlobalsBase, ov::excel::XGlobals > ScVbaGlobals_BASE; + +class ScVbaGlobals : public ScVbaGlobals_BASE +{ + css::uno::Reference< ov::excel::XApplication > mxApplication; + /// @throws css::uno::RuntimeException + css::uno::Reference< ov::excel::XApplication > const & getApplication(); +public: + + ScVbaGlobals( css::uno::Sequence< css::uno::Any > const& aArgs, + css::uno::Reference< css::uno::XComponentContext >const& rxContext ); + virtual ~ScVbaGlobals() override; + + // XGlobals + virtual css::uno::Reference< ov::excel::XWorkbook > SAL_CALL getActiveWorkbook() override; + virtual css::uno::Reference< ov::excel::XWindow > SAL_CALL getActiveWindow() override; + virtual css::uno::Reference< ov::excel::XWorksheet > SAL_CALL getActiveSheet() override; + virtual css::uno::Reference< ov::XAssistant > SAL_CALL getAssistant() override; + virtual void SAL_CALL Calculate( ) override; + + virtual css::uno::Any SAL_CALL getSelection() override; + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL getActiveCell() override; + virtual css::uno::Reference< ov::excel::XWorkbook > SAL_CALL getThisWorkbook() override; + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Cells( const css::uno::Any& RowIndex, const css::uno::Any& ColumnIndex ) override; + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Columns( const css::uno::Any& aIndex ) override; + virtual css::uno::Any SAL_CALL CommandBars( const css::uno::Any& aIndex ) override; + virtual css::uno::Any SAL_CALL Evaluate( const OUString& Name ) override; + + virtual css::uno::Any SAL_CALL WorkSheets(const css::uno::Any& aIndex ) override; + virtual css::uno::Any SAL_CALL WorkBooks(const css::uno::Any& aIndex ) override; + virtual css::uno::Any SAL_CALL WorksheetFunction( ) override; + virtual css::uno::Any SAL_CALL Windows( const css::uno::Any& aIndex ) override; + virtual css::uno::Any SAL_CALL Sheets( const css::uno::Any& aIndex ) override; + virtual css::uno::Any SAL_CALL Range( const css::uno::Any& Cell1, const css::uno::Any& Cell2 ) override; + virtual css::uno::Reference< ::ooo::vba::excel::XRange > SAL_CALL Rows( const css::uno::Any& aIndex ) override; + virtual css::uno::Any SAL_CALL Names( const css::uno::Any& aIndex ) override; + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Intersect( const css::uno::Reference< ov::excel::XRange >& Arg1, const css::uno::Reference< ov::excel::XRange >& Arg2, const css::uno::Any& Arg3, const css::uno::Any& Arg4, const css::uno::Any& Arg5, const css::uno::Any& Arg6, const css::uno::Any& Arg7, const css::uno::Any& Arg8, const css::uno::Any& Arg9, const css::uno::Any& Arg10, const css::uno::Any& Arg11, const css::uno::Any& Arg12, const css::uno::Any& Arg13, const css::uno::Any& Arg14, const css::uno::Any& Arg15, const css::uno::Any& Arg16, const css::uno::Any& Arg17, const css::uno::Any& Arg18, const css::uno::Any& Arg19, const css::uno::Any& Arg20, const css::uno::Any& Arg21, const css::uno::Any& Arg22, const css::uno::Any& Arg23, const css::uno::Any& Arg24, const css::uno::Any& Arg25, const css::uno::Any& Arg26, const css::uno::Any& Arg27, const css::uno::Any& Arg28, const css::uno::Any& Arg29, const css::uno::Any& Arg30 ) override; + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Union( const css::uno::Reference< ov::excel::XRange >& Arg1, const css::uno::Reference< ov::excel::XRange >& Arg2, const css::uno::Any& Arg3, const css::uno::Any& Arg4, const css::uno::Any& Arg5, const css::uno::Any& Arg6, const css::uno::Any& Arg7, const css::uno::Any& Arg8, const css::uno::Any& Arg9, const css::uno::Any& Arg10, const css::uno::Any& Arg11, const css::uno::Any& Arg12, const css::uno::Any& Arg13, const css::uno::Any& Arg14, const css::uno::Any& Arg15, const css::uno::Any& Arg16, const css::uno::Any& Arg17, const css::uno::Any& Arg18, const css::uno::Any& Arg19, const css::uno::Any& Arg20, const css::uno::Any& Arg21, const css::uno::Any& Arg22, const css::uno::Any& Arg23, const css::uno::Any& Arg24, const css::uno::Any& Arg25, const css::uno::Any& Arg26, const css::uno::Any& Arg27, const css::uno::Any& Arg28, const css::uno::Any& Arg29, const css::uno::Any& Arg30 ) override; + virtual css::uno::Reference< ov::excel::XApplication > SAL_CALL getExcel() override; + virtual css::uno::Any SAL_CALL getDebug() override; + virtual css::uno::Any SAL_CALL MenuBars( const css::uno::Any& aIndex ) override; + + // XMultiServiceFactory + virtual css::uno::Sequence< OUString > SAL_CALL getAvailableServiceNames( ) override; + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +#endif +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbahyperlink.cxx b/sc/source/ui/vba/vbahyperlink.cxx new file mode 100644 index 000000000..2bd355421 --- /dev/null +++ b/sc/source/ui/vba/vbahyperlink.cxx @@ -0,0 +1,236 @@ +/* -*- 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 <sal/config.h> + +#include "vbahyperlink.hxx" +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/table/XCellRange.hpp> +#include <com/sun/star/text/XText.hpp> +#include <com/sun/star/text/XTextFieldsSupplier.hpp> +#include <ooo/vba/office/MsoHyperlinkType.hpp> +#include <ooo/vba/msforms/XShape.hpp> +#include "vbarange.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +ScVbaHyperlink::ScVbaHyperlink( const uno::Sequence< uno::Any >& rArgs, + const uno::Reference< uno::XComponentContext >& rxContext ) : + HyperlinkImpl_BASE( getXSomethingFromArgs< XHelperInterface >( rArgs, 0 ), rxContext ), + mxCell( getXSomethingFromArgs< table::XCell >( rArgs, 1, false ) ), + mnType( office::MsoHyperlinkType::msoHyperlinkRange ) +{ + uno::Reference< text::XTextFieldsSupplier > xTextFields( mxCell, uno::UNO_QUERY_THROW ); + uno::Reference< container::XIndexAccess > xIndex( xTextFields->getTextFields(), uno::UNO_QUERY_THROW ); + mxTextField.set( xIndex->getByIndex(0), uno::UNO_QUERY_THROW ); +} + +ScVbaHyperlink::ScVbaHyperlink( const uno::Reference< XHelperInterface >& rxAnchor, + const uno::Reference< uno::XComponentContext >& rxContext, + const uno::Any& rAddress, const uno::Any& rSubAddress, + const uno::Any& rScreenTip, const uno::Any& rTextToDisplay ) : + HyperlinkImpl_BASE( rxAnchor, rxContext ) // parent of Hyperlink is the anchor object +{ + // extract parameters, Address must not be empty + UrlComponents aUrlComp; + OUString aTextToDisplay; + if( !(rAddress >>= aUrlComp.first) || aUrlComp.first.isEmpty() ) + throw uno::RuntimeException("Cannot get address" ); + rSubAddress >>= aUrlComp.second; + rScreenTip >>= maScreenTip; + rTextToDisplay >>= aTextToDisplay; + + // get anchor range or anchor shape + uno::Reference< excel::XRange > xAnchorRange( rxAnchor, uno::UNO_QUERY ); + if( xAnchorRange.is() ) + { + mnType = office::MsoHyperlinkType::msoHyperlinkRange; + // only single ranges are allowed + uno::Reference< table::XCellRange > xUnoRange( ScVbaRange::getCellRange( xAnchorRange ), uno::UNO_QUERY_THROW ); + // insert the hyperlink into the top-left cell only + mxCell.set( xUnoRange->getCellByPosition( 0, 0 ), uno::UNO_SET_THROW ); + uno::Reference< text::XText > xText( mxCell, uno::UNO_QUERY_THROW ); + // use cell text or URL if no TextToDisplay has been passed + if( aTextToDisplay.isEmpty() ) + { + aTextToDisplay = xText->getString(); + if( aTextToDisplay.isEmpty() ) + { + OUStringBuffer aBuffer( aUrlComp.first ); + if( !aUrlComp.second.isEmpty() ) + aBuffer.append( " - " + aUrlComp.second ); + aTextToDisplay = aBuffer.makeStringAndClear(); + } + } + // create and initialize a new URL text field + uno::Reference< lang::XMultiServiceFactory > xFactory( ScVbaRange::getUnoModel( xAnchorRange ), uno::UNO_QUERY_THROW ); + uno::Reference< text::XTextContent > xUrlField( xFactory->createInstance("com.sun.star.text.TextField.URL"), uno::UNO_QUERY_THROW ); + mxTextField.set( xUrlField, uno::UNO_QUERY_THROW ); + setUrlComponents( aUrlComp ); + setTextToDisplay( aTextToDisplay ); + // insert the text field into the document + xText->setString( OUString() ); + uno::Reference< text::XTextRange > xRange( xText->createTextCursor(), uno::UNO_QUERY_THROW ); + xText->insertTextContent( xRange, xUrlField, false ); + } + else + { + uno::Reference< msforms::XShape > xAnchorShape( rxAnchor, uno::UNO_QUERY_THROW ); + mnType = office::MsoHyperlinkType::msoHyperlinkShape; + // FIXME: insert hyperlink into shape + throw uno::RuntimeException(); + } +} + +ScVbaHyperlink::~ScVbaHyperlink() +{ +} + +OUString ScVbaHyperlink::getName() +{ + // it seems this attribute is same as TextToDisplay + return getTextToDisplay(); +} + +void ScVbaHyperlink::setName( const OUString& rName ) +{ + setTextToDisplay( rName ); +} + +OUString ScVbaHyperlink::getAddress() +{ + return getUrlComponents().first; +} + +void ScVbaHyperlink::setAddress( const OUString& rAddress ) +{ + UrlComponents aUrlComp = getUrlComponents(); + aUrlComp.first = rAddress; + setUrlComponents( aUrlComp ); +} + +OUString ScVbaHyperlink::getSubAddress() +{ + return getUrlComponents().second; +} + +void ScVbaHyperlink::setSubAddress( const OUString& rSubAddress ) +{ + UrlComponents aUrlComp = getUrlComponents(); + aUrlComp.second = rSubAddress; + setUrlComponents( aUrlComp ); +} + +OUString SAL_CALL ScVbaHyperlink::getScreenTip() +{ + return maScreenTip; +} + +void SAL_CALL ScVbaHyperlink::setScreenTip( const OUString& rScreenTip ) +{ + maScreenTip = rScreenTip; +} + +OUString ScVbaHyperlink::getTextToDisplay() +{ + ensureTextField(); + OUString aTextToDisplay; + mxTextField->getPropertyValue("Representation") >>= aTextToDisplay; + return aTextToDisplay; +} + +void ScVbaHyperlink::setTextToDisplay( const OUString& rTextToDisplay ) +{ + ensureTextField(); + mxTextField->setPropertyValue("Representation", uno::Any( rTextToDisplay ) ); +} + +sal_Int32 SAL_CALL ScVbaHyperlink::getType() +{ + return mnType; +} + +uno::Reference< excel::XRange > SAL_CALL ScVbaHyperlink::getRange() +{ + if( mnType == office::MsoHyperlinkType::msoHyperlinkRange ) + { + // if constructed from Hyperlinks object, range has been passed as parent + uno::Reference< excel::XRange > xAnchorRange( getParent(), uno::UNO_QUERY ); + if( !xAnchorRange.is() ) + { + // if constructed via service c'tor, create new range based on cell + uno::Reference< table::XCellRange > xRange( mxCell, uno::UNO_QUERY_THROW ); + // FIXME: need to pass current worksheet as the parent of XRange. + xAnchorRange.set( new ScVbaRange( uno::Reference< XHelperInterface >(), mxContext, xRange ) ); + } + return xAnchorRange; + } + // error if called at a shape Hyperlink object + throw uno::RuntimeException(); +} + +uno::Reference< msforms::XShape > SAL_CALL ScVbaHyperlink::getShape() +{ + // error if called at a range Hyperlink object + return uno::Reference< msforms::XShape >( getParent(), uno::UNO_QUERY_THROW ); +} + +VBAHELPER_IMPL_XHELPERINTERFACE( ScVbaHyperlink, "ooo.vba.excel.Hyperlink" ) + +// private -------------------------------------------------------------------- + +void ScVbaHyperlink::ensureTextField() +{ + if( !mxTextField.is() ) + throw uno::RuntimeException(); +} + +ScVbaHyperlink::UrlComponents ScVbaHyperlink::getUrlComponents() +{ + ensureTextField(); + OUString aUrl; + mxTextField->getPropertyValue("URL") >>= aUrl; + sal_Int32 nHashPos = aUrl.indexOf( '#' ); + if( nHashPos < 0 ) + return UrlComponents( aUrl, OUString() ); + return UrlComponents( aUrl.copy( 0, nHashPos ), aUrl.copy( nHashPos + 1 ) ); +} + +void ScVbaHyperlink::setUrlComponents( const UrlComponents& rUrlComp ) +{ + ensureTextField(); + OUStringBuffer aUrl( rUrlComp.first ); + if( !rUrlComp.second.isEmpty() ) + aUrl.append( '#' ).append( rUrlComp.second ); + mxTextField->setPropertyValue("URL", uno::Any( aUrl.makeStringAndClear() ) ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +Calc_ScVbaHyperlink_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& args) +{ + return cppu::acquire(new ScVbaHyperlink(args, context)); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbahyperlink.hxx b/sc/source/ui/vba/vbahyperlink.hxx new file mode 100644 index 000000000..391853be7 --- /dev/null +++ b/sc/source/ui/vba/vbahyperlink.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 . + */ + +#pragma once + +#include <ooo/vba/excel/XHyperlink.hpp> + +#include <vbahelper/vbahelperinterface.hxx> +#include <tools/long.hxx> + +namespace ooo::vba::excel { class XRange; } +namespace com::sun::star::beans { class XPropertySet; } +namespace com::sun::star::table { class XCell; } + +typedef InheritedHelperInterfaceWeakImpl< ov::excel::XHyperlink > HyperlinkImpl_BASE; + +class ScVbaHyperlink : public HyperlinkImpl_BASE +{ +public: + /// @throws css::lang::IllegalArgumentException + /// @throws css::uno::RuntimeException + ScVbaHyperlink( + const css::uno::Sequence< css::uno::Any >& rArgs, + const css::uno::Reference< css::uno::XComponentContext >& rxContext ); + + /// @throws css::uno::RuntimeException + ScVbaHyperlink( + const css::uno::Reference< ov::XHelperInterface >& rxAnchor, + const css::uno::Reference< css::uno::XComponentContext >& rxContext, + const css::uno::Any& rAddress, const css::uno::Any& rSubAddress, + const css::uno::Any& rScreenTip, const css::uno::Any& rTextToDisplay ); + + virtual ~ScVbaHyperlink() override; + + // Attributes + virtual OUString SAL_CALL getName() override; + virtual void SAL_CALL setName( const OUString& rName ) override; + virtual OUString SAL_CALL getAddress() override; + virtual void SAL_CALL setAddress( const OUString& rAddress ) override; + virtual OUString SAL_CALL getSubAddress() override; + virtual void SAL_CALL setSubAddress( const OUString& rSubAddress ) override; + virtual OUString SAL_CALL getScreenTip() override; + virtual void SAL_CALL setScreenTip( const OUString& rScreenTip ) override; + virtual OUString SAL_CALL getTextToDisplay() override; + virtual void SAL_CALL setTextToDisplay( const OUString& rTextToDisplay ) override; + virtual sal_Int32 SAL_CALL getType() override; + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL getRange() override; + virtual css::uno::Reference< ov::msforms::XShape > SAL_CALL getShape() override; + + // XHelperInterface + VBAHELPER_DECL_XHELPERINTERFACE + +private: + typedef ::std::pair< OUString, OUString > UrlComponents; + + /// @throws css::uno::RuntimeException + void ensureTextField(); + /// @throws css::uno::RuntimeException + UrlComponents getUrlComponents(); + /// @throws css::uno::RuntimeException + void setUrlComponents( const UrlComponents& rUrlComp ); + +private: + css::uno::Reference< css::table::XCell > mxCell; + css::uno::Reference< css::beans::XPropertySet > mxTextField; + OUString maScreenTip; + tools::Long mnType; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbahyperlinks.cxx b/sc/source/ui/vba/vbahyperlinks.cxx new file mode 100644 index 000000000..d309f5f44 --- /dev/null +++ b/sc/source/ui/vba/vbahyperlinks.cxx @@ -0,0 +1,277 @@ +/* -*- 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 "vbahyperlinks.hxx" +#include <algorithm> +#include <vector> +#include <cppuhelper/implbase.hxx> +#include <ooo/vba/office/MsoHyperlinkType.hpp> +#include <rangelst.hxx> +#include "vbahyperlink.hxx" +#include "vbarange.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +namespace { + +/** Returns true, if every range of rxInner is contained in any range of rScOuter. + + @throws css::uno::RuntimeException +*/ +bool lclContains( const ScRangeList& rScOuter, const uno::Reference< excel::XRange >& rxInner ) +{ + const ScRangeList& rScInner = ScVbaRange::getScRangeList( rxInner ); + if( rScInner.empty() || rScOuter.empty() ) + throw uno::RuntimeException("Empty range objects" ); + + for( size_t nIndex = 0, nCount = rScInner.size(); nIndex < nCount; ++nIndex ) + if( !rScOuter.Contains( rScInner[ nIndex ] ) ) + return false; + return true; +} + +/** Functor to decide whether the anchors of two Hyperlink objects are equal. */ +struct EqualAnchorFunctor +{ + uno::Reference< excel::XRange > mxAnchorRange; + uno::Reference< msforms::XShape > mxAnchorShape; + sal_Int32 mnType; + /// @throws uno::RuntimeException + explicit EqualAnchorFunctor( const uno::Reference< excel::XHyperlink >& rxHlink ); + /// @throws uno::RuntimeException + bool operator()( const uno::Reference< excel::XHyperlink >& rxHlink ) const; +}; + +EqualAnchorFunctor::EqualAnchorFunctor( const uno::Reference< excel::XHyperlink >& rxHlink ) : + mnType( rxHlink->getType() ) +{ + switch( mnType ) + { + case office::MsoHyperlinkType::msoHyperlinkRange: + mxAnchorRange.set( rxHlink->getRange(), uno::UNO_SET_THROW ); + break; + case office::MsoHyperlinkType::msoHyperlinkShape: + case office::MsoHyperlinkType::msoHyperlinkInlineShape: + mxAnchorShape.set( rxHlink->getShape(), uno::UNO_SET_THROW ); + break; + default: + throw uno::RuntimeException(); + } +} + +bool EqualAnchorFunctor::operator()( const uno::Reference< excel::XHyperlink >& rxHlink ) const +{ + sal_Int32 nType = rxHlink->getType(); + if( nType != mnType ) + return false; + + switch( nType ) + { + case office::MsoHyperlinkType::msoHyperlinkRange: + { + uno::Reference< excel::XRange > xAnchorRange( rxHlink->getRange(), uno::UNO_SET_THROW ); + const ScRangeList& rScRanges1 = ScVbaRange::getScRangeList( xAnchorRange ); + const ScRangeList& rScRanges2 = ScVbaRange::getScRangeList( mxAnchorRange ); + return (rScRanges1.size() == 1) && (rScRanges2.size() == 1) && (rScRanges1[ 0 ] == rScRanges2[ 0 ]); + } + case office::MsoHyperlinkType::msoHyperlinkShape: + case office::MsoHyperlinkType::msoHyperlinkInlineShape: + { + uno::Reference< msforms::XShape > xAnchorShape( rxHlink->getShape(), uno::UNO_SET_THROW ); + return xAnchorShape.get() == mxAnchorShape.get(); + } + default: + throw uno::RuntimeException(); + } +} + +} // namespace + +namespace detail { + +class ScVbaHlinkContainer : public ::cppu::WeakImplHelper< container::XIndexAccess > +{ +public: + /// @throws uno::RuntimeException + explicit ScVbaHlinkContainer(); + /// @throws uno::RuntimeException + explicit ScVbaHlinkContainer( const ScVbaHlinkContainerRef& rxSheetContainer, const ScRangeList& rScRanges ); + + /** Inserts the passed hyperlink into the collection. Will remove a + Hyperlink object with the same anchor as the passed Hyperlink object. + + @throws uno::RuntimeException + */ + void insertHyperlink( const uno::Reference< excel::XHyperlink >& rxHlink ); + + // XIndexAccess + virtual sal_Int32 SAL_CALL getCount() override; + virtual uno::Any SAL_CALL getByIndex( sal_Int32 nIndex ) override; + + // XElementAccess + virtual uno::Type SAL_CALL getElementType() override; + virtual sal_Bool SAL_CALL hasElements() override; + +private: + typedef ::std::vector< uno::Reference< excel::XHyperlink > > HyperlinkVector; + HyperlinkVector maHlinks; +}; + +ScVbaHlinkContainer::ScVbaHlinkContainer() +{ + // TODO FIXME: fill with existing hyperlinks +} + +ScVbaHlinkContainer::ScVbaHlinkContainer( const ScVbaHlinkContainerRef& rxSheetContainer, + const ScRangeList& rScRanges ) +{ + for( sal_Int32 nIndex = 0, nCount = rxSheetContainer->getCount(); nIndex < nCount; ++nIndex ) + { + uno::Reference< excel::XHyperlink > xHlink( rxSheetContainer->getByIndex( nIndex ), uno::UNO_QUERY_THROW ); + uno::Reference< excel::XRange > xHlinkRange( xHlink->getRange(), uno::UNO_SET_THROW ); + if( lclContains( rScRanges, xHlinkRange ) ) + maHlinks.push_back( xHlink ); + } +} + +void ScVbaHlinkContainer::insertHyperlink( const uno::Reference< excel::XHyperlink >& rxHlink ) +{ + HyperlinkVector::iterator aIt = ::std::find_if( maHlinks.begin(), maHlinks.end(), EqualAnchorFunctor( rxHlink ) ); + if( aIt == maHlinks.end() ) + maHlinks.push_back( rxHlink ); + else + *aIt = rxHlink; +} + +sal_Int32 SAL_CALL ScVbaHlinkContainer::getCount() +{ + return static_cast< sal_Int32 >( maHlinks.size() ); +} + +uno::Any SAL_CALL ScVbaHlinkContainer::getByIndex( sal_Int32 nIndex ) +{ + if( (0 <= nIndex) && (nIndex < getCount()) ) + return uno::Any( maHlinks[ static_cast< size_t >( nIndex ) ] ); + throw lang::IndexOutOfBoundsException(); +} + +uno::Type SAL_CALL ScVbaHlinkContainer::getElementType() +{ + return cppu::UnoType<excel::XHyperlink>::get(); +} + +sal_Bool SAL_CALL ScVbaHlinkContainer::hasElements() +{ + return !maHlinks.empty(); +} + +ScVbaHlinkContainerMember::ScVbaHlinkContainerMember( ScVbaHlinkContainer* pContainer ) : + mxContainer( pContainer ) +{ +} + +ScVbaHlinkContainerMember::~ScVbaHlinkContainerMember() +{ +} + +} // namespace detail + +ScVbaHyperlinks::ScVbaHyperlinks( const uno::Reference< XHelperInterface >& rxParent, + const uno::Reference< uno::XComponentContext >& rxContext ) : + detail::ScVbaHlinkContainerMember( new detail::ScVbaHlinkContainer ), + ScVbaHyperlinks_BASE( rxParent, rxContext, uno::Reference< container::XIndexAccess >( mxContainer ) ) +{ +} + +ScVbaHyperlinks::ScVbaHyperlinks( const uno::Reference< XHelperInterface >& rxParent, + const uno::Reference< uno::XComponentContext >& rxContext, + const ScVbaHyperlinksRef& rxSheetHlinks, const ScRangeList& rScRanges ) : + detail::ScVbaHlinkContainerMember( new detail::ScVbaHlinkContainer( rxSheetHlinks->mxContainer, rScRanges ) ), + ScVbaHyperlinks_BASE( rxParent, rxContext, uno::Reference< container::XIndexAccess >( mxContainer ) ), + mxSheetHlinks( rxSheetHlinks ) +{ +} + +ScVbaHyperlinks::~ScVbaHyperlinks() +{ +} + +// XHyperlinks ---------------------------------------------------------------- + +uno::Reference< excel::XHyperlink > SAL_CALL ScVbaHyperlinks::Add( + const uno::Any& rAnchor, const uno::Any& rAddress, const uno::Any& rSubAddress, + const uno::Any& rScreenTip, const uno::Any& rTextToDisplay ) +{ + /* If this Hyperlinks object has been created from a Range object, the + call to Add() is passed to the Hyperlinks object of the parent + worksheet. This container will not be modified (it will not contain the + inserted hyperlink). + For details, see documentation in hyperlinks.hxx. + */ + if( mxSheetHlinks.is() ) + return mxSheetHlinks->Add( rAnchor, rAddress, rSubAddress, rScreenTip, rTextToDisplay ); + + // get anchor object (can be a Range or a Shape object) + uno::Reference< XHelperInterface > xAnchor( rAnchor, uno::UNO_QUERY_THROW ); + + /* Create the Hyperlink object, this tries to insert the hyperlink into + the spreadsheet document. Parent of the Hyperlink is the anchor object. */ + uno::Reference< excel::XHyperlink > xHlink( new ScVbaHyperlink( + xAnchor, mxContext, rAddress, rSubAddress, rScreenTip, rTextToDisplay ) ); + + /* If creation of the hyperlink did not throw, insert it into the + collection. */ + mxContainer->insertHyperlink( xHlink ); + return xHlink; +} + +void SAL_CALL ScVbaHyperlinks::Delete() +{ + // FIXME not implemented + throw uno::RuntimeException(); +} + +// XEnumerationAccess --------------------------------------------------------- + +uno::Reference< container::XEnumeration > SAL_CALL ScVbaHyperlinks::createEnumeration() +{ + return new SimpleIndexAccessToEnumeration( m_xIndexAccess ); +} + +// XElementAccess ------------------------------------------------------------- + +uno::Type SAL_CALL ScVbaHyperlinks::getElementType() +{ + return cppu::UnoType<excel::XHyperlink>::get(); +} + +// ScVbaCollectionBase -------------------------------------------------------- + +uno::Any ScVbaHyperlinks::createCollectionObject( const uno::Any& rSource ) +{ + // container stores XHyperlink objects, just return the passed object + return rSource; +} + +// XHelperInterface ----------------------------------------------------------- + +VBAHELPER_IMPL_XHELPERINTERFACE( ScVbaHyperlinks, "ooo.vba.excel.Hyperlinks" ) + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbahyperlinks.hxx b/sc/source/ui/vba/vbahyperlinks.hxx new file mode 100644 index 000000000..7538fe50b --- /dev/null +++ b/sc/source/ui/vba/vbahyperlinks.hxx @@ -0,0 +1,136 @@ +/* -*- 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 . + */ + +#pragma once + +#include <ooo/vba/excel/XHyperlinks.hpp> +#include <rtl/ref.hxx> +#include <vbahelper/vbacollectionimpl.hxx> + +class ScRangeList; + +namespace detail { + +class ScVbaHlinkContainer; +typedef ::rtl::Reference< ScVbaHlinkContainer > ScVbaHlinkContainerRef; + +/** Base class for ScVbaHyperlinks to get an initialized ScVbaHlinkContainer + class member before the ScVbaHyperlinks_BASE base class will be constructed. + */ +struct ScVbaHlinkContainerMember +{ + ScVbaHlinkContainerRef mxContainer; + + explicit ScVbaHlinkContainerMember( ScVbaHlinkContainer* pContainer ); + ~ScVbaHlinkContainerMember(); +}; + +} // namespace detail + +class ScVbaHyperlinks; +typedef ::rtl::Reference< ScVbaHyperlinks > ScVbaHyperlinksRef; + +typedef CollTestImplHelper< ov::excel::XHyperlinks > ScVbaHyperlinks_BASE; + +/** Represents a collection of hyperlinks of a worksheet or of a range. + + When a Hyperlinks collection object has been constructed from a VBA + Worksheet object, it will always represent the current set of all + hyperlinks existing in the sheet. Insertion and deletion of hyperlinks will + be reflected by the instance. + + When a Hyperlinks collection object has been constructed from a VBA Range + object, it will represent the set of hyperlinks that have existed at its + construction time, and that are located completely inside the range(s) + represented by the Range object. Insertion and deletion of hyperlinks will + *not* be reflected by that instance. The instance will always offer all + hyperlinks it has been constructed with, even if they no longer exist. + Furthermore, the instance will not offer hyperlinks inserted later, even if + the instance itself has been used to insert the new hyperlinks. + + VBA code example: + + With ThisWorkbook.Worksheets(1) + + Set hlinks = .Hyperlinks ' global Hyperlinks object + Set myrange = .Range("A1:C3") + Set rangelinks1 = myrange.Hyperlinks ' hyperlinks of range A1:C3 + + MsgBox hlinks.Count ' 0 + MsgBox rangelinks1.Count ' 0 + + hlinks.Add .Range("A1"), "http://example.com" + ' a new hyperlink has been added in cell A1 + + MsgBox hlinks.Count ' 1 + MsgBox rangelinks1.Count ' still 0! + Set rangelinks2 = myrange.Hyperlinks ' hyperlinks of range A1:C3 + MsgBox rangelinks2.Count ' 1 (constructed after Add) + + rangelinks1.Add .Range("A2"), "http://example.com" + ' a new hyperlink has been constructed via the rangelinks1 object + ' but this addition has been done by the worksheet Hyperlinks object + + MsgBox hlinks.Count ' 2 + MsgBox rangelinks1.Count ' still 0!!! + MsgBox rangelinks2.Count ' still 1!!! + MsgBox myrange.Hyperlinks.Count ' 2 (constructed after Add) + + End With + */ +class ScVbaHyperlinks : private detail::ScVbaHlinkContainerMember, public ScVbaHyperlinks_BASE +{ +public: + /// @throws css::uno::RuntimeException + explicit ScVbaHyperlinks( + const css::uno::Reference< ov::XHelperInterface >& rxParent, + const css::uno::Reference< css::uno::XComponentContext >& rxContext ); + + /// @throws css::uno::RuntimeException + explicit ScVbaHyperlinks( + const css::uno::Reference< ov::XHelperInterface >& rxParent, + const css::uno::Reference< css::uno::XComponentContext >& rxContext, + const ScVbaHyperlinksRef& rxSheetHlinks, const ScRangeList& rScRanges ); + + virtual ~ScVbaHyperlinks() override; + + // XHyperlinks + virtual css::uno::Reference< ov::excel::XHyperlink > SAL_CALL Add( + const css::uno::Any& rAnchor, const css::uno::Any& rAddress, const css::uno::Any& rSubAddress, + const css::uno::Any& rScreenTip, const css::uno::Any& rTextToDisplay ) override; + + virtual void SAL_CALL Delete() override; + + // XEnumerationAccess + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + + // XElementAccess + virtual css::uno::Type SAL_CALL getElementType() override; + + // ScVbaCollectionBase + virtual css::uno::Any createCollectionObject( const css::uno::Any& rSource ) override; + + // XHelperInterface + VBAHELPER_DECL_XHELPERINTERFACE + +private: + ScVbaHyperlinksRef mxSheetHlinks; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbainterior.cxx b/sc/source/ui/vba/vbainterior.cxx new file mode 100644 index 000000000..2849ed672 --- /dev/null +++ b/sc/source/ui/vba/vbainterior.cxx @@ -0,0 +1,413 @@ +/* -*- 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 <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/xml/AttributeData.hpp> + +#include <ooo/vba/excel/XlColorIndex.hpp> +#include <ooo/vba/excel/XlPattern.hpp> + +#include <map> + +#include <sal/macros.h> + +#include "vbainterior.hxx" +#include "vbapalette.hxx" +#include <document.hxx> + +using namespace ::com::sun::star; +using namespace ::ooo::vba; +using namespace ::ooo::vba::excel::XlPattern; + +constexpr OUStringLiteral BACKCOLOR = u"CellBackColor"; +constexpr OUStringLiteral PATTERN = u"Pattern"; +constexpr OUStringLiteral PATTERNCOLOR = u"PatternColor"; + +static std::map< sal_Int32, sal_Int32 > aPatternMap { + { xlPatternAutomatic, 0 }, + { xlPatternChecker, 9 }, + { xlPatternCrissCross, 16 }, + { xlPatternDown, 7 }, + { xlPatternGray16, 17 }, + { xlPatternGray25, 4 }, + { xlPatternGray50, 2 }, + { xlPatternGray75, 3 }, + { xlPatternGray8, 18 }, + { xlPatternGrid, 15 }, + { xlPatternHorizontal, 5 }, + { xlPatternLightDown, 13 }, + { xlPatternLightHorizontal, 11 }, + { xlPatternLightUp, 14 }, + { xlPatternLightVertical, 12 }, + { xlPatternNone, 0 }, + { xlPatternSemiGray75, 10 }, + { xlPatternSolid, 0 }, + { xlPatternUp, 8 }, + { xlPatternVertical, 6 } +}; + +ScVbaInterior::ScVbaInterior( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< beans::XPropertySet >& xProps, ScDocument* pScDoc ) : ScVbaInterior_BASE( xParent, xContext ), m_xProps(xProps), m_pScDoc( pScDoc ) +{ + // auto color + m_aPattColor = Color(0); + m_nPattern = 0; + if ( !m_xProps.is() ) + throw lang::IllegalArgumentException("properties", uno::Reference< uno::XInterface >(), 2 ); +} + +uno::Any +ScVbaInterior::getColor() +{ + return uno::Any( OORGBToXLRGB( GetBackColor() ) ); +} + +void +ScVbaInterior::setColor( const uno::Any& _color ) +{ + sal_Int32 nColor = 0; + if( _color >>= nColor ) + { + SetUserDefinedAttributes( BACKCOLOR, SetAttributeData( XLRGBToOORGB( nColor ) ) ); + SetMixedColor(); + } +} + +void +ScVbaInterior::SetMixedColor() +{ + // pattern + uno::Any aPattern = GetUserDefinedAttributes( PATTERN ); + if( aPattern.hasValue() ) + { + m_nPattern = GetAttributeData( aPattern ); + } + sal_Int32 nPattern = aPatternMap[ m_nPattern ]; + // pattern color + uno::Any aPatternColor = GetUserDefinedAttributes( PATTERNCOLOR ); + if( aPatternColor.hasValue() ) + { + sal_uInt32 nPatternColor = GetAttributeData( aPatternColor ); + m_aPattColor = Color(ColorTransparency, nPatternColor); + } + Color nPatternColor = m_aPattColor; + // back color + Color aBackColor( GetBackColor() ); + // set mixed color + Color aMixedColor; + if( nPattern > 0 ) + aMixedColor = GetPatternColor( nPatternColor, aBackColor, static_cast<sal_uInt32>(nPattern) ); + else + aMixedColor = GetPatternColor( aBackColor, aBackColor, static_cast<sal_uInt32>(nPattern) ); + Color nMixedColor = aMixedColor.GetRGBColor(); + m_xProps->setPropertyValue( BACKCOLOR , uno::Any( nMixedColor ) ); +} + +uno::Reference< container::XIndexAccess > +ScVbaInterior::getPalette() const +{ + if ( !m_pScDoc ) + throw uno::RuntimeException(); + SfxObjectShell* pShell = m_pScDoc->GetDocumentShell(); + ScVbaPalette aPalette( pShell ); + return aPalette.getPalette(); +} + +void SAL_CALL +ScVbaInterior::setColorIndex( const css::uno::Any& _colorindex ) +{ + sal_Int32 nIndex = 0; + _colorindex >>= nIndex; + + // hackly for excel::XlColorIndex::xlColorIndexNone + if( nIndex == excel::XlColorIndex::xlColorIndexNone ) + { + m_xProps->setPropertyValue( BACKCOLOR, uno::Any( sal_Int32( -1 ) ) ); + } + else + { + // setColor expects colors in XL RGB values + // #FIXME this is daft we convert OO RGB val to XL RGB val and + // then back again to OO RGB value + setColor( OORGBToXLRGB( GetIndexColor( nIndex ) ) ); + } +} +uno::Any +ScVbaInterior::GetIndexColor( sal_Int32 nColorIndex ) +{ + sal_Int32 nIndex = nColorIndex; + // #FIXME xlColorIndexAutomatic & xlColorIndexNone are not really + // handled properly here + if ( !nIndex || ( nIndex == excel::XlColorIndex::xlColorIndexAutomatic ) || ( nIndex == excel::XlColorIndex::xlColorIndexNone ) ) + nIndex = 2; // default is white ( this maybe will probably break, e.g. we may at some stage need to know what this interior is, a cell or something else and then pick a default colour based on that ) + --nIndex; // OOo indices are zero bases + uno::Reference< container::XIndexAccess > xIndex = getPalette(); + return xIndex->getByIndex( nIndex ); +} + +sal_Int32 +ScVbaInterior::GetColorIndex( const sal_Int32 nColor ) +{ + uno::Reference< container::XIndexAccess > xIndex = getPalette(); + sal_Int32 nElems = xIndex->getCount(); + sal_Int32 nIndex = -1; + for ( sal_Int32 count=0; count<nElems; ++count ) + { + sal_Int32 nPaletteColor = 0; + xIndex->getByIndex( count ) >>= nPaletteColor; + if ( nPaletteColor == nColor ) + { + nIndex = count + 1; // 1 based + break; + } + } + return nIndex; +} + +uno::Any SAL_CALL +ScVbaInterior::getColorIndex() +{ + sal_Int32 nColor = 0; + // hackly for excel::XlColorIndex::xlColorIndexNone + uno::Any aColor = m_xProps->getPropertyValue( BACKCOLOR ); + if( ( aColor >>= nColor ) && ( nColor == -1 ) ) + { + nColor = excel::XlColorIndex::xlColorIndexNone; + return uno::Any( nColor ); + } + + // getColor returns Xl ColorValue, need to convert it to OO val + // as the palette deals with OO RGB values + // #FIXME this is daft in getColor we convert OO RGB val to XL RGB val + // and then back again to OO RGB value + XLRGBToOORGB( getColor() ) >>= nColor; + + return uno::Any( GetColorIndex( nColor ) ); +} +Color +ScVbaInterior::GetPatternColor( const Color& rPattColor, const Color& rBackColor, sal_uInt32 nXclPattern ) +{ + // 0x00 == 0% transparence (full rPattColor) + // 0x80 == 100% transparence (full rBackColor) + static const sal_uInt8 pnRatioTable[] = + { + 0x80, 0x00, 0x40, 0x20, 0x60, 0x40, 0x40, 0x40, // 00 - 07 + 0x40, 0x40, 0x20, 0x60, 0x60, 0x60, 0x60, 0x48, // 08 - 15 + 0x50, 0x70, 0x78 // 16 - 18 + }; + return ( nXclPattern < SAL_N_ELEMENTS( pnRatioTable ) ) ? + GetMixedColor( rPattColor, rBackColor, pnRatioTable[ nXclPattern ] ) : rPattColor; +} +Color +ScVbaInterior::GetMixedColor( const Color& rFore, const Color& rBack, sal_uInt8 nTrans ) +{ + return Color( + ColorTransparency, nTrans, + GetMixedColorComp( rFore.GetRed(), rBack.GetRed(), nTrans ), + GetMixedColorComp( rFore.GetGreen(), rBack.GetGreen(), nTrans ), + GetMixedColorComp( rFore.GetBlue(), rBack.GetBlue(), nTrans )); +} +sal_uInt8 +ScVbaInterior::GetMixedColorComp( sal_uInt8 nFore, sal_uInt8 nBack, sal_uInt8 nTrans ) +{ + sal_uInt32 nTemp = ((static_cast< sal_Int32 >( nBack ) - nFore) * nTrans) / 0x80 + nFore; + return static_cast< sal_uInt8 >( nTemp ); +} +uno::Reference< container::XNameContainer > +ScVbaInterior::GetAttributeContainer() +{ + return uno::Reference < container::XNameContainer > ( m_xProps->getPropertyValue("UserDefinedAttributes"), uno::UNO_QUERY_THROW ); +} +sal_Int32 +ScVbaInterior::GetAttributeData( uno::Any const & aValue ) +{ + xml::AttributeData aDataValue; + if( aValue >>= aDataValue ) + { + return aDataValue.Value.toInt32(); + } + return 0; +} +uno::Any +ScVbaInterior::SetAttributeData( sal_Int32 nValue ) +{ + xml::AttributeData aAttributeData; + aAttributeData.Type = "sal_Int32"; + aAttributeData.Value = OUString::number( nValue ); + return uno::Any( aAttributeData ); +} +uno::Any +ScVbaInterior::GetUserDefinedAttributes( const OUString& sName ) +{ + uno::Reference< container::XNameContainer > xNameContainer( GetAttributeContainer(), uno::UNO_SET_THROW ); + if( xNameContainer->hasByName( sName ) ) + { + return xNameContainer->getByName( sName ); + } + return uno::Any(); +} +void +ScVbaInterior::SetUserDefinedAttributes( const OUString& sName, const uno::Any& aValue ) +{ + if( aValue.hasValue() ) + { + uno::Reference< container::XNameContainer > xNameContainer( GetAttributeContainer(), uno::UNO_SET_THROW ); + if( xNameContainer->hasByName( sName ) ) + xNameContainer->removeByName( sName ); + xNameContainer->insertByName( sName, aValue ); + m_xProps->setPropertyValue("UserDefinedAttributes", uno::Any( xNameContainer ) ); + } +} +// OOo do not support below API +uno::Any SAL_CALL +ScVbaInterior::getPattern() +{ + // XlPattern + uno::Any aPattern = GetUserDefinedAttributes( PATTERN ); + if( aPattern.hasValue() ) + return uno::Any( GetAttributeData( aPattern ) ); + return uno::Any( excel::XlPattern::xlPatternNone ); +} +void SAL_CALL +ScVbaInterior::setPattern( const uno::Any& _pattern ) +{ + if( !(_pattern >>= m_nPattern) ) + throw uno::RuntimeException("Invalid Pattern index" ); + + SetUserDefinedAttributes( PATTERN, SetAttributeData( m_nPattern ) ); + SetMixedColor(); + +} +Color +ScVbaInterior::GetBackColor() +{ + sal_Int32 nColor = 0; + Color aBackColor; + uno::Any aColor = GetUserDefinedAttributes( BACKCOLOR ); + if( aColor.hasValue() ) + { + nColor = GetAttributeData( aColor ); + aBackColor = Color(ColorTransparency, nColor); + } + else + { + uno::Any aAny = OORGBToXLRGB( m_xProps->getPropertyValue( BACKCOLOR ) ); + if( aAny >>= nColor ) + { + nColor = XLRGBToOORGB( nColor ); + aBackColor = Color(ColorTransparency, nColor); + SetUserDefinedAttributes( BACKCOLOR, SetAttributeData( nColor ) ); + } + } + return aBackColor; +} +uno::Any SAL_CALL +ScVbaInterior::getPatternColor() +{ + // 0 is the default color. no filled. + uno::Any aPatternColor = GetUserDefinedAttributes( PATTERNCOLOR ); + if( aPatternColor.hasValue() ) + { + sal_uInt32 nPatternColor = GetAttributeData( aPatternColor ); + return uno::Any( OORGBToXLRGB( Color(ColorTransparency, nPatternColor) ) ); + } + return uno::Any( sal_Int32( 0 ) ); +} +void SAL_CALL +ScVbaInterior::setPatternColor( const uno::Any& _patterncolor ) +{ + sal_Int32 nPattColor = 0; + if( !(_patterncolor >>= nPattColor) ) + throw uno::RuntimeException("Invalid Pattern Color" ); + + SetUserDefinedAttributes( PATTERNCOLOR, SetAttributeData( XLRGBToOORGB( nPattColor ) ) ); + SetMixedColor(); + +} +uno::Any SAL_CALL +ScVbaInterior::getPatternColorIndex() +{ + sal_Int32 nColor = 0; + XLRGBToOORGB( getPatternColor() ) >>= nColor; + + return uno::Any( GetColorIndex( nColor ) ); +} +void SAL_CALL +ScVbaInterior::setPatternColorIndex( const uno::Any& _patterncolorindex ) +{ + sal_Int32 nColorIndex = 0; + if( !(_patterncolorindex >>= nColorIndex) ) + throw uno::RuntimeException("Invalid Pattern Color" ); + + if( nColorIndex == 0 ) + return; + Color nPattColor; + GetIndexColor( nColorIndex ) >>= nPattColor; + setPatternColor( uno::Any( OORGBToXLRGB( nPattColor ) ) ); + +} + +uno::Any SAL_CALL ScVbaInterior::getThemeColor() +{ + // Just a stub for now. + return uno::Any(static_cast<sal_Int32>(0)); +} + +void SAL_CALL ScVbaInterior::setThemeColor(const uno::Any& /*rAny*/) +{ + // Just a stub for now. +} + +uno::Any SAL_CALL ScVbaInterior::getTintAndShade() +{ + // Just a stub for now. + return uno::Any(static_cast<double>(0)); +} + +void SAL_CALL ScVbaInterior::setTintAndShade(const uno::Any& /*rAny*/) +{ + // Just a stub for now. +} + +uno::Any SAL_CALL ScVbaInterior::getPatternTintAndShade() +{ + // Just a stub for now. + return uno::Any(static_cast<double>(0)); +} + +void SAL_CALL ScVbaInterior::setPatternTintAndShade(const uno::Any& /*rAny*/) +{ + // Just a stub for now. +} + +OUString +ScVbaInterior::getServiceImplName() +{ + return "ScVbaInterior"; +} + +uno::Sequence< OUString > +ScVbaInterior::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.Interior" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbainterior.hxx b/sc/source/ui/vba/vbainterior.hxx new file mode 100644 index 000000000..1ea226e63 --- /dev/null +++ b/sc/source/ui/vba/vbainterior.hxx @@ -0,0 +1,83 @@ +/* -*- 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 . + */ +#pragma once + +#include <ooo/vba/excel/XInterior.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/container/XNameContainer.hpp> + +#include <vbahelper/vbahelperinterface.hxx> + +#include <tools/color.hxx> + +class ScDocument; + +typedef InheritedHelperInterfaceWeakImpl< ov::excel::XInterior > ScVbaInterior_BASE; + +class ScVbaInterior final : public ScVbaInterior_BASE +{ + css::uno::Reference< css::beans::XPropertySet > m_xProps; + ScDocument* m_pScDoc; + Color m_aPattColor; + sal_Int32 m_nPattern; + + css::uno::Reference< css::container::XIndexAccess > getPalette() const; + css::uno::Reference< css::container::XNameContainer > GetAttributeContainer(); + static css::uno::Any SetAttributeData( sal_Int32 nValue ); + static sal_Int32 GetAttributeData( css::uno::Any const & aValue ); + Color GetBackColor(); + static Color GetPatternColor( const Color& rPattColor, const Color& rBackColor, sal_uInt32 nXclPattern ); + static Color GetMixedColor( const Color& rFore, const Color& rBack, sal_uInt8 nTrans ); + static sal_uInt8 GetMixedColorComp( sal_uInt8 nFore, sal_uInt8 nBack, sal_uInt8 nTrans ); + css::uno::Any GetIndexColor( sal_Int32 nColorIndex ); + sal_Int32 GetColorIndex( const sal_Int32 nColor ); + css::uno::Any GetUserDefinedAttributes( const OUString& sName ); + void SetUserDefinedAttributes( const OUString& sName, const css::uno::Any& aValue ); + void SetMixedColor(); + +public: + /// @throws css::lang::IllegalArgumentException + ScVbaInterior( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext, + const css::uno::Reference< css::beans::XPropertySet >& xProps, ScDocument* pScDoc = nullptr); + + virtual css::uno::Any SAL_CALL getColor() override ; + virtual void SAL_CALL setColor( const css::uno::Any& _color ) override ; + + virtual css::uno::Any SAL_CALL getColorIndex() override; + virtual void SAL_CALL setColorIndex( const css::uno::Any& _colorindex ) override; + virtual css::uno::Any SAL_CALL getPattern() override; + virtual void SAL_CALL setPattern( const css::uno::Any& _pattern ) override; + virtual css::uno::Any SAL_CALL getPatternColor() override; + virtual void SAL_CALL setPatternColor( const css::uno::Any& _patterncolor ) override; + virtual css::uno::Any SAL_CALL getPatternColorIndex() override; + virtual void SAL_CALL setPatternColorIndex( const css::uno::Any& _patterncolorindex ) override; + css::uno::Any SAL_CALL getThemeColor() override; + void SAL_CALL setThemeColor(const css::uno::Any& rAny) override; + css::uno::Any SAL_CALL getTintAndShade() override; + void SAL_CALL setTintAndShade(const css::uno::Any& rAny) override; + css::uno::Any SAL_CALL getPatternTintAndShade() override; + void SAL_CALL setPatternTintAndShade(const css::uno::Any& rAny) override; + //XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbalineshape.cxx b/sc/source/ui/vba/vbalineshape.cxx new file mode 100644 index 000000000..fac0f1715 --- /dev/null +++ b/sc/source/ui/vba/vbalineshape.cxx @@ -0,0 +1,34 @@ +/* -*- 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 "vbalineshape.hxx" + +using namespace com::sun::star; +using namespace ooo::vba; + +/* + * This is implemented as a new class in order to provide XTypeProvider + * interface. This is needed by TypeOf ... Is ... basic operator. + */ + +ScVbaLineShape::ScVbaLineShape( const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< drawing::XShape >& xShape, const uno::Reference< drawing::XShapes >& xShapes, const uno::Reference< frame::XModel >& xModel ) : LineShapeImpl_BASE( uno::Reference< XHelperInterface >(), xContext, xShape, xShapes, xModel, ScVbaShape::getType( xShape ) ) +{} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbalineshape.hxx b/sc/source/ui/vba/vbalineshape.hxx new file mode 100644 index 000000000..953bc87a3 --- /dev/null +++ b/sc/source/ui/vba/vbalineshape.hxx @@ -0,0 +1,34 @@ +/* -*- 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 . + */ +#pragma once + +#include <ooo/vba/msforms/XLine.hpp> +#include <cppuhelper/implbase.hxx> +#include <vbahelper/vbashape.hxx> + +typedef cppu::ImplInheritanceHelper< ScVbaShape, ov::msforms::XLine > LineShapeImpl_BASE; + +class ScVbaLineShape : public LineShapeImpl_BASE +{ +public: + ScVbaLineShape( const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Reference< css::drawing::XShape >& xShape, const css::uno::Reference< css::drawing::XShapes >& xShapes, const css::uno::Reference< css::frame::XModel >& xModel ); + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbamenu.cxx b/sc/source/ui/vba/vbamenu.cxx new file mode 100644 index 000000000..38b4feb11 --- /dev/null +++ b/sc/source/ui/vba/vbamenu.cxx @@ -0,0 +1,67 @@ +/* -*- 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/. + */ + +#include "vbamenu.hxx" +#include "vbamenuitems.hxx" +#include <ooo/vba/XCommandBarControls.hpp> + +using namespace com::sun::star; +using namespace ooo::vba; + +ScVbaMenu::ScVbaMenu( const uno::Reference< ov::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, const uno::Reference< XCommandBarControl >& rCommandBarControl ) : Menu_BASE( rParent, rContext ), m_xCommandBarControl( rCommandBarControl ) +{ +} + +OUString SAL_CALL +ScVbaMenu::getCaption() +{ + return m_xCommandBarControl->getCaption(); +} + +void SAL_CALL +ScVbaMenu::setCaption( const OUString& _caption ) +{ + m_xCommandBarControl->setCaption( _caption ); +} + +void SAL_CALL +ScVbaMenu::Delete( ) +{ + m_xCommandBarControl->Delete(); +} + +uno::Any SAL_CALL +ScVbaMenu::MenuItems( const uno::Any& aIndex ) +{ + uno::Reference< XCommandBarControls > xCommandBarControls( m_xCommandBarControl->Controls( uno::Any() ), uno::UNO_QUERY_THROW ); + uno::Reference< excel::XMenuItems > xMenuItems( new ScVbaMenuItems( this, mxContext, xCommandBarControls ) ); + if( aIndex.hasValue() ) + { + return xMenuItems->Item( aIndex, uno::Any() ); + } + return uno::Any( xMenuItems ); +} + +OUString +ScVbaMenu::getServiceImplName() +{ + return "ScVbaMenu"; +} + +uno::Sequence<OUString> +ScVbaMenu::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.Menu" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbamenu.hxx b/sc/source/ui/vba/vbamenu.hxx new file mode 100644 index 000000000..284e2bc76 --- /dev/null +++ b/sc/source/ui/vba/vbamenu.hxx @@ -0,0 +1,37 @@ +/* -*- 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/. + */ +#pragma once + +#include <ooo/vba/excel/XMenu.hpp> +#include <ooo/vba/XCommandBarControl.hpp> +#include <vbahelper/vbahelperinterface.hxx> + +typedef InheritedHelperInterfaceWeakImpl< ov::excel::XMenu > Menu_BASE; + +class ScVbaMenu : public Menu_BASE +{ +private: + css::uno::Reference< ov::XCommandBarControl > m_xCommandBarControl; + +public: + /// @throws css::uno::RuntimeException + ScVbaMenu( const css::uno::Reference< ov::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext, const css::uno::Reference< ov::XCommandBarControl >& rCommandBarControl ); + + virtual OUString SAL_CALL getCaption() override; + virtual void SAL_CALL setCaption( const OUString& _caption ) override; + + virtual void SAL_CALL Delete( ) override; + virtual css::uno::Any SAL_CALL MenuItems( const css::uno::Any& aIndex ) override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbamenubar.cxx b/sc/source/ui/vba/vbamenubar.cxx new file mode 100644 index 000000000..bd25c02a7 --- /dev/null +++ b/sc/source/ui/vba/vbamenubar.cxx @@ -0,0 +1,48 @@ +/* -*- 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/. + */ +#include "vbamenubar.hxx" +#include "vbamenus.hxx" +#include <ooo/vba/XCommandBarControls.hpp> + +using namespace com::sun::star; +using namespace ooo::vba; + +ScVbaMenuBar::ScVbaMenuBar( const uno::Reference< ov::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, const uno::Reference< XCommandBar >& rCommandBar ) : MenuBar_BASE(rParent, rContext), m_xCommandBar(rCommandBar) +{ +} + +uno::Any SAL_CALL +ScVbaMenuBar::Menus( const uno::Any& aIndex ) +{ + uno::Reference< XCommandBarControls > xCommandBarControls( m_xCommandBar->Controls( uno::Any() ), uno::UNO_QUERY_THROW ); + uno::Reference< excel::XMenus > xMenus( new ScVbaMenus( this, mxContext, xCommandBarControls ) ); + if( aIndex.hasValue() ) + { + return xMenus->Item( aIndex, uno::Any() ); + } + return uno::Any( xMenus ); +} + +OUString +ScVbaMenuBar::getServiceImplName() +{ + return "ScVbaMenuBar"; +} + +uno::Sequence<OUString> +ScVbaMenuBar::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.MenuBar" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbamenubar.hxx b/sc/source/ui/vba/vbamenubar.hxx new file mode 100644 index 000000000..75c1854c6 --- /dev/null +++ b/sc/source/ui/vba/vbamenubar.hxx @@ -0,0 +1,33 @@ +/* -*- 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/. + */ +#pragma once + +#include <ooo/vba/excel/XMenuBar.hpp> +#include <ooo/vba/XCommandBar.hpp> +#include <vbahelper/vbahelperinterface.hxx> + +typedef InheritedHelperInterfaceWeakImpl< ov::excel::XMenuBar > MenuBar_BASE; + +class ScVbaMenuBar : public MenuBar_BASE +{ +private: + css::uno::Reference< ov::XCommandBar > m_xCommandBar; + +public: + /// @throws css::uno::RuntimeException + ScVbaMenuBar( const css::uno::Reference< ov::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext, const css::uno::Reference< ov::XCommandBar >& rCommandBar ); + + virtual css::uno::Any SAL_CALL Menus( const css::uno::Any& aIndex ) override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbamenubars.cxx b/sc/source/ui/vba/vbamenubars.cxx new file mode 100644 index 000000000..6bcea2baa --- /dev/null +++ b/sc/source/ui/vba/vbamenubars.cxx @@ -0,0 +1,118 @@ +/* -*- 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/. + */ +#include "vbamenubars.hxx" +#include "vbamenubar.hxx" +#include <cppuhelper/implbase.hxx> +#include <ooo/vba/excel/XlSheetType.hpp> +#include <ooo/vba/XCommandBars.hpp> + +using namespace com::sun::star; +using namespace ooo::vba; + +namespace { + +class MenuBarEnumeration : public ::cppu::WeakImplHelper< container::XEnumeration > +{ + uno::Reference< XHelperInterface > m_xParent; + uno::Reference< uno::XComponentContext > m_xContext; + uno::Reference< container::XEnumeration > m_xEnumeration; +public: + /// @throws uno::RuntimeException + MenuBarEnumeration( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< container::XEnumeration >& xEnumeration) : m_xParent( xParent ), m_xContext( xContext ), m_xEnumeration( xEnumeration ) + { + } + virtual sal_Bool SAL_CALL hasMoreElements() override + { + return m_xEnumeration->hasMoreElements(); + } + virtual uno::Any SAL_CALL nextElement() override + { + // FIXME: should be add menubar + if( !hasMoreElements() ) + throw container::NoSuchElementException(); + + uno::Reference< XCommandBar > xCommandBar( m_xEnumeration->nextElement(), uno::UNO_QUERY_THROW ); + uno::Reference< excel::XMenuBar > xMenuBar( new ScVbaMenuBar( m_xParent, m_xContext, xCommandBar ) ); + return uno::Any( xMenuBar ); + } +}; + +} + +ScVbaMenuBars::ScVbaMenuBars( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< XCommandBars >& xCommandBars ) : MenuBars_BASE( xParent, xContext, uno::Reference< container::XIndexAccess>() ), m_xCommandBars( xCommandBars ) +{ +} + +ScVbaMenuBars::~ScVbaMenuBars() +{ +} + +// XEnumerationAccess +uno::Type SAL_CALL +ScVbaMenuBars::getElementType() +{ + return cppu::UnoType<excel::XMenuBar>::get(); +} + +uno::Reference< container::XEnumeration > +ScVbaMenuBars::createEnumeration() +{ + uno::Reference< container::XEnumerationAccess > xEnumAccess( m_xCommandBars, uno::UNO_QUERY_THROW ); + return uno::Reference< container::XEnumeration >( new MenuBarEnumeration( this, mxContext, xEnumAccess->createEnumeration() ) ); +} + +uno::Any +ScVbaMenuBars::createCollectionObject( const uno::Any& aSource ) +{ + // make no sense + return aSource; +} + +sal_Int32 SAL_CALL +ScVbaMenuBars::getCount() +{ + return m_xCommandBars->getCount(); +} + +// ScVbaCollectionBaseImpl +uno::Any SAL_CALL +ScVbaMenuBars::Item( const uno::Any& aIndex, const uno::Any& /*aIndex2*/ ) +{ + sal_Int16 nIndex = 0; + aIndex >>= nIndex; + if( nIndex == excel::XlSheetType::xlWorksheet ) + { + uno::Any aSource; + aSource <<= OUString( "Worksheet Menu Bar" ); + uno::Reference< XCommandBar > xCommandBar( m_xCommandBars->Item( aSource, uno::Any() ), uno::UNO_QUERY_THROW ); + uno::Reference< excel::XMenuBar > xMenuBar( new ScVbaMenuBar( this, mxContext, xCommandBar ) ); + return uno::Any( xMenuBar ); + } + + throw uno::RuntimeException("Not implemented" ); +} + +// XHelperInterface +OUString +ScVbaMenuBars::getServiceImplName() +{ + return "ScVbaMenuBars"; +} + +uno::Sequence<OUString> +ScVbaMenuBars::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.MenuBars" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbamenubars.hxx b/sc/source/ui/vba/vbamenubars.hxx new file mode 100644 index 000000000..1303a0ff3 --- /dev/null +++ b/sc/source/ui/vba/vbamenubars.hxx @@ -0,0 +1,40 @@ +/* -*- 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/. + */ +#pragma once + +#include <ooo/vba/excel/XMenuBars.hpp> +#include <vbahelper/vbacollectionimpl.hxx> + +namespace ooo::vba { class XCommandBars; } + +typedef CollTestImplHelper< ov::excel::XMenuBars > MenuBars_BASE; + +class ScVbaMenuBars : public MenuBars_BASE +{ +private: + css::uno::Reference< ov::XCommandBars > m_xCommandBars; + +public: + /// @throws css::uno::RuntimeException + ScVbaMenuBars( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Reference< ov::XCommandBars >& xCommandBars ); + virtual ~ScVbaMenuBars() override; + + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override; + + virtual sal_Int32 SAL_CALL getCount() override; + virtual css::uno::Any SAL_CALL Item( const css::uno::Any& aIndex, const css::uno::Any& /*aIndex2*/ ) override; + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbamenuitem.cxx b/sc/source/ui/vba/vbamenuitem.cxx new file mode 100644 index 000000000..2dba780ba --- /dev/null +++ b/sc/source/ui/vba/vbamenuitem.cxx @@ -0,0 +1,64 @@ +/* -*- 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/. + */ +#include "vbamenuitem.hxx" + +using namespace com::sun::star; +using namespace ooo::vba; + +ScVbaMenuItem::ScVbaMenuItem( const uno::Reference< ov::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, const uno::Reference< XCommandBarControl >& rCommandBarControl ) : MenuItem_BASE( rParent, rContext ), m_xCommandBarControl( rCommandBarControl ) +{ +} + +OUString SAL_CALL +ScVbaMenuItem::getCaption() +{ + return m_xCommandBarControl->getCaption(); +} + +void SAL_CALL +ScVbaMenuItem::setCaption( const OUString& _caption ) +{ + m_xCommandBarControl->setCaption( _caption ); +} + +OUString SAL_CALL +ScVbaMenuItem::getOnAction() +{ + return m_xCommandBarControl->getOnAction(); +} + +void SAL_CALL +ScVbaMenuItem::setOnAction( const OUString& _onaction ) +{ + m_xCommandBarControl->setOnAction( _onaction ); +} + +void SAL_CALL +ScVbaMenuItem::Delete( ) +{ + m_xCommandBarControl->Delete(); +} + +OUString +ScVbaMenuItem::getServiceImplName() +{ + return "ScVbaMenuItem"; +} + +uno::Sequence<OUString> +ScVbaMenuItem::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.MenuItem" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbamenuitem.hxx b/sc/source/ui/vba/vbamenuitem.hxx new file mode 100644 index 000000000..bf8c35b29 --- /dev/null +++ b/sc/source/ui/vba/vbamenuitem.hxx @@ -0,0 +1,38 @@ +/* -*- 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/. + */ +#pragma once + +#include <ooo/vba/excel/XMenuItem.hpp> +#include <ooo/vba/XCommandBarControl.hpp> +#include <vbahelper/vbahelperinterface.hxx> + +typedef InheritedHelperInterfaceWeakImpl< ov::excel::XMenuItem > MenuItem_BASE; + +class ScVbaMenuItem : public MenuItem_BASE +{ +private: + css::uno::Reference< ov::XCommandBarControl > m_xCommandBarControl; + +public: + /// @throws css::uno::RuntimeException + ScVbaMenuItem( const css::uno::Reference< ov::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext, const css::uno::Reference< ov::XCommandBarControl >& rCommandBarControl ); + + virtual OUString SAL_CALL getCaption() override; + virtual void SAL_CALL setCaption( const OUString& _caption ) override; + virtual OUString SAL_CALL getOnAction() override; + virtual void SAL_CALL setOnAction( const OUString& _onaction ) override; + + virtual void SAL_CALL Delete( ) override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbamenuitems.cxx b/sc/source/ui/vba/vbamenuitems.cxx new file mode 100644 index 000000000..646fd82cb --- /dev/null +++ b/sc/source/ui/vba/vbamenuitems.cxx @@ -0,0 +1,138 @@ +/* -*- 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/. + */ +#include "vbamenuitems.hxx" +#include "vbamenuitem.hxx" +#include "vbamenu.hxx" +#include <cppuhelper/implbase.hxx> +#include <ooo/vba/office/MsoControlType.hpp> +#include <ooo/vba/XCommandBarControls.hpp> + +using namespace com::sun::star; +using namespace ooo::vba; + +typedef ::cppu::WeakImplHelper< container::XEnumeration > MenuEnumeration_BASE; + +namespace { + +class MenuEnumeration : public MenuEnumeration_BASE +{ + uno::Reference< XHelperInterface > m_xParent; + uno::Reference< uno::XComponentContext > m_xContext; + uno::Reference< container::XEnumeration > m_xEnumeration; +public: + /// @throws uno::RuntimeException + MenuEnumeration( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< container::XEnumeration >& xEnumeration) : m_xParent( xParent ), m_xContext( xContext ), m_xEnumeration( xEnumeration ) + { + } + virtual sal_Bool SAL_CALL hasMoreElements() override + { + return m_xEnumeration->hasMoreElements(); + } + virtual uno::Any SAL_CALL nextElement() override + { + // FIXME: should be add menu + if( !hasMoreElements() ) + throw container::NoSuchElementException(); + + uno::Reference< XCommandBarControl > xCommandBarControl( m_xEnumeration->nextElement(), uno::UNO_QUERY_THROW ); + if( xCommandBarControl->getType() == office::MsoControlType::msoControlPopup ) + { + uno::Reference< excel::XMenu > xMenu( new ScVbaMenu( m_xParent, m_xContext, xCommandBarControl ) ); + return uno::Any( xMenu ); + } + else if( xCommandBarControl->getType() == office::MsoControlType::msoControlButton ) + { + uno::Reference< excel::XMenuItem > xMenuItem( new ScVbaMenuItem( m_xParent, m_xContext, xCommandBarControl ) ); + return uno::Any( xMenuItem ); + } + nextElement(); + + return uno::Any(); + } +}; + +} + +ScVbaMenuItems::ScVbaMenuItems( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< XCommandBarControls >& xCommandBarControls ) : MenuItems_BASE( xParent, xContext, uno::Reference< container::XIndexAccess>() ), m_xCommandBarControls( xCommandBarControls ) +{ +} + +// XEnumerationAccess +uno::Type SAL_CALL +ScVbaMenuItems::getElementType() +{ + return cppu::UnoType<excel::XMenuItem>::get(); +} + +uno::Reference< container::XEnumeration > +ScVbaMenuItems::createEnumeration() +{ + uno::Reference< container::XEnumerationAccess > xEnumAccess( m_xCommandBarControls, uno::UNO_QUERY_THROW ); + return uno::Reference< container::XEnumeration >( new MenuEnumeration( this, mxContext, xEnumAccess->createEnumeration() ) ); +} + +uno::Any +ScVbaMenuItems::createCollectionObject( const uno::Any& aSource ) +{ + // make no sense + return aSource; +} + +sal_Int32 SAL_CALL +ScVbaMenuItems::getCount() +{ + // FIXME: should check if it is a popup menu + return m_xCommandBarControls->getCount(); +} + +// ScVbaCollectionBaseImpl +uno::Any SAL_CALL +ScVbaMenuItems::Item( const uno::Any& aIndex, const uno::Any& /*aIndex2*/ ) +{ + uno::Reference< XCommandBarControl > xCommandBarControl( m_xCommandBarControls->Item( aIndex, uno::Any() ), uno::UNO_QUERY_THROW ); + if( xCommandBarControl->getType() == office::MsoControlType::msoControlPopup ) + return uno::Any( uno::Reference< excel::XMenu > ( new ScVbaMenu( this, mxContext, xCommandBarControl ) ) ); + else if( xCommandBarControl->getType() == office::MsoControlType::msoControlButton ) + return uno::Any( uno::Reference< excel::XMenuItem > ( new ScVbaMenuItem( this, mxContext, xCommandBarControl ) ) ); + throw uno::RuntimeException(); +} + +uno::Reference< excel::XMenuItem > SAL_CALL ScVbaMenuItems::Add( const OUString& Caption, const css::uno::Any& OnAction, const css::uno::Any& /*ShortcutKey*/, const css::uno::Any& Before, const css::uno::Any& Restore, const css::uno::Any& /*StatusBar*/, const css::uno::Any& /*HelpFile*/, const css::uno::Any& /*HelpContextID*/ ) +{ + uno::Reference< XCommandBarControl > xCommandBarControl = m_xCommandBarControls->Add( + uno::Any( office::MsoControlType::msoControlButton ), + uno::Any(), uno::Any(), Before, Restore ); + xCommandBarControl->setCaption( Caption ); + if( OnAction.hasValue() ) + { + OUString sAction; + OnAction >>= sAction; + xCommandBarControl->setOnAction( sAction ); + } + return uno::Reference< excel::XMenuItem >( new ScVbaMenuItem( this, mxContext, xCommandBarControl ) ); +} + +// XHelperInterface +OUString +ScVbaMenuItems::getServiceImplName() +{ + return "ScVbaMenuItems"; +} + +uno::Sequence<OUString> +ScVbaMenuItems::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.MenuItems" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbamenuitems.hxx b/sc/source/ui/vba/vbamenuitems.hxx new file mode 100644 index 000000000..71f43e634 --- /dev/null +++ b/sc/source/ui/vba/vbamenuitems.hxx @@ -0,0 +1,42 @@ +/* -*- 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/. + */ +#pragma once + +#include <ooo/vba/excel/XMenuItems.hpp> +#include <vbahelper/vbacollectionimpl.hxx> + +namespace ooo::vba { class XCommandBarControls; } +namespace ooo::vba::excel { class XMenuItem; } + +typedef CollTestImplHelper< ov::excel::XMenuItems > MenuItems_BASE; + +class ScVbaMenuItems : public MenuItems_BASE +{ +private: + css::uno::Reference< ov::XCommandBarControls > m_xCommandBarControls; + +public: + /// @throws css::uno::RuntimeException + ScVbaMenuItems( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Reference< ov::XCommandBarControls >& xCommandBarControls ); + + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override; + + // Methods + virtual sal_Int32 SAL_CALL getCount() override; + virtual css::uno::Any SAL_CALL Item( const css::uno::Any& Index, const css::uno::Any& /*Index2*/ ) override; + virtual css::uno::Reference< ov::excel::XMenuItem > SAL_CALL Add( const OUString& Caption, const css::uno::Any& OnAction, const css::uno::Any& ShortcutKey, const css::uno::Any& Before, const css::uno::Any& Restore, const css::uno::Any& StatusBar, const css::uno::Any& HelpFile, const css::uno::Any& HelpContextID ) override; + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbamenus.cxx b/sc/source/ui/vba/vbamenus.cxx new file mode 100644 index 000000000..807f0cf5a --- /dev/null +++ b/sc/source/ui/vba/vbamenus.cxx @@ -0,0 +1,124 @@ +/* -*- 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/. + */ +#include "vbamenus.hxx" +#include "vbamenu.hxx" +#include <cppuhelper/implbase.hxx> +#include <ooo/vba/office/MsoControlType.hpp> +#include <ooo/vba/XCommandBarControls.hpp> + +using namespace com::sun::star; +using namespace ooo::vba; + +typedef ::cppu::WeakImplHelper< container::XEnumeration > MenuEnumeration_BASE; + +namespace { + +class MenuEnumeration : public MenuEnumeration_BASE +{ + uno::Reference< XHelperInterface > m_xParent; + uno::Reference< uno::XComponentContext > m_xContext; + uno::Reference< container::XEnumeration > m_xEnumeration; +public: + /// @throws uno::RuntimeException + MenuEnumeration( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< container::XEnumeration >& xEnumeration) : m_xParent( xParent ), m_xContext( xContext ), m_xEnumeration( xEnumeration ) + { + } + virtual sal_Bool SAL_CALL hasMoreElements() override + { + return m_xEnumeration->hasMoreElements(); + } + virtual uno::Any SAL_CALL nextElement() override + { + // FIXME: should be add menu + if( !hasMoreElements() ) + throw container::NoSuchElementException(); + + uno::Reference< XCommandBarControl > xCommandBarControl( m_xEnumeration->nextElement(), uno::UNO_QUERY_THROW ); + if( xCommandBarControl->getType() == office::MsoControlType::msoControlPopup ) + { + uno::Reference< excel::XMenu > xMenu( new ScVbaMenu( m_xParent, m_xContext, xCommandBarControl ) ); + return uno::Any( xMenu ); + } + nextElement(); + + return uno::Any(); + } +}; + +} + +ScVbaMenus::ScVbaMenus( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< XCommandBarControls >& xCommandBarControls ) : Menus_BASE( xParent, xContext, uno::Reference< container::XIndexAccess>() ), m_xCommandBarControls( xCommandBarControls ) +{ +} + +// XEnumerationAccess +uno::Type SAL_CALL +ScVbaMenus::getElementType() +{ + return cppu::UnoType<excel::XMenu>::get(); +} + +uno::Reference< container::XEnumeration > +ScVbaMenus::createEnumeration() +{ + uno::Reference< container::XEnumerationAccess > xEnumAccess( m_xCommandBarControls, uno::UNO_QUERY_THROW ); + return uno::Reference< container::XEnumeration >( new MenuEnumeration( this, mxContext, xEnumAccess->createEnumeration() ) ); +} + +uno::Any +ScVbaMenus::createCollectionObject( const uno::Any& aSource ) +{ + // make no sense + return aSource; +} + +sal_Int32 SAL_CALL +ScVbaMenus::getCount() +{ + // FIXME: should check if it is a popup menu + return m_xCommandBarControls->getCount(); +} + +// ScVbaCollectionBaseImpl +uno::Any SAL_CALL +ScVbaMenus::Item( const uno::Any& aIndex, const uno::Any& /*aIndex2*/ ) +{ + uno::Reference< XCommandBarControl > xCommandBarControl( m_xCommandBarControls->Item( aIndex, uno::Any() ), uno::UNO_QUERY_THROW ); + if( xCommandBarControl->getType() != office::MsoControlType::msoControlPopup ) + throw uno::RuntimeException(); + return uno::Any( uno::Reference< excel::XMenu > ( new ScVbaMenu( this, mxContext, xCommandBarControl ) ) ); +} + +uno::Reference< excel::XMenu > SAL_CALL ScVbaMenus::Add( const OUString& Caption, const css::uno::Any& Before, const css::uno::Any& Restore ) +{ + uno::Reference< XCommandBarControl > xCommandBarControl = m_xCommandBarControls->Add( + uno::Any( office::MsoControlType::msoControlPopup ), + uno::Any(), uno::Any(), Before, Restore ); + xCommandBarControl->setCaption( Caption ); + return uno::Reference< excel::XMenu >( new ScVbaMenu( this, mxContext, xCommandBarControl ) ); +} + +// XHelperInterface +OUString +ScVbaMenus::getServiceImplName() +{ + return "ScVbaMenus"; +} + +uno::Sequence<OUString> +ScVbaMenus::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.Menus" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbamenus.hxx b/sc/source/ui/vba/vbamenus.hxx new file mode 100644 index 000000000..2a14cf3cb --- /dev/null +++ b/sc/source/ui/vba/vbamenus.hxx @@ -0,0 +1,42 @@ +/* -*- 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/. + */ +#pragma once + +#include <ooo/vba/excel/XMenus.hpp> +#include <vbahelper/vbacollectionimpl.hxx> + +namespace ooo::vba { class XCommandBarControls; } +namespace ooo::vba::excel { class XMenu; } + +typedef CollTestImplHelper< ov::excel::XMenus > Menus_BASE; + +class ScVbaMenus : public Menus_BASE +{ +private: + css::uno::Reference< ov::XCommandBarControls > m_xCommandBarControls; + +public: + /// @throws css::uno::RuntimeException + ScVbaMenus( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Reference< ov::XCommandBarControls >& xCommandBarControls ); + + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override; + + // Methods + virtual sal_Int32 SAL_CALL getCount() override; + virtual css::uno::Any SAL_CALL Item( const css::uno::Any& Index, const css::uno::Any& /*Index2*/ ) override; + virtual css::uno::Reference< ov::excel::XMenu > SAL_CALL Add( const OUString& Caption, const css::uno::Any& Before, const css::uno::Any& Restore ) override; + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaname.cxx b/sc/source/ui/vba/vbaname.cxx new file mode 100644 index 000000000..7ef8fe129 --- /dev/null +++ b/sc/source/ui/vba/vbaname.cxx @@ -0,0 +1,216 @@ +/* -*- 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 "excelvbahelper.hxx" +#include "vbaname.hxx" +#include "vbarange.hxx" +#include <docsh.hxx> +#include <rangenam.hxx> +#include <nameuno.hxx> +#include <compiler.hxx> +#include <tokenarray.hxx> + +#include <memory> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +ScVbaName::ScVbaName(const css::uno::Reference< ov::XHelperInterface >& xParent, + const css::uno::Reference< css::uno::XComponentContext >& xContext, + const css::uno::Reference< css::sheet::XNamedRange >& xName, + const css::uno::Reference< css::sheet::XNamedRanges >& xNames, + const css::uno::Reference< css::frame::XModel >& xModel ): + NameImpl_BASE( xParent , xContext ), + mxModel( xModel ), + mxNamedRange( xName ), + mxNames( xNames ) +{ +} + +ScVbaName::~ScVbaName() +{ +} + +OUString +ScVbaName::getName() +{ + return mxNamedRange->getName(); +} + +void +ScVbaName::setName( const OUString & rName ) +{ + mxNamedRange->setName( rName ); +} + +OUString +ScVbaName::getNameLocal() +{ + return getName(); +} + +void +ScVbaName::setNameLocal( const OUString & rName ) +{ + setName( rName ); +} + +sal_Bool +ScVbaName::getVisible() +{ + return true; +} + +void +ScVbaName::setVisible( sal_Bool /*bVisible*/ ) +{ +} + +OUString ScVbaName::getContent( const formula::FormulaGrammar::Grammar eGrammar ) +{ + ScNamedRangeObj* pNamedRange = dynamic_cast< ScNamedRangeObj* >( mxNamedRange.get() ); + OUString aContent; + if ( pNamedRange ) + { + ScRangeData* pData = pNamedRange->GetRangeData_Impl(); + if (pData) + aContent = pData->GetSymbol( eGrammar ); + } + if (aContent.indexOf('=') != 0) + aContent = "=" + aContent; + return aContent; +} + +void ScVbaName::setContent( const OUString& rContent, const formula::FormulaGrammar::Grammar eGrammar ) +{ + OUString sContent( rContent ); + if (sContent.startsWith("=")) + sContent = sContent.copy(1); + ScNamedRangeObj* pNamedRange = dynamic_cast< ScNamedRangeObj* >( mxNamedRange.get() ); + + // We should be able to do the below by just setting calling SetCode on pNamedRange + // right? + if ( !(pNamedRange && pNamedRange->pDocShell) ) + return; + + ScDocument& rDoc = pNamedRange->pDocShell->GetDocument(); + ScRangeData* pOldData = pNamedRange->GetRangeData_Impl(); + if (pOldData) + { + // Shorter way of doing this ? + ScCompiler aComp( rDoc, pOldData->GetPos(), eGrammar ); + std::unique_ptr<ScTokenArray> pArray(aComp.CompileString(sContent)); + pOldData->SetCode(*pArray); + } +} + +OUString +ScVbaName::getValue() +{ + OUString sResult = getContent( formula::FormulaGrammar::GRAM_NATIVE_XL_A1 ); + + return sResult; +} + +void +ScVbaName::setValue( const OUString & rValue ) +{ + setContent( rValue, formula::FormulaGrammar::GRAM_NATIVE_XL_A1 ); +} + +OUString +ScVbaName::getRefersTo() +{ + return getValue(); +} + +void +ScVbaName::setRefersTo( const OUString & rRefersTo ) +{ + setValue( rRefersTo ); +} + +OUString +ScVbaName::getRefersToLocal() +{ + return getRefersTo(); +} + +void +ScVbaName::setRefersToLocal( const OUString & rRefersTo ) +{ + setRefersTo( rRefersTo ); +} + +OUString +ScVbaName::getRefersToR1C1() +{ + OUString sResult = getContent( formula::FormulaGrammar::GRAM_NATIVE_XL_R1C1 ); + return sResult; +} + +void +ScVbaName::setRefersToR1C1( const OUString & rRefersTo ) +{ + setContent( rRefersTo, formula::FormulaGrammar::GRAM_NATIVE_XL_R1C1 ); +} + +OUString +ScVbaName::getRefersToR1C1Local() +{ + return getRefersToR1C1(); +} + +void +ScVbaName::setRefersToR1C1Local( const OUString & rRefersTo ) +{ + setRefersTo( rRefersTo ); +} + +css::uno::Reference< ov::excel::XRange > +ScVbaName::getRefersToRange() +{ + uno::Reference< ov::excel::XRange > xRange = ScVbaRange::getRangeObjectForName( + mxContext, mxNamedRange->getName(), excel::getDocShell( mxModel ), formula::FormulaGrammar::CONV_XL_R1C1 ); + return xRange; +} + +void +ScVbaName::Delete() +{ + mxNames->removeByName( mxNamedRange->getName() ); +} + +OUString +ScVbaName::getServiceImplName() +{ + return "ScVbaName"; +} + +uno::Sequence< OUString > +ScVbaName::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.Name" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaname.hxx b/sc/source/ui/vba/vbaname.hxx new file mode 100644 index 000000000..194b047fa --- /dev/null +++ b/sc/source/ui/vba/vbaname.hxx @@ -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 . + */ +#pragma once + +#include <ooo/vba/excel/XName.hpp> + +#include <vbahelper/vbahelperinterface.hxx> +#include <formula/grammar.hxx> + +namespace com::sun::star::sheet { class XNamedRange; } +namespace com::sun::star::sheet { class XNamedRanges; } + +typedef InheritedHelperInterfaceWeakImpl< ov::excel::XName > NameImpl_BASE; + +class ScVbaName : public NameImpl_BASE +{ + css::uno::Reference< css::frame::XModel > mxModel; + css::uno::Reference< css::sheet::XNamedRange > mxNamedRange; + css::uno::Reference< css::sheet::XNamedRanges > mxNames; + OUString getContent( const formula::FormulaGrammar::Grammar eGrammar ); + void setContent( const OUString& sContent, const formula::FormulaGrammar::Grammar eGrammar ); +public: + ScVbaName( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Reference< css::sheet::XNamedRange >& xName , const css::uno::Reference< css::sheet::XNamedRanges >& xNames , const css::uno::Reference< css::frame::XModel >& xModel ); + virtual ~ScVbaName() override; + + // Attributes + virtual OUString SAL_CALL getName() override; + virtual void SAL_CALL setName( const OUString &rName ) override; + virtual OUString SAL_CALL getNameLocal() override; + virtual void SAL_CALL setNameLocal( const OUString &rName ) override; + virtual sal_Bool SAL_CALL getVisible() override; + virtual void SAL_CALL setVisible( sal_Bool bVisible ) override; + virtual OUString SAL_CALL getValue() override; + virtual void SAL_CALL setValue( const OUString &rValue ) override; + virtual OUString SAL_CALL getRefersTo() override; + virtual void SAL_CALL setRefersTo( const OUString &rRefersTo ) override; + virtual OUString SAL_CALL getRefersToLocal() override; + virtual void SAL_CALL setRefersToLocal( const OUString &rRefersTo ) override; + virtual OUString SAL_CALL getRefersToR1C1() override; + virtual void SAL_CALL setRefersToR1C1( const OUString &rRefersTo ) override; + virtual OUString SAL_CALL getRefersToR1C1Local() override; + virtual void SAL_CALL setRefersToR1C1Local( const OUString &rRefersTo ) override; + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL getRefersToRange() override; + + // Methods + virtual void SAL_CALL Delete() override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbanames.cxx b/sc/source/ui/vba/vbanames.cxx new file mode 100644 index 000000000..287dbcf3c --- /dev/null +++ b/sc/source/ui/vba/vbanames.cxx @@ -0,0 +1,260 @@ +/* -*- 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 <com/sun/star/table/XCellRange.hpp> +#include <com/sun/star/sheet/XCellRangeAddressable.hpp> +#include <com/sun/star/sheet/XNamedRange.hpp> +#include <com/sun/star/sheet/XNamedRanges.hpp> + +#include "excelvbahelper.hxx" +#include "vbanames.hxx" +#include "vbaname.hxx" +#include "vbarange.hxx" +#include <tabvwsh.hxx> +#include <viewdata.hxx> +#include <compiler.hxx> +#include <tokenarray.hxx> +#include <cellsuno.hxx> + +#include <memory> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +namespace { + +class NamesEnumeration : public EnumerationHelperImpl +{ + uno::Reference< frame::XModel > m_xModel; + uno::Reference< sheet::XNamedRanges > m_xNames; +public: + /// @throws uno::RuntimeException + NamesEnumeration( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< container::XEnumeration >& xEnumeration, const uno::Reference< frame::XModel >& xModel , const uno::Reference< sheet::XNamedRanges >& xNames ) : EnumerationHelperImpl( xParent, xContext, xEnumeration ), m_xModel( xModel ), m_xNames( xNames ) {} + + virtual uno::Any SAL_CALL nextElement( ) override + { + uno::Reference< sheet::XNamedRange > xNamed( m_xEnumeration->nextElement(), uno::UNO_QUERY_THROW ); + return uno::Any( uno::Reference< excel::XName > ( new ScVbaName( m_xParent, m_xContext, xNamed ,m_xNames , m_xModel ) ) ); + } + +}; + +} + +ScVbaNames::ScVbaNames(const css::uno::Reference< ov::XHelperInterface >& xParent, + const css::uno::Reference< css::uno::XComponentContext >& xContext, + const css::uno::Reference< css::sheet::XNamedRanges >& xNames, + const css::uno::Reference< css::frame::XModel >& xModel ): + ScVbaNames_BASE( xParent , xContext , uno::Reference< container::XIndexAccess >( xNames, uno::UNO_QUERY ) ), + mxModel( xModel ), + mxNames( xNames ) +{ + m_xNameAccess.set( xNames, uno::UNO_QUERY_THROW ); +} + +ScVbaNames::~ScVbaNames() +{ +} + +ScDocument& +ScVbaNames::getScDocument() +{ + uno::Reference< frame::XModel > xModel( getModel() , uno::UNO_SET_THROW ); + ScTabViewShell * pTabViewShell = excel::getBestViewShell( xModel ); + if ( !pTabViewShell ) + throw uno::RuntimeException( "No ViewShell available" ); + ScViewData& rViewData = pTabViewShell->GetViewData(); + return rViewData.GetDocument(); +} + +css::uno::Any +ScVbaNames::Add( const css::uno::Any& Name , + const css::uno::Any& RefersTo, + const css::uno::Any& /*Visible*/, + const css::uno::Any& /*MacroType*/, + const css::uno::Any& /*ShoutcutKey*/, + const css::uno::Any& /*Category*/, + const css::uno::Any& NameLocal, + const css::uno::Any& /*RefersToLocal*/, + const css::uno::Any& /*CategoryLocal*/, + const css::uno::Any& RefersToR1C1, + const css::uno::Any& RefersToR1C1Local ) +{ + OUString sName; + uno::Reference< excel::XRange > xRange; + if ( Name.hasValue() ) + Name >>= sName; + else if ( NameLocal.hasValue() ) + NameLocal >>= sName; + if ( !sName.isEmpty() ) + { + if (ScRangeData::IsNameValid(sName, getScDocument()) + != ScRangeData::IsNameValidType::NAME_VALID) + { + const sal_Int32 nIndex{ sName.indexOf('!') }; + if (nIndex>=0) + sName = sName.copy(nIndex+1); + if (ScRangeData::IsNameValid(sName, getScDocument()) + != ScRangeData::IsNameValidType::NAME_VALID) + throw uno::RuntimeException( "This Name is not valid ." ); + } + } + uno::Reference< table::XCellRange > xUnoRange; + if ( RefersTo.hasValue() || RefersToR1C1.hasValue() || RefersToR1C1Local.hasValue() ) + { + OUString sFormula; + + formula::FormulaGrammar::Grammar eGram = formula::FormulaGrammar::GRAM_NATIVE_XL_A1; + if ( RefersTo.hasValue() ) + { + if ( RefersTo.getValueTypeClass() == uno::TypeClass_STRING ) + RefersTo >>= sFormula; + else + RefersTo >>= xRange; + } + if ( RefersToR1C1.hasValue() ) + { + if ( RefersToR1C1.getValueTypeClass() == uno::TypeClass_STRING ) + { + RefersToR1C1 >>= sFormula; + eGram = formula::FormulaGrammar::GRAM_NATIVE_XL_R1C1; + } + else + RefersToR1C1 >>= xRange; + } + if ( RefersToR1C1Local.hasValue() ) + { + if ( RefersToR1C1Local.getValueTypeClass() == uno::TypeClass_STRING ) + { + RefersToR1C1Local >>= sFormula; + eGram = formula::FormulaGrammar::GRAM_NATIVE_XL_R1C1; + } + else + RefersToR1C1Local >>= xRange; + } + if ( !xRange.is() && !sFormula.isEmpty() ) + { + ScAddress aBlank; + ScCompiler aComp( getScDocument(), aBlank, eGram ); + std::unique_ptr<ScTokenArray> pTokens(aComp.CompileString(sFormula)); + if ( pTokens ) + { + ScRange aRange; + ScDocShell* pDocSh = excel::getDocShell(getModel()); + if (pTokens->IsValidReference(aRange, aBlank)) + xUnoRange = new ScCellRangeObj( pDocSh, aRange ); + else + { + // assume it's an address try strip the '=' if it's there + // and try and create a range ( must be a better way ) + if ( sFormula.startsWith("=") ) + sFormula = sFormula.copy(1); + ScRangeList aCellRanges; + ScRefFlags nFlags = ScRefFlags::ZERO; + formula::FormulaGrammar::AddressConvention eConv = ( eGram == formula::FormulaGrammar::GRAM_NATIVE_XL_A1 ) ? formula::FormulaGrammar::CONV_XL_A1 : formula::FormulaGrammar::CONV_XL_R1C1; + if ( ScVbaRange::getCellRangesForAddress( nFlags, sFormula, pDocSh, aCellRanges, eConv , ',' ) ) + { + if ( aCellRanges.size() == 1 ) + xUnoRange = new ScCellRangeObj( pDocSh, aCellRanges.front() ); + else + { + uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( pDocSh, aCellRanges ) ); + xRange = new ScVbaRange( mxParent, mxContext, xRanges ); + } + } + + } + } + } + } + + if ( xRange.is() || xUnoRange.is() ) + { + if ( !xRange.is() ) + xRange = new ScVbaRange( mxParent, mxContext, xUnoRange ); + + uno::Reference< excel::XRange > xArea( xRange->Areas( uno::Any( sal_Int32(1) ) ), uno::UNO_QUERY ); + + uno::Any aAny = xArea->getCellRange() ; + + uno::Reference< sheet::XCellRangeAddressable > thisRangeAdd( aAny, ::uno::UNO_QUERY_THROW); + + table::CellRangeAddress aAddr = thisRangeAdd->getRangeAddress(); + uno::Any aAny2; + if ( mxNames.is() ) + { + table::CellAddress aCellAddr( aAddr.Sheet , aAddr.StartColumn , aAddr.StartRow ); + if ( mxNames->hasByName( sName ) ) + mxNames->removeByName(sName); + OUStringBuffer sTmp = "$"; + uno::Reference< ov::XCollection > xCol( xRange->Areas( uno::Any() ), uno::UNO_QUERY ); + for ( sal_Int32 nArea = 1; nArea <= xCol->getCount(); ++nArea ) + { + xArea.set( xRange->Areas( uno::Any( nArea ) ), uno::UNO_QUERY_THROW ); + + OUString sRangeAdd = xArea->Address( aAny2, aAny2 , aAny2 , aAny2, aAny2 ); + if ( nArea > 1 ) + sTmp.append(","); + sTmp.append("'" + xRange->getWorksheet()->getName() + "'." + sRangeAdd); + } + mxNames->addNewByName( sName, sTmp.makeStringAndClear(), aCellAddr, 0/*nUnoType*/); + return Item( uno::Any( sName ), uno::Any() ); + } + } + return css::uno::Any(); +} + +// XEnumerationAccess +css::uno::Type +ScVbaNames::getElementType() +{ + return cppu::UnoType<ov::excel::XName>::get(); +} + +uno::Reference< container::XEnumeration > +ScVbaNames::createEnumeration() +{ + uno::Reference< container::XEnumerationAccess > xEnumAccess( mxNames, uno::UNO_QUERY_THROW ); + return new NamesEnumeration( getParent(), mxContext, xEnumAccess->createEnumeration(), mxModel , mxNames ); +} + +uno::Any +ScVbaNames::createCollectionObject( const uno::Any& aSource ) +{ + uno::Reference< sheet::XNamedRange > xName( aSource, uno::UNO_QUERY ); + return uno::Any( uno::Reference< excel::XName > ( new ScVbaName( getParent(), mxContext, xName, mxNames , mxModel ) ) ); +} + +OUString +ScVbaNames::getServiceImplName() +{ + return "ScVbaNames"; +} + +css::uno::Sequence<OUString> +ScVbaNames::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.NamedRanges" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbanames.hxx b/sc/source/ui/vba/vbanames.hxx new file mode 100644 index 000000000..96f03d435 --- /dev/null +++ b/sc/source/ui/vba/vbanames.hxx @@ -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 . + */ +#pragma once + +#include <ooo/vba/excel/XNames.hpp> +#include <vbahelper/vbacollectionimpl.hxx> + +namespace com::sun::star::sheet { class XNamedRanges; } + +class ScDocument; + +typedef CollTestImplHelper< ov::excel::XNames > ScVbaNames_BASE; + +class ScVbaNames final : public ScVbaNames_BASE +{ + css::uno::Reference< css::frame::XModel > mxModel; + css::uno::Reference< css::sheet::XNamedRanges > mxNames; + + const css::uno::Reference< css::frame::XModel >& getModel() const { return mxModel; } + +public: + ScVbaNames( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Reference< css::sheet::XNamedRanges >& xNames , const css::uno::Reference< css::frame::XModel >& xModel ); + + ScDocument& getScDocument(); + + virtual ~ScVbaNames() override; + + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + + // Methods + virtual css::uno::Any SAL_CALL Add( const css::uno::Any& aName , + const css::uno::Any& aRefersTo, + const css::uno::Any& aVisible, + const css::uno::Any& aMacroType, + const css::uno::Any& aShoutcutKey, + const css::uno::Any& aCategory, + const css::uno::Any& aNameLocal, + const css::uno::Any& aRefersToLocal, + const css::uno::Any& aCategoryLocal, + const css::uno::Any& aRefersToR1C1, + const css::uno::Any& aRefersToR1C1Local ) override; + + virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override; + + // ScVbaNames_BASE + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaoleobject.cxx b/sc/source/ui/vba/vbaoleobject.cxx new file mode 100644 index 000000000..f2cd5de40 --- /dev/null +++ b/sc/source/ui/vba/vbaoleobject.cxx @@ -0,0 +1,150 @@ +/* -*- 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 <com/sun/star/awt/XControlModel.hpp> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/lang/XMultiComponentFactory.hpp> +#include <ooo/vba/XControlProvider.hpp> + +#include "vbaoleobject.hxx" + +using namespace com::sun::star; +using namespace ooo::vba; + +ScVbaOLEObject::ScVbaOLEObject( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, + css::uno::Reference< css::drawing::XControlShape > const & xControlShape ) +: OLEObjectImpl_BASE( xParent, xContext ) +{ + //init m_xWindowPeer + uno::Reference< awt::XControlModel > xControlModel( xControlShape->getControl(), css::uno::UNO_SET_THROW ); + uno::Reference< container::XChild > xChild( xControlModel, uno::UNO_QUERY_THROW ); + xChild.set( xChild->getParent(), uno::UNO_QUERY_THROW ); + xChild.set( xChild->getParent(), uno::UNO_QUERY_THROW ); + uno::Reference<frame::XModel> xModel( xChild->getParent(), uno::UNO_QUERY_THROW ); + uno::Reference<lang::XMultiComponentFactory > xServiceManager( mxContext->getServiceManager(), uno::UNO_SET_THROW ); + uno::Reference< XControlProvider > xControlProvider( xServiceManager->createInstanceWithContext("ooo.vba.ControlProvider", mxContext ), uno::UNO_QUERY_THROW ); + m_xControl.set( xControlProvider->createControl( xControlShape, xModel ) ); +} + +uno::Reference< uno::XInterface > SAL_CALL +ScVbaOLEObject::getObject() +{ + return uno::Reference< uno::XInterface >( m_xControl, uno::UNO_QUERY_THROW ); +} + +sal_Bool SAL_CALL +ScVbaOLEObject::getEnabled() +{ + return m_xControl->getEnabled(); +} + +void SAL_CALL +ScVbaOLEObject::setEnabled( sal_Bool _enabled ) +{ + m_xControl->setEnabled( _enabled ); +} + +sal_Bool SAL_CALL +ScVbaOLEObject::getVisible() +{ + return m_xControl->getVisible(); +} + +void SAL_CALL +ScVbaOLEObject::setVisible( sal_Bool _visible ) +{ + m_xControl->setVisible( _visible ); +} + +double SAL_CALL +ScVbaOLEObject::getLeft() +{ + return m_xControl->getLeft(); +} + +void SAL_CALL +ScVbaOLEObject::setLeft( double _left ) +{ + m_xControl->setLeft( _left ); + +} + +double SAL_CALL +ScVbaOLEObject::getTop() +{ + return m_xControl->getTop(); +} + +void SAL_CALL +ScVbaOLEObject::setTop( double _top ) +{ + m_xControl->setTop( _top ); +} + +double SAL_CALL +ScVbaOLEObject::getHeight() +{ + return m_xControl->getHeight(); +} + +void SAL_CALL +ScVbaOLEObject::setHeight( double _height ) +{ + m_xControl->setHeight( _height ); +} + +double SAL_CALL +ScVbaOLEObject::getWidth() +{ + return m_xControl->getWidth(); +} + +void SAL_CALL +ScVbaOLEObject::setWidth( double _width ) +{ + m_xControl->setWidth( _width ); +} + +OUString SAL_CALL ScVbaOLEObject::getLinkedCell() +{ + return m_xControl->getControlSource(); +} + +void SAL_CALL ScVbaOLEObject::setLinkedCell( const OUString& _linkedcell ) +{ + m_xControl->setControlSource( _linkedcell ); +} + +OUString +ScVbaOLEObject::getServiceImplName() +{ + return "ScVbaOLEObject"; +} + +uno::Sequence< OUString > +ScVbaOLEObject::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.OLEObject" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaoleobject.hxx b/sc/source/ui/vba/vbaoleobject.hxx new file mode 100644 index 000000000..9eecf5fdc --- /dev/null +++ b/sc/source/ui/vba/vbaoleobject.hxx @@ -0,0 +1,57 @@ +/* -*- 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 . + */ +#pragma once + +#include <com/sun/star/drawing/XControlShape.hpp> +#include <ooo/vba/excel/XOLEObject.hpp> +#include <ooo/vba/msforms/XControl.hpp> + +#include <vbahelper/vbahelperinterface.hxx> + +typedef InheritedHelperInterfaceWeakImpl< ov::excel::XOLEObject > OLEObjectImpl_BASE; + +class ScVbaOLEObject final : public OLEObjectImpl_BASE +{ + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; + css::uno::Reference< ov::msforms::XControl> m_xControl; +public: + ScVbaOLEObject( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext, + css::uno::Reference< css::drawing::XControlShape > const & xControlShape ); + + // XOLEObject Attributes + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getObject() override; + virtual sal_Bool SAL_CALL getEnabled() override; + virtual void SAL_CALL setEnabled( sal_Bool _enabled ) override; + virtual sal_Bool SAL_CALL getVisible() override; + virtual void SAL_CALL setVisible( sal_Bool _visible ) override; + + virtual double SAL_CALL getLeft() override; + virtual void SAL_CALL setLeft( double _left ) override; + virtual double SAL_CALL getTop() override; + virtual void SAL_CALL setTop( double _top ) override; + virtual double SAL_CALL getHeight() override; + virtual void SAL_CALL setHeight( double _height ) override; + virtual double SAL_CALL getWidth() override; + virtual void SAL_CALL setWidth( double _width ) override; + virtual OUString SAL_CALL getLinkedCell() override; + virtual void SAL_CALL setLinkedCell( const OUString& _linkedcell ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaoleobjects.cxx b/sc/source/ui/vba/vbaoleobjects.cxx new file mode 100644 index 000000000..11a8c3934 --- /dev/null +++ b/sc/source/ui/vba/vbaoleobjects.cxx @@ -0,0 +1,184 @@ +/* -*- 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 <com/sun/star/drawing/XControlShape.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <ooo/vba/excel/XOLEObject.hpp> + +#include "vbaoleobject.hxx" +#include "vbaoleobjects.hxx" +#include <cppuhelper/implbase.hxx> + +using namespace com::sun::star; +using namespace ooo::vba; + +typedef ::cppu::WeakImplHelper< container::XIndexAccess > XIndexAccess_BASE; + +namespace { + +class IndexAccessWrapper : public XIndexAccess_BASE +{ +typedef std::vector< uno::Reference< drawing::XControlShape > > OLEObjects; + OLEObjects vObjects; +public: + explicit IndexAccessWrapper( const uno::Reference< container::XIndexAccess >& xIndexAccess ) + { + sal_Int32 nLen = xIndexAccess->getCount(); + for ( sal_Int32 index = 0; index < nLen; ++index ) + { + uno::Reference< drawing::XControlShape > xControlShape( xIndexAccess->getByIndex( index), uno::UNO_QUERY); + if ( xControlShape.is() ) + vObjects.push_back( xControlShape ); + } + } + + virtual ::sal_Int32 SAL_CALL getCount() override + { + return vObjects.size(); + } + + virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override + { + if ( Index < 0 || Index >= getCount() ) + throw lang::IndexOutOfBoundsException(); + return uno::Any( vObjects[ Index ] ); + } + + // Methods XElementAccess + virtual uno::Type SAL_CALL getElementType() override + { + return cppu::UnoType<drawing::XControlShape>::get(); + } + + virtual sal_Bool SAL_CALL hasElements() override + { + return ( getCount() > 0 ); + } + +}; + +class EnumWrapper : public EnumerationHelper_BASE +{ + + uno::Reference<XHelperInterface > m_xParent; + uno::Reference<uno::XComponentContext > m_xContext; + uno::Reference<container::XIndexAccess > m_xIndexAccess; + sal_Int32 nIndex; +public: + EnumWrapper( const uno::Reference< XHelperInterface >& xParent, + const uno::Reference< uno::XComponentContext >& xContext, + const uno::Reference< container::XIndexAccess >& xIndexAccess ) + : m_xParent( xParent ), m_xContext( xContext), m_xIndexAccess( xIndexAccess ), nIndex( 0 ) {} + + virtual sal_Bool SAL_CALL hasMoreElements( ) override + { + return ( nIndex < m_xIndexAccess->getCount() ); + } + + virtual uno::Any SAL_CALL nextElement( ) override + { + if ( nIndex < m_xIndexAccess->getCount() ) + { + uno::Reference< drawing::XControlShape > xControlShape ( m_xIndexAccess->getByIndex( nIndex++ ), uno::UNO_QUERY_THROW ); + return uno::Any( uno::Reference< ov::excel::XOLEObject >( new ScVbaOLEObject( m_xParent, m_xContext, xControlShape ) ) ); + } + throw container::NoSuchElementException(); + } +}; + +uno::Reference< container::XIndexAccess > oleObjectIndexWrapper( const uno::Reference< container::XIndexAccess >& xIndexAccess ) +{ + return new IndexAccessWrapper( xIndexAccess ); +} + +} + +ScVbaOLEObjects::ScVbaOLEObjects( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, + const css::uno::Reference< css::container::XIndexAccess >& xIndexAccess ) + : OLEObjectsImpl_BASE( xParent, xContext, oleObjectIndexWrapper( xIndexAccess ) ) +{ +} +uno::Reference< container::XEnumeration > +ScVbaOLEObjects::createEnumeration() +{ + return new EnumWrapper( getParent(), mxContext, m_xIndexAccess ); +} + +uno::Any +ScVbaOLEObjects::createCollectionObject( const css::uno::Any& aSource ) +{ + if( aSource.hasValue() ) + { + uno::Reference< drawing::XControlShape > xControlShape( aSource, uno::UNO_QUERY_THROW ); + // parent of OLEObject is the same parent as the collection ( e.g. the sheet ) + return uno::Any( uno::Reference< ov::excel::XOLEObject >( new ScVbaOLEObject( getParent(), mxContext, xControlShape ) ) ); + } + return uno::Any(); +} + +uno::Any +ScVbaOLEObjects::getItemByStringIndex( const OUString& sIndex ) +{ + try + { + return OLEObjectsImpl_BASE::getItemByStringIndex( sIndex ); + } + catch (const uno::RuntimeException&) + { + uno::Reference< container::XIndexAccess > xIndexAccess( m_xIndexAccess, uno::UNO_SET_THROW ); + sal_Int32 nCount = xIndexAccess->getCount(); + for( int index = 0; index < nCount; index++ ) + { + uno::Any aUnoObj = xIndexAccess->getByIndex( index ); + uno::Reference< drawing::XControlShape > xControlShape( aUnoObj, uno::UNO_QUERY_THROW ); + uno::Reference< awt::XControlModel > xControlModel( xControlShape->getControl() ); + uno::Reference< container::XNamed > xNamed( xControlModel, uno::UNO_QUERY_THROW ); + if( sIndex == xNamed->getName() ) + { + return createCollectionObject( aUnoObj ); + } + + } + return uno::Any(); + } +} + +uno::Type +ScVbaOLEObjects::getElementType() +{ + return cppu::UnoType<ooo::vba::excel::XOLEObject>::get(); +} + +OUString +ScVbaOLEObjects::getServiceImplName() +{ + return "ScVbaOLEObjects"; +} + +uno::Sequence< OUString > +ScVbaOLEObjects::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.OLEObjects" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaoleobjects.hxx b/sc/source/ui/vba/vbaoleobjects.hxx new file mode 100644 index 000000000..9d4eab048 --- /dev/null +++ b/sc/source/ui/vba/vbaoleobjects.hxx @@ -0,0 +1,47 @@ +/* -*- 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 . + */ +#pragma once + +#include <ooo/vba/excel/XOLEObjects.hpp> + +#include <vbahelper/vbacollectionimpl.hxx> + +typedef CollTestImplHelper<ov::excel::XOLEObjects> OLEObjectsImpl_BASE; + +class ScVbaOLEObjects : public OLEObjectsImpl_BASE +{ +protected: + virtual css::uno::Any getItemByStringIndex(const OUString& sIndex) override; + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; + +public: + ScVbaOLEObjects(const css::uno::Reference<ov::XHelperInterface>& xParent, + const css::uno::Reference<css::uno::XComponentContext>& xContext, + const css::uno::Reference<css::container::XIndexAccess>& xIndexAccess); + + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference<css::container::XEnumeration> SAL_CALL createEnumeration() override; + + // ScVbaCollectionBaseImpl + virtual css::uno::Any createCollectionObject(const css::uno::Any& aSource) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaoutline.cxx b/sc/source/ui/vba/vbaoutline.cxx new file mode 100644 index 000000000..60bc12921 --- /dev/null +++ b/sc/source/ui/vba/vbaoutline.cxx @@ -0,0 +1,58 @@ +/* -*- 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 "vbaoutline.hxx" +#include <com/sun/star/sheet/XSheetOutline.hpp> + +using namespace ::com::sun::star; +using namespace ::ooo::vba; + +void +ScVbaOutline::ShowLevels( const uno::Any& RowLevels, const uno::Any& ColumnLevels ) +{ + if (mxOutline.is()) + { + sal_Int16 nLevel = 0; + if (RowLevels >>= nLevel) + { + mxOutline->showLevel(nLevel, table::TableOrientation_ROWS); + } + if (ColumnLevels >>= nLevel) + { + mxOutline->showLevel(nLevel,table::TableOrientation_COLUMNS); + } + } +} + +OUString +ScVbaOutline::getServiceImplName() +{ + return "ScVbaOutline"; +} + +uno::Sequence< OUString > +ScVbaOutline::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.Outline" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaoutline.hxx b/sc/source/ui/vba/vbaoutline.hxx new file mode 100644 index 000000000..4554083e9 --- /dev/null +++ b/sc/source/ui/vba/vbaoutline.hxx @@ -0,0 +1,43 @@ +/* -*- 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 . + */ +#pragma once + +#include <ooo/vba/excel/XOutline.hpp> +#include <vbahelper/vbahelperinterface.hxx> + +namespace com::sun::star::uno { class XComponentContext; } +namespace com::sun::star::sheet { class XSheetOutline; } + +typedef InheritedHelperInterfaceWeakImpl< ov::excel::XOutline > ScVbaOutline_BASE; + +class ScVbaOutline : public ScVbaOutline_BASE +{ + css::uno::Reference< css::sheet::XSheetOutline > mxOutline; +public: + ScVbaOutline( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext, + css::uno::Reference<css::sheet::XSheetOutline> const & outline): ScVbaOutline_BASE( xParent, xContext) , mxOutline(outline) + {} + + virtual void SAL_CALL ShowLevels( const css::uno::Any& RowLevels, const css::uno::Any& ColumnLevels ) override ; + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaovalshape.cxx b/sc/source/ui/vba/vbaovalshape.cxx new file mode 100644 index 000000000..8efc877ee --- /dev/null +++ b/sc/source/ui/vba/vbaovalshape.cxx @@ -0,0 +1,34 @@ +/* -*- 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 "vbaovalshape.hxx" + +using namespace com::sun::star; +using namespace ooo::vba; + +/* + * This is implemented as a new class in order to provide XTypeProvider + * interface. This is needed by TypeOf ... Is ... basic operator. + */ + +ScVbaOvalShape::ScVbaOvalShape( const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< drawing::XShape >& xShape, const uno::Reference< drawing::XShapes >& xShapes, const uno::Reference< frame::XModel >& xModel ) : OvalShapeImpl_BASE( uno::Reference< XHelperInterface >(), xContext, xShape, xShapes, xModel, ScVbaShape::getType( xShape ) ) +{} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaovalshape.hxx b/sc/source/ui/vba/vbaovalshape.hxx new file mode 100644 index 000000000..1155cd1fc --- /dev/null +++ b/sc/source/ui/vba/vbaovalshape.hxx @@ -0,0 +1,34 @@ +/* -*- 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 . + */ +#pragma once + +#include <ooo/vba/msforms/XOval.hpp> +#include <cppuhelper/implbase.hxx> +#include <vbahelper/vbashape.hxx> + +typedef cppu::ImplInheritanceHelper< ScVbaShape, ov::msforms::XOval > OvalShapeImpl_BASE; + +class ScVbaOvalShape : public OvalShapeImpl_BASE +{ +public: + ScVbaOvalShape( const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Reference< css::drawing::XShape >& xShape, const css::uno::Reference< css::drawing::XShapes >& xShapes, const css::uno::Reference< css::frame::XModel >& xModel ); + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbapagebreak.cxx b/sc/source/ui/vba/vbapagebreak.cxx new file mode 100644 index 000000000..3d9269c72 --- /dev/null +++ b/sc/source/ui/vba/vbapagebreak.cxx @@ -0,0 +1,142 @@ +/* -*- 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 "vbapagebreak.hxx" +#include "vbarange.hxx" +#include <basic/sberrors.hxx> +#include <ooo/vba/excel/XlPageBreak.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/table/XCellRange.hpp> + +using namespace ::com::sun::star; +using namespace ::ooo::vba; + +template< typename... Ifc > +ScVbaPageBreak< Ifc... >::ScVbaPageBreak( const uno::Reference< XHelperInterface >& xParent, + const uno::Reference< uno::XComponentContext >& xContext, + const uno::Reference< beans::XPropertySet >& xProps, + sheet::TablePageBreakData aTablePageBreakData): + ScVbaPageBreak_BASE( xParent, xContext ), + mxRowColPropertySet( xProps ), + maTablePageBreakData( aTablePageBreakData ) +{ +} + +template< typename... Ifc > +sal_Int32 ScVbaPageBreak< Ifc... >::getType() +{ + uno::Any aValue = mxRowColPropertySet->getPropertyValue("IsStartOfNewPage"); + bool hasPageBreak = false; + aValue >>= hasPageBreak; + + if( !hasPageBreak ) + return excel::XlPageBreak::xlPageBreakNone; + + if( maTablePageBreakData.ManualBreak ) + return excel::XlPageBreak::xlPageBreakManual; + + return excel::XlPageBreak::xlPageBreakAutomatic; +} + +template< typename... Ifc > +void ScVbaPageBreak< Ifc... >::setType(sal_Int32 type) +{ + if( (type != excel::XlPageBreak::xlPageBreakNone) && + (type != excel::XlPageBreak::xlPageBreakManual) && + (type != excel::XlPageBreak::xlPageBreakAutomatic) ) + { + DebugHelper::runtimeexception(ERRCODE_BASIC_BAD_PARAMETER); + } + + if( type == excel::XlPageBreak::xlPageBreakNone ) + { + mxRowColPropertySet->setPropertyValue("IsStartOfNewPage", uno::Any(false)); + return; + } + + mxRowColPropertySet->setPropertyValue("IsStartOfNewPage", uno::Any(true)); + if( type == excel::XlPageBreak::xlPageBreakManual ) + maTablePageBreakData.ManualBreak = true; + else + maTablePageBreakData.ManualBreak = false; +} + +template< typename... Ifc > +void ScVbaPageBreak< Ifc... >::Delete() +{ + mxRowColPropertySet->setPropertyValue("IsStartOfNewPage", uno::Any(false)); +} + +template< typename... Ifc > +uno::Reference< excel::XRange> ScVbaPageBreak< Ifc... >::Location() +{ + uno::Reference< table::XCellRange > xRange( mxRowColPropertySet, uno::UNO_QUERY_THROW ); + return new ScVbaRange( ScVbaPageBreak_BASE::getParent(), ScVbaPageBreak_BASE::mxContext, xRange); +} + +template class ScVbaPageBreak< excel::XHPageBreak >; + +/* class ScVbaHPageBreak */ +OUString +ScVbaHPageBreak::getServiceImplName() +{ + return "ScVbaHPageBreak"; +} + +uno::Sequence< OUString > +ScVbaHPageBreak::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.HPageBreak" + }; + return aServiceNames; +} + +template class ScVbaPageBreak< excel::XVPageBreak >; + +/* class ScVbaVPageBreak */ +ScVbaVPageBreak::ScVbaVPageBreak( const css::uno::Reference< ov::XHelperInterface >& xParent, + const css::uno::Reference< css::uno::XComponentContext >& xContext, + const css::uno::Reference< css::beans::XPropertySet >& xProps, + css::sheet::TablePageBreakData aTablePageBreakData ) +: ScVbaVPageBreak_BASE( xParent, xContext, xProps, aTablePageBreakData ) +{ +} + +ScVbaVPageBreak::~ScVbaVPageBreak() +{ +} + +OUString +ScVbaVPageBreak::getServiceImplName() +{ + return "ScVbaVPageBreak"; +} + +uno::Sequence< OUString > +ScVbaVPageBreak::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.VPageBreak" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbapagebreak.hxx b/sc/source/ui/vba/vbapagebreak.hxx new file mode 100644 index 000000000..537258923 --- /dev/null +++ b/sc/source/ui/vba/vbapagebreak.hxx @@ -0,0 +1,87 @@ +/* -*- 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 . + */ +#pragma once + +#include <ooo/vba/excel/XHPageBreak.hpp> +#include <ooo/vba/excel/XVPageBreak.hpp> +#include <com/sun/star/sheet/TablePageBreakData.hpp> +#include <vbahelper/vbahelperinterface.hxx> + +namespace com::sun::star::beans { class XPropertySet; } +namespace com::sun::star::uno { class XComponentContext; } +namespace ooo::vba::excel { class XRange; } + +template< typename... Ifc > +class ScVbaPageBreak : public InheritedHelperInterfaceWeakImpl< Ifc... > +{ +typedef InheritedHelperInterfaceWeakImpl< Ifc... > ScVbaPageBreak_BASE; +protected: + css::uno::Reference< css::beans::XPropertySet > mxRowColPropertySet; + css::sheet::TablePageBreakData maTablePageBreakData; +public: + /// @throws css::uno::RuntimeException + ScVbaPageBreak( const css::uno::Reference< ov::XHelperInterface >& xParent, + const css::uno::Reference< css::uno::XComponentContext >& xContext, + const css::uno::Reference< css::beans::XPropertySet >& xProps, + css::sheet::TablePageBreakData aTablePageBreakData); + + virtual sal_Int32 SAL_CALL getType( ) override; + virtual void SAL_CALL setType(sal_Int32 type) override; + + virtual void SAL_CALL Delete() override; + virtual css::uno::Reference< ov::excel::XRange> SAL_CALL Location() override; +}; + +typedef ScVbaPageBreak < ov::excel::XHPageBreak > ScVbaHPageBreak_BASE; + +class ScVbaHPageBreak : public ScVbaHPageBreak_BASE +{ +public: + /// @throws css::uno::RuntimeException + ScVbaHPageBreak( const css::uno::Reference< ov::XHelperInterface >& xParent, + const css::uno::Reference< css::uno::XComponentContext >& xContext, + const css::uno::Reference< css::beans::XPropertySet >& xProps, + css::sheet::TablePageBreakData aTablePageBreakData): + ScVbaHPageBreak_BASE( xParent,xContext,xProps,aTablePageBreakData ){} + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +//VPageBreak +typedef ScVbaPageBreak < ov::excel::XVPageBreak > ScVbaVPageBreak_BASE; + +class ScVbaVPageBreak : public ScVbaVPageBreak_BASE +{ +public: + /// @throws css::uno::RuntimeException + ScVbaVPageBreak( const css::uno::Reference< ov::XHelperInterface >& xParent, + const css::uno::Reference< css::uno::XComponentContext >& xContext, + const css::uno::Reference< css::beans::XPropertySet >& xProps, + css::sheet::TablePageBreakData aTablePageBreakData); + + virtual ~ScVbaVPageBreak() override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbapagebreaks.cxx b/sc/source/ui/vba/vbapagebreaks.cxx new file mode 100644 index 000000000..36d9f5c7f --- /dev/null +++ b/sc/source/ui/vba/vbapagebreaks.cxx @@ -0,0 +1,322 @@ +/* -*- 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 "vbapagebreaks.hxx" +#include "vbapagebreak.hxx" +#include <basic/sberrors.hxx> +#include <cppuhelper/implbase.hxx> +#include <ooo/vba/excel/XWorksheet.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/sheet/XSheetPageBreak.hpp> +#include <com/sun/star/table/XColumnRowRange.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +using namespace ::com::sun::star; +using namespace ::ooo::vba; + +namespace { + +class RangePageBreaks : public ::cppu::WeakImplHelper<container::XIndexAccess > +{ +private: + uno::Reference< XHelperInterface > mxParent; + uno::Reference< uno::XComponentContext > mxContext; + uno::Reference< sheet::XSheetPageBreak > mxSheetPageBreak; + bool m_bColumn; + +public: + RangePageBreaks( const uno::Reference< XHelperInterface >& xParent, + const uno::Reference< uno::XComponentContext >& xContext, + const uno::Reference< sheet::XSheetPageBreak >& xSheetPageBreak, + bool bColumn ) : mxParent( xParent ), mxContext( xContext ), mxSheetPageBreak( xSheetPageBreak ), m_bColumn( bColumn ) + { + } + + /// @throws css::uno::RuntimeException + sal_Int32 getAPIStartofRange( const uno::Reference< excel::XRange >& xRange ) + { + if( m_bColumn ) + return xRange->getColumn() - 1; + return xRange->getRow() - 1; + } + + /// @throws uno::RuntimeException + sal_Int32 getAPIEndIndexofRange( const uno::Reference< excel::XRange >& xRange, sal_Int32 nUsedStart ) + { + if( m_bColumn ) + return nUsedStart + xRange->Columns( uno::Any() )->getCount() - 1; + return nUsedStart + xRange->Rows( uno::Any() )->getCount(); + } + + /// @throws uno::RuntimeException + uno::Sequence<sheet::TablePageBreakData> getAllPageBreaks() + { + if( m_bColumn ) + return mxSheetPageBreak->getColumnPageBreaks(); + return mxSheetPageBreak->getRowPageBreaks(); + } + + /// @throws uno::RuntimeException + uno::Reference<container::XIndexAccess> getRowColContainer() const + { + uno::Reference< table::XColumnRowRange > xColumnRowRange( mxSheetPageBreak, uno::UNO_QUERY_THROW ); + uno::Reference<container::XIndexAccess> xIndexAccess; + if( m_bColumn ) + xIndexAccess.set( xColumnRowRange->getColumns(), uno::UNO_QUERY_THROW ); + else + xIndexAccess.set( xColumnRowRange->getRows(), uno::UNO_QUERY_THROW ); + return xIndexAccess; + } + + /// @throws uno::RuntimeException + sheet::TablePageBreakData getTablePageBreakData( sal_Int32 nAPIItemIndex ); + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + uno::Any Add( const css::uno::Any& Before ); + + // XIndexAccess + virtual sal_Int32 SAL_CALL getCount( ) override; + virtual uno::Any SAL_CALL getByIndex( sal_Int32 Index ) override; + virtual uno::Type SAL_CALL getElementType( ) override + { + if( m_bColumn ) + return cppu::UnoType<excel::XVPageBreak>::get(); + return cppu::UnoType<excel::XHPageBreak>::get(); + } + virtual sal_Bool SAL_CALL hasElements( ) override + { + return true; + } +}; + +} + +/** @TODO Unlike MS Excel this method only considers the pagebreaks that intersect the used range +* To become completely compatible the print area has to be considered. As far as I found out this printarea +* also considers the position and sizes of shapes and manually inserted page breaks +* Note: In MS there is a limit of 1026 horizontal page breaks per sheet. +*/ +sal_Int32 SAL_CALL RangePageBreaks::getCount( ) +{ + uno::Reference< excel::XWorksheet > xWorksheet( mxParent, uno::UNO_QUERY_THROW ); + uno::Reference< excel::XRange > xRange = xWorksheet->getUsedRange(); + sal_Int32 nUsedStart = getAPIStartofRange( xRange ); + sal_Int32 nUsedEnd = getAPIEndIndexofRange( xRange, nUsedStart ); + const uno::Sequence<sheet::TablePageBreakData> aTablePageBreakData = getAllPageBreaks(); + + auto pPageBreak = std::find_if(aTablePageBreakData.begin(), aTablePageBreakData.end(), + [nUsedEnd](const sheet::TablePageBreakData& rPageBreak) { return rPageBreak.Position > nUsedEnd + 1; }); + + return static_cast<sal_Int32>(std::distance(aTablePageBreakData.begin(), pPageBreak)); +} + +uno::Any SAL_CALL RangePageBreaks::getByIndex( sal_Int32 Index ) +{ + if( (Index < getCount()) && ( Index >= 0 )) + { + sheet::TablePageBreakData aTablePageBreakData = getTablePageBreakData( Index ); + uno::Reference< container::XIndexAccess > xIndexAccess = getRowColContainer(); + sal_Int32 nPos = aTablePageBreakData.Position; + if( (nPos < xIndexAccess->getCount()) && (nPos > -1) ) + { + uno::Reference< beans::XPropertySet > xRowColPropertySet( xIndexAccess->getByIndex(nPos), uno::UNO_QUERY_THROW ); + if( m_bColumn ) + return uno::Any( uno::Reference< excel::XVPageBreak >( new ScVbaVPageBreak( mxParent, mxContext, xRowColPropertySet, aTablePageBreakData) )); + return uno::Any( uno::Reference< excel::XHPageBreak >( new ScVbaHPageBreak( mxParent, mxContext, xRowColPropertySet, aTablePageBreakData) )); + } + } + throw lang::IndexOutOfBoundsException(); +} + +sheet::TablePageBreakData RangePageBreaks::getTablePageBreakData( sal_Int32 nAPIItemIndex ) +{ + sal_Int32 index = -1; + sheet::TablePageBreakData aTablePageBreakData; + uno::Reference< excel::XWorksheet > xWorksheet( mxParent, uno::UNO_QUERY_THROW ); + uno::Reference< excel::XRange > xRange = xWorksheet->getUsedRange(); + sal_Int32 nUsedStart = getAPIStartofRange( xRange ); + sal_Int32 nUsedEnd = getAPIEndIndexofRange( xRange, nUsedStart ); + const uno::Sequence<sheet::TablePageBreakData> aTablePageBreakDataList = getAllPageBreaks(); + + for( const auto& rTablePageBreakData : aTablePageBreakDataList ) + { + aTablePageBreakData = rTablePageBreakData; + sal_Int32 nPos = aTablePageBreakData.Position; + if( nPos > nUsedEnd + 1 ) + DebugHelper::runtimeexception(ERRCODE_BASIC_METHOD_FAILED); + index++; + if( index == nAPIItemIndex ) + return aTablePageBreakData; + } + + return aTablePageBreakData; +} + +uno::Any RangePageBreaks::Add( const css::uno::Any& Before ) +{ + uno::Reference< excel::XRange > xRange; + Before >>= xRange; + if( !xRange.is() ) + { + DebugHelper::basicexception(ERRCODE_BASIC_BAD_ARGUMENT, {}); + } + + sal_Int32 nAPIRowColIndex = getAPIStartofRange( xRange ); + uno::Reference< container::XIndexAccess > xIndexAccess = getRowColContainer(); + uno::Reference< beans::XPropertySet > xRowColPropertySet( xIndexAccess->getByIndex(nAPIRowColIndex), uno::UNO_QUERY_THROW ); + xRowColPropertySet->setPropertyValue("IsStartOfNewPage", uno::Any(true)); + sheet::TablePageBreakData aTablePageBreakData; + aTablePageBreakData.ManualBreak = true; + aTablePageBreakData.Position = nAPIRowColIndex; + if( m_bColumn ) + return uno::Any( uno::Reference< excel::XVPageBreak >( new ScVbaVPageBreak( mxParent, mxContext, xRowColPropertySet, aTablePageBreakData) )); + return uno::Any( uno::Reference< excel::XHPageBreak >( new ScVbaHPageBreak( mxParent, mxContext, xRowColPropertySet, aTablePageBreakData) )); +} + +namespace { + +class RangePageBreaksEnumWrapper : public EnumerationHelper_BASE +{ + uno::Reference<container::XIndexAccess > m_xIndexAccess; + sal_Int32 nIndex; +public: + explicit RangePageBreaksEnumWrapper( const uno::Reference< container::XIndexAccess >& xIndexAccess ) : m_xIndexAccess( xIndexAccess ), nIndex( 0 ) {} + virtual sal_Bool SAL_CALL hasMoreElements( ) override + { + return ( nIndex < m_xIndexAccess->getCount() ); + } + + virtual uno::Any SAL_CALL nextElement( ) override + { + if ( nIndex < m_xIndexAccess->getCount() ) + return m_xIndexAccess->getByIndex( nIndex++ ); + throw container::NoSuchElementException(); + } +}; + +} + +ScVbaHPageBreaks::ScVbaHPageBreaks( const uno::Reference< XHelperInterface >& xParent, + const uno::Reference< uno::XComponentContext >& xContext, + const uno::Reference< sheet::XSheetPageBreak >& xSheetPageBreak): + ScVbaHPageBreaks_BASE( xParent,xContext, new RangePageBreaks( xParent, xContext, xSheetPageBreak, false )) +{ +} + +uno::Any SAL_CALL ScVbaHPageBreaks::Add( const uno::Any& Before) +{ + RangePageBreaks* pPageBreaks = dynamic_cast< RangePageBreaks* >( m_xIndexAccess.get() ); + if( pPageBreaks ) + { + return pPageBreaks->Add( Before ); + } + return uno::Any(); +} + +uno::Reference< container::XEnumeration > +ScVbaHPageBreaks::createEnumeration() +{ + return new RangePageBreaksEnumWrapper( m_xIndexAccess ); +} + +uno::Any +ScVbaHPageBreaks::createCollectionObject( const css::uno::Any& aSource ) +{ + return aSource; // it's already a pagebreak object +} + +uno::Type +ScVbaHPageBreaks::getElementType() +{ + return cppu::UnoType<excel::XHPageBreak>::get(); +} + +OUString +ScVbaHPageBreaks::getServiceImplName() +{ + return "ScVbaHPageBreaks"; +} + +uno::Sequence< OUString > +ScVbaHPageBreaks::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.HPageBreaks" + }; + return aServiceNames; +} + +//VPageBreak +ScVbaVPageBreaks::ScVbaVPageBreaks( const uno::Reference< XHelperInterface >& xParent, + const uno::Reference< uno::XComponentContext >& xContext, + const uno::Reference< sheet::XSheetPageBreak >& xSheetPageBreak ) +: ScVbaVPageBreaks_BASE( xParent, xContext, new RangePageBreaks( xParent, xContext, xSheetPageBreak, true ) ) +{ +} + +ScVbaVPageBreaks::~ScVbaVPageBreaks() +{ +} + +uno::Any SAL_CALL +ScVbaVPageBreaks::Add( const uno::Any& Before ) +{ + RangePageBreaks* pPageBreaks = dynamic_cast< RangePageBreaks* >( m_xIndexAccess.get() ); + if( pPageBreaks ) + { + return pPageBreaks->Add( Before ); + } + return uno::Any(); +} + +uno::Reference< container::XEnumeration > +ScVbaVPageBreaks::createEnumeration() +{ + return new RangePageBreaksEnumWrapper( m_xIndexAccess ); +} + +uno::Any +ScVbaVPageBreaks::createCollectionObject( const css::uno::Any& aSource ) +{ + return aSource; // it's already a pagebreak object +} + +uno::Type +ScVbaVPageBreaks::getElementType() +{ + return cppu::UnoType<excel::XVPageBreak>::get(); +} + +OUString +ScVbaVPageBreaks::getServiceImplName() +{ + return "ScVbaVPageBreaks"; +} + +uno::Sequence< OUString > +ScVbaVPageBreaks::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.VPageBreaks" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbapagebreaks.hxx b/sc/source/ui/vba/vbapagebreaks.hxx new file mode 100644 index 000000000..a04f94145 --- /dev/null +++ b/sc/source/ui/vba/vbapagebreaks.hxx @@ -0,0 +1,83 @@ +/* -*- 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 . + */ +#pragma once + +#include <ooo/vba/excel/XHPageBreaks.hpp> +#include <ooo/vba/excel/XVPageBreaks.hpp> +#include <vbahelper/vbacollectionimpl.hxx> + +namespace com::sun::star::sheet +{ +class XSheetPageBreak; +} +namespace com::sun::star::uno +{ +class XComponentContext; +} + +typedef CollTestImplHelper<ov::excel::XHPageBreaks> ScVbaHPageBreaks_BASE; + +class ScVbaHPageBreaks : public ScVbaHPageBreaks_BASE +{ +public: + /// @throws css::uno::RuntimeException + ScVbaHPageBreaks(const css::uno::Reference<ov::XHelperInterface>& xParent, + const css::uno::Reference<css::uno::XComponentContext>& xContext, + const css::uno::Reference<css::sheet::XSheetPageBreak>& xSheetPageBreak); + + // XHPageBreaks + virtual css::uno::Any SAL_CALL Add(const css::uno::Any& Before) override; + + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference<css::container::XEnumeration> SAL_CALL createEnumeration() override; + virtual css::uno::Any createCollectionObject(const css::uno::Any&) override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +//VPageBreaks +typedef CollTestImplHelper<ov::excel::XVPageBreaks> ScVbaVPageBreaks_BASE; + +class ScVbaVPageBreaks : public ScVbaVPageBreaks_BASE +{ +public: + /// @throws css::uno::RuntimeException + ScVbaVPageBreaks(const css::uno::Reference<ov::XHelperInterface>& xParent, + const css::uno::Reference<css::uno::XComponentContext>& xContext, + const css::uno::Reference<css::sheet::XSheetPageBreak>& xSheetPageBreak); + + virtual ~ScVbaVPageBreaks() override; + + // XVPageBreaks + virtual css::uno::Any SAL_CALL Add(const css::uno::Any& Before) override; + + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference<css::container::XEnumeration> SAL_CALL createEnumeration() override; + virtual css::uno::Any createCollectionObject(const css::uno::Any&) override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbapagesetup.cxx b/sc/source/ui/vba/vbapagesetup.cxx new file mode 100644 index 000000000..7b7b23d16 --- /dev/null +++ b/sc/source/ui/vba/vbapagesetup.cxx @@ -0,0 +1,631 @@ +/* -*- 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 "vbapagesetup.hxx" +#include <convuno.hxx> +#include <rangelst.hxx> +#include <docsh.hxx> +#include "excelvbahelper.hxx" +#include "vbarange.hxx" +#include <com/sun/star/sheet/XPrintAreas.hpp> +#include <com/sun/star/sheet/XHeaderFooterContent.hpp> +#include <com/sun/star/text/XText.hpp> +#include <com/sun/star/style/XStyleFamiliesSupplier.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <ooo/vba/excel/XlPageOrientation.hpp> +#include <ooo/vba/excel/XlOrder.hpp> +#include <ooo/vba/excel/Constants.hpp> +#include <ooo/vba/excel/XlPaperSize.hpp> +#include <basic/sberrors.hxx> +#include <filter/msfilter/util.hxx> + +using namespace ::com::sun::star; +using namespace ::ooo::vba; + +#define ZOOM_IN 10 +#define ZOOM_MAX 400 + +ScVbaPageSetup::ScVbaPageSetup(const uno::Reference< XHelperInterface >& xParent, + const uno::Reference< uno::XComponentContext >& xContext, + const uno::Reference< sheet::XSpreadsheet >& xSheet, + const uno::Reference< frame::XModel >& xModel): + ScVbaPageSetup_BASE( xParent, xContext ), mxSheet( xSheet ), mbIsLandscape( false ) +{ + // query for current page style + mxModel.set( xModel, uno::UNO_SET_THROW ); + uno::Reference< beans::XPropertySet > xSheetProps( mxSheet, uno::UNO_QUERY_THROW ); + uno::Any aValue = xSheetProps->getPropertyValue("PageStyle"); + OUString aStyleName; + aValue >>= aStyleName; + + uno::Reference< style::XStyleFamiliesSupplier > xStyleFamiliesSup( mxModel, uno::UNO_QUERY_THROW ); + uno::Reference< container::XNameAccess > xStyleFamilies = xStyleFamiliesSup->getStyleFamilies(); + uno::Reference< container::XNameAccess > xPageStyle( xStyleFamilies->getByName("PageStyles"), uno::UNO_QUERY_THROW ); + mxPageProps.set( xPageStyle->getByName(aStyleName), uno::UNO_QUERY_THROW ); + mnOrientLandscape = excel::XlPageOrientation::xlLandscape; + mnOrientPortrait = excel::XlPageOrientation::xlPortrait; + mxPageProps->getPropertyValue("IsLandscape") >>= mbIsLandscape; +} + +OUString SAL_CALL ScVbaPageSetup::getPrintArea() +{ + OUString aPrintArea; + uno::Reference< sheet::XPrintAreas > xPrintAreas( mxSheet, uno::UNO_QUERY_THROW ); + const uno::Sequence< table::CellRangeAddress > aSeq = xPrintAreas->getPrintAreas(); + if( aSeq.hasElements() ) + { + ScRangeList aRangeList; + for( const auto& rRange : aSeq ) + { + ScRange aRange; + ScUnoConversion::FillScRange( aRange, rRange ); + aRangeList.push_back( aRange ); + } + ScDocument& rDoc = excel::getDocShell( mxModel )->GetDocument(); + aRangeList.Format( aPrintArea, ScRefFlags::RANGE_ABS, rDoc, formula::FormulaGrammar::CONV_XL_A1, ',' ); + } + + return aPrintArea; +} + +void SAL_CALL ScVbaPageSetup::setPrintArea( const OUString& rAreas ) +{ + uno::Reference< sheet::XPrintAreas > xPrintAreas( mxSheet, uno::UNO_QUERY_THROW ); + if( rAreas.isEmpty() || + rAreas.equalsIgnoreAsciiCase( "FALSE" ) ) + { + // print the whole sheet + uno::Sequence< table::CellRangeAddress > aSeq; + xPrintAreas->setPrintAreas( aSeq ); + } + else + { + ScRangeList aCellRanges; + ScRange aRange; + if( getScRangeListForAddress( rAreas, excel::getDocShell( mxModel ) , aRange, aCellRanges ) ) + { + uno::Sequence< table::CellRangeAddress > aSeq( aCellRanges.size() ); + auto aSeqRange = asNonConstRange(aSeq); + for ( size_t i = 0, nRanges = aCellRanges.size(); i < nRanges; ++i ) + { + ScRange & rRange = aCellRanges[ i ]; + table::CellRangeAddress aRangeAddress; + ScUnoConversion::FillApiRange( aRangeAddress, rRange ); + aSeqRange[ i++ ] = aRangeAddress; + } + xPrintAreas->setPrintAreas( aSeq ); + } + } +} + +double SAL_CALL ScVbaPageSetup::getHeaderMargin() +{ + return VbaPageSetupBase::getHeaderMargin(); +} + +void SAL_CALL ScVbaPageSetup::setHeaderMargin( double margin ) +{ + VbaPageSetupBase::setHeaderMargin( margin ); +} + +double SAL_CALL ScVbaPageSetup::getFooterMargin() +{ + return VbaPageSetupBase::getFooterMargin(); +} + +void SAL_CALL ScVbaPageSetup::setFooterMargin( double margin ) +{ + VbaPageSetupBase::setFooterMargin( margin ); +} + +uno::Any SAL_CALL ScVbaPageSetup::getFitToPagesTall() +{ + return mxPageProps->getPropertyValue("ScaleToPagesY"); +} + +void SAL_CALL ScVbaPageSetup::setFitToPagesTall( const uno::Any& fitToPagesTall) +{ + try + { + sal_uInt16 scaleToPageY = 0; + bool aValue; + if( fitToPagesTall.getValueTypeClass() != uno::TypeClass_BOOLEAN || (fitToPagesTall >>= aValue)) + { + fitToPagesTall >>= scaleToPageY; + } + + mxPageProps->setPropertyValue("ScaleToPagesY", uno::Any( scaleToPageY )); + } + catch( uno::Exception& ) + { + } +} + +uno::Any SAL_CALL ScVbaPageSetup::getFitToPagesWide() +{ + return mxPageProps->getPropertyValue("ScaleToPagesX"); +} + +void SAL_CALL ScVbaPageSetup::setFitToPagesWide( const uno::Any& fitToPagesWide) +{ + try + { + sal_uInt16 scaleToPageX = 0; + bool aValue = false; + if( fitToPagesWide.getValueTypeClass() != uno::TypeClass_BOOLEAN || (fitToPagesWide >>= aValue)) + { + fitToPagesWide >>= scaleToPageX; + } + + mxPageProps->setPropertyValue("ScaleToPagesX", uno::Any( scaleToPageX )); + } + catch( uno::Exception& ) + { + } +} + +uno::Any SAL_CALL ScVbaPageSetup::getZoom() +{ + return mxPageProps->getPropertyValue("PageScale"); +} + +void SAL_CALL ScVbaPageSetup::setZoom( const uno::Any& zoom) +{ + sal_uInt16 pageScale = 0; + try + { + if( zoom.getValueTypeClass() == uno::TypeClass_BOOLEAN ) + { + bool aValue = false; + zoom >>= aValue; + if( aValue ) + { + DebugHelper::runtimeexception(ERRCODE_BASIC_BAD_PARAMETER); + } + } + else + { + zoom >>= pageScale; + if(( pageScale < ZOOM_IN )||( pageScale > ZOOM_MAX )) + { + DebugHelper::runtimeexception(ERRCODE_BASIC_BAD_PARAMETER); + } + } + + // these only exist in S08 + sal_uInt16 nScale = 0; + mxPageProps->setPropertyValue("ScaleToPages", uno::Any( nScale )); + mxPageProps->setPropertyValue("ScaleToPagesX", uno::Any( nScale )); + mxPageProps->setPropertyValue("ScaleToPagesY", uno::Any( nScale )); + } + catch (const beans::UnknownPropertyException&) + { + if( pageScale == 0 ) + { + DebugHelper::runtimeexception(ERRCODE_BASIC_BAD_PARAMETER); + } + } + catch (const uno::Exception&) + { + } + + mxPageProps->setPropertyValue("PageScale", uno::Any( pageScale )); +} + +OUString SAL_CALL ScVbaPageSetup::getLeftHeader() +{ + OUString leftHeader; + try + { + uno::Reference<sheet::XHeaderFooterContent> xHeaderContent( mxPageProps->getPropertyValue("RightPageHeaderContent"), uno::UNO_QUERY_THROW); + uno::Reference< text::XText > xText = xHeaderContent->getLeftText(); + leftHeader = xText->getString(); + } + catch( uno::Exception& ) + { + } + + return leftHeader; +} + +void SAL_CALL ScVbaPageSetup::setLeftHeader( const OUString& leftHeader) +{ + try + { + uno::Reference<sheet::XHeaderFooterContent> xHeaderContent( mxPageProps->getPropertyValue("RightPageHeaderContent"), uno::UNO_QUERY_THROW); + uno::Reference< text::XText > xText = xHeaderContent->getLeftText(); + xText->setString( leftHeader ); + mxPageProps->setPropertyValue("RightPageHeaderContent", uno::Any(xHeaderContent) ); + } + catch( uno::Exception& ) + { + } +} + +OUString SAL_CALL ScVbaPageSetup::getCenterHeader() +{ + OUString centerHeader; + try + { + uno::Reference<sheet::XHeaderFooterContent> xHeaderContent( mxPageProps->getPropertyValue("RightPageHeaderContent"), uno::UNO_QUERY_THROW); + uno::Reference< text::XText > xText = xHeaderContent->getCenterText(); + centerHeader = xText->getString(); + } + catch( uno::Exception& ) + { + } + + return centerHeader; +} + +void SAL_CALL ScVbaPageSetup::setCenterHeader( const OUString& centerHeader) +{ + try + { + uno::Reference<sheet::XHeaderFooterContent> xHeaderContent( mxPageProps->getPropertyValue("RightPageHeaderContent"), uno::UNO_QUERY_THROW); + uno::Reference< text::XText > xText = xHeaderContent->getCenterText(); + xText->setString( centerHeader ); + mxPageProps->setPropertyValue("RightPageHeaderContent", uno::Any(xHeaderContent) ); + } + catch( uno::Exception& ) + { + } +} + +OUString SAL_CALL ScVbaPageSetup::getRightHeader() +{ + OUString rightHeader; + try + { + uno::Reference<sheet::XHeaderFooterContent> xHeaderContent( mxPageProps->getPropertyValue("RightPageHeaderContent"), uno::UNO_QUERY_THROW); + uno::Reference< text::XText > xText = xHeaderContent->getRightText(); + rightHeader = xText->getString(); + } + catch( uno::Exception& ) + { + } + + return rightHeader; +} + +void SAL_CALL ScVbaPageSetup::setRightHeader( const OUString& rightHeader) +{ + try + { + uno::Reference<sheet::XHeaderFooterContent> xHeaderContent( mxPageProps->getPropertyValue("RightPageHeaderContent"), uno::UNO_QUERY_THROW); + uno::Reference< text::XText > xText = xHeaderContent->getRightText(); + xText->setString( rightHeader ); + mxPageProps->setPropertyValue("RightPageHeaderContent", uno::Any(xHeaderContent) ); + } + catch( uno::Exception& ) + { + } +} + +OUString SAL_CALL ScVbaPageSetup::getLeftFooter() +{ + OUString leftFooter; + try + { + uno::Reference<sheet::XHeaderFooterContent> xFooterContent( mxPageProps->getPropertyValue("RightPageFooterContent"), uno::UNO_QUERY_THROW); + uno::Reference< text::XText > xText = xFooterContent->getLeftText(); + leftFooter = xText->getString(); + } + catch( uno::Exception& ) + { + } + + return leftFooter; +} + +void SAL_CALL ScVbaPageSetup::setLeftFooter( const OUString& leftFooter) +{ + try + { + uno::Reference<sheet::XHeaderFooterContent> xFooterContent( mxPageProps->getPropertyValue("RightPageFooterContent"), uno::UNO_QUERY_THROW); + uno::Reference< text::XText > xText = xFooterContent->getLeftText(); + xText->setString( leftFooter ); + mxPageProps->setPropertyValue("RightPageFooterContent", uno::Any(xFooterContent) ); + } + catch( uno::Exception& ) + { + } +} + +OUString SAL_CALL ScVbaPageSetup::getCenterFooter() +{ + OUString centerFooter; + try + { + uno::Reference<sheet::XHeaderFooterContent> xFooterContent( mxPageProps->getPropertyValue("RightPageFooterContent"), uno::UNO_QUERY_THROW); + uno::Reference< text::XText > xText = xFooterContent->getCenterText(); + centerFooter = xText->getString(); + } + catch( uno::Exception& ) + { + } + + return centerFooter; +} + +void SAL_CALL ScVbaPageSetup::setCenterFooter( const OUString& centerFooter) +{ + try + { + uno::Reference<sheet::XHeaderFooterContent> xFooterContent( mxPageProps->getPropertyValue("RightPageFooterContent"), uno::UNO_QUERY_THROW); + uno::Reference< text::XText > xText = xFooterContent->getCenterText(); + xText->setString( centerFooter ); + mxPageProps->setPropertyValue("RightPageFooterContent", uno::Any(xFooterContent) ); + } + catch( uno::Exception& ) + { + } + +} + +OUString SAL_CALL ScVbaPageSetup::getRightFooter() +{ + OUString rightFooter; + try + { + uno::Reference<sheet::XHeaderFooterContent> xFooterContent( mxPageProps->getPropertyValue("RightPageFooterContent"), uno::UNO_QUERY_THROW); + uno::Reference< text::XText > xText = xFooterContent->getRightText(); + rightFooter = xText->getString(); + } + catch( uno::Exception& ) + { + } + + return rightFooter; +} + +void SAL_CALL ScVbaPageSetup::setRightFooter( const OUString& rightFooter) +{ + try + { + uno::Reference<sheet::XHeaderFooterContent> xFooterContent( mxPageProps->getPropertyValue("RightPageFooterContent"), uno::UNO_QUERY_THROW); + uno::Reference< text::XText > xText = xFooterContent->getRightText(); + xText->setString( rightFooter ); + mxPageProps->setPropertyValue("RightPageFooterContent", uno::Any(xFooterContent) ); + } + catch( uno::Exception& ) + { + } +} + +sal_Int32 SAL_CALL ScVbaPageSetup::getOrder() +{ + sal_Int32 order = excel::XlOrder::xlDownThenOver; + try + { + uno::Any aValue = mxPageProps->getPropertyValue("PrintDownFirst"); + bool bPrintDownFirst = false; + aValue >>= bPrintDownFirst; + if( !bPrintDownFirst ) + order = excel::XlOrder::xlOverThenDown; + } + catch( uno::Exception& ) + { + } + + return order; +} + +void SAL_CALL ScVbaPageSetup::setOrder(sal_Int32 order) +{ + bool bOrder = true; + switch( order ) + { + case excel::XlOrder::xlDownThenOver: + break; + case excel::XlOrder::xlOverThenDown: + bOrder = false; + break; + default: + DebugHelper::runtimeexception(ERRCODE_BASIC_BAD_PARAMETER); + } + + try + { + mxPageProps->setPropertyValue("PrintDownFirst", uno::Any( bOrder )); + } + catch (const uno::Exception&) + { + } +} + +sal_Int32 SAL_CALL ScVbaPageSetup::getFirstPageNumber() +{ + sal_Int16 number = 0; + try + { + uno::Any aValue = mxPageProps->getPropertyValue("FirstPageNumber"); + aValue >>= number; + } + catch( uno::Exception& ) + { + } + + if( number ==0 ) + { + number = excel::Constants::xlAutomatic; + } + + return number; +} + +void SAL_CALL ScVbaPageSetup::setFirstPageNumber( sal_Int32 firstPageNumber) +{ + if( firstPageNumber == excel::Constants::xlAutomatic ) + firstPageNumber = 0; + + try + { + uno::Any aValue; + aValue <<= static_cast<sal_Int16>(firstPageNumber); + mxPageProps->setPropertyValue("FirstPageNumber", aValue ); + } + catch (const uno::Exception&) + { + } +} + +sal_Bool SAL_CALL ScVbaPageSetup::getCenterVertically() +{ + bool centerVertically = false; + try + { + uno::Any aValue = mxPageProps->getPropertyValue("CenterVertically"); + aValue >>= centerVertically; + } + catch (const uno::Exception&) + { + } + return centerVertically; +} + +void SAL_CALL ScVbaPageSetup::setCenterVertically( sal_Bool centerVertically) +{ + try + { + mxPageProps->setPropertyValue("CenterVertically", uno::Any( centerVertically )); + } + catch (const uno::Exception&) + { + } +} + +sal_Bool SAL_CALL ScVbaPageSetup::getCenterHorizontally() +{ + bool centerHorizontally = false; + try + { + uno::Any aValue = mxPageProps->getPropertyValue("CenterHorizontally"); + aValue >>= centerHorizontally; + } + catch (const uno::Exception&) + { + } + return centerHorizontally; +} + +void SAL_CALL ScVbaPageSetup::setCenterHorizontally( sal_Bool centerHorizontally) +{ + try + { + mxPageProps->setPropertyValue("CenterHorizontally", uno::Any( centerHorizontally )); + } + catch (const uno::Exception&) + { + } +} + +sal_Bool SAL_CALL ScVbaPageSetup::getPrintHeadings() +{ + bool printHeadings = false; + try + { + uno::Any aValue = mxPageProps->getPropertyValue("PrintHeaders"); + aValue >>= printHeadings; + } + catch (const uno::Exception&) + { + } + return printHeadings; +} + +void SAL_CALL ScVbaPageSetup::setPrintHeadings( sal_Bool printHeadings) +{ + try + { + mxPageProps->setPropertyValue("PrintHeaders", uno::Any( printHeadings )); + } + catch( uno::Exception& ) + { + } +} + +sal_Bool SAL_CALL ScVbaPageSetup::getPrintGridlines() +{ + return false; +} + +void SAL_CALL ScVbaPageSetup::setPrintGridlines( sal_Bool /*_printgridlines*/ ) +{ +} + +OUString SAL_CALL ScVbaPageSetup::getPrintTitleRows() +{ + return OUString(); +} +void SAL_CALL ScVbaPageSetup::setPrintTitleRows( const OUString& /*_printtitlerows*/ ) +{ +} +OUString SAL_CALL ScVbaPageSetup::getPrintTitleColumns() +{ + return OUString(); +} + +void SAL_CALL ScVbaPageSetup::setPrintTitleColumns( const OUString& /*_printtitlecolumns*/ ) +{ +} + +sal_Int32 SAL_CALL ScVbaPageSetup::getPaperSize() +{ + awt::Size aSize; // current papersize + mxPageProps->getPropertyValue( "Size" ) >>= aSize; + if ( mbIsLandscape ) + ::std::swap( aSize.Width, aSize.Height ); + + sal_Int32 nPaperSizeIndex = msfilter::util::PaperSizeConv::getMSPaperSizeIndex( aSize ); + if ( nPaperSizeIndex == 0 ) + nPaperSizeIndex = excel::XlPaperSize::xlPaperUser; + return nPaperSizeIndex; +} + +void SAL_CALL ScVbaPageSetup::setPaperSize( sal_Int32 papersize ) +{ + if ( papersize != excel::XlPaperSize::xlPaperUser ) + { + awt::Size aPaperSize; + const msfilter::util::ApiPaperSize& rConvertedSize = msfilter::util::PaperSizeConv::getApiSizeForMSPaperSizeIndex( papersize ); + aPaperSize.Height = rConvertedSize.mnHeight; + aPaperSize.Width = rConvertedSize.mnWidth; + if ( mbIsLandscape ) + ::std::swap( aPaperSize.Width, aPaperSize.Height ); + mxPageProps->setPropertyValue( "Size", uno::Any( aPaperSize ) ); + } +} + +OUString +ScVbaPageSetup::getServiceImplName() +{ + return "ScVbaPageSetup"; +} + +uno::Sequence< OUString > +ScVbaPageSetup::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.PageSetup" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbapagesetup.hxx b/sc/source/ui/vba/vbapagesetup.hxx new file mode 100644 index 000000000..75e3ed1d3 --- /dev/null +++ b/sc/source/ui/vba/vbapagesetup.hxx @@ -0,0 +1,90 @@ +/* -*- 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 . + */ +#pragma once + +#include <cppuhelper/implbase.hxx> +#include <ooo/vba/excel/XPageSetup.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/sheet/XSpreadsheet.hpp> +#include <vbahelper/vbapagesetupbase.hxx> + +typedef cppu::ImplInheritanceHelper<VbaPageSetupBase, ov::excel::XPageSetup> ScVbaPageSetup_BASE; + +class ScVbaPageSetup : public ScVbaPageSetup_BASE +{ + css::uno::Reference<css::sheet::XSpreadsheet> mxSheet; + bool mbIsLandscape; + +public: + /// @throws css::uno::RuntimeException + ScVbaPageSetup(const css::uno::Reference<ov::XHelperInterface>& xParent, + const css::uno::Reference<css::uno::XComponentContext>& xContext, + const css::uno::Reference<css::sheet::XSpreadsheet>& xSheet, + const css::uno::Reference<css::frame::XModel>& xModel); + + // Attribute + virtual OUString SAL_CALL getPrintArea() override; + virtual void SAL_CALL setPrintArea(const OUString& rAreas) override; + virtual double SAL_CALL getHeaderMargin() override; + void SAL_CALL setHeaderMargin(double margin) override; + double SAL_CALL getFooterMargin() override; + void SAL_CALL setFooterMargin(double margin) override; + virtual css::uno::Any SAL_CALL getFitToPagesTall() override; + virtual void SAL_CALL setFitToPagesTall(const css::uno::Any& fitToPagesTall) override; + virtual css::uno::Any SAL_CALL getFitToPagesWide() override; + virtual void SAL_CALL setFitToPagesWide(const css::uno::Any& fitToPagesWide) override; + virtual css::uno::Any SAL_CALL getZoom() override; + virtual void SAL_CALL setZoom(const css::uno::Any& zoom) override; + virtual OUString SAL_CALL getLeftHeader() override; + virtual void SAL_CALL setLeftHeader(const OUString& leftHeader) override; + virtual OUString SAL_CALL getCenterHeader() override; + virtual void SAL_CALL setCenterHeader(const OUString& centerHeader) override; + virtual OUString SAL_CALL getRightHeader() override; + virtual void SAL_CALL setRightHeader(const OUString& rightHeader) override; + virtual OUString SAL_CALL getLeftFooter() override; + virtual void SAL_CALL setLeftFooter(const OUString& leftFooter) override; + virtual OUString SAL_CALL getCenterFooter() override; + virtual void SAL_CALL setCenterFooter(const OUString& centerFooter) override; + virtual OUString SAL_CALL getRightFooter() override; + virtual void SAL_CALL setRightFooter(const OUString& rightFooter) override; + virtual sal_Int32 SAL_CALL getOrder() override; + virtual void SAL_CALL setOrder(sal_Int32 order) override; + virtual sal_Int32 SAL_CALL getFirstPageNumber() override; + virtual void SAL_CALL setFirstPageNumber(sal_Int32 firstPageNumber) override; + virtual sal_Bool SAL_CALL getCenterVertically() override; + virtual void SAL_CALL setCenterVertically(sal_Bool centerVertically) override; + virtual sal_Bool SAL_CALL getCenterHorizontally() override; + virtual void SAL_CALL setCenterHorizontally(sal_Bool centerHorizontally) override; + virtual sal_Bool SAL_CALL getPrintHeadings() override; + virtual void SAL_CALL setPrintHeadings(sal_Bool printHeadings) override; + + virtual sal_Bool SAL_CALL getPrintGridlines() override; + virtual void SAL_CALL setPrintGridlines(sal_Bool _printgridlines) override; + virtual OUString SAL_CALL getPrintTitleRows() override; + virtual void SAL_CALL setPrintTitleRows(const OUString& _printtitlerows) override; + virtual OUString SAL_CALL getPrintTitleColumns() override; + virtual void SAL_CALL setPrintTitleColumns(const OUString& _printtitlecolumns) override; + virtual sal_Int32 SAL_CALL getPaperSize() override; + virtual void SAL_CALL setPaperSize(sal_Int32 papersize) override; + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbapalette.cxx b/sc/source/ui/vba/vbapalette.cxx new file mode 100644 index 000000000..81caebab6 --- /dev/null +++ b/sc/source/ui/vba/vbapalette.cxx @@ -0,0 +1,115 @@ +/* -*- 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 "vbapalette.hxx" + +#include <sal/macros.h> +#include <cppuhelper/implbase.hxx> +#include <sfx2/objsh.hxx> +#include <docsh.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include "excelvbahelper.hxx" + +using namespace ::com::sun::star; +using namespace ::ooo::vba; + +/** Standard EGA colors, bright. */ +#define EXC_PALETTE_EGA_COLORS_LIGHT \ + Color(0x000000), Color(0xFFFFFF), Color(0xFF0000), Color(0x00FF00), Color(0x0000FF), Color(0xFFFF00), Color(0xFF00FF), Color(0x00FFFF) +/** Standard EGA colors), dark. */ +#define EXC_PALETTE_EGA_COLORS_DARK \ + Color(0x800000), Color(0x008000), Color(0x000080), Color(0x808000), Color(0x800080), Color(0x008080), Color(0xC0C0C0), Color(0x808080) + +const Color spnDefColorTable8[] = +{ +/* 8 */ EXC_PALETTE_EGA_COLORS_LIGHT, +/* 16 */ EXC_PALETTE_EGA_COLORS_DARK, +/* 24 */ Color(0x9999FF), Color(0x993366), Color(0xFFFFCC), Color(0xCCFFFF), Color(0x660066), Color(0xFF8080), Color(0x0066CC), Color(0xCCCCFF), +/* 32 */ Color(0x000080), Color(0xFF00FF), Color(0xFFFF00), Color(0x00FFFF), Color(0x800080), Color(0x800000), Color(0x008080), Color(0x0000FF), +/* 40 */ Color(0x00CCFF), Color(0xCCFFFF), Color(0xCCFFCC), Color(0xFFFF99), Color(0x99CCFF), Color(0xFF99CC), Color(0xCC99FF), Color(0xFFCC99), +/* 48 */ Color(0x3366FF), Color(0x33CCCC), Color(0x99CC00), Color(0xFFCC00), Color(0xFF9900), Color(0xFF6600), Color(0x666699), Color(0x969696), +/* 56 */ Color(0x003366), Color(0x339966), Color(0x003300), Color(0x333300), Color(0x993300), Color(0x993366), Color(0x333399), Color(0x333333) +}; + +typedef ::cppu::WeakImplHelper< container::XIndexAccess > XIndexAccess_BASE; + +namespace { + +class DefaultPalette : public XIndexAccess_BASE +{ +public: + DefaultPalette(){} + + // Methods XIndexAccess + virtual ::sal_Int32 SAL_CALL getCount() override + { + return SAL_N_ELEMENTS(spnDefColorTable8); + } + + virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override + { + if ( Index < 0 || Index >= getCount() ) + throw lang::IndexOutOfBoundsException(); + return uno::Any( sal_Int32( spnDefColorTable8[ Index ] ) ); + } + + // Methods XElementAccess + virtual uno::Type SAL_CALL getElementType() override + { + return ::cppu::UnoType<sal_Int32>::get(); + } + virtual sal_Bool SAL_CALL hasElements() override + { + return true; + } + +}; + +} + +ScVbaPalette::ScVbaPalette( const uno::Reference< frame::XModel >& rxModel ) : + m_pShell( excel::getDocShell( rxModel ) ) +{ +} + +uno::Reference< container::XIndexAccess > +ScVbaPalette::getDefaultPalette() +{ + return new DefaultPalette(); +} + +uno::Reference< container::XIndexAccess > +ScVbaPalette::getPalette() const +{ + uno::Reference< container::XIndexAccess > xIndex; + uno::Reference< beans::XPropertySet > xProps; + if ( !m_pShell ) + throw uno::RuntimeException("Can't extract palette, no doc shell" ); + + xProps.set( m_pShell->GetModel(), uno::UNO_QUERY_THROW ); + + xIndex.set( xProps->getPropertyValue("ColorPalette"), uno::UNO_QUERY ); + if ( !xIndex.is() ) + return new DefaultPalette(); + return xIndex; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbapalette.hxx b/sc/source/ui/vba/vbapalette.hxx new file mode 100644 index 000000000..cc0d66f3c --- /dev/null +++ b/sc/source/ui/vba/vbapalette.hxx @@ -0,0 +1,44 @@ +/* -*- 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 . + */ + +#pragma once + +#include <com/sun/star/uno/Reference.hxx> + +namespace com::sun::star { + namespace container { class XIndexAccess; } + namespace frame { class XModel; } +} + +class SfxObjectShell; + +class ScVbaPalette +{ +private: + SfxObjectShell* m_pShell; +public: + explicit ScVbaPalette( SfxObjectShell* pShell ) : m_pShell( pShell ) {} + explicit ScVbaPalette( const css::uno::Reference< css::frame::XModel >& rxModel ); + // if no palette available e.g. because the document doesn't have a + // palette defined then a default palette will be returned. + css::uno::Reference< css::container::XIndexAccess > getPalette() const; + static css::uno::Reference< css::container::XIndexAccess > getDefaultPalette(); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbapane.cxx b/sc/source/ui/vba/vbapane.cxx new file mode 100644 index 000000000..1f7f0b540 --- /dev/null +++ b/sc/source/ui/vba/vbapane.cxx @@ -0,0 +1,196 @@ +/* -*- 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 "vbapane.hxx" +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/sheet/XSpreadsheet.hpp> +#include <com/sun/star/sheet/XSpreadsheetDocument.hpp> +#include <com/sun/star/table/CellRangeAddress.hpp> +#include "vbarange.hxx" + +using namespace com::sun::star; +using namespace ooo::vba; + +ScVbaPane::ScVbaPane( + const css::uno::Reference< ov::XHelperInterface >& xParent, + const uno::Reference< uno::XComponentContext >& xContext, + const uno::Reference< frame::XModel >& rModel, + const uno::Reference< sheet::XViewPane >& rViewPane ) : + m_xModel(rModel, uno::UNO_SET_THROW), + m_xViewPane(rViewPane, uno::UNO_SET_THROW), + m_xParent(xParent), + m_xContext(xContext) +{ +} + +sal_Int32 SAL_CALL +ScVbaPane::getScrollColumn() +{ + return ( m_xViewPane->getFirstVisibleColumn() + 1 ); +} + +void SAL_CALL +ScVbaPane::setScrollColumn( sal_Int32 _scrollcolumn ) +{ + if( _scrollcolumn < 1 ) + { + throw uno::RuntimeException("Column number should not be less than 1" ); + } + m_xViewPane->setFirstVisibleColumn( _scrollcolumn - 1 ); +} + +sal_Int32 SAL_CALL +ScVbaPane::getScrollRow() +{ + return ( m_xViewPane->getFirstVisibleRow() + 1 ); +} + +void SAL_CALL +ScVbaPane::setScrollRow( sal_Int32 _scrollrow ) +{ + if( _scrollrow < 1 ) + { + throw uno::RuntimeException("Row number should not be less than 1" ); + } + m_xViewPane->setFirstVisibleRow( _scrollrow - 1 ); +} + +uno::Reference< excel::XRange > SAL_CALL +ScVbaPane::getVisibleRange() +{ + // TODO: Excel includes partly visible rows/columns, Calc does not + table::CellRangeAddress aRangeAddr = m_xViewPane->getVisibleRange(); + uno::Reference< sheet::XSpreadsheetDocument > xDoc( m_xModel, uno::UNO_QUERY_THROW ); + uno::Reference< container::XIndexAccess > xSheetsIA( xDoc->getSheets(), uno::UNO_QUERY_THROW ); + uno::Reference< sheet::XSpreadsheet > xSheet( xSheetsIA->getByIndex( aRangeAddr.Sheet ), uno::UNO_QUERY_THROW ); + uno::Reference< table::XCellRange > xRange( xSheet->getCellRangeByPosition( aRangeAddr.StartColumn, aRangeAddr.StartRow, aRangeAddr.EndColumn, aRangeAddr.EndRow ), uno::UNO_SET_THROW ); + // TODO: m_xParent is the window, Range needs the worksheet + return new ScVbaRange( m_xParent, m_xContext, xRange ); +} + +//Method +void SAL_CALL +ScVbaPane::SmallScroll( const uno::Any& Down, const uno::Any& Up, const uno::Any& ToRight, const uno::Any& ToLeft ) +{ + OUString messageBuffer; + sal_Int32 downRows = 0; + sal_Int32 rightCols = 0; + table::CellRangeAddress visibleRange = m_xViewPane->getVisibleRange(); + + if( Down.hasValue() ) + { + sal_Int32 down = 0; + if( Down >>= down ) + downRows += down; + else + messageBuffer += "Error getting parameter: Down\n"; + } + if( Up.hasValue() ) + { + sal_Int32 up = 0; + if( Up >>= up ) + downRows -= up; + else + messageBuffer += "Error getting parameter: Up\n"; + } + if( ToRight.hasValue() ) + { + sal_Int32 right = 0; + if( ToRight >>= right ) + rightCols += right; + else + messageBuffer += "Error getting parameter: ToRight\n"; + } + if( ToLeft.hasValue() ) + { + sal_Int32 left = 0; + if( ToLeft >>= left ) + rightCols -= left; + else + messageBuffer += "Error getting parameter: ToLeft\n"; + } + if( !messageBuffer.isEmpty() ) + throw uno::RuntimeException( messageBuffer ); + + sal_Int32 newStartRow = visibleRange.StartRow + downRows; + if( newStartRow < 0 ) + newStartRow = 0; + sal_Int32 newStartCol = visibleRange.StartColumn + rightCols; + if( newStartCol < 0 ) + newStartCol = 0; + m_xViewPane->setFirstVisibleRow( newStartRow ); + m_xViewPane->setFirstVisibleColumn( newStartCol ); +} + +void SAL_CALL +ScVbaPane::LargeScroll( const uno::Any& Down, const uno::Any& Up, const uno::Any& ToRight, const uno::Any& ToLeft ) +{ + OUString messageBuffer; + table::CellRangeAddress visibleRange = m_xViewPane->getVisibleRange(); + + sal_Int32 vertPageSize = 1 + visibleRange.EndRow - visibleRange.StartRow; + sal_Int32 horizPageSize = 1 + visibleRange.EndColumn - visibleRange.StartColumn; + sal_Int32 downPages = 0; + sal_Int32 acrossPages = 0; + if( Down.hasValue() ) + { + sal_Int32 down = 0; + if( Down >>= down ) + downPages += down; + else + messageBuffer += "Error getting parameter: Down\n"; + } + if( Up.hasValue() ) + { + sal_Int32 up = 0; + if( Up >>= up ) + downPages -= up; + else + messageBuffer += "Error getting parameter: Up\n"; + } + if( ToRight.hasValue() ) + { + sal_Int32 right = 0; + if( ToRight >>= right ) + acrossPages += right; + else + messageBuffer += "Error getting parameter: ToRight\n"; + } + if( ToLeft.hasValue() ) + { + sal_Int32 left = 0; + if( ToLeft >>= left ) + acrossPages -= left; + else + messageBuffer += "Error getting parameter: ToLeft\n"; + } + if( !messageBuffer.isEmpty() ) + throw uno::RuntimeException( messageBuffer ); + + sal_Int32 newStartRow = visibleRange.StartRow + (downPages * vertPageSize ); + if( newStartRow < 0 ) + newStartRow = 0; + sal_Int32 newStartCol = visibleRange.StartColumn + (acrossPages * horizPageSize ); + if( newStartCol < 0 ) + newStartCol = 0; + m_xViewPane->setFirstVisibleRow( newStartRow ); + m_xViewPane->setFirstVisibleColumn( newStartCol ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbapane.hxx b/sc/source/ui/vba/vbapane.hxx new file mode 100644 index 000000000..cf4fd8328 --- /dev/null +++ b/sc/source/ui/vba/vbapane.hxx @@ -0,0 +1,55 @@ +/* -*- 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 . + */ +#pragma once + +#include <com/sun/star/sheet/XViewPane.hpp> +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/weakref.hxx> +#include <ooo/vba/excel/XPane.hpp> +#include <vbahelper/vbahelper.hxx> + +class ScVbaPane final : public cppu::WeakImplHelper< ov::excel::XPane > +{ +public: + /// @throws css::uno::RuntimeException + ScVbaPane( + const css::uno::Reference< ov::XHelperInterface >& rParent, + const css::uno::Reference< css::uno::XComponentContext >& rContext, + const css::uno::Reference< css::frame::XModel >& rModel, + const css::uno::Reference< css::sheet::XViewPane >& rViewPane ); + + // XPane attributes + virtual sal_Int32 SAL_CALL getScrollColumn() override; + virtual void SAL_CALL setScrollColumn( sal_Int32 _scrollcolumn ) override; + virtual sal_Int32 SAL_CALL getScrollRow() override; + virtual void SAL_CALL setScrollRow( sal_Int32 _scrollrow ) override; + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL getVisibleRange() override; + + // XPane methods + virtual void SAL_CALL SmallScroll( const css::uno::Any& Down, const css::uno::Any& Up, const css::uno::Any& ToRight, const css::uno::Any& ToLeft ) override; + virtual void SAL_CALL LargeScroll( const css::uno::Any& Down, const css::uno::Any& Up, const css::uno::Any& ToRight, const css::uno::Any& ToLeft ) override; + +private: + css::uno::Reference< css::frame::XModel > m_xModel; + css::uno::Reference< css::sheet::XViewPane > m_xViewPane; + css::uno::WeakReference< ov::XHelperInterface > m_xParent; + css::uno::Reference< css::uno::XComponentContext > m_xContext; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbapivotcache.cxx b/sc/source/ui/vba/vbapivotcache.cxx new file mode 100644 index 000000000..54c6a4ad7 --- /dev/null +++ b/sc/source/ui/vba/vbapivotcache.cxx @@ -0,0 +1,50 @@ +/* -*- 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 "vbapivotcache.hxx" + +using namespace ::com::sun::star; +using namespace ::ooo::vba; + +ScVbaPivotCache::ScVbaPivotCache( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< sheet::XDataPilotTable >& xTable ) : PivotCacheImpl_BASE( xParent, xContext ), m_xTable( xTable ) +{ +} + +void SAL_CALL +ScVbaPivotCache::Refresh() +{ + m_xTable->refresh(); +} + +OUString +ScVbaPivotCache::getServiceImplName() +{ + return "ScVbaPivotCache"; +} + +uno::Sequence< OUString > +ScVbaPivotCache::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.PivotCache" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbapivotcache.hxx b/sc/source/ui/vba/vbapivotcache.hxx new file mode 100644 index 000000000..c02f30920 --- /dev/null +++ b/sc/source/ui/vba/vbapivotcache.hxx @@ -0,0 +1,40 @@ +/* -*- 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 . + */ +#pragma once +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/sheet/XDataPilotTable.hpp> + +#include <ooo/vba/excel/XPivotCache.hpp> +#include <vbahelper/vbahelperinterface.hxx> + +typedef InheritedHelperInterfaceWeakImpl<ov::excel::XPivotCache > PivotCacheImpl_BASE; + +class ScVbaPivotCache : public PivotCacheImpl_BASE +{ + css::uno::Reference< css::sheet::XDataPilotTable > m_xTable; +public: + ScVbaPivotCache( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Reference< css::sheet::XDataPilotTable >& xTable ); + + virtual void SAL_CALL Refresh() override; + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbapivottable.cxx b/sc/source/ui/vba/vbapivottable.cxx new file mode 100644 index 000000000..775ac390c --- /dev/null +++ b/sc/source/ui/vba/vbapivottable.cxx @@ -0,0 +1,53 @@ +/* -*- 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 "vbapivottable.hxx" +#include "vbapivotcache.hxx" + +using namespace ::com::sun::star; +using namespace ::ooo::vba; + +ScVbaPivotTable::ScVbaPivotTable( const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< sheet::XDataPilotTable >& xTable ) : PivotTableImpl_BASE( uno::Reference< XHelperInterface >(), xContext), m_xTable( xTable ) +{ +} + +uno::Reference< excel::XPivotCache > +ScVbaPivotTable::PivotCache() +{ + // #FIXME with a quick example failed to determine what the parent + // should be, leaving as null at the moment + return new ScVbaPivotCache( uno::Reference< XHelperInterface >(), mxContext, m_xTable ); +} + +OUString +ScVbaPivotTable::getServiceImplName() +{ + return "ScVbaPivotTable"; +} + +uno::Sequence< OUString > +ScVbaPivotTable::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.PivotTable" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbapivottable.hxx b/sc/source/ui/vba/vbapivottable.hxx new file mode 100644 index 000000000..3d3392168 --- /dev/null +++ b/sc/source/ui/vba/vbapivottable.hxx @@ -0,0 +1,40 @@ +/* -*- 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 . + */ +#pragma once +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/sheet/XDataPilotTable.hpp> +#include <ooo/vba/excel/XPivotTable.hpp> +#include <vbahelper/vbahelperinterface.hxx> + +typedef InheritedHelperInterfaceWeakImpl<ov::excel::XPivotTable> PivotTableImpl_BASE; + +class ScVbaPivotTable : public PivotTableImpl_BASE +{ + css::uno::Reference<css::sheet::XDataPilotTable> m_xTable; + +public: + ScVbaPivotTable(const css::uno::Reference<css::uno::XComponentContext>& xContext, + const css::uno::Reference<css::sheet::XDataPilotTable>& xTable); + virtual css::uno::Reference<ov::excel::XPivotCache> SAL_CALL PivotCache() override; + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbapivottables.cxx b/sc/source/ui/vba/vbapivottables.cxx new file mode 100644 index 000000000..f49fbeaeb --- /dev/null +++ b/sc/source/ui/vba/vbapivottables.cxx @@ -0,0 +1,89 @@ +/* -*- 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 "vbapivottables.hxx" +#include "vbapivottable.hxx" +#include <com/sun/star/sheet/XDataPilotTable.hpp> +#include <ooo/vba/excel/XPivotTable.hpp> + +using namespace ::com::sun::star; +using namespace ::ooo::vba; + +static uno::Any DataPilotToPivotTable( const uno::Any& aSource, const uno::Reference< uno::XComponentContext > & xContext ) +{ + uno::Reference< sheet::XDataPilotTable > xTable( aSource, uno::UNO_QUERY_THROW ); + return uno::Any( uno::Reference< excel::XPivotTable > ( new ScVbaPivotTable( xContext, xTable ) ) ); +} + +namespace { + +class PivotTableEnumeration : public EnumerationHelperImpl +{ +public: + /// @throws uno::RuntimeException + PivotTableEnumeration( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< container::XEnumeration >& xEnumeration ) : EnumerationHelperImpl( xParent, xContext, xEnumeration ) {} + + virtual uno::Any SAL_CALL nextElement( ) override + { + return DataPilotToPivotTable( m_xEnumeration->nextElement(), m_xContext ); + } + +}; + +} + +ScVbaPivotTables::ScVbaPivotTables( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext > & xContext, const uno::Reference< container::XIndexAccess >& xIndexAccess ): ScVbaPivotTables_BASE( xParent, xContext, xIndexAccess ) +{ +} + +uno::Reference< container::XEnumeration > +ScVbaPivotTables::createEnumeration() +{ + uno::Reference< container::XEnumerationAccess > xEnumAccess( m_xIndexAccess, uno::UNO_QUERY_THROW ); + return new PivotTableEnumeration( mxParent, mxContext, xEnumAccess->createEnumeration() ); +} + +uno::Any +ScVbaPivotTables::createCollectionObject( const css::uno::Any& aSource ) +{ + return DataPilotToPivotTable( aSource, mxContext ); +} + +uno::Type +ScVbaPivotTables::getElementType() +{ + return cppu::UnoType<excel::XPivotTable>::get(); +} + +OUString +ScVbaPivotTables::getServiceImplName() +{ + return "ScVbaPivotTables"; +} + +css::uno::Sequence<OUString> +ScVbaPivotTables::getServiceNames() +{ + static uno::Sequence< OUString > const sNames + { + "ooo.vba.excel.PivotTables" + }; + return sNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbapivottables.hxx b/sc/source/ui/vba/vbapivottables.hxx new file mode 100644 index 000000000..69b16b96f --- /dev/null +++ b/sc/source/ui/vba/vbapivottables.hxx @@ -0,0 +1,49 @@ +/* -*- 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 . + */ +#pragma once + +#include <ooo/vba/excel/XPivotTables.hpp> + +#include <vbahelper/vbacollectionimpl.hxx> + +namespace com::sun::star::uno { class XComponentContext; } + +typedef CollTestImplHelper< ov::excel::XPivotTables > ScVbaPivotTables_BASE; + +class ScVbaPivotTables : public ScVbaPivotTables_BASE +{ + virtual css::uno::Sequence<OUString> getServiceNames() override; + +public: + ScVbaPivotTables( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::container::XIndexAccess >& xIndexAccess ); + + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + + // XPivotTables + + // ScVbaPivotTables_BASE + virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override; + + virtual OUString getServiceImplName() override; + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbarange.cxx b/sc/source/ui/vba/vbarange.cxx new file mode 100644 index 000000000..99933f165 --- /dev/null +++ b/sc/source/ui/vba/vbarange.cxx @@ -0,0 +1,5720 @@ +/* -*- 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 "vbarange.hxx" + +#include <comphelper/types.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <o3tl/any.hxx> +#include <o3tl/safeint.hxx> +#include <o3tl/unit_conversion.hxx> +#include <rtl/math.hxx> +#include <tools/diagnose_ex.h> +#include <o3tl/string_view.hxx> + +#include <com/sun/star/script/ArrayWrapper.hpp> +#include <com/sun/star/script/XTypeConverter.hpp> +#include <com/sun/star/script/vba/VBAEventId.hpp> +#include <com/sun/star/script/vba/XVBAEventProcessor.hpp> +#include <com/sun/star/sheet/XDatabaseRange.hpp> +#include <com/sun/star/sheet/XUnnamedDatabaseRanges.hpp> +#include <com/sun/star/sheet/XGoalSeek.hpp> +#include <com/sun/star/sheet/XSheetOperation.hpp> +#include <com/sun/star/sheet/CellFlags.hpp> +#include <com/sun/star/table/XColumnRowRange.hpp> +#include <com/sun/star/sheet/XCellAddressable.hpp> +#include <com/sun/star/table/CellContentType.hpp> +#include <com/sun/star/sheet/XCellSeries.hpp> +#include <com/sun/star/text/XTextRange.hpp> +#include <com/sun/star/sheet/XCellRangeAddressable.hpp> +#include <com/sun/star/table/CellAddress.hpp> +#include <com/sun/star/table/CellRangeAddress.hpp> +#include <com/sun/star/sheet/XSpreadsheetView.hpp> +#include <com/sun/star/sheet/XCellRangeReferrer.hpp> +#include <com/sun/star/sheet/XSheetCellRange.hpp> +#include <com/sun/star/sheet/XSpreadsheet.hpp> +#include <com/sun/star/sheet/XSheetCellCursor.hpp> +#include <com/sun/star/sheet/XArrayFormulaRange.hpp> +#include <com/sun/star/sheet/XNamedRange.hpp> +#include <com/sun/star/sheet/XNamedRanges.hpp> +#include <com/sun/star/sheet/XPrintAreas.hpp> +#include <com/sun/star/sheet/XCellRangesQuery.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/view/XSelectionSupplier.hpp> +#include <com/sun/star/table/XTableRows.hpp> +#include <com/sun/star/table/XTableColumns.hpp> +#include <com/sun/star/table/TableSortField.hpp> +#include <com/sun/star/util/XMergeable.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/util/XNumberFormatsSupplier.hpp> +#include <com/sun/star/util/XNumberFormats.hpp> +#include <com/sun/star/util/NumberFormat.hpp> +#include <com/sun/star/util/XNumberFormatTypes.hpp> +#include <com/sun/star/util/XReplaceable.hpp> +#include <com/sun/star/util/XSortable.hpp> +#include <com/sun/star/sheet/XCellRangeMovement.hpp> +#include <com/sun/star/sheet/FormulaResult.hpp> +#include <com/sun/star/sheet/FilterOperator2.hpp> +#include <com/sun/star/sheet/TableFilterField2.hpp> +#include <com/sun/star/sheet/XSheetFilterDescriptor2.hpp> +#include <com/sun/star/sheet/FilterConnection.hpp> +#include <com/sun/star/util/TriState.hpp> + +#include <com/sun/star/sheet/XSubTotalCalculatable.hpp> +#include <com/sun/star/sheet/XSubTotalDescriptor.hpp> +#include <com/sun/star/sheet/GeneralFunction.hpp> + +#include <com/sun/star/sheet/XSheetAnnotationsSupplier.hpp> +#include <com/sun/star/sheet/XSheetAnnotations.hpp> + +#include <ooo/vba/excel/XlPasteSpecialOperation.hpp> +#include <ooo/vba/excel/XlPasteType.hpp> +#include <ooo/vba/excel/XlFindLookIn.hpp> +#include <ooo/vba/excel/XlLookAt.hpp> +#include <ooo/vba/excel/XlSearchOrder.hpp> +#include <ooo/vba/excel/XlSortOrder.hpp> +#include <ooo/vba/excel/XlYesNoGuess.hpp> +#include <ooo/vba/excel/XlSortOrientation.hpp> +#include <ooo/vba/excel/XlSortMethod.hpp> +#include <ooo/vba/excel/XlDirection.hpp> +#include <ooo/vba/excel/XlSortDataOption.hpp> +#include <ooo/vba/excel/XlDeleteShiftDirection.hpp> +#include <ooo/vba/excel/XlInsertShiftDirection.hpp> +#include <ooo/vba/excel/XlReferenceStyle.hpp> +#include <ooo/vba/excel/XlBordersIndex.hpp> +#include <ooo/vba/excel/XlPageBreak.hpp> +#include <ooo/vba/excel/XlAutoFilterOperator.hpp> +#include <ooo/vba/excel/XlAutoFillType.hpp> +#include <ooo/vba/excel/XlCellType.hpp> +#include <ooo/vba/excel/XlSpecialCellsValue.hpp> +#include <ooo/vba/excel/XlConsolidationFunction.hpp> +#include <ooo/vba/excel/XlSearchDirection.hpp> + +#include <scitems.hxx> +#include <svl/srchitem.hxx> +#include <cellsuno.hxx> +#include <dbdata.hxx> +#include <docfunc.hxx> +#include <columnspanset.hxx> +#include <queryparam.hxx> +#include <sortparam.hxx> + +#include <sfx2/dispatch.hxx> +#include <sfx2/app.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/viewfrm.hxx> +#include <sc.hrc> +#include <unonames.hxx> + +#include "excelvbahelper.hxx" +#include "vbaapplication.hxx" +#include "vbafont.hxx" +#include "vbacomment.hxx" +#include "vbainterior.hxx" +#include "vbacharacters.hxx" +#include "vbaborders.hxx" +#include "vbaworksheet.hxx" +#include "vbavalidation.hxx" +#include "vbahyperlinks.hxx" + +#include <tabvwsh.hxx> +#include <rangelst.hxx> +#include <convuno.hxx> +#include <compiler.hxx> +#include <patattr.hxx> +#include <olinetab.hxx> +#include <transobj.hxx> +#include <queryentry.hxx> +#include <markdata.hxx> +#include <basic/sberrors.hxx> +#include <cppuhelper/implbase.hxx> + +#include <global.hxx> + +#include "vbastyle.hxx" +#include "vbaname.hxx" +#include <vector> +#include <vbahelper/vbacollectionimpl.hxx> + +#include <com/sun/star/bridge/oleautomation/Date.hpp> +#include <tokenarray.hxx> +#include <tokenuno.hxx> + +#include <memory> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; +using ::std::vector; + +// difference between VBA and file format width, in character units +const double fExtraWidth = 182.0 / 256.0; + +const sal_Int16 supportedIndexTable[] = { excel::XlBordersIndex::xlEdgeLeft, excel::XlBordersIndex::xlEdgeTop, excel::XlBordersIndex::xlEdgeBottom, excel::XlBordersIndex::xlEdgeRight, excel::XlBordersIndex::xlDiagonalDown, excel::XlBordersIndex::xlDiagonalUp, excel::XlBordersIndex::xlInsideVertical, excel::XlBordersIndex::xlInsideHorizontal }; + +static sal_uInt16 lcl_pointsToTwips( double nVal ) +{ + nVal = nVal * static_cast<double>(20); + short nTwips = static_cast<short>(nVal); + return nTwips; +} +static double lcl_TwipsToPoints( sal_uInt16 nVal ) +{ + double nPoints = nVal; + return nPoints / 20; +} + +static double lcl_Round2DecPlaces( double nVal ) +{ + nVal = (nVal * double(100)); + tools::Long tmp = static_cast<tools::Long>(nVal); + if ( ( nVal - tmp ) >= 0.5 ) + ++tmp; + nVal = double(tmp)/100; + return nVal; +} + +static uno::Any lcl_makeRange( const uno::Reference< XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, const uno::Any& rAny, bool bIsRows, bool bIsColumns ) +{ + uno::Reference< table::XCellRange > xCellRange(rAny, uno::UNO_QUERY_THROW); + return uno::Any( uno::Reference< excel::XRange >( new ScVbaRange( rParent, rContext, xCellRange, bIsRows, bIsColumns ) ) ); +} + +static uno::Reference< excel::XRange > lcl_makeXRangeFromSheetCellRanges( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< sheet::XSheetCellRanges >& xLocSheetCellRanges, ScDocShell* pDoc ) +{ + uno::Reference< excel::XRange > xRange; + const uno::Sequence< table::CellRangeAddress > sAddresses = xLocSheetCellRanges->getRangeAddresses(); + ScRangeList aCellRanges; + if ( sAddresses.hasElements() ) + { + for ( const auto& rAddress : sAddresses ) + { + ScRange refRange; + ScUnoConversion::FillScRange( refRange, rAddress ); + aCellRanges.push_back( refRange ); + } + // Single range + if ( aCellRanges.size() == 1 ) + { + uno::Reference< table::XCellRange > xTmpRange( new ScCellRangeObj( pDoc, aCellRanges.front() ) ); + xRange = new ScVbaRange( xParent, xContext, xTmpRange ); + } + else + { + uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( pDoc, aCellRanges ) ); + xRange = new ScVbaRange( xParent, xContext, xRanges ); + } + } + return xRange; +} + +ScCellRangesBase* ScVbaRange::getCellRangesBase() +{ + if( mxRanges.is() ) + return comphelper::getFromUnoTunnel<ScCellRangesBase>( mxRanges ); + if( mxRange.is() ) + return comphelper::getFromUnoTunnel<ScCellRangesBase>( mxRange ); + throw uno::RuntimeException("General Error creating range - Unknown" ); +} + +ScCellRangeObj* ScVbaRange::getCellRangeObj() +{ + return dynamic_cast< ScCellRangeObj* >( getCellRangesBase() ); +} + +SfxItemSet* ScVbaRange::getCurrentDataSet( ) +{ + SfxItemSet* pDataSet = excel::ScVbaCellRangeAccess::GetDataSet( getCellRangesBase() ); + if ( !pDataSet ) + throw uno::RuntimeException("Can't access Itemset for range" ); + return pDataSet; +} + +void ScVbaRange::fireChangeEvent() +{ + if( !ScVbaApplication::getDocumentEventsEnabled() ) + return; + + ScDocument& rDoc = getScDocument(); + const uno::Reference< script::vba::XVBAEventProcessor >& xVBAEvents = rDoc.GetVbaEventProcessor(); + if( xVBAEvents.is() ) try + { + uno::Sequence< uno::Any > aArgs{ uno::Any(uno::Reference< excel::XRange >( this )) }; + xVBAEvents->processVbaEvent( script::vba::VBAEventId::WORKSHEET_CHANGE, aArgs ); + } + catch( uno::Exception& ) + { + } +} + +namespace { + +class SingleRangeEnumeration : public EnumerationHelper_BASE +{ + uno::Reference< table::XCellRange > m_xRange; + bool bHasMore; +public: + /// @throws uno::RuntimeException + explicit SingleRangeEnumeration( const uno::Reference< table::XCellRange >& xRange ) : m_xRange( xRange ), bHasMore( true ) { } + virtual sal_Bool SAL_CALL hasMoreElements( ) override { return bHasMore; } + virtual uno::Any SAL_CALL nextElement( ) override + { + if ( !bHasMore ) + throw container::NoSuchElementException(); + bHasMore = false; + return uno::Any( m_xRange ); + } +}; + +// very simple class to pass to ScVbaCollectionBaseImpl containing +// just one item + +class SingleRangeIndexAccess : public ::cppu::WeakImplHelper< container::XIndexAccess, + container::XEnumerationAccess > +{ +private: + uno::Reference< table::XCellRange > m_xRange; + +public: + explicit SingleRangeIndexAccess( const uno::Reference< table::XCellRange >& xRange ) : m_xRange( xRange ) {} + // XIndexAccess + virtual ::sal_Int32 SAL_CALL getCount() override { return 1; } + virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override + { + if ( Index != 0 ) + throw lang::IndexOutOfBoundsException(); + return uno::Any( m_xRange ); + } + // XElementAccess + virtual uno::Type SAL_CALL getElementType() override { return cppu::UnoType<table::XCellRange>::get(); } + virtual sal_Bool SAL_CALL hasElements() override { return true; } + // XEnumerationAccess + virtual uno::Reference< container::XEnumeration > SAL_CALL createEnumeration() override { return new SingleRangeEnumeration( m_xRange ); } + +}; + +class RangesEnumerationImpl : public EnumerationHelperImpl +{ + bool mbIsRows; + bool mbIsColumns; +public: + /// @throws uno::RuntimeException + RangesEnumerationImpl( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< container::XEnumeration >& xEnumeration, bool bIsRows, bool bIsColumns ) : EnumerationHelperImpl( xParent, xContext, xEnumeration ), mbIsRows( bIsRows ), mbIsColumns( bIsColumns ) {} + virtual uno::Any SAL_CALL nextElement( ) override + { + return lcl_makeRange( m_xParent, m_xContext, m_xEnumeration->nextElement(), mbIsRows, mbIsColumns ); + } +}; + +class ScVbaRangeAreas : public ScVbaCollectionBaseImpl +{ + bool mbIsRows; + bool mbIsColumns; +public: + ScVbaRangeAreas( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< container::XIndexAccess >& xIndexAccess, bool bIsRows, bool bIsColumns ) : ScVbaCollectionBaseImpl( xParent, xContext, xIndexAccess ), mbIsRows( bIsRows ), mbIsColumns( bIsColumns ) {} + + // XEnumerationAccess + virtual uno::Reference< container::XEnumeration > SAL_CALL createEnumeration() override; + + // XElementAccess + virtual uno::Type SAL_CALL getElementType() override { return cppu::UnoType<excel::XRange>::get(); } + + virtual uno::Any createCollectionObject( const uno::Any& aSource ) override; + + virtual OUString getServiceImplName() override { return OUString(); } + + virtual uno::Sequence< OUString > getServiceNames() override { return uno::Sequence< OUString >(); } + +}; + +} + +uno::Reference< container::XEnumeration > SAL_CALL +ScVbaRangeAreas::createEnumeration() +{ + uno::Reference< container::XEnumerationAccess > xEnumAccess( m_xIndexAccess, uno::UNO_QUERY_THROW ); + return new RangesEnumerationImpl( mxParent, mxContext, xEnumAccess->createEnumeration(), mbIsRows, mbIsColumns ); +} + +uno::Any +ScVbaRangeAreas::createCollectionObject( const uno::Any& aSource ) +{ + return lcl_makeRange( mxParent, mxContext, aSource, mbIsRows, mbIsColumns ); +} + +// assume that xIf is in fact a ScCellRangesBase +/// @throws uno::RuntimeException +static ScDocShell* +getDocShellFromIf( const uno::Reference< uno::XInterface >& xIf ) +{ + ScCellRangesBase* pUno = comphelper::getFromUnoTunnel<ScCellRangesBase>( xIf ); + if ( !pUno ) + throw uno::RuntimeException("Failed to access underlying uno range object" ); + return pUno->GetDocShell(); +} + +/// @throws uno::RuntimeException +static ScDocShell* +getDocShellFromRange( const uno::Reference< table::XCellRange >& xRange ) +{ + // need the ScCellRangesBase to get docshell + uno::Reference< uno::XInterface > xIf( xRange ); + return getDocShellFromIf(xIf ); +} + +/// @throws uno::RuntimeException +static ScDocShell* +getDocShellFromRanges( const uno::Reference< sheet::XSheetCellRangeContainer >& xRanges ) +{ + // need the ScCellRangesBase to get docshell + uno::Reference< uno::XInterface > xIf( xRanges ); + return getDocShellFromIf(xIf ); +} + +/// @throws uno::RuntimeException +static uno::Reference< frame::XModel > getModelFromXIf( const uno::Reference< uno::XInterface >& xIf ) +{ + ScDocShell* pDocShell = getDocShellFromIf(xIf ); + return pDocShell->GetModel(); +} + +/// @throws uno::RuntimeException +static uno::Reference< frame::XModel > getModelFromRange( const uno::Reference< table::XCellRange >& xRange ) +{ + // the XInterface for getImplementation can be any derived interface, no need for queryInterface + uno::Reference< uno::XInterface > xIf( xRange ); + return getModelFromXIf( xIf ); +} + +static ScDocument& +getDocumentFromRange( const uno::Reference< table::XCellRange >& xRange ) +{ + ScDocShell* pDocShell = getDocShellFromRange( xRange ); + if ( !pDocShell ) + throw uno::RuntimeException("Failed to access underlying docshell from uno range object" ); + ScDocument& rDoc = pDocShell->GetDocument(); + return rDoc; +} + +ScDocument& +ScVbaRange::getScDocument() +{ + if ( mxRanges.is() ) + { + uno::Reference< container::XIndexAccess > xIndex( mxRanges, uno::UNO_QUERY_THROW ); + uno::Reference< table::XCellRange > xRange( xIndex->getByIndex( 0 ), uno::UNO_QUERY_THROW ); + return getDocumentFromRange( xRange ); + } + return getDocumentFromRange( mxRange ); +} + +ScDocShell* +ScVbaRange::getScDocShell() +{ + if ( mxRanges.is() ) + { + uno::Reference< container::XIndexAccess > xIndex( mxRanges, uno::UNO_QUERY_THROW ); + uno::Reference< table::XCellRange > xRange( xIndex->getByIndex( 0 ), uno::UNO_QUERY_THROW ); + return getDocShellFromRange( xRange ); + } + return getDocShellFromRange( mxRange ); +} + +ScVbaRange* ScVbaRange::getImplementation( const uno::Reference< excel::XRange >& rxRange ) +{ + // FIXME: always save to use dynamic_cast? Or better to (implement and) use XTunnel? + return dynamic_cast< ScVbaRange* >( rxRange.get() ); +} + +uno::Reference< frame::XModel > ScVbaRange::getUnoModel() +{ + if( ScDocShell* pDocShell = getScDocShell() ) + return pDocShell->GetModel(); + throw uno::RuntimeException(); +} + +uno::Reference< frame::XModel > ScVbaRange::getUnoModel( const uno::Reference< excel::XRange >& rxRange ) +{ + if( ScVbaRange* pScVbaRange = getImplementation( rxRange ) ) + return pScVbaRange->getUnoModel(); + throw uno::RuntimeException(); +} + +const ScRangeList& ScVbaRange::getScRangeList() +{ + if( ScCellRangesBase* pScRangesBase = getCellRangesBase() ) + return pScRangesBase->GetRangeList(); + throw uno::RuntimeException("Cannot obtain UNO range implementation object" ); +} + +const ScRangeList& ScVbaRange::getScRangeList( const uno::Reference< excel::XRange >& rxRange ) +{ + if( ScVbaRange* pScVbaRange = getImplementation( rxRange ) ) + return pScVbaRange->getScRangeList(); + throw uno::RuntimeException("Cannot obtain VBA range implementation object" ); +} + +namespace { + +class NumFormatHelper +{ + uno::Reference< util::XNumberFormatsSupplier > mxSupplier; + uno::Reference< beans::XPropertySet > mxRangeProps; + uno::Reference< util::XNumberFormats > mxFormats; +public: + explicit NumFormatHelper( const uno::Reference< table::XCellRange >& xRange ) + { + mxSupplier.set( getModelFromRange( xRange ), uno::UNO_QUERY_THROW ); + mxRangeProps.set( xRange, uno::UNO_QUERY_THROW); + mxFormats = mxSupplier->getNumberFormats(); + } + uno::Reference< beans::XPropertySet > getNumberProps() + { + tools::Long nIndexKey = 0; + uno::Any aValue = mxRangeProps->getPropertyValue( "NumberFormat" ); + aValue >>= nIndexKey; + + if ( mxFormats.is() ) + return mxFormats->getByKey( nIndexKey ); + return uno::Reference< beans::XPropertySet > (); + } + + bool isBooleanType() + { + + return (getNumberFormat() & util::NumberFormat::LOGICAL) != 0; + } + + bool isDateType() + { + sal_Int16 nType = getNumberFormat(); + return ( nType & util::NumberFormat::DATETIME ) != 0; + } + + OUString getNumberFormatString() + { + uno::Reference< uno::XInterface > xIf( mxRangeProps, uno::UNO_QUERY_THROW ); + ScCellRangesBase* pUnoCellRange = comphelper::getFromUnoTunnel<ScCellRangesBase>( xIf ); + if ( pUnoCellRange ) + { + + SfxItemSet* pDataSet = excel::ScVbaCellRangeAccess::GetDataSet( pUnoCellRange ); + SfxItemState eState = pDataSet->GetItemState( ATTR_VALUE_FORMAT); + // one of the cells in the range is not like the other ;-) + // so return a zero length format to indicate that + if ( eState == SfxItemState::DONTCARE ) + return OUString(); + } + + uno::Reference< beans::XPropertySet > xNumberProps( getNumberProps(), uno::UNO_SET_THROW ); + OUString aFormatString; + uno::Any aString = xNumberProps->getPropertyValue( "FormatString" ); + aString >>= aFormatString; + return aFormatString; + } + + sal_Int16 getNumberFormat() + { + uno::Reference< beans::XPropertySet > xNumberProps = getNumberProps(); + sal_Int16 nType = ::comphelper::getINT16( + xNumberProps->getPropertyValue( "Type" ) ); + return nType; + } + + void setNumberFormat( const OUString& rFormat ) + { + // #163288# treat "General" as "Standard" format + sal_Int32 nNewIndex = 0; + if( !rFormat.equalsIgnoreAsciiCase( "General" ) ) + { + lang::Locale aLocale; + uno::Reference< beans::XPropertySet > xNumProps = getNumberProps(); + xNumProps->getPropertyValue( "Locale" ) >>= aLocale; + nNewIndex = mxFormats->queryKey( rFormat, aLocale, false ); + if ( nNewIndex == -1 ) // format not defined + nNewIndex = mxFormats->addNew( rFormat, aLocale ); + } + mxRangeProps->setPropertyValue( "NumberFormat", uno::Any( nNewIndex ) ); + } + + void setNumberFormat( sal_Int16 nType ) + { + uno::Reference< beans::XPropertySet > xNumberProps = getNumberProps(); + lang::Locale aLocale; + xNumberProps->getPropertyValue( "Locale" ) >>= aLocale; + uno::Reference<util::XNumberFormatTypes> xTypes( mxFormats, uno::UNO_QUERY ); + if ( xTypes.is() ) + { + sal_Int32 nNewIndex = xTypes->getStandardFormat( nType, aLocale ); + mxRangeProps->setPropertyValue( "NumberFormat", uno::Any( nNewIndex ) ); + } + } + +}; + +struct CellPos +{ + CellPos( sal_Int32 nRow, sal_Int32 nCol, sal_Int32 nArea ):m_nRow(nRow), m_nCol(nCol), m_nArea( nArea ) {}; +sal_Int32 m_nRow; +sal_Int32 m_nCol; +sal_Int32 m_nArea; +}; + +} + +typedef ::cppu::WeakImplHelper< container::XEnumeration > CellsEnumeration_BASE; +typedef ::std::vector< CellPos > vCellPos; + +namespace { + +// #FIXME - QUICK +// we could probably could and should modify CellsEnumeration below +// to handle rows and columns (but I do this separately for now +// and... this class only handles single areas (does it have to handle +// multi area ranges??) +class ColumnsRowEnumeration: public CellsEnumeration_BASE +{ + uno::Reference< excel::XRange > mxRange; + sal_Int32 mMaxElems; + sal_Int32 mCurElem; + +public: + ColumnsRowEnumeration( const uno::Reference< excel::XRange >& xRange, sal_Int32 nElems ) : mxRange( xRange ), mMaxElems( nElems ), mCurElem( 0 ) + { + } + + virtual sal_Bool SAL_CALL hasMoreElements() override { return mCurElem < mMaxElems; } + + virtual uno::Any SAL_CALL nextElement() override + { + if ( !hasMoreElements() ) + throw container::NoSuchElementException(); + sal_Int32 vbaIndex = 1 + mCurElem++; + return uno::Any( mxRange->Item( uno::Any( vbaIndex ), uno::Any() ) ); + } +}; + +class CellsEnumeration : public CellsEnumeration_BASE +{ + uno::WeakReference< XHelperInterface > mxParent; + uno::Reference< uno::XComponentContext > mxContext; + uno::Reference< XCollection > m_xAreas; + vCellPos m_CellPositions; + vCellPos::const_iterator m_it; + + /// @throws uno::RuntimeException + uno::Reference< table::XCellRange > getArea( sal_Int32 nVBAIndex ) + { + if ( nVBAIndex < 1 || nVBAIndex > m_xAreas->getCount() ) + throw uno::RuntimeException(); + uno::Reference< excel::XRange > xRange( m_xAreas->Item( uno::Any(nVBAIndex), uno::Any() ), uno::UNO_QUERY_THROW ); + uno::Reference< table::XCellRange > xCellRange( ScVbaRange::getCellRange( xRange ), uno::UNO_QUERY_THROW ); + return xCellRange; + } + + void populateArea( sal_Int32 nVBAIndex ) + { + uno::Reference< table::XCellRange > xRange = getArea( nVBAIndex ); + uno::Reference< table::XColumnRowRange > xColumnRowRange(xRange, uno::UNO_QUERY_THROW ); + sal_Int32 nRowCount = xColumnRowRange->getRows()->getCount(); + sal_Int32 nColCount = xColumnRowRange->getColumns()->getCount(); + for ( sal_Int32 i=0; i<nRowCount; ++i ) + { + for ( sal_Int32 j=0; j<nColCount; ++j ) + m_CellPositions.emplace_back( i,j,nVBAIndex ); + } + } +public: + CellsEnumeration( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< XCollection >& xAreas ): mxParent( xParent ), mxContext( xContext ), m_xAreas( xAreas ) + { + sal_Int32 nItems = m_xAreas->getCount(); + for ( sal_Int32 index=1; index <= nItems; ++index ) + { + populateArea( index ); + } + m_it = m_CellPositions.begin(); + } + virtual sal_Bool SAL_CALL hasMoreElements() override { return m_it != m_CellPositions.end(); } + + virtual uno::Any SAL_CALL nextElement() override + { + if ( !hasMoreElements() ) + throw container::NoSuchElementException(); + CellPos aPos = *m_it++; + + uno::Reference< table::XCellRange > xRangeArea = getArea( aPos.m_nArea ); + uno::Reference< table::XCellRange > xCellRange( xRangeArea->getCellByPosition( aPos.m_nCol, aPos.m_nRow ), uno::UNO_QUERY_THROW ); + return uno::Any( uno::Reference< excel::XRange >( new ScVbaRange( mxParent, mxContext, xCellRange ) ) ); + + } +}; + +} + +constexpr OUStringLiteral ISVISIBLE = u"IsVisible"; +const char EQUALS[] = "="; +const char NOTEQUALS[] = "<>"; +const char GREATERTHAN[] = ">"; +const char GREATERTHANEQUALS[] = ">="; +const char LESSTHAN[] = "<"; +const char LESSTHANEQUALS[] = "<="; +constexpr OUStringLiteral STR_ERRORMESSAGE_APPLIESTOSINGLERANGEONLY(u"The command you chose cannot be performed with multiple selections.\nSelect a single range and click the command again"); +constexpr OUStringLiteral CELLSTYLE = u"CellStyle"; + +namespace { + +class CellValueSetter : public ValueSetter +{ +protected: + uno::Any maValue; +public: + explicit CellValueSetter( const uno::Any& aValue ); + virtual bool processValue( const uno::Any& aValue, const uno::Reference< table::XCell >& xCell ) override; + virtual void visitNode( sal_Int32 x, sal_Int32 y, const uno::Reference< table::XCell >& xCell ) override; + +}; + +} + +CellValueSetter::CellValueSetter( const uno::Any& aValue ): maValue( aValue ) {} + +void +CellValueSetter::visitNode( sal_Int32 /*i*/, sal_Int32 /*j*/, const uno::Reference< table::XCell >& xCell ) +{ + processValue( maValue, xCell ); +} + +bool +CellValueSetter::processValue( const uno::Any& aValue, const uno::Reference< table::XCell >& xCell ) +{ + + bool isExtracted = false; + switch ( aValue.getValueTypeClass() ) + { + case uno::TypeClass_BOOLEAN: + { + bool bState = false; + if ( aValue >>= bState ) + { + uno::Reference< table::XCellRange > xRange( xCell, uno::UNO_QUERY_THROW ); + if ( bState ) + xCell->setValue( double(1) ); + else + xCell->setValue( double(0) ); + NumFormatHelper cellNumFormat( xRange ); + cellNumFormat.setNumberFormat( util::NumberFormat::LOGICAL ); + } + break; + } + case uno::TypeClass_STRING: + { + OUString aString; + if ( aValue >>= aString ) + { + // The required behavior for a string value is: + // 1. If the first character is a single quote, use the rest as a string cell, regardless of the cell's number format. + // 2. Otherwise, if the cell's number format is "text", use the string value as a string cell. + // 3. Otherwise, parse the string value in English locale, and apply a corresponding number format with the cell's locale + // if the cell's number format was "General". + // Case 1 is handled here, the rest in ScCellObj::InputEnglishString + + if ( aString.toChar() == '\'' ) // case 1 - handle with XTextRange + { + OUString aRemainder( aString.copy(1) ); // strip the quote + uno::Reference< text::XTextRange > xTextRange( xCell, uno::UNO_QUERY_THROW ); + xTextRange->setString( aRemainder ); + } + else + { + // call implementation method InputEnglishString + ScCellObj* pCellObj = dynamic_cast< ScCellObj* >( xCell.get() ); + if ( pCellObj ) + pCellObj->InputEnglishString( aString ); + } + } + else + isExtracted = false; + break; + } + default: + { + double nDouble = 0.0; + if ( aValue >>= nDouble ) + { + uno::Reference< table::XCellRange > xRange( xCell, uno::UNO_QUERY_THROW ); + NumFormatHelper cellFormat( xRange ); + // If we are setting a number and the cell types was logical + // then we need to reset the logical format. ( see case uno::TypeClass_BOOLEAN: + // handling above ) + if ( cellFormat.isBooleanType() ) + cellFormat.setNumberFormat("General"); + xCell->setValue( nDouble ); + } + else + isExtracted = false; + break; + } + } + return isExtracted; + +} + +namespace { + +class CellValueGetter : public ValueGetter +{ +protected: + uno::Any maValue; +public: + CellValueGetter() {} + virtual void visitNode( sal_Int32 x, sal_Int32 y, const uno::Reference< table::XCell >& xCell ) override; + virtual void processValue( const uno::Any& aValue ) override; + const uno::Any& getValue() const override { return maValue; } + +}; + +} + +void +CellValueGetter::processValue( const uno::Any& aValue ) +{ + maValue = aValue; +} +void CellValueGetter::visitNode( sal_Int32 /*x*/, sal_Int32 /*y*/, const uno::Reference< table::XCell >& xCell ) +{ + uno::Any aValue; + table::CellContentType eType = xCell->getType(); + if( eType == table::CellContentType_VALUE || eType == table::CellContentType_FORMULA ) + { + if ( eType == table::CellContentType_FORMULA ) + { + + OUString sFormula = xCell->getFormula(); + if ( sFormula == "=TRUE()" ) + aValue <<= true; + else if ( sFormula == "=FALSE()" ) + aValue <<= false; + else + { + uno::Reference< beans::XPropertySet > xProp( xCell, uno::UNO_QUERY_THROW ); + + sal_Int32 nResultType = sheet::FormulaResult::VALUE; + // some formulas give textual results + xProp->getPropertyValue( "FormulaResultType2" ) >>= nResultType; + + if ( nResultType == sheet::FormulaResult::STRING ) + { + uno::Reference< text::XTextRange > xTextRange(xCell, ::uno::UNO_QUERY_THROW); + aValue <<= xTextRange->getString(); + } + else + aValue <<= xCell->getValue(); + } + } + else + { + uno::Reference< table::XCellRange > xRange( xCell, uno::UNO_QUERY_THROW ); + NumFormatHelper cellFormat( xRange ); + if ( cellFormat.isBooleanType() ) + aValue <<= ( xCell->getValue() != 0.0 ); + else if ( cellFormat.isDateType() ) + aValue <<= bridge::oleautomation::Date( xCell->getValue() ); + else + aValue <<= xCell->getValue(); + } + } + if( eType == table::CellContentType_TEXT ) + { + uno::Reference< text::XTextRange > xTextRange(xCell, ::uno::UNO_QUERY_THROW); + aValue <<= xTextRange->getString(); + } + processValue( aValue ); +} + +namespace { + +class CellFormulaValueSetter : public CellValueSetter +{ +private: + ScDocument& m_rDoc; + formula::FormulaGrammar::Grammar m_eGrammar; +public: + CellFormulaValueSetter( const uno::Any& aValue, ScDocument& rDoc, formula::FormulaGrammar::Grammar eGram ):CellValueSetter( aValue ), m_rDoc( rDoc ), m_eGrammar( eGram ){} +protected: + bool processValue( const uno::Any& aValue, const uno::Reference< table::XCell >& xCell ) override + { + OUString sFormula; + double aDblValue = 0.0; + if ( aValue >>= sFormula ) + { + // convert to GRAM_API style grammar because XCell::setFormula + // always compile it in that grammar. Perhaps + // css.sheet.FormulaParser should be used in future to directly + // pass formula tokens when that API stabilizes. + if ( m_eGrammar != formula::FormulaGrammar::GRAM_API && ( o3tl::starts_with(o3tl::trim(sFormula), u"=") ) ) + { + uno::Reference< uno::XInterface > xIf( xCell, uno::UNO_QUERY_THROW ); + ScCellRangesBase* pUnoRangesBase = dynamic_cast< ScCellRangesBase* >( xIf.get() ); + if ( pUnoRangesBase ) + { + const ScRangeList& rCellRanges = pUnoRangesBase->GetRangeList(); + if (!rCellRanges.empty()) + { + ScCompiler aCompiler( m_rDoc, rCellRanges.front().aStart, m_eGrammar ); + // compile the string in the format passed in + std::unique_ptr<ScTokenArray> pArray(aCompiler.CompileString(sFormula)); + // convert to API grammar + aCompiler.SetGrammar( formula::FormulaGrammar::GRAM_API ); + OUString sConverted; + aCompiler.CreateStringFromTokenArray(sConverted); + sFormula = EQUALS + sConverted; + } + } + } + + xCell->setFormula( sFormula ); + return true; + } + else if ( aValue >>= aDblValue ) + { + xCell->setValue( aDblValue ); + return true; + } + return false; + } + +}; + +class CellFormulaValueGetter : public CellValueGetter +{ +private: + ScDocument& m_rDoc; + formula::FormulaGrammar::Grammar m_eGrammar; +public: + CellFormulaValueGetter(ScDocument& rDoc, formula::FormulaGrammar::Grammar eGram ) : m_rDoc( rDoc ), m_eGrammar( eGram ) {} + virtual void visitNode( sal_Int32 /*x*/, sal_Int32 /*y*/, const uno::Reference< table::XCell >& xCell ) override + { + uno::Any aValue; + aValue <<= xCell->getFormula(); + // XCell::getFormula() returns the formula in API grammar, convert. + if ((xCell->getType() == table::CellContentType_FORMULA) + && m_eGrammar != formula::FormulaGrammar::GRAM_API) + { + uno::Reference< uno::XInterface > xIf( xCell, uno::UNO_QUERY_THROW ); + ScCellRangesBase* pUnoRangesBase = dynamic_cast< ScCellRangesBase* >( xIf.get() ); + if (pUnoRangesBase) + { + OUString sVal; + aValue >>= sVal; + const ScRangeList& rCellRanges = pUnoRangesBase->GetRangeList(); + if (!rCellRanges.empty()) + { + // Compile string from API grammar. + ScCompiler aCompiler( m_rDoc, rCellRanges.front().aStart, formula::FormulaGrammar::GRAM_API ); + std::unique_ptr<ScTokenArray> pArray(aCompiler.CompileString(sVal)); + // Convert to desired grammar. + aCompiler.SetGrammar( m_eGrammar ); + OUString sConverted; + aCompiler.CreateStringFromTokenArray(sConverted); + sVal = EQUALS + sConverted; + aValue <<= sVal; + } + } + } + + processValue( aValue ); + } + +}; + +class Dim2ArrayValueGetter : public ArrayVisitor +{ +protected: + uno::Any maValue; + ValueGetter& mValueGetter; + void processValue( sal_Int32 x, sal_Int32 y, const uno::Any& aValue ) + { + uno::Sequence< uno::Sequence< uno::Any > >& aMatrix = const_cast<css::uno::Sequence<css::uno::Sequence<css::uno::Any>> &>(*o3tl::doAccess<uno::Sequence<uno::Sequence<uno::Any>>>(maValue)); + aMatrix.getArray()[x].getArray()[y] = aValue; + } + +public: + Dim2ArrayValueGetter(sal_Int32 nRowCount, sal_Int32 nColCount, ValueGetter& rValueGetter ): mValueGetter(rValueGetter) + { + uno::Sequence< uno::Sequence< uno::Any > > aMatrix; + aMatrix.realloc( nRowCount ); + auto pMatrix = aMatrix.getArray(); + for ( sal_Int32 index = 0; index < nRowCount; ++index ) + pMatrix[index].realloc( nColCount ); + maValue <<= aMatrix; + } + void visitNode( sal_Int32 x, sal_Int32 y, const uno::Reference< table::XCell >& xCell ) override + + { + mValueGetter.visitNode( x, y, xCell ); + processValue( x, y, mValueGetter.getValue() ); + } + const uno::Any& getValue() const { return maValue; } + +}; + +} + +constexpr OUStringLiteral sNA = u"#N/A"; + +namespace { + +class Dim1ArrayValueSetter : public ArrayVisitor +{ + uno::Sequence< uno::Any > aMatrix; + sal_Int32 nColCount; + ValueSetter& mCellValueSetter; +public: + Dim1ArrayValueSetter( const uno::Any& aValue, ValueSetter& rCellValueSetter ):mCellValueSetter( rCellValueSetter ) + { + aValue >>= aMatrix; + nColCount = aMatrix.getLength(); + } + virtual void visitNode( sal_Int32 /*x*/, sal_Int32 y, const uno::Reference< table::XCell >& xCell ) override + { + if ( y < nColCount ) + mCellValueSetter.processValue( aMatrix[ y ], xCell ); + else + mCellValueSetter.processValue( uno::Any( OUString(sNA) ), xCell ); + } +}; + +class Dim2ArrayValueSetter : public ArrayVisitor +{ + uno::Sequence< uno::Sequence< uno::Any > > aMatrix; + ValueSetter& mCellValueSetter; + sal_Int32 nRowCount; + sal_Int32 nColCount; +public: + Dim2ArrayValueSetter( const uno::Any& aValue, ValueSetter& rCellValueSetter ) : mCellValueSetter( rCellValueSetter ) + { + aValue >>= aMatrix; + nRowCount = aMatrix.getLength(); + nColCount = aMatrix[0].getLength(); + } + + virtual void visitNode( sal_Int32 x, sal_Int32 y, const uno::Reference< table::XCell >& xCell ) override + { + if ( x < nRowCount && y < nColCount ) + mCellValueSetter.processValue( aMatrix[ x ][ y ], xCell ); + else + mCellValueSetter.processValue( uno::Any( OUString(sNA) ), xCell ); + + } +}; + +class RangeProcessor +{ +public: + virtual void process( const uno::Reference< excel::XRange >& xRange ) = 0; + +protected: + ~RangeProcessor() {} +}; + +class RangeValueProcessor : public RangeProcessor +{ + const uno::Any& m_aVal; +public: + explicit RangeValueProcessor( const uno::Any& rVal ):m_aVal( rVal ) {} + virtual ~RangeValueProcessor() {} + virtual void process( const uno::Reference< excel::XRange >& xRange ) override + { + xRange->setValue( m_aVal ); + } +}; + +class RangeFormulaProcessor : public RangeProcessor +{ + const uno::Any& m_aVal; +public: + explicit RangeFormulaProcessor( const uno::Any& rVal ):m_aVal( rVal ) {} + virtual ~RangeFormulaProcessor() {} + virtual void process( const uno::Reference< excel::XRange >& xRange ) override + { + xRange->setFormula( m_aVal ); + } +}; + +class RangeCountProcessor : public RangeProcessor +{ + sal_Int32 nCount; +public: + RangeCountProcessor():nCount(0){} + virtual ~RangeCountProcessor() {} + virtual void process( const uno::Reference< excel::XRange >& xRange ) override + { + nCount = nCount + xRange->getCount(); + } + sal_Int32 value() { return nCount; } +}; +class AreasVisitor +{ +private: + uno::Reference< XCollection > m_Areas; +public: + explicit AreasVisitor( const uno::Reference< XCollection >& rAreas ):m_Areas( rAreas ){} + + void visit( RangeProcessor& processor ) + { + if ( m_Areas.is() ) + { + sal_Int32 nItems = m_Areas->getCount(); + for ( sal_Int32 index=1; index <= nItems; ++index ) + { + uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW ); + processor.process( xRange ); + } + } + } +}; + +class RangeHelper +{ + uno::Reference< table::XCellRange > m_xCellRange; + +public: + /// @throws uno::RuntimeException + explicit RangeHelper( const uno::Reference< table::XCellRange >& xCellRange ) : m_xCellRange( xCellRange ) + { + if ( !m_xCellRange.is() ) + throw uno::RuntimeException(); + } + /// @throws uno::RuntimeException + explicit RangeHelper( const uno::Any& rCellRange ) + { + m_xCellRange.set(rCellRange, uno::UNO_QUERY_THROW); + } + /// @throws uno::RuntimeException + uno::Reference< sheet::XSheetCellRange > getSheetCellRange() const + { + return uno::Reference< sheet::XSheetCellRange >(m_xCellRange, uno::UNO_QUERY_THROW); + } + /// @throws uno::RuntimeException + uno::Reference< sheet::XSpreadsheet > getSpreadSheet() const + { + return getSheetCellRange()->getSpreadsheet(); + } + + /// @throws uno::RuntimeException + uno::Reference< table::XCellRange > getCellRangeFromSheet() const + { + return uno::Reference< table::XCellRange >(getSpreadSheet(), uno::UNO_QUERY_THROW ); + } + + /// @throws uno::RuntimeException + uno::Reference< sheet::XCellRangeAddressable > getCellRangeAddressable() const + { + return uno::Reference< sheet::XCellRangeAddressable >(m_xCellRange, ::uno::UNO_QUERY_THROW); + + } + + /// @throws uno::RuntimeException + uno::Reference< sheet::XSheetCellCursor > getSheetCellCursor() const + { + return uno::Reference< sheet::XSheetCellCursor >( getSpreadSheet()->createCursorByRange( getSheetCellRange() ), uno::UNO_SET_THROW ); + } + + static uno::Reference< excel::XRange > createRangeFromRange( const uno::Reference< XHelperInterface >& xParent, const uno::Reference<uno::XComponentContext >& xContext, + const uno::Reference< table::XCellRange >& xRange, const uno::Reference< sheet::XCellRangeAddressable >& xCellRangeAddressable ) + { + const table::CellRangeAddress aRA( xCellRangeAddressable->getRangeAddress()); + return uno::Reference< excel::XRange >( new ScVbaRange( xParent, xContext, + xRange->getCellRangeByPosition( aRA.StartColumn, aRA.StartRow, aRA.EndColumn, aRA.EndRow))); + } + +}; + +} + +bool +ScVbaRange::getCellRangesForAddress( ScRefFlags& rResFlags, std::u16string_view sAddress, ScDocShell* pDocSh, ScRangeList& rCellRanges, formula::FormulaGrammar::AddressConvention eConv, char cDelimiter ) +{ + + if ( pDocSh ) + { + ScDocument& rDoc = pDocSh->GetDocument(); + rResFlags = rCellRanges.Parse( sAddress, rDoc, eConv, 0, cDelimiter ); + if ( rResFlags & ScRefFlags::VALID ) + { + return true; + } + } + return false; +} + +bool getScRangeListForAddress( const OUString& sName, ScDocShell* pDocSh, const ScRange& refRange, ScRangeList& aCellRanges, formula::FormulaGrammar::AddressConvention aConv ) +{ + // see if there is a match with a named range + uno::Reference< beans::XPropertySet > xProps( pDocSh->GetModel(), uno::UNO_QUERY_THROW ); + uno::Reference< container::XNameAccess > xNameAccess( xProps->getPropertyValue( "NamedRanges" ), uno::UNO_QUERY_THROW ); + // Strange enough you can have Range( "namedRange1, namedRange2, etc," ) + // loop around each ',' separated name + std::vector< OUString > vNames; + sal_Int32 nIndex = 0; + do + { + OUString aToken = sName.getToken( 0, ',', nIndex ); + vNames.push_back( aToken ); + } while ( nIndex >= 0 ); + + if ( vNames.empty() ) + vNames.push_back( sName ); + + for ( const auto& rName : vNames ) + { + formula::FormulaGrammar::AddressConvention eConv = aConv; + // spaces are illegal ( but the user of course can enter them ) + OUString sAddress = rName.trim(); + // if a local name ( on the active sheet ) exists this will + // take precedence over a global with the same name + if ( !xNameAccess->hasByName( sAddress ) ) + { + // try a local name + ScDocument& rDoc = pDocSh->GetDocument(); + SCTAB nCurTab = ScDocShell::GetCurTab(); + ScRangeName* pRangeName = rDoc.GetRangeName(nCurTab); + if (pRangeName) + { + // TODO: Handle local names correctly: + // bool bLocalName = pRangeName->findByUpperName(ScGlobal::getCharClass().uppercase(sAddress)) != nullptr; + } + } + char aChar = 0; + if ( xNameAccess->hasByName( sAddress ) ) + { + uno::Reference< sheet::XNamedRange > xNamed( xNameAccess->getByName( sAddress ), uno::UNO_QUERY_THROW ); + sAddress = xNamed->getContent(); + // As the address comes from OOO, the addressing + // style is may not be XL_A1 + eConv = pDocSh->GetDocument().GetAddressConvention(); + aChar = ';'; + } + + ScRefFlags nFlags = ScRefFlags::ZERO; + if ( !ScVbaRange::getCellRangesForAddress( nFlags, sAddress, pDocSh, aCellRanges, eConv, aChar ) ) + return false; + + bool bTabFromReferrer = !( nFlags & ScRefFlags::TAB_3D ); + + for ( size_t i = 0, nRanges = aCellRanges.size(); i < nRanges; ++i ) + { + ScRange & rRange = aCellRanges[ i ]; + rRange.aStart.SetCol( refRange.aStart.Col() + rRange.aStart.Col() ); + rRange.aStart.SetRow( refRange.aStart.Row() + rRange.aStart.Row() ); + rRange.aStart.SetTab( bTabFromReferrer ? refRange.aStart.Tab() : rRange.aStart.Tab() ); + rRange.aEnd.SetCol( refRange.aStart.Col() + rRange.aEnd.Col() ); + rRange.aEnd.SetRow( refRange.aStart.Row() + rRange.aEnd.Row() ); + rRange.aEnd.SetTab( bTabFromReferrer ? refRange.aEnd.Tab() : rRange.aEnd.Tab() ); + } + } + return true; +} + +/// @throws uno::RuntimeException +static rtl::Reference<ScVbaRange> +getRangeForName( const uno::Reference< uno::XComponentContext >& xContext, const OUString& sName, ScDocShell* pDocSh, const table::CellRangeAddress& pAddr, formula::FormulaGrammar::AddressConvention eConv = formula::FormulaGrammar::CONV_XL_A1 ) +{ + ScRangeList aCellRanges; + ScRange refRange; + ScUnoConversion::FillScRange( refRange, pAddr ); + if ( !getScRangeListForAddress ( sName, pDocSh, refRange, aCellRanges, eConv ) ) + throw uno::RuntimeException(); + // Single range + if ( aCellRanges.size() == 1 ) + { + uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( pDocSh, aCellRanges.front() ) ); + uno::Reference< XHelperInterface > xFixThisParent = excel::getUnoSheetModuleObj( xRange ); + return new ScVbaRange( xFixThisParent, xContext, xRange ); + } + uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( pDocSh, aCellRanges ) ); + + uno::Reference< XHelperInterface > xFixThisParent = excel::getUnoSheetModuleObj( xRanges ); + return new ScVbaRange( xFixThisParent, xContext, xRanges ); +} + +namespace { + +/// @throws uno::RuntimeException +template< typename RangeType > +table::CellRangeAddress lclGetRangeAddress( const uno::Reference< RangeType >& rxCellRange ) +{ + return uno::Reference< sheet::XCellRangeAddressable >( rxCellRange, uno::UNO_QUERY_THROW )->getRangeAddress(); +} + +/// @throws uno::RuntimeException +void lclClearRange( const uno::Reference< table::XCellRange >& rxCellRange ) +{ + using namespace ::com::sun::star::sheet::CellFlags; + sal_Int32 const nFlags = VALUE | DATETIME | STRING | ANNOTATION | FORMULA | HARDATTR | STYLES | EDITATTR | FORMATTED; + uno::Reference< sheet::XSheetOperation > xSheetOperation( rxCellRange, uno::UNO_QUERY_THROW ); + xSheetOperation->clearContents( nFlags ); +} + +/// @throws uno::RuntimeException +uno::Reference< sheet::XSheetCellRange > lclExpandToMerged( const uno::Reference< table::XCellRange >& rxCellRange, bool bRecursive ) +{ + uno::Reference< sheet::XSheetCellRange > xNewCellRange( rxCellRange, uno::UNO_QUERY_THROW ); + uno::Reference< sheet::XSpreadsheet > xSheet( xNewCellRange->getSpreadsheet(), uno::UNO_SET_THROW ); + table::CellRangeAddress aNewAddress = lclGetRangeAddress( xNewCellRange ); + table::CellRangeAddress aOldAddress; + // expand as long as there are new merged ranges included + do + { + aOldAddress = aNewAddress; + uno::Reference< sheet::XSheetCellCursor > xCursor( xSheet->createCursorByRange( xNewCellRange ), uno::UNO_SET_THROW ); + if (xCursor.is()) + { + xCursor->collapseToMergedArea(); + xNewCellRange.set( xCursor, uno::UNO_QUERY_THROW ); + aNewAddress = lclGetRangeAddress( xNewCellRange ); + } + } + while( bRecursive && (aOldAddress != aNewAddress) ); + return xNewCellRange; +} + +/// @throws uno::RuntimeException +uno::Reference< sheet::XSheetCellRangeContainer > lclExpandToMerged( const uno::Reference< sheet::XSheetCellRangeContainer >& rxCellRanges ) +{ + if( !rxCellRanges.is() ) + throw uno::RuntimeException("Missing cell ranges object" ); + sal_Int32 nCount = rxCellRanges->getCount(); + if( nCount < 1 ) + throw uno::RuntimeException("Missing cell ranges object" ); + + ScRangeList aScRanges; + for( sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex ) + { + uno::Reference< table::XCellRange > xRange( rxCellRanges->getByIndex( nIndex ), uno::UNO_QUERY_THROW ); + table::CellRangeAddress aRangeAddr = lclGetRangeAddress( lclExpandToMerged( xRange, /*bRecursive*/true ) ); + ScRange aScRange; + ScUnoConversion::FillScRange( aScRange, aRangeAddr ); + aScRanges.push_back( aScRange ); + } + return new ScCellRangesObj( getDocShellFromRanges( rxCellRanges ), aScRanges ); +} + +/// @throws uno::RuntimeException +void lclExpandAndMerge( const uno::Reference< table::XCellRange >& rxCellRange, bool bMerge ) +{ + uno::Reference< util::XMergeable > xMerge( lclExpandToMerged( rxCellRange, true ), uno::UNO_QUERY_THROW ); + // Calc cannot merge over merged ranges, always unmerge first + xMerge->merge( false ); + if( !bMerge ) + return; + + // clear all contents of the covered cells (not the top-left cell) + table::CellRangeAddress aRangeAddr = lclGetRangeAddress( rxCellRange ); + sal_Int32 nLastColIdx = aRangeAddr.EndColumn - aRangeAddr.StartColumn; + sal_Int32 nLastRowIdx = aRangeAddr.EndRow - aRangeAddr.StartRow; + // clear cells of top row, right of top-left cell + if( nLastColIdx > 0 ) + lclClearRange( rxCellRange->getCellRangeByPosition( 1, 0, nLastColIdx, 0 ) ); + // clear all rows below top row + if( nLastRowIdx > 0 ) + lclClearRange( rxCellRange->getCellRangeByPosition( 0, 1, nLastColIdx, nLastRowIdx ) ); + // merge the range + xMerge->merge( true ); +} + +/// @throws uno::RuntimeException +util::TriState lclGetMergedState( const uno::Reference< table::XCellRange >& rxCellRange ) +{ + /* 1) Check if range is completely inside one single merged range. To do + this, try to extend from top-left cell only (not from entire range). + This will exclude cases where this range consists of several merged + ranges (or parts of them). */ + table::CellRangeAddress aRangeAddr = lclGetRangeAddress( rxCellRange ); + uno::Reference< table::XCellRange > xTopLeft( rxCellRange->getCellRangeByPosition( 0, 0, 0, 0 ), uno::UNO_SET_THROW ); + uno::Reference< sheet::XSheetCellRange > xExpanded( lclExpandToMerged( xTopLeft, false ), uno::UNO_SET_THROW ); + table::CellRangeAddress aExpAddr = lclGetRangeAddress( xExpanded ); + // check that expanded range has more than one cell (really merged) + if( ((aExpAddr.StartColumn < aExpAddr.EndColumn) || (aExpAddr.StartRow < aExpAddr.EndRow)) && ScUnoConversion::Contains( aExpAddr, aRangeAddr ) ) + return util::TriState_YES; + + /* 2) Check if this range contains any merged cells (completely or + partly). This seems to be hardly possible via API, as + XMergeable::getIsMerged() returns only true, if the top-left cell of a + merged range is part of this range, so cases where just the lower part + of a merged range is part of this range are not covered. */ + ScRange aScRange; + ScUnoConversion::FillScRange( aScRange, aRangeAddr ); + bool bHasMerged = getDocumentFromRange( rxCellRange ).HasAttrib( aScRange, HasAttrFlags::Merged | HasAttrFlags::Overlapped ); + return bHasMerged ? util::TriState_INDETERMINATE : util::TriState_NO; +} + +} // namespace + +css::uno::Reference< excel::XRange > +ScVbaRange::getRangeObjectForName( + const uno::Reference< uno::XComponentContext >& xContext, const OUString& sRangeName, + ScDocShell* pDocSh, formula::FormulaGrammar::AddressConvention eConv ) +{ + table::CellRangeAddress refAddr; + return getRangeForName( xContext, sRangeName, pDocSh, refAddr, eConv ); +} + +/// @throws uno::RuntimeException +static table::CellRangeAddress getCellRangeAddressForVBARange( const uno::Any& aParam, ScDocShell* pDocSh ) +{ + uno::Reference< table::XCellRange > xRangeParam; + switch ( aParam.getValueTypeClass() ) + { + case uno::TypeClass_STRING: + { + OUString rString; + aParam >>= rString; + ScRangeList aCellRanges; + ScRange refRange; + if ( getScRangeListForAddress ( rString, pDocSh, refRange, aCellRanges ) ) + { + if ( aCellRanges.size() == 1 ) + { + table::CellRangeAddress aRangeAddress; + ScUnoConversion::FillApiRange( aRangeAddress, aCellRanges.front() ); + return aRangeAddress; + } + } + } + break; + + case uno::TypeClass_INTERFACE: + { + uno::Reference< excel::XRange > xRange; + aParam >>= xRange; + if ( xRange.is() ) + xRange->getCellRange() >>= xRangeParam; + } + break; + + default: + throw uno::RuntimeException("Can't extract CellRangeAddress from type" ); + } + return lclGetRangeAddress( xRangeParam ); +} + +/// @throws uno::RuntimeException +static uno::Reference< XCollection > +lcl_setupBorders( const uno::Reference< excel::XRange >& xParentRange, const uno::Reference<uno::XComponentContext>& xContext, const uno::Reference< table::XCellRange >& xRange ) +{ + uno::Reference< XHelperInterface > xParent( xParentRange, uno::UNO_QUERY_THROW ); + ScDocument& rDoc = getDocumentFromRange(xRange); + ScVbaPalette aPalette( rDoc.GetDocumentShell() ); + uno::Reference< XCollection > borders( new ScVbaBorders( xParent, xContext, xRange, aPalette ) ); + return borders; +} + +ScVbaRange::ScVbaRange( uno::Sequence< uno::Any> const & args, + uno::Reference< uno::XComponentContext> const & xContext ) : ScVbaRange_BASE( getXSomethingFromArgs< XHelperInterface >( args, 0 ), xContext, getXSomethingFromArgs< beans::XPropertySet >( args, 1, false ), getModelFromXIf( getXSomethingFromArgs< uno::XInterface >( args, 1 ) ), true ), mbIsRows( false ), mbIsColumns( false ) +{ + mxRange.set( mxPropertySet, uno::UNO_QUERY ); + mxRanges.set( mxPropertySet, uno::UNO_QUERY ); + uno::Reference< container::XIndexAccess > xIndex; + if ( mxRange.is() ) + { + xIndex = new SingleRangeIndexAccess( mxRange ); + } + else if ( mxRanges.is() ) + { + xIndex.set( mxRanges, uno::UNO_QUERY_THROW ); + } + m_Areas = new ScVbaRangeAreas( mxParent, mxContext, xIndex, mbIsRows, mbIsColumns ); +} + +ScVbaRange::ScVbaRange( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< table::XCellRange >& xRange, bool bIsRows, bool bIsColumns ) +: ScVbaRange_BASE( xParent, xContext, uno::Reference< beans::XPropertySet >( xRange, uno::UNO_QUERY_THROW ), getModelFromRange( xRange), true ), mxRange( xRange ), + mbIsRows( bIsRows ), + mbIsColumns( bIsColumns ) +{ + if ( !xContext.is() ) + throw lang::IllegalArgumentException("context is not set ", uno::Reference< uno::XInterface >() , 1 ); + if ( !xRange.is() ) + throw lang::IllegalArgumentException("range is not set ", uno::Reference< uno::XInterface >() , 1 ); + + uno::Reference< container::XIndexAccess > xIndex( new SingleRangeIndexAccess( xRange ) ); + m_Areas = new ScVbaRangeAreas( mxParent, mxContext, xIndex, mbIsRows, mbIsColumns ); + +} + +ScVbaRange::ScVbaRange(const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< sheet::XSheetCellRangeContainer >& xRanges, bool bIsRows, bool bIsColumns) +: ScVbaRange_BASE( xParent, xContext, uno::Reference< beans::XPropertySet >( xRanges, uno::UNO_QUERY_THROW ), getModelFromXIf( uno::Reference< uno::XInterface >( xRanges, uno::UNO_QUERY_THROW ) ), true ), mxRanges( xRanges ),mbIsRows( bIsRows ), mbIsColumns( bIsColumns ) + +{ + uno::Reference< container::XIndexAccess > xIndex( mxRanges, uno::UNO_QUERY_THROW ); + m_Areas = new ScVbaRangeAreas( xParent, mxContext, xIndex, mbIsRows, mbIsColumns ); + +} + +ScVbaRange::~ScVbaRange() +{ +} + +uno::Reference< XCollection >& ScVbaRange::getBorders() +{ + if ( !m_Borders.is() ) + { + uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( sal_Int32(1) ), uno::Any() ), uno::UNO_QUERY_THROW ); + m_Borders = lcl_setupBorders( this, mxContext, uno::Reference< table::XCellRange >( xRange->getCellRange(), uno::UNO_QUERY_THROW ) ); + } + return m_Borders; +} + +void +ScVbaRange::visitArray( ArrayVisitor& visitor ) +{ + ScDocShell* pDocSh = nullptr; + if(ScCellRangeObj* range = dynamic_cast<ScCellRangeObj*>(mxRange.get())) + pDocSh = range->GetDocShell(); + if ( pDocSh ) + pDocSh->LockPaint(); + table::CellRangeAddress aRangeAddr = lclGetRangeAddress( mxRange ); + sal_Int32 nRowCount = aRangeAddr.EndRow - aRangeAddr.StartRow + 1; + sal_Int32 nColCount = aRangeAddr.EndColumn - aRangeAddr.StartColumn + 1; + for ( sal_Int32 i=0; i<nRowCount; ++i ) + { + for ( sal_Int32 j=0; j<nColCount; ++j ) + { + uno::Reference< table::XCell > xCell( mxRange->getCellByPosition( j, i ), uno::UNO_SET_THROW ); + + visitor.visitNode( i, j, xCell ); + } + } + if ( pDocSh ) + pDocSh->UnlockPaint(); +} + +uno::Any +ScVbaRange::getValue( ValueGetter& valueGetter) +{ + uno::Reference< table::XColumnRowRange > xColumnRowRange(mxRange, uno::UNO_QUERY_THROW ); + // single cell range + if ( isSingleCellRange() ) + { + visitArray( valueGetter ); + return valueGetter.getValue(); + } + sal_Int32 nRowCount = xColumnRowRange->getRows()->getCount(); + sal_Int32 nColCount = xColumnRowRange->getColumns()->getCount(); + // multi cell range ( return array ) + Dim2ArrayValueGetter arrayGetter( nRowCount, nColCount, valueGetter ); + visitArray( arrayGetter ); + return uno::Any( script::ArrayWrapper( false, arrayGetter.getValue() ) ); +} + +uno::Any SAL_CALL +ScVbaRange::getValue() +{ + // #TODO code within the test below "if ( m_Areas... " can be removed + // Test is performed only because m_xRange is NOT set to be + // the first range in m_Areas ( to force failure while + // the implementations for each method are being updated ) + if ( m_Areas->getCount() > 1 ) + { + uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW ); + return xRange->getValue(); + } + + CellValueGetter valueGetter; + return getValue( valueGetter ); + +} + +void +ScVbaRange::setValue( const uno::Any& aValue, ValueSetter& valueSetter ) +{ + uno::TypeClass aClass = aValue.getValueTypeClass(); + if ( aClass == uno::TypeClass_SEQUENCE ) + { + const uno::Reference< script::XTypeConverter >& xConverter = getTypeConverter( mxContext ); + uno::Any aConverted; + try + { + // test for single dimension, could do + // with a better test than this + if ( aValue.getValueTypeName().indexOf('[') == aValue.getValueTypeName().lastIndexOf('[') ) + { + aConverted = xConverter->convertTo( aValue, cppu::UnoType<uno::Sequence< uno::Any >>::get() ); + Dim1ArrayValueSetter setter( aConverted, valueSetter ); + visitArray( setter ); + } + else + { + aConverted = xConverter->convertTo( aValue, cppu::UnoType<uno::Sequence< uno::Sequence< uno::Any > >>::get() ); + Dim2ArrayValueSetter setter( aConverted, valueSetter ); + visitArray( setter ); + } + } + catch ( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("sc", "Bahhh, caught" ); + } + } + else + { + visitArray( valueSetter ); + } + fireChangeEvent(); +} + +void SAL_CALL +ScVbaRange::setValue( const uno::Any &aValue ) +{ + // If this is a multiple selection apply setValue over all areas + if ( m_Areas->getCount() > 1 ) + { + AreasVisitor aVisitor( m_Areas ); + RangeValueProcessor valueProcessor( aValue ); + aVisitor.visit( valueProcessor ); + return; + } + CellValueSetter valueSetter( aValue ); + setValue( aValue, valueSetter ); +} + +void SAL_CALL +ScVbaRange::Clear() +{ + using namespace ::com::sun::star::sheet::CellFlags; + sal_Int32 const nFlags = VALUE | DATETIME | STRING | FORMULA | HARDATTR | EDITATTR | FORMATTED; + ClearContents( nFlags, true ); +} + +//helper ClearContent +void +ScVbaRange::ClearContents( sal_Int32 nFlags, bool bFireEvent ) +{ + // #TODO code within the test below "if ( m_Areas... " can be removed + // Test is performed only because m_xRange is NOT set to be + // the first range in m_Areas ( to force failure while + // the implementations for each method are being updated ) + if ( m_Areas->getCount() > 1 ) + { + sal_Int32 nItems = m_Areas->getCount(); + for ( sal_Int32 index=1; index <= nItems; ++index ) + { + uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW ); + ScVbaRange* pRange = getImplementation( xRange ); + if ( pRange ) + pRange->ClearContents( nFlags, false ); // do not fire for single ranges + } + // fire change event for the entire range list + if( bFireEvent ) fireChangeEvent(); + return; + } + + uno::Reference< sheet::XSheetOperation > xSheetOperation(mxRange, uno::UNO_QUERY_THROW); + xSheetOperation->clearContents( nFlags ); + if( bFireEvent ) fireChangeEvent(); +} + +void SAL_CALL +ScVbaRange::ClearComments() +{ + ClearContents( sheet::CellFlags::ANNOTATION, false ); +} + +void SAL_CALL +ScVbaRange::ClearContents() +{ + using namespace ::com::sun::star::sheet::CellFlags; + sal_Int32 const nFlags = VALUE | DATETIME | STRING | FORMULA; + ClearContents( nFlags, true ); +} + +void SAL_CALL +ScVbaRange::ClearFormats() +{ + // FIXME: need to check if we need to combine FORMATTED + using namespace ::com::sun::star::sheet::CellFlags; + sal_Int32 const nFlags = HARDATTR | FORMATTED | EDITATTR; + ClearContents( nFlags, false ); +} + +void +ScVbaRange::setFormulaValue( const uno::Any& rFormula, formula::FormulaGrammar::Grammar eGram ) +{ + // If this is a multiple selection apply setFormula over all areas + if ( m_Areas->getCount() > 1 ) + { + AreasVisitor aVisitor( m_Areas ); + RangeFormulaProcessor valueProcessor( rFormula ); + aVisitor.visit( valueProcessor ); + return; + } + CellFormulaValueSetter formulaValueSetter( rFormula, getScDocument(), eGram ); + setValue( rFormula, formulaValueSetter ); +} + +uno::Any +ScVbaRange::getFormulaValue( formula::FormulaGrammar::Grammar eGram ) +{ + // #TODO code within the test below "if ( m_Areas... " can be removed + // Test is performed only because m_xRange is NOT set to be + // the first range in m_Areas ( to force failure while + // the implementations for each method are being updated ) + if ( m_Areas->getCount() > 1 ) + { + uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW ); + return xRange->getFormula(); + } + CellFormulaValueGetter valueGetter( getScDocument(), eGram ); + return getValue( valueGetter ); + +} + +uno::Any +ScVbaRange::getFormula() +{ + return getFormulaValue( formula::FormulaGrammar::GRAM_ENGLISH_XL_A1 ); +} + +void +ScVbaRange::setFormula(const uno::Any &rFormula ) +{ + setFormulaValue( rFormula, formula::FormulaGrammar::GRAM_ENGLISH_XL_A1 ); +} + +uno::Any +ScVbaRange::getFormulaR1C1() +{ + return getFormulaValue( formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1 ); +} + +void +ScVbaRange::setFormulaR1C1(const uno::Any& rFormula ) +{ + setFormulaValue( rFormula, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1 ); +} + +uno::Any +ScVbaRange::getFormulaLocal() +{ + return getFormulaValue( formula::FormulaGrammar::GRAM_NATIVE_XL_A1 ); +} + +void +ScVbaRange::setFormulaLocal(const uno::Any &rFormula ) +{ + setFormulaValue( rFormula, formula::FormulaGrammar::GRAM_NATIVE_XL_A1 ); +} + +uno::Any +ScVbaRange::getFormulaR1C1Local() +{ + return getFormulaValue( formula::FormulaGrammar::GRAM_NATIVE_XL_R1C1 ); +} + +void +ScVbaRange::setFormulaR1C1Local(const uno::Any& rFormula ) +{ + setFormulaValue( rFormula, formula::FormulaGrammar::GRAM_NATIVE_XL_R1C1 ); +} + +sal_Int32 +ScVbaRange::getCount() +{ + // If this is a multiple selection apply setValue over all areas + if ( m_Areas->getCount() > 1 ) + { + AreasVisitor aVisitor( m_Areas ); + RangeCountProcessor valueProcessor; + aVisitor.visit( valueProcessor ); + return valueProcessor.value(); + } + sal_Int32 rowCount = 0; + sal_Int32 colCount = 0; + uno::Reference< table::XColumnRowRange > xColumnRowRange(mxRange, uno::UNO_QUERY_THROW ); + rowCount = xColumnRowRange->getRows()->getCount(); + colCount = xColumnRowRange->getColumns()->getCount(); + + if( mbIsRows ) + return rowCount; + if( mbIsColumns ) + return colCount; + return rowCount * colCount; +} + +sal_Int32 +ScVbaRange::getRow() +{ + // #TODO code within the test below "if ( m_Areas... " can be removed + // Test is performed only because m_xRange is NOT set to be + // the first range in m_Areas ( to force failure while + // the implementations for each method are being updated ) + if ( m_Areas->getCount() > 1 ) + { + uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW ); + return xRange->getRow(); + } + uno::Reference< sheet::XCellAddressable > xCellAddressable(mxRange->getCellByPosition(0, 0), uno::UNO_QUERY_THROW ); + return xCellAddressable->getCellAddress().Row + 1; // Zero value indexing +} + +sal_Int32 +ScVbaRange::getColumn() +{ + // #TODO code within the test below "if ( m_Areas... " can be removed + // Test is performed only because m_xRange is NOT set to be + // the first range in m_Areas ( to force failure while + // the implementations for each method are being updated ) + if ( m_Areas->getCount() > 1 ) + { + uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW ); + return xRange->getColumn(); + } + uno::Reference< sheet::XCellAddressable > xCellAddressable(mxRange->getCellByPosition(0, 0), uno::UNO_QUERY_THROW ); + return xCellAddressable->getCellAddress().Column + 1; // Zero value indexing +} + +uno::Any +ScVbaRange::HasFormula() +{ + if ( m_Areas->getCount() > 1 ) + { + sal_Int32 nItems = m_Areas->getCount(); + uno::Any aResult = aNULL(); + for ( sal_Int32 index=1; index <= nItems; ++index ) + { + uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW ); + // if the HasFormula for any area is different to another + // return null + if ( index > 1 ) + if ( aResult != xRange->HasFormula() ) + return aNULL(); + aResult = xRange->HasFormula(); + if ( aNULL() == aResult ) + return aNULL(); + } + return aResult; + } + uno::Reference< uno::XInterface > xIf( mxRange, uno::UNO_QUERY_THROW ); + ScCellRangesBase* pThisRanges = dynamic_cast< ScCellRangesBase * > ( xIf.get() ); + if ( pThisRanges ) + { + uno::Reference<uno::XInterface> xRanges( pThisRanges->queryFormulaCells( sheet::FormulaResult::ERROR | sheet::FormulaResult::VALUE | sheet::FormulaResult::STRING ), uno::UNO_QUERY_THROW ); + ScCellRangesBase* pFormulaRanges = dynamic_cast< ScCellRangesBase * > ( xRanges.get() ); + assert(pFormulaRanges); + // check if there are no formula cell, return false + if ( pFormulaRanges->GetRangeList().empty() ) + return uno::Any(false); + + // check if there are holes (where some cells are not formulas) + // or returned range is not equal to this range + if ( ( pFormulaRanges->GetRangeList().size() > 1 ) + || ( pFormulaRanges->GetRangeList().front().aStart != pThisRanges->GetRangeList().front().aStart ) + || ( pFormulaRanges->GetRangeList().front().aEnd != pThisRanges->GetRangeList().front().aEnd ) + ) + return aNULL(); // should return aNULL; + } + return uno::Any( true ); +} +void +ScVbaRange::fillSeries( sheet::FillDirection nFillDirection, sheet::FillMode nFillMode, sheet::FillDateMode nFillDateMode, double fStep, double fEndValue ) +{ + if ( m_Areas->getCount() > 1 ) + { + // Multi-Area Range + uno::Reference< XCollection > xCollection( m_Areas, uno::UNO_SET_THROW ); + for ( sal_Int32 index = 1; index <= xCollection->getCount(); ++index ) + { + uno::Reference< excel::XRange > xRange( xCollection->Item( uno::Any( index ), uno::Any() ), uno::UNO_QUERY_THROW ); + ScVbaRange* pThisRange = getImplementation( xRange ); + pThisRange->fillSeries( nFillDirection, nFillMode, nFillDateMode, fStep, fEndValue ); + + } + return; + } + + uno::Reference< sheet::XCellSeries > xCellSeries(mxRange, uno::UNO_QUERY_THROW ); + xCellSeries->fillSeries( nFillDirection, nFillMode, nFillDateMode, fStep, fEndValue ); + fireChangeEvent(); +} + +void +ScVbaRange::FillLeft() +{ + fillSeries(sheet::FillDirection_TO_LEFT, + sheet::FillMode_SIMPLE, sheet::FillDateMode_FILL_DATE_DAY, 0, 0x7FFFFFFF); +} + +void +ScVbaRange::FillRight() +{ + fillSeries(sheet::FillDirection_TO_RIGHT, + sheet::FillMode_SIMPLE, sheet::FillDateMode_FILL_DATE_DAY, 0, 0x7FFFFFFF); +} + +void +ScVbaRange::FillUp() +{ + fillSeries(sheet::FillDirection_TO_TOP, + sheet::FillMode_SIMPLE, sheet::FillDateMode_FILL_DATE_DAY, 0, 0x7FFFFFFF); +} + +void +ScVbaRange::FillDown() +{ + fillSeries(sheet::FillDirection_TO_BOTTOM, + sheet::FillMode_SIMPLE, sheet::FillDateMode_FILL_DATE_DAY, 0, 0x7FFFFFFF); +} + +OUString +ScVbaRange::getText() +{ + // #TODO code within the test below "if ( m_Areas... " can be removed + // Test is performed only because m_xRange is NOT set to be + // the first range in m_Areas ( to force failure while + // the implementations for each method are being updated ) + if ( m_Areas->getCount() > 1 ) + { + uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW ); + return xRange->getText(); + } + uno::Reference< text::XTextRange > xTextRange(mxRange->getCellByPosition(0,0), uno::UNO_QUERY_THROW ); + return xTextRange->getString(); +} + +uno::Reference< excel::XRange > +ScVbaRange::Offset( const ::uno::Any &nRowOff, const uno::Any &nColOff ) +{ + SCROW nRowOffset = 0; + SCCOL nColOffset = 0; + bool bIsRowOffset = ( nRowOff >>= nRowOffset ); + bool bIsColumnOffset = ( nColOff >>= nColOffset ); + ScCellRangesBase* pUnoRangesBase = getCellRangesBase(); + + ScRangeList aCellRanges = pUnoRangesBase->GetRangeList(); + + for ( size_t i = 0, nRanges = aCellRanges.size(); i < nRanges; ++i ) + { + ScRange & rRange = aCellRanges[ i ]; + if ( bIsColumnOffset ) + { + rRange.aStart.SetCol( rRange.aStart.Col() + nColOffset ); + rRange.aEnd.SetCol( rRange.aEnd.Col() + nColOffset ); + } + if ( bIsRowOffset ) + { + rRange.aStart.SetRow( rRange.aStart.Row() + nRowOffset ); + rRange.aEnd.SetRow( rRange.aEnd.Row() + nRowOffset ); + } + } + + if ( aCellRanges.size() > 1 ) // Multi-Area + { + uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( pUnoRangesBase->GetDocShell(), aCellRanges ) ); + return new ScVbaRange( mxParent, mxContext, xRanges ); + } + // normal range + const ScRange aRange( obtainRangeEvenIfRangeListIsEmpty( aCellRanges)); + uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( pUnoRangesBase->GetDocShell(), aRange)); + return new ScVbaRange( mxParent, mxContext, xRange ); +} + +uno::Reference< excel::XRange > +ScVbaRange::CurrentRegion() +{ + // #TODO code within the test below "if ( m_Areas... " can be removed + // Test is performed only because m_xRange is NOT set to be + // the first range in m_Areas ( to force failure while + // the implementations for each method are being updated ) + if ( m_Areas->getCount() > 1 ) + { + uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW ); + return xRange->CurrentRegion(); + } + + RangeHelper helper( mxRange ); + uno::Reference< sheet::XSheetCellCursor > xSheetCellCursor = + helper.getSheetCellCursor(); + xSheetCellCursor->collapseToCurrentRegion(); + uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable(xSheetCellCursor, uno::UNO_QUERY_THROW); + return RangeHelper::createRangeFromRange( mxParent, mxContext, helper.getCellRangeFromSheet(), xCellRangeAddressable ); +} + +uno::Reference< excel::XRange > +ScVbaRange::CurrentArray() +{ + // #TODO code within the test below "if ( m_Areas... " can be removed + // Test is performed only because m_xRange is NOT set to be + // the first range in m_Areas ( to force failure while + // the implementations for each method are being updated ) + if ( m_Areas->getCount() > 1 ) + { + uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW ); + return xRange->CurrentArray(); + } + RangeHelper helper( mxRange ); + uno::Reference< sheet::XSheetCellCursor > xSheetCellCursor = + helper.getSheetCellCursor(); + xSheetCellCursor->collapseToCurrentArray(); + uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable(xSheetCellCursor, uno::UNO_QUERY_THROW); + return RangeHelper::createRangeFromRange( mxParent, mxContext, helper.getCellRangeFromSheet(), xCellRangeAddressable ); +} + +uno::Any +ScVbaRange::getFormulaArray() +{ + // #TODO code within the test below "if ( m_Areas... " can be removed + // Test is performed only because m_xRange is NOT set to be + // the first range in m_Areas ( to force failure while + // the implementations for each method are being updated ) + if ( m_Areas->getCount() > 1 ) + { + uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW ); + return xRange->getFormulaArray(); + } + + // return a formula if there is one or else an array + // still not sure when the return as array code should run + // ( I think it is if there is more than one formula ) at least + // that is what the doc says ( but I am not even sure how to detect that ) + // for the moment any tests we have pass + uno::Reference< sheet::XArrayFormulaRange> xFormulaArray( mxRange, uno::UNO_QUERY_THROW ); + if ( !xFormulaArray->getArrayFormula().isEmpty() ) + return uno::Any( xFormulaArray->getArrayFormula() ); + + uno::Reference< sheet::XCellRangeFormula> xCellRangeFormula( mxRange, uno::UNO_QUERY_THROW ); + const uno::Reference< script::XTypeConverter >& xConverter = getTypeConverter( mxContext ); + uno::Any aSingleValueOrMatrix; + // When dealing with a single element ( embedded in the sequence of sequence ) unwrap and return + // that value + uno::Sequence< uno::Sequence<OUString> > aTmpSeq = xCellRangeFormula->getFormulaArray(); + if ( aTmpSeq.getLength() == 1 ) + { + if ( aTmpSeq[ 0 ].getLength() == 1 ) + aSingleValueOrMatrix <<= aTmpSeq[ 0 ][ 0 ]; + } + else + aSingleValueOrMatrix = xConverter->convertTo( uno::Any( aTmpSeq ) , cppu::UnoType<uno::Sequence< uno::Sequence< uno::Any > >>::get() ) ; + return aSingleValueOrMatrix; +} + +void +ScVbaRange::setFormulaArray(const uno::Any& rFormula) +{ + // #TODO code within the test below "if ( m_Areas... " can be removed + // Test is performed only because m_xRange is NOT set to be + // the first range in m_Areas ( to force failure while + // the implementations for each method are being updated ) + if ( m_Areas->getCount() > 1 ) + { + uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW ); + return xRange->setFormulaArray( rFormula ); + } + // #TODO need to distinguish between getFormula and getFormulaArray e.g. (R1C1) + // but for the moment it's just easier to treat them the same for setting + // seems + uno::Reference< lang::XMultiServiceFactory > xModelFactory( getUnoModel(), uno::UNO_QUERY_THROW ); + uno::Reference< sheet::XFormulaParser > xParser( xModelFactory->createInstance( "com.sun.star.sheet.FormulaParser" ), uno::UNO_QUERY_THROW ); + uno::Reference< sheet::XCellRangeAddressable > xSource( mxRange, uno::UNO_QUERY_THROW); + + table::CellRangeAddress aRangeAddress = xSource->getRangeAddress(); + // #TODO check if api orders the address + // e.g. do we need to order the RangeAddress to get the topleft ( or can we assume it + // is in the correct order ) + table::CellAddress aAddress; + aAddress.Sheet = aRangeAddress.Sheet; + aAddress.Column = aRangeAddress.StartColumn; + aAddress.Row = aRangeAddress.StartRow; + OUString sFormula; + rFormula >>= sFormula; + uno::Sequence<sheet::FormulaToken> aTokens = xParser->parseFormula( sFormula, aAddress ); + ScTokenArray aTokenArray(getScDocument()); + (void)ScTokenConversion::ConvertToTokenArray( getScDocument(), aTokenArray, aTokens ); + + getScDocShell()->GetDocFunc().EnterMatrix( getScRangeList()[0], nullptr, &aTokenArray, OUString(), true, true, OUString(), formula::FormulaGrammar::GRAM_API ); +} + +OUString +ScVbaRange::Characters(const uno::Any& Start, const uno::Any& Length) +{ + // #TODO code within the test below "if ( m_Areas... " can be removed + // Test is performed only because m_xRange is NOT set to be + // the first range in m_Areas ( to force failure while + // the implementations for each method are being updated ) + if ( m_Areas->getCount() > 1 ) + { + uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW ); + return xRange->Characters( Start, Length ); + } + + tools::Long nIndex = 0, nCount = 0; + OUString rString; + uno::Reference< text::XTextRange > xTextRange(mxRange, ::uno::UNO_QUERY_THROW ); + rString = xTextRange->getString(); + if( !( Start >>= nIndex ) && !( Length >>= nCount ) ) + return rString; + if(!( Start >>= nIndex ) ) + nIndex = 1; + if(!( Length >>= nCount ) ) + nIndex = rString.getLength(); + return rString.copy( --nIndex, nCount ); // Zero value indexing +} + +OUString +ScVbaRange::Address( const uno::Any& RowAbsolute, const uno::Any& ColumnAbsolute, const uno::Any& ReferenceStyle, const uno::Any& External, const uno::Any& RelativeTo ) +{ + if ( m_Areas->getCount() > 1 ) + { + // Multi-Area Range + OUStringBuffer sAddress; + uno::Reference< XCollection > xCollection( m_Areas, uno::UNO_SET_THROW ); + uno::Any aExternalCopy = External; + for ( sal_Int32 index = 1; index <= xCollection->getCount(); ++index ) + { + uno::Reference< excel::XRange > xRange( xCollection->Item( uno::Any( index ), uno::Any() ), uno::UNO_QUERY_THROW ); + if ( index > 1 ) + { + sAddress.append(","); + // force external to be false + // only first address should have the + // document and sheet specifications + aExternalCopy <<= false; + } + sAddress.append(xRange->Address( RowAbsolute, ColumnAbsolute, ReferenceStyle, aExternalCopy, RelativeTo )); + } + return sAddress.makeStringAndClear(); + + } + ScAddress::Details dDetails( formula::FormulaGrammar::CONV_XL_A1, 0, 0 ); + if ( ReferenceStyle.hasValue() ) + { + sal_Int32 refStyle = excel::XlReferenceStyle::xlA1; + ReferenceStyle >>= refStyle; + if ( refStyle == excel::XlReferenceStyle::xlR1C1 ) + dDetails = ScAddress::Details( formula::FormulaGrammar::CONV_XL_R1C1, 0, 0 ); + } + // default + ScRefFlags nFlags = ScRefFlags::RANGE_ABS; + ScDocShell* pDocShell = getScDocShell(); + ScDocument& rDoc = pDocShell->GetDocument(); + + RangeHelper thisRange( mxRange ); + table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); + ScRange aRange( static_cast< SCCOL >( thisAddress.StartColumn ), static_cast< SCROW >( thisAddress.StartRow ), static_cast< SCTAB >( thisAddress.Sheet ), static_cast< SCCOL >( thisAddress.EndColumn ), static_cast< SCROW >( thisAddress.EndRow ), static_cast< SCTAB >( thisAddress.Sheet ) ); + constexpr ScRefFlags ROW_ABS = ScRefFlags::ROW_ABS | ScRefFlags::ROW2_ABS; + constexpr ScRefFlags COL_ABS = ScRefFlags::COL_ABS | ScRefFlags::COL2_ABS; + + if ( RowAbsolute.hasValue() ) + { + bool bVal = true; + RowAbsolute >>= bVal; + if ( !bVal ) + nFlags &= ~ROW_ABS; + } + if ( ColumnAbsolute.hasValue() ) + { + bool bVal = true; + ColumnAbsolute >>= bVal; + if ( !bVal ) + nFlags &= ~COL_ABS; + } + if ( External.hasValue() ) + { + bool bLocal = false; + External >>= bLocal; + if ( bLocal ) + nFlags |= ScRefFlags::TAB_3D | ScRefFlags::FORCE_DOC; + } + if ( RelativeTo.hasValue() ) + { + // #TODO should I throw an error if R1C1 is not set? + + table::CellRangeAddress refAddress = getCellRangeAddressForVBARange( RelativeTo, pDocShell ); + dDetails = ScAddress::Details( formula::FormulaGrammar::CONV_XL_R1C1, static_cast< SCROW >( refAddress.StartRow ), static_cast< SCCOL >( refAddress.StartColumn ) ); + } + return aRange.Format(rDoc, nFlags, dDetails); +} + +uno::Reference < excel::XFont > +ScVbaRange::Font() +{ + uno::Reference< beans::XPropertySet > xProps(mxRange, ::uno::UNO_QUERY ); + ScDocument& rDoc = getScDocument(); + if ( mxRange.is() ) + xProps.set(mxRange, ::uno::UNO_QUERY ); + else if ( mxRanges.is() ) + xProps.set(mxRanges, ::uno::UNO_QUERY ); + + ScVbaPalette aPalette( rDoc.GetDocumentShell() ); + ScCellRangeObj* pRangeObj = nullptr; + try + { + pRangeObj = getCellRangeObj(); + } + catch( uno::Exception& ) + { + } + return new ScVbaFont( this, mxContext, aPalette, xProps, pRangeObj ); +} + +uno::Reference< excel::XRange > +ScVbaRange::Cells( const uno::Any &nRowIndex, const uno::Any &nColumnIndex ) +{ + // #TODO code within the test below "if ( m_Areas... " can be removed + // Test is performed only because m_xRange is NOT set to be + // the first range in m_Areas ( to force failure while + // the implementations for each method are being updated ) + if ( m_Areas->getCount() > 1 ) + { + uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW ); + return xRange->Cells( nRowIndex, nColumnIndex ); + } + + // Performance: Use a common helper method for ScVbaRange::Cells and ScVbaWorksheet::Cells, + // instead of creating a new ScVbaRange object in often-called ScVbaWorksheet::Cells + return CellsHelper( getScDocument(), mxParent, mxContext, mxRange, nRowIndex, nColumnIndex ); +} + +// static +uno::Reference< excel::XRange > +ScVbaRange::CellsHelper( const ScDocument& rDoc, + const uno::Reference< ov::XHelperInterface >& xParent, + const uno::Reference< uno::XComponentContext >& xContext, + const uno::Reference< css::table::XCellRange >& xRange, + const uno::Any &nRowIndex, const uno::Any &nColumnIndex ) +{ + sal_Int32 nRow = 0, nColumn = 0; + + bool bIsIndex = nRowIndex.hasValue(); + bool bIsColumnIndex = nColumnIndex.hasValue(); + + // Sometimes we might get a float or a double or whatever + // set in the Any, we should convert as appropriate + // #FIXME - perhaps worth turning this into some sort of + // conversion routine e.g. bSuccess = getValueFromAny( nRow, nRowIndex, cppu::UnoType<sal_Int32>::get() ) + if ( nRowIndex.hasValue() && !( nRowIndex >>= nRow ) ) + { + const uno::Reference< script::XTypeConverter >& xConverter = getTypeConverter( xContext ); + uno::Any aConverted; + try + { + aConverted = xConverter->convertTo( nRowIndex, cppu::UnoType<sal_Int32>::get() ); + bIsIndex = ( aConverted >>= nRow ); + } + catch( uno::Exception& ) {} // silence any errors + } + + if ( bIsColumnIndex ) + { + // Column index can be a col address e.g Cells( 1, "B" ) etc. + OUString sCol; + if ( nColumnIndex >>= sCol ) + { + ScAddress::Details dDetails( formula::FormulaGrammar::CONV_XL_A1, 0, 0 ); + ScRange tmpRange; + ScRefFlags flags = tmpRange.ParseCols( rDoc, sCol, dDetails ); + if ( (flags & ScRefFlags::COL_VALID) == ScRefFlags::ZERO ) + throw uno::RuntimeException(); + nColumn = tmpRange.aStart.Col() + 1; + } + else + { + if ( !( nColumnIndex >>= nColumn ) ) + { + const uno::Reference< script::XTypeConverter >& xConverter = getTypeConverter( xContext ); + uno::Any aConverted; + try + { + aConverted = xConverter->convertTo( nColumnIndex, cppu::UnoType<sal_Int32>::get() ); + bIsColumnIndex = ( aConverted >>= nColumn ); + } + catch( uno::Exception& ) {} // silence any errors + } + } + } + RangeHelper thisRange( xRange ); + table::CellRangeAddress thisRangeAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); + uno::Reference< table::XCellRange > xSheetRange = thisRange.getCellRangeFromSheet(); + if( !bIsIndex && !bIsColumnIndex ) // .Cells + // #FIXME needs proper parent ( Worksheet ) + return uno::Reference< excel::XRange >( new ScVbaRange( xParent, xContext, xRange ) ); + + sal_Int32 nIndex = --nRow; + if( bIsIndex && !bIsColumnIndex ) // .Cells(n) + { + uno::Reference< table::XColumnRowRange > xColumnRowRange(xRange, ::uno::UNO_QUERY_THROW); + sal_Int32 nColCount = xColumnRowRange->getColumns()->getCount(); + + if ( !nIndex || nIndex < 0 ) + nRow = 0; + else + nRow = nIndex / nColCount; + nColumn = nIndex % nColCount; + } + else + --nColumn; + nRow = nRow + thisRangeAddress.StartRow; + nColumn = nColumn + thisRangeAddress.StartColumn; + return new ScVbaRange( xParent, xContext, xSheetRange->getCellRangeByPosition( nColumn, nRow, nColumn, nRow ) ); +} + +void +ScVbaRange::Select() +{ + ScCellRangesBase* pUnoRangesBase = getCellRangesBase(); + if ( !pUnoRangesBase ) + throw uno::RuntimeException("Failed to access underlying uno range object" ); + ScDocShell* pShell = pUnoRangesBase->GetDocShell(); + if ( !pShell ) + return; + + uno::Reference< frame::XModel > xModel( pShell->GetModel(), uno::UNO_SET_THROW ); + uno::Reference< view::XSelectionSupplier > xSelection( xModel->getCurrentController(), uno::UNO_QUERY_THROW ); + if ( mxRanges.is() ) + xSelection->select( uno::Any( lclExpandToMerged( mxRanges ) ) ); + else + xSelection->select( uno::Any( lclExpandToMerged( mxRange, true ) ) ); + // set focus on document e.g. + // ThisComponent.CurrentController.Frame.getContainerWindow.SetFocus + try + { + uno::Reference< frame::XController > xController( xModel->getCurrentController(), uno::UNO_SET_THROW ); + uno::Reference< frame::XFrame > xFrame( xController->getFrame(), uno::UNO_SET_THROW ); + uno::Reference< awt::XWindow > xWin( xFrame->getContainerWindow(), uno::UNO_SET_THROW ); + xWin->setFocus(); + } + catch( uno::Exception& ) + { + } +} + +static bool cellInRange( const table::CellRangeAddress& rAddr, sal_Int32 nCol, sal_Int32 nRow ) +{ + return nCol >= rAddr.StartColumn && nCol <= rAddr.EndColumn && + nRow >= rAddr.StartRow && nRow <= rAddr.EndRow; +} + +static void setCursor( SCCOL nCol, SCROW nRow, const uno::Reference< frame::XModel >& xModel, bool bInSel = true ) +{ + ScTabViewShell* pShell = excel::getBestViewShell( xModel ); + if ( pShell ) + { + if ( bInSel ) + pShell->SetCursor( nCol, nRow ); + else + pShell->MoveCursorAbs( nCol, nRow, SC_FOLLOW_NONE, false, false, true ); + } +} + +void +ScVbaRange::Activate() +{ + // get first cell of current range + uno::Reference< table::XCellRange > xCellRange; + if ( mxRanges.is() ) + { + uno::Reference< container::XIndexAccess > xIndex( mxRanges, uno::UNO_QUERY_THROW ); + xCellRange.set( xIndex->getByIndex( 0 ), uno::UNO_QUERY_THROW ); + } + else + xCellRange.set( mxRange, uno::UNO_SET_THROW ); + + RangeHelper thisRange( xCellRange ); + uno::Reference< sheet::XCellRangeAddressable > xThisRangeAddress = thisRange.getCellRangeAddressable(); + table::CellRangeAddress thisRangeAddress = xThisRangeAddress->getRangeAddress(); + uno::Reference< frame::XModel > xModel; + ScDocShell* pShell = getScDocShell(); + + if ( pShell ) + xModel = pShell->GetModel(); + + if ( !xModel.is() ) + throw uno::RuntimeException(); + + // get current selection + uno::Reference< sheet::XCellRangeAddressable > xRange( xModel->getCurrentSelection(), ::uno::UNO_QUERY); + + uno::Reference< sheet::XSheetCellRanges > xRanges( xModel->getCurrentSelection(), ::uno::UNO_QUERY); + + if ( xRanges.is() ) + { + const uno::Sequence< table::CellRangeAddress > nAddrs = xRanges->getRangeAddresses(); + for ( const auto& rAddr : nAddrs ) + { + if ( cellInRange( rAddr, thisRangeAddress.StartColumn, thisRangeAddress.StartRow ) ) + { + setCursor( static_cast< SCCOL >( thisRangeAddress.StartColumn ), static_cast< SCROW >( thisRangeAddress.StartRow ), xModel ); + return; + } + + } + } + + if ( xRange.is() && cellInRange( xRange->getRangeAddress(), thisRangeAddress.StartColumn, thisRangeAddress.StartRow ) ) + setCursor( static_cast< SCCOL >( thisRangeAddress.StartColumn ), static_cast< SCROW >( thisRangeAddress.StartRow ), xModel ); + else + { + // if this range is multi cell select the range other + // wise just position the cell at this single range position + if ( isSingleCellRange() ) + // This top-leftmost cell of this Range is not in the current + // selection so just select this range + setCursor( static_cast< SCCOL >( thisRangeAddress.StartColumn ), static_cast< SCROW >( thisRangeAddress.StartRow ), xModel, false ); + else + Select(); + } + +} + +ScRange ScVbaRange::obtainRangeEvenIfRangeListIsEmpty( const ScRangeList& rCellRanges ) const +{ + // XXX It may be that using the current range list was never correct, but + // always the initial sheet range would be instead, history is unclear. + + if (!rCellRanges.empty()) + return rCellRanges.front(); + + table::CellRangeAddress aRA( lclGetRangeAddress( mxRange )); + return ScRange( aRA.StartColumn, aRA.StartRow, aRA.Sheet, aRA.EndColumn, aRA.EndRow, aRA.Sheet); +} + +uno::Reference< excel::XRange > +ScVbaRange::Rows(const uno::Any& aIndex ) +{ + if ( aIndex.hasValue() ) + { + ScCellRangesBase* pUnoRangesBase = getCellRangesBase(); + ScRange aRange( obtainRangeEvenIfRangeListIsEmpty( pUnoRangesBase->GetRangeList())); + + sal_Int32 nValue = 0; + OUString sAddress; + if( aIndex >>= nValue ) + { + aRange.aStart.SetRow( aRange.aStart.Row() + --nValue ); + aRange.aEnd.SetRow( aRange.aStart.Row() ); + } + else if ( aIndex >>= sAddress ) + { + ScAddress::Details dDetails( formula::FormulaGrammar::CONV_XL_A1, 0, 0 ); + ScRange tmpRange; + tmpRange.ParseRows( getScDocument(), sAddress, dDetails ); + SCROW nStartRow = tmpRange.aStart.Row(); + SCROW nEndRow = tmpRange.aEnd.Row(); + + aRange.aStart.SetRow( aRange.aStart.Row() + nStartRow ); + aRange.aEnd.SetRow( aRange.aStart.Row() + ( nEndRow - nStartRow )); + } + else + throw uno::RuntimeException("Illegal param" ); + + if ( aRange.aStart.Row() < 0 || aRange.aEnd.Row() < 0 ) + throw uno::RuntimeException("Internal failure, illegal param" ); + // return a normal range ( even for multi-selection + uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( pUnoRangesBase->GetDocShell(), aRange ) ); + return new ScVbaRange( mxParent, mxContext, xRange, true ); + } + // Rows() - no params + if ( m_Areas->getCount() > 1 ) + return new ScVbaRange( mxParent, mxContext, mxRanges, true ); + return new ScVbaRange( mxParent, mxContext, mxRange, true ); +} + +uno::Reference< excel::XRange > +ScVbaRange::Columns(const uno::Any& aIndex ) +{ + ScCellRangesBase* pUnoRangesBase = getCellRangesBase(); + ScRange aRange( obtainRangeEvenIfRangeListIsEmpty( pUnoRangesBase->GetRangeList())); + + if ( aIndex.hasValue() ) + { + OUString sAddress; + sal_Int32 nValue = 0; + if ( aIndex >>= nValue ) + { + aRange.aStart.SetCol( aRange.aStart.Col() + static_cast< SCCOL > ( --nValue ) ); + aRange.aEnd.SetCol( aRange.aStart.Col() ); + } + + else if ( aIndex >>= sAddress ) + { + ScAddress::Details dDetails( formula::FormulaGrammar::CONV_XL_A1, 0, 0 ); + ScRange tmpRange; + tmpRange.ParseCols( getScDocument(), sAddress, dDetails ); + SCCOL nStartCol = tmpRange.aStart.Col(); + SCCOL nEndCol = tmpRange.aEnd.Col(); + + aRange.aStart.SetCol( aRange.aStart.Col() + nStartCol ); + aRange.aEnd.SetCol( aRange.aStart.Col() + ( nEndCol - nStartCol )); + } + else + throw uno::RuntimeException("Illegal param" ); + + if ( aRange.aStart.Col() < 0 || aRange.aEnd.Col() < 0 ) + throw uno::RuntimeException("Internal failure, illegal param" ); + } + // Columns() - no params + uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( pUnoRangesBase->GetDocShell(), aRange ) ); + return new ScVbaRange( mxParent, mxContext, xRange, false, true ); +} + +void +ScVbaRange::setMergeCells( const uno::Any& aIsMerged ) +{ + bool bMerge = extractBoolFromAny( aIsMerged ); + + if( mxRanges.is() ) + { + sal_Int32 nCount = mxRanges->getCount(); + + // VBA does nothing (no error) if the own ranges overlap somehow + ::std::vector< table::CellRangeAddress > aList; + for( sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex ) + { + uno::Reference< sheet::XCellRangeAddressable > xRangeAddr( mxRanges->getByIndex( nIndex ), uno::UNO_QUERY_THROW ); + table::CellRangeAddress aAddress = xRangeAddr->getRangeAddress(); + if (std::any_of(aList.begin(), aList.end(), + [&aAddress](const table::CellRangeAddress& rAddress) + { return ScUnoConversion::Intersects( rAddress, aAddress ); })) + return; + aList.push_back( aAddress ); + } + + // (un)merge every range after it has been extended to intersecting merged ranges from sheet + for( sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex ) + { + uno::Reference< table::XCellRange > xRange( mxRanges->getByIndex( nIndex ), uno::UNO_QUERY_THROW ); + lclExpandAndMerge( xRange, bMerge ); + } + return; + } + + // otherwise, merge single range + lclExpandAndMerge( mxRange, bMerge ); +} + +uno::Any +ScVbaRange::getMergeCells() +{ + if( mxRanges.is() ) + { + sal_Int32 nCount = mxRanges->getCount(); + for( sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex ) + { + uno::Reference< table::XCellRange > xRange( mxRanges->getByIndex( nIndex ), uno::UNO_QUERY_THROW ); + util::TriState eMerged = lclGetMergedState( xRange ); + /* Excel always returns NULL, if one range of the range list is + partly or completely merged. Even if all ranges are completely + merged, the return value is still NULL. */ + if( eMerged != util::TriState_NO ) + return aNULL(); + } + // no range is merged anyhow, return false + return uno::Any( false ); + } + + // otherwise, check single range + switch( lclGetMergedState( mxRange ) ) + { + case util::TriState_YES: return uno::Any( true ); + case util::TriState_NO: return uno::Any( false ); + default: return aNULL(); + } +} + +void +ScVbaRange::Copy(const ::uno::Any& Destination) +{ + if ( Destination.hasValue() ) + { + // TODO copy with multiple selections should work here too + if ( m_Areas->getCount() > 1 ) + throw uno::RuntimeException("That command cannot be used on multiple selections" ); + uno::Reference< excel::XRange > xRange( Destination, uno::UNO_QUERY_THROW ); + uno::Any aRange = xRange->getCellRange(); + uno::Reference< table::XCellRange > xCellRange; + aRange >>= xCellRange; + uno::Reference< sheet::XSheetCellRange > xSheetCellRange(xCellRange, ::uno::UNO_QUERY_THROW); + uno::Reference< sheet::XSpreadsheet > xSheet = xSheetCellRange->getSpreadsheet(); + uno::Reference< table::XCellRange > xDest( xSheet, uno::UNO_QUERY_THROW ); + uno::Reference< sheet::XCellRangeMovement > xMover( xSheet, uno::UNO_QUERY_THROW); + uno::Reference< sheet::XCellAddressable > xDestination( xDest->getCellByPosition( + xRange->getColumn()-1,xRange->getRow()-1), uno::UNO_QUERY_THROW ); + uno::Reference< sheet::XCellRangeAddressable > xSource( mxRange, uno::UNO_QUERY); + xMover->copyRange( xDestination->getCellAddress(), xSource->getRangeAddress() ); + if ( ScVbaRange* pRange = getImplementation( xRange ) ) + pRange->fireChangeEvent(); + } + else + { + Select(); + excel::implnCopy(getUnoModel()); + } +} + +void +ScVbaRange::Cut(const ::uno::Any& Destination) +{ + if ( m_Areas->getCount() > 1 ) + throw uno::RuntimeException("That command cannot be used on multiple selections" ); + if (Destination.hasValue()) + { + uno::Reference< excel::XRange > xRange( Destination, uno::UNO_QUERY_THROW ); + uno::Reference< table::XCellRange > xCellRange( xRange->getCellRange(), uno::UNO_QUERY_THROW ); + uno::Reference< sheet::XSheetCellRange > xSheetCellRange(xCellRange, ::uno::UNO_QUERY_THROW ); + uno::Reference< sheet::XSpreadsheet > xSheet = xSheetCellRange->getSpreadsheet(); + uno::Reference< table::XCellRange > xDest( xSheet, uno::UNO_QUERY_THROW ); + uno::Reference< sheet::XCellRangeMovement > xMover( xSheet, uno::UNO_QUERY_THROW); + uno::Reference< sheet::XCellAddressable > xDestination( xDest->getCellByPosition( + xRange->getColumn()-1,xRange->getRow()-1), uno::UNO_QUERY); + uno::Reference< sheet::XCellRangeAddressable > xSource( mxRange, uno::UNO_QUERY); + xMover->moveRange( xDestination->getCellAddress(), xSource->getRangeAddress() ); + } + else + { + uno::Reference< frame::XModel > xModel = getModelFromRange( mxRange ); + Select(); + excel::implnCut( xModel ); + } +} + +void +ScVbaRange::setNumberFormat( const uno::Any& aFormat ) +{ + OUString sFormat; + aFormat >>= sFormat; + if ( m_Areas->getCount() > 1 ) + { + sal_Int32 nItems = m_Areas->getCount(); + for ( sal_Int32 index=1; index <= nItems; ++index ) + { + uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW ); + xRange->setNumberFormat( aFormat ); + } + return; + } + NumFormatHelper numFormat( mxRange ); + numFormat.setNumberFormat( sFormat ); +} + +uno::Any +ScVbaRange::getNumberFormat() +{ + + if ( m_Areas->getCount() > 1 ) + { + sal_Int32 nItems = m_Areas->getCount(); + uno::Any aResult = aNULL(); + for ( sal_Int32 index=1; index <= nItems; ++index ) + { + uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW ); + // if the numberformat of one area is different to another + // return null + if ( index > 1 ) + if ( aResult != xRange->getNumberFormat() ) + return aNULL(); + aResult = xRange->getNumberFormat(); + if ( aNULL() == aResult ) + return aNULL(); + } + return aResult; + } + NumFormatHelper numFormat( mxRange ); + OUString sFormat = numFormat.getNumberFormatString(); + if ( !sFormat.isEmpty() ) + return uno::Any( sFormat ); + return aNULL(); +} + +uno::Reference< excel::XRange > +ScVbaRange::Resize( const uno::Any &RowSize, const uno::Any &ColumnSize ) +{ + tools::Long nRowSize = 0, nColumnSize = 0; + bool bIsRowChanged = ( RowSize >>= nRowSize ), bIsColumnChanged = ( ColumnSize >>= nColumnSize ); + uno::Reference< table::XColumnRowRange > xColumnRowRange(mxRange, ::uno::UNO_QUERY_THROW); + uno::Reference< sheet::XSheetCellRange > xSheetRange(mxRange, ::uno::UNO_QUERY_THROW); + uno::Reference< sheet::XSheetCellCursor > xCursor( xSheetRange->getSpreadsheet()->createCursorByRange(xSheetRange), ::uno::UNO_SET_THROW ); + + if( !bIsRowChanged ) + nRowSize = xColumnRowRange->getRows()->getCount(); + if( !bIsColumnChanged ) + nColumnSize = xColumnRowRange->getColumns()->getCount(); + + xCursor->collapseToSize( nColumnSize, nRowSize ); + uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable(xCursor, ::uno::UNO_QUERY_THROW ); + uno::Reference< table::XCellRange > xRange( xSheetRange->getSpreadsheet(), ::uno::UNO_QUERY_THROW ); + return new ScVbaRange( mxParent, mxContext,xRange->getCellRangeByPosition( + xCellRangeAddressable->getRangeAddress().StartColumn, + xCellRangeAddressable->getRangeAddress().StartRow, + xCellRangeAddressable->getRangeAddress().EndColumn, + xCellRangeAddressable->getRangeAddress().EndRow ) ); +} + +void +ScVbaRange::setWrapText( const uno::Any& aIsWrapped ) +{ + if ( m_Areas->getCount() > 1 ) + { + sal_Int32 nItems = m_Areas->getCount(); + for ( sal_Int32 index=1; index <= nItems; ++index ) + { + uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW ); + xRange->setWrapText( aIsWrapped ); + } + return; + } + + uno::Reference< beans::XPropertySet > xProps(mxRange, ::uno::UNO_QUERY_THROW ); + bool bIsWrapped = extractBoolFromAny( aIsWrapped ); + xProps->setPropertyValue( "IsTextWrapped", uno::Any( bIsWrapped ) ); +} + +uno::Any +ScVbaRange::getWrapText() +{ + if ( m_Areas->getCount() > 1 ) + { + sal_Int32 nItems = m_Areas->getCount(); + uno::Any aResult; + for ( sal_Int32 index=1; index <= nItems; ++index ) + { + uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW ); + if ( index > 1 ) + if ( aResult != xRange->getWrapText() ) + return aNULL(); + aResult = xRange->getWrapText(); + } + return aResult; + } + + SfxItemSet* pDataSet = getCurrentDataSet(); + + SfxItemState eState = pDataSet->GetItemState( ATTR_LINEBREAK); + if ( eState == SfxItemState::DONTCARE ) + return aNULL(); + + uno::Reference< beans::XPropertySet > xProps(mxRange, ::uno::UNO_QUERY_THROW ); + uno::Any aValue = xProps->getPropertyValue( "IsTextWrapped" ); + return aValue; +} + +uno::Reference< excel::XInterior > ScVbaRange::Interior( ) +{ + uno::Reference< beans::XPropertySet > xProps( mxRange, uno::UNO_QUERY_THROW ); + return new ScVbaInterior ( this, mxContext, xProps, &getScDocument() ); +} +uno::Reference< excel::XRange > +ScVbaRange::Range( const uno::Any &Cell1, const uno::Any &Cell2 ) +{ + return Range( Cell1, Cell2, false ); +} +uno::Reference< excel::XRange > +ScVbaRange::Range( const uno::Any &Cell1, const uno::Any &Cell2, bool bForceUseInpuRangeTab ) + +{ + uno::Reference< table::XCellRange > xCellRange = mxRange; + + if ( m_Areas->getCount() > 1 ) + { + uno::Reference< container::XIndexAccess > xIndex( mxRanges, uno::UNO_QUERY_THROW ); + xCellRange.set( xIndex->getByIndex( 0 ), uno::UNO_QUERY_THROW ); + } + else + xCellRange.set( mxRange ); + + RangeHelper thisRange( xCellRange ); + uno::Reference< table::XCellRange > xRanges = thisRange.getCellRangeFromSheet(); + uno::Reference< sheet::XCellRangeAddressable > xAddressable( xRanges, uno::UNO_QUERY_THROW ); + + uno::Reference< table::XCellRange > xReferrer = + xRanges->getCellRangeByPosition( getColumn()-1, getRow()-1, + xAddressable->getRangeAddress().EndColumn, + xAddressable->getRangeAddress().EndRow ); + // xAddressable now for this range + xAddressable.set( xReferrer, uno::UNO_QUERY_THROW ); + + if( !Cell1.hasValue() ) + throw uno::RuntimeException( "Invalid Argument" ); + + table::CellRangeAddress parentRangeAddress = xAddressable->getRangeAddress(); + + ScRange aRange; + // Cell1 defined only + if ( !Cell2.hasValue() ) + { + OUString sName; + Cell1 >>= sName; + RangeHelper referRange( xReferrer ); + table::CellRangeAddress referAddress = referRange.getCellRangeAddressable()->getRangeAddress(); + return getRangeForName( mxContext, sName, getScDocShell(), referAddress ); + + } + else + { + table::CellRangeAddress cell1, cell2; + cell1 = getCellRangeAddressForVBARange( Cell1, getScDocShell() ); + // Cell1 & Cell2 defined + // Excel seems to combine the range as the range defined by + // the combination of Cell1 & Cell2 + + cell2 = getCellRangeAddressForVBARange( Cell2, getScDocShell() ); + + table::CellRangeAddress resultAddress; + resultAddress.StartColumn = ( cell1.StartColumn < cell2.StartColumn ) ? cell1.StartColumn : cell2.StartColumn; + resultAddress.StartRow = ( cell1.StartRow < cell2.StartRow ) ? cell1.StartRow : cell2.StartRow; + resultAddress.EndColumn = std::max( cell1.EndColumn, cell2.EndColumn ); + resultAddress.EndRow = std::max( cell1.EndRow, cell2.EndRow ); + if ( bForceUseInpuRangeTab ) + { + // this is a call from Application.Range( x,y ) + // it's possible for x or y to specify a different sheet from + // the current or active on ( but they must be the same ) + if ( cell1.Sheet != cell2.Sheet ) + throw uno::RuntimeException(); + parentRangeAddress.Sheet = cell1.Sheet; + } + else + { + // this is not a call from Application.Range( x,y ) + // if a different sheet from this range is specified it's + // an error + if ( parentRangeAddress.Sheet != cell1.Sheet + || parentRangeAddress.Sheet != cell2.Sheet + ) + throw uno::RuntimeException(); + + } + ScUnoConversion::FillScRange( aRange, resultAddress ); + } + ScRange parentAddress; + ScUnoConversion::FillScRange( parentAddress, parentRangeAddress); + if ( aRange.aStart.Col() >= 0 && aRange.aStart.Row() >= 0 && aRange.aEnd.Col() >= 0 && aRange.aEnd.Row() >= 0 ) + { + sal_Int32 nStartX = parentAddress.aStart.Col() + aRange.aStart.Col(); + sal_Int32 nStartY = parentAddress.aStart.Row() + aRange.aStart.Row(); + sal_Int32 nEndX = parentAddress.aStart.Col() + aRange.aEnd.Col(); + sal_Int32 nEndY = parentAddress.aStart.Row() + aRange.aEnd.Row(); + + if ( nStartX <= nEndX && nEndX <= parentAddress.aEnd.Col() && + nStartY <= nEndY && nEndY <= parentAddress.aEnd.Row() ) + { + ScRange aNew( static_cast<SCCOL>(nStartX), static_cast<SCROW>(nStartY), parentAddress.aStart.Tab(), + static_cast<SCCOL>(nEndX), static_cast<SCROW>(nEndY), parentAddress.aEnd.Tab() ); + xCellRange = new ScCellRangeObj( getScDocShell(), aNew ); + } + } + + return new ScVbaRange( mxParent, mxContext, xCellRange ); + +} + +// Allow access to underlying openoffice uno api ( useful for debugging +// with openoffice basic ) +uno::Any SAL_CALL ScVbaRange::getCellRange( ) +{ + uno::Any aAny; + if ( mxRanges.is() ) + aAny <<= mxRanges; + else if ( mxRange.is() ) + aAny <<= mxRange; + return aAny; +} + +uno::Any ScVbaRange::getCellRange( const uno::Reference< excel::XRange >& rxRange ) +{ + if( ScVbaRange* pVbaRange = getImplementation( rxRange ) ) + return pVbaRange->getCellRange(); + throw uno::RuntimeException(); +} + +static InsertDeleteFlags getPasteFlags (sal_Int32 Paste) +{ + InsertDeleteFlags nFlags = InsertDeleteFlags::NONE; + switch (Paste) { + case excel::XlPasteType::xlPasteComments: + nFlags = InsertDeleteFlags::NOTE;break; + case excel::XlPasteType::xlPasteFormats: + nFlags = InsertDeleteFlags::ATTRIB;break; + case excel::XlPasteType::xlPasteFormulas: + nFlags = InsertDeleteFlags::FORMULA;break; + case excel::XlPasteType::xlPasteFormulasAndNumberFormats : + case excel::XlPasteType::xlPasteValues: + nFlags = ( InsertDeleteFlags::VALUE | InsertDeleteFlags::DATETIME | InsertDeleteFlags::STRING | InsertDeleteFlags::SPECIAL_BOOLEAN ); break; + case excel::XlPasteType::xlPasteValuesAndNumberFormats: + nFlags = InsertDeleteFlags::VALUE | InsertDeleteFlags::ATTRIB; break; + case excel::XlPasteType::xlPasteColumnWidths: + case excel::XlPasteType::xlPasteValidation: + nFlags = InsertDeleteFlags::NONE;break; + case excel::XlPasteType::xlPasteAll: + case excel::XlPasteType::xlPasteAllExceptBorders: + default: + nFlags = InsertDeleteFlags::ALL;break; + } + return nFlags; +} + +static ScPasteFunc +getPasteFormulaBits( sal_Int32 Operation) +{ + ScPasteFunc nFormulaBits = ScPasteFunc::NONE; + switch (Operation) + { + case excel::XlPasteSpecialOperation::xlPasteSpecialOperationAdd: + nFormulaBits = ScPasteFunc::ADD; break; + case excel::XlPasteSpecialOperation::xlPasteSpecialOperationSubtract: + nFormulaBits = ScPasteFunc::SUB;break; + case excel::XlPasteSpecialOperation::xlPasteSpecialOperationMultiply: + nFormulaBits = ScPasteFunc::MUL;break; + case excel::XlPasteSpecialOperation::xlPasteSpecialOperationDivide: + nFormulaBits = ScPasteFunc::DIV;break; + + case excel::XlPasteSpecialOperation::xlPasteSpecialOperationNone: + default: + nFormulaBits = ScPasteFunc::NONE; break; + } + + return nFormulaBits; +} +void SAL_CALL +ScVbaRange::PasteSpecial( const uno::Any& Paste, const uno::Any& Operation, const uno::Any& SkipBlanks, const uno::Any& Transpose ) +{ + if ( m_Areas->getCount() > 1 ) + throw uno::RuntimeException("That command cannot be used on multiple selections" ); + ScDocShell* pShell = getScDocShell(); + + if (!pShell) + throw uno::RuntimeException("That command cannot be used with no ScDocShell" ); + + uno::Reference< frame::XModel > xModel(pShell->GetModel(), uno::UNO_SET_THROW); + uno::Reference< view::XSelectionSupplier > xSelection( xModel->getCurrentController(), uno::UNO_QUERY_THROW ); + // select this range + xSelection->select( uno::Any( mxRange ) ); + // set up defaults + sal_Int32 nPaste = excel::XlPasteType::xlPasteAll; + sal_Int32 nOperation = excel::XlPasteSpecialOperation::xlPasteSpecialOperationNone; + bool bTranspose = false; + bool bSkipBlanks = false; + + if ( Paste.hasValue() ) + Paste >>= nPaste; + if ( Operation.hasValue() ) + Operation >>= nOperation; + if ( SkipBlanks.hasValue() ) + SkipBlanks >>= bSkipBlanks; + if ( Transpose.hasValue() ) + Transpose >>= bTranspose; + + InsertDeleteFlags nFlags = getPasteFlags(nPaste); + ScPasteFunc nFormulaBits = getPasteFormulaBits(nOperation); + + excel::implnPasteSpecial(xModel, nFlags, nFormulaBits, bSkipBlanks, bTranspose); +} + +uno::Reference< excel::XRange > +ScVbaRange::getEntireColumnOrRow( bool bColumn ) +{ + ScCellRangesBase* pUnoRangesBase = getCellRangesBase(); + // copy the range list + ScRangeList aCellRanges = pUnoRangesBase->GetRangeList(); + ScDocument& rDoc = getScDocument(); + + for ( size_t i = 0, nRanges = aCellRanges.size(); i < nRanges; ++i ) + { + ScRange & rRange = aCellRanges[ i ]; + if ( bColumn ) + { + rRange.aStart.SetRow( 0 ); + rRange.aEnd.SetRow( rDoc.MaxRow() ); + } + else + { + rRange.aStart.SetCol( 0 ); + rRange.aEnd.SetCol( rDoc.MaxCol() ); + } + } + if ( aCellRanges.size() > 1 ) // Multi-Area + { + uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( pUnoRangesBase->GetDocShell(), aCellRanges ) ); + + return new ScVbaRange( mxParent, mxContext, xRanges, !bColumn, bColumn ); + } + const ScRange aRange( obtainRangeEvenIfRangeListIsEmpty( aCellRanges)); + uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( pUnoRangesBase->GetDocShell(), aRange)); + return new ScVbaRange( mxParent, mxContext, xRange, !bColumn, bColumn ); +} + +uno::Reference< excel::XRange > SAL_CALL +ScVbaRange::getEntireRow() +{ + return getEntireColumnOrRow(false); +} + +uno::Reference< excel::XRange > SAL_CALL +ScVbaRange::getEntireColumn() +{ + return getEntireColumnOrRow(true); +} + +uno::Reference< excel::XComment > SAL_CALL +ScVbaRange::AddComment( const uno::Any& Text ) +{ + // if there is already a comment in the top-left cell then throw + if( getComment().is() ) + throw uno::RuntimeException(); + + // workaround: Excel allows to create empty comment, Calc does not + OUString aNoteText; + if( Text.hasValue() && !(Text >>= aNoteText) ) + throw uno::RuntimeException(); + if( aNoteText.isEmpty() ) + aNoteText = " "; + + // try to create a new annotation + table::CellRangeAddress aRangePos = lclGetRangeAddress( mxRange ); + table::CellAddress aNotePos( aRangePos.Sheet, aRangePos.StartColumn, aRangePos.StartRow ); + uno::Reference< sheet::XSheetCellRange > xCellRange( mxRange, uno::UNO_QUERY_THROW ); + uno::Reference< sheet::XSheetAnnotationsSupplier > xAnnosSupp( xCellRange->getSpreadsheet(), uno::UNO_QUERY_THROW ); + uno::Reference< sheet::XSheetAnnotations > xAnnos( xAnnosSupp->getAnnotations(), uno::UNO_SET_THROW ); + xAnnos->insertNew( aNotePos, aNoteText ); + return new ScVbaComment( this, mxContext, getUnoModel(), mxRange ); +} + +uno::Reference< excel::XComment > SAL_CALL +ScVbaRange::getComment() +{ + // intentional behavior to return a null object if no + // comment defined + uno::Reference< excel::XComment > xComment( new ScVbaComment( this, mxContext, getUnoModel(), mxRange ) ); + if ( xComment->Text( uno::Any(), uno::Any(), uno::Any() ).isEmpty() ) + return nullptr; + return xComment; + +} + +/// @throws uno::RuntimeException +static uno::Reference< beans::XPropertySet > +getRowOrColumnProps( const uno::Reference< table::XCellRange >& xCellRange, bool bRows ) +{ + uno::Reference< table::XColumnRowRange > xColRow( xCellRange, uno::UNO_QUERY_THROW ); + uno::Reference< beans::XPropertySet > xProps; + if ( bRows ) + xProps.set( xColRow->getRows(), uno::UNO_QUERY_THROW ); + else + xProps.set( xColRow->getColumns(), uno::UNO_QUERY_THROW ); + return xProps; +} + +uno::Any SAL_CALL +ScVbaRange::getHidden() +{ + // if multi-area result is the result of the + // first area + if ( m_Areas->getCount() > 1 ) + { + uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(sal_Int32(1)), uno::Any() ), uno::UNO_QUERY_THROW ); + return xRange->getHidden(); + } + bool bIsVisible = false; + try + { + uno::Reference< beans::XPropertySet > xProps = getRowOrColumnProps( mxRange, mbIsRows ); + if ( !( xProps->getPropertyValue( ISVISIBLE ) >>= bIsVisible ) ) + throw uno::RuntimeException("Failed to get IsVisible property" ); + } + catch( const uno::Exception& e ) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( e.Message, + nullptr, anyEx ); + } + return uno::Any( !bIsVisible ); +} + +void SAL_CALL +ScVbaRange::setHidden( const uno::Any& _hidden ) +{ + if ( m_Areas->getCount() > 1 ) + { + sal_Int32 nItems = m_Areas->getCount(); + for ( sal_Int32 index=1; index <= nItems; ++index ) + { + uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW ); + xRange->setHidden( _hidden ); + } + return; + } + + bool bHidden = extractBoolFromAny( _hidden ); + try + { + uno::Reference< beans::XPropertySet > xProps = getRowOrColumnProps( mxRange, mbIsRows ); + xProps->setPropertyValue( ISVISIBLE, uno::Any( !bHidden ) ); + } + catch( const uno::Exception& e ) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( e.Message, + nullptr, anyEx ); + } +} + +sal_Bool SAL_CALL +ScVbaRange::Replace( const OUString& What, const OUString& Replacement, const uno::Any& LookAt, const uno::Any& SearchOrder, const uno::Any& MatchCase, const uno::Any& MatchByte, const uno::Any& SearchFormat, const uno::Any& ReplaceFormat ) +{ + if ( m_Areas->getCount() > 1 ) + { + for ( sal_Int32 index = 1; index <= m_Areas->getCount(); ++index ) + { + uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( index ), uno::Any() ), uno::UNO_QUERY_THROW ); + xRange->Replace( What, Replacement, LookAt, SearchOrder, MatchCase, MatchByte, SearchFormat, ReplaceFormat ); + } + return true; // seems to return true always ( or at least I haven't found the trick of + } + + // sanity check required params + if ( What.isEmpty() ) + throw uno::RuntimeException("Range::Replace, missing params" ); + OUString sWhat = VBAToRegexp( What); + // #TODO #FIXME SearchFormat & ReplacesFormat are not processed + // What do we do about MatchByte... we don't seem to support that + const SvxSearchItem& globalSearchOptions = ScGlobal::GetSearchItem(); + SvxSearchItem newOptions( globalSearchOptions ); + + uno::Reference< util::XReplaceable > xReplace( mxRange, uno::UNO_QUERY ); + if ( xReplace.is() ) + { + uno::Reference< util::XReplaceDescriptor > xDescriptor = + xReplace->createReplaceDescriptor(); + + xDescriptor->setSearchString( sWhat); + xDescriptor->setPropertyValue( SC_UNO_SRCHREGEXP, uno::Any( true ) ); + xDescriptor->setReplaceString( Replacement); + if ( LookAt.hasValue() ) + { + // sets SearchWords ( true is Cell match ) + sal_Int16 nLook = ::comphelper::getINT16( LookAt ); + bool bSearchWords = false; + if ( nLook == excel::XlLookAt::xlPart ) + bSearchWords = false; + else if ( nLook == excel::XlLookAt::xlWhole ) + bSearchWords = true; + else + throw uno::RuntimeException("Range::Replace, illegal value for LookAt" ); + // set global search props ( affects the find dialog + // and of course the defaults for this method + newOptions.SetWordOnly( bSearchWords ); + xDescriptor->setPropertyValue( SC_UNO_SRCHWORDS, uno::Any( bSearchWords ) ); + } + // sets SearchByRow ( true for Rows ) + if ( SearchOrder.hasValue() ) + { + sal_Int16 nSearchOrder = ::comphelper::getINT16( SearchOrder ); + bool bSearchByRow = false; + if ( nSearchOrder == excel::XlSearchOrder::xlByColumns ) + bSearchByRow = false; + else if ( nSearchOrder == excel::XlSearchOrder::xlByRows ) + bSearchByRow = true; + else + throw uno::RuntimeException("Range::Replace, illegal value for SearchOrder" ); + + newOptions.SetRowDirection( bSearchByRow ); + xDescriptor->setPropertyValue( SC_UNO_SRCHBYROW, uno::Any( bSearchByRow ) ); + } + if ( MatchCase.hasValue() ) + { + bool bMatchCase = false; + + // SearchCaseSensitive + MatchCase >>= bMatchCase; + xDescriptor->setPropertyValue( SC_UNO_SRCHCASE, uno::Any( bMatchCase ) ); + } + + ScGlobal::SetSearchItem( newOptions ); + // ignore MatchByte for the moment, it's not supported in + // OOo.org afaik + + uno::Reference< container::XIndexAccess > xIndexAccess = xReplace->findAll( xDescriptor ); + xReplace->replaceAll( xDescriptor ); + if ( xIndexAccess.is() && xIndexAccess->getCount() > 0 ) + { + for ( sal_Int32 i = 0; i < xIndexAccess->getCount(); ++i ) + { + uno::Reference< table::XCellRange > xCellRange( xIndexAccess->getByIndex( i ), uno::UNO_QUERY ); + if ( xCellRange.is() ) + { + uno::Reference< excel::XRange > xRange( new ScVbaRange( mxParent, mxContext, xCellRange ) ); + uno::Reference< container::XEnumerationAccess > xEnumAccess( xRange, uno::UNO_QUERY_THROW ); + uno::Reference< container::XEnumeration > xEnum = xEnumAccess->createEnumeration(); + while ( xEnum->hasMoreElements() ) + { + uno::Reference< excel::XRange > xNextRange( xEnum->nextElement(), uno::UNO_QUERY_THROW ); + ScVbaRange* pRange = dynamic_cast< ScVbaRange * > ( xNextRange.get() ); + if ( pRange ) + pRange->fireChangeEvent(); + } + } + } + } + } + return true; // always +} + +uno::Reference< excel::XRange > SAL_CALL +ScVbaRange::Find( const uno::Any& What, const uno::Any& After, const uno::Any& LookIn, const uno::Any& LookAt, const uno::Any& SearchOrder, const uno::Any& SearchDirection, const uno::Any& MatchCase, const uno::Any& /*MatchByte*/, const uno::Any& /*SearchFormat*/ ) +{ + // return a Range object that represents the first cell where that information is found. + OUString sWhat; + sal_Int32 nWhat = 0; + double fWhat = 0.0; + + // string. + if( What >>= sWhat ) + {} + else if( What >>= nWhat ) + { + sWhat = OUString::number( nWhat ); + } + else if( What >>= fWhat ) + { + sWhat = OUString::number( fWhat ); + } + else + throw uno::RuntimeException("Range::Find, missing search-for-what param" ); + + OUString sSearch = VBAToRegexp( sWhat ); + + const SvxSearchItem& globalSearchOptions = ScGlobal::GetSearchItem(); + SvxSearchItem newOptions( globalSearchOptions ); + + uno::Reference< util::XSearchable > xSearch( mxRange, uno::UNO_QUERY ); + if( xSearch.is() ) + { + uno::Reference< util::XSearchDescriptor > xDescriptor = xSearch->createSearchDescriptor(); + xDescriptor->setSearchString( sSearch ); + xDescriptor->setPropertyValue( SC_UNO_SRCHREGEXP, uno::Any( true ) ); + + uno::Reference< excel::XRange > xAfterRange; + uno::Reference< table::XCellRange > xStartCell; + if( After >>= xAfterRange ) + { + // After must be a single cell in the range + if( xAfterRange->getCount() > 1 ) + throw uno::RuntimeException("After must be a single cell." ); + uno::Reference< excel::XRange > xCell( Cells( uno::Any( xAfterRange->getRow() ), uno::Any( xAfterRange->getColumn() ) ), uno::UNO_SET_THROW ); + xStartCell.set( xAfterRange->getCellRange(), uno::UNO_QUERY_THROW ); + } + + // LookIn + if( LookIn.hasValue() ) + { + sal_Int32 nLookIn = 0; + if( LookIn >>= nLookIn ) + { + SvxSearchCellType nSearchType; + switch( nLookIn ) + { + case excel::XlFindLookIn::xlComments : + nSearchType = SvxSearchCellType::NOTE; // Notes + break; + case excel::XlFindLookIn::xlFormulas : + nSearchType = SvxSearchCellType::FORMULA; + break; + case excel::XlFindLookIn::xlValues : + nSearchType = SvxSearchCellType::VALUE; + break; + default: + throw uno::RuntimeException("Range::Find, illegal value for LookIn." ); + } + newOptions.SetCellType( nSearchType ); + xDescriptor->setPropertyValue( "SearchType", uno::Any( static_cast<sal_uInt16>(nSearchType) ) ); + } + } + + // LookAt + if ( LookAt.hasValue() ) + { + sal_Int16 nLookAt = ::comphelper::getINT16( LookAt ); + bool bSearchWords = false; + if ( nLookAt == excel::XlLookAt::xlPart ) + bSearchWords = false; + else if ( nLookAt == excel::XlLookAt::xlWhole ) + bSearchWords = true; + else + throw uno::RuntimeException("Range::Find, illegal value for LookAt" ); + newOptions.SetWordOnly( bSearchWords ); + xDescriptor->setPropertyValue( SC_UNO_SRCHWORDS, uno::Any( bSearchWords ) ); + } + + // SearchOrder + if ( SearchOrder.hasValue() ) + { + sal_Int16 nSearchOrder = ::comphelper::getINT16( SearchOrder ); + bool bSearchByRow = false; + if ( nSearchOrder == excel::XlSearchOrder::xlByColumns ) + bSearchByRow = false; + else if ( nSearchOrder == excel::XlSearchOrder::xlByRows ) + bSearchByRow = true; + else + throw uno::RuntimeException("Range::Find, illegal value for SearchOrder" ); + + newOptions.SetRowDirection( bSearchByRow ); + xDescriptor->setPropertyValue( SC_UNO_SRCHBYROW, uno::Any( bSearchByRow ) ); + } + + // SearchDirection + if ( SearchDirection.hasValue() ) + { + sal_Int32 nSearchDirection = 0; + if( SearchDirection >>= nSearchDirection ) + { + bool bSearchBackwards = false; + if ( nSearchDirection == excel::XlSearchDirection::xlNext ) + bSearchBackwards = false; + else if( nSearchDirection == excel::XlSearchDirection::xlPrevious ) + bSearchBackwards = true; + else + throw uno::RuntimeException("Range::Find, illegal value for SearchDirection" ); + newOptions.SetBackward( bSearchBackwards ); + xDescriptor->setPropertyValue( "SearchBackwards", uno::Any( bSearchBackwards ) ); + } + } + + // MatchCase + bool bMatchCase = false; + if ( MatchCase.hasValue() ) + { + // SearchCaseSensitive + if( !( MatchCase >>= bMatchCase ) ) + throw uno::RuntimeException("Range::Find illegal value for MatchCase" ); + } + xDescriptor->setPropertyValue( SC_UNO_SRCHCASE, uno::Any( bMatchCase ) ); + + // MatchByte + // SearchFormat + // ignore + + ScGlobal::SetSearchItem( newOptions ); + + uno::Reference< uno::XInterface > xInterface = xStartCell.is() ? xSearch->findNext( xStartCell, xDescriptor) : xSearch->findFirst( xDescriptor ); + uno::Reference< table::XCellRange > xCellRange( xInterface, uno::UNO_QUERY ); + // if we are searching from a starting cell and failed to find a match + // then try from the beginning + if ( !xCellRange.is() && xStartCell.is() ) + { + xInterface = xSearch->findFirst( xDescriptor ); + xCellRange.set( xInterface, uno::UNO_QUERY ); + } + if ( xCellRange.is() ) + { + uno::Reference< excel::XRange > xResultRange = new ScVbaRange( mxParent, mxContext, xCellRange ); + if( xResultRange.is() ) + { + return xResultRange; + } + } + + } + + return uno::Reference< excel::XRange >(); +} + +static uno::Reference< table::XCellRange > processKey( const uno::Any& Key, const uno::Reference< uno::XComponentContext >& xContext, ScDocShell* pDocSh ) +{ + uno::Reference< excel::XRange > xKeyRange; + if ( Key.getValueType() == cppu::UnoType<excel::XRange>::get() ) + { + xKeyRange.set( Key, uno::UNO_QUERY_THROW ); + } + else if ( Key.getValueType() == ::cppu::UnoType<OUString>::get() ) + + { + OUString sRangeName = ::comphelper::getString( Key ); + table::CellRangeAddress aRefAddr; + if ( !pDocSh ) + throw uno::RuntimeException("Range::Sort no docshell to calculate key param" ); + xKeyRange = getRangeForName( xContext, sRangeName, pDocSh, aRefAddr ); + } + else + throw uno::RuntimeException("Range::Sort illegal type value for key param" ); + uno::Reference< table::XCellRange > xKey; + xKey.set( xKeyRange->getCellRange(), uno::UNO_QUERY_THROW ); + return xKey; +} + +// helper method for Sort +/// @throws uno::RuntimeException +static sal_Int32 findSortPropertyIndex( const uno::Sequence< beans::PropertyValue >& props, +const OUString& sPropName ) +{ + const beans::PropertyValue* pProp = std::find_if(props.begin(), props.end(), + [&sPropName](const beans::PropertyValue& rProp) { return rProp.Name == sPropName; }); + + if ( pProp == props.end() ) + throw uno::RuntimeException("Range::Sort unknown sort property" ); + return static_cast<sal_Int32>(std::distance(props.begin(), pProp)); +} + +// helper method for Sort +/// @throws uno::RuntimeException +static void updateTableSortField( const uno::Reference< table::XCellRange >& xParentRange, + const uno::Reference< table::XCellRange >& xColRowKey, sal_Int16 nOrder, + table::TableSortField& aTableField, bool bIsSortColumn, bool bMatchCase ) +{ + RangeHelper parentRange( xParentRange ); + RangeHelper colRowRange( xColRowKey ); + + table::CellRangeAddress parentRangeAddress = parentRange.getCellRangeAddressable()->getRangeAddress(); + + table::CellRangeAddress colRowKeyAddress = colRowRange.getCellRangeAddressable()->getRangeAddress(); + + // make sure that upper left point of key range is within the + // parent range + if ( + ( bIsSortColumn || colRowKeyAddress.StartColumn < parentRangeAddress.StartColumn || + colRowKeyAddress.StartColumn > parentRangeAddress.EndColumn ) + && + ( !bIsSortColumn || colRowKeyAddress.StartRow < parentRangeAddress.StartRow || + colRowKeyAddress.StartRow > parentRangeAddress.EndRow ) + ) + throw uno::RuntimeException("Illegal Key param" ); + + //determine col/row index + if ( bIsSortColumn ) + aTableField.Field = colRowKeyAddress.StartRow - parentRangeAddress.StartRow; + else + aTableField.Field = colRowKeyAddress.StartColumn - parentRangeAddress.StartColumn; + aTableField.IsCaseSensitive = bMatchCase; + + if ( nOrder == excel::XlSortOrder::xlAscending ) + aTableField.IsAscending = true; + else + aTableField.IsAscending = false; + + +} + +void SAL_CALL +ScVbaRange::Sort( const uno::Any& Key1, const uno::Any& Order1, const uno::Any& Key2, const uno::Any& /*Type*/, const uno::Any& Order2, const uno::Any& Key3, const uno::Any& Order3, const uno::Any& Header, const uno::Any& OrderCustom, const uno::Any& MatchCase, const uno::Any& Orientation, const uno::Any& SortMethod, const uno::Any& DataOption1, const uno::Any& DataOption2, const uno::Any& DataOption3 ) +{ + // #TODO# #FIXME# can we do something with Type + if ( m_Areas->getCount() > 1 ) + throw uno::RuntimeException("That command cannot be used on multiple selections" ); + + sal_Int16 nDataOption1 = excel::XlSortDataOption::xlSortNormal; + sal_Int16 nDataOption2 = excel::XlSortDataOption::xlSortNormal; + sal_Int16 nDataOption3 = excel::XlSortDataOption::xlSortNormal; + + ScDocument& rDoc = getScDocument(); + + uno::Reference< table::XCellRange > xRangeCurrent; + if (isSingleCellRange()) + { + // Expand to CurrentRegion + uno::Reference< excel::XRange > xCurrent( CurrentRegion()); + if (xCurrent.is()) + { + const ScVbaRange* pRange = getImplementation( xCurrent ); + if (pRange) + xRangeCurrent = pRange->mxRange; + } + } + if (!xRangeCurrent.is()) + xRangeCurrent = mxRange; + RangeHelper thisRange( xRangeCurrent ); + table::CellRangeAddress thisRangeAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); + + ScSortParam aSortParam; + SCTAB nTab = thisRangeAddress.Sheet; + rDoc.GetSortParam( aSortParam, nTab ); + + if ( DataOption1.hasValue() ) + DataOption1 >>= nDataOption1; + if ( DataOption2.hasValue() ) + DataOption2 >>= nDataOption2; + if ( DataOption3.hasValue() ) + DataOption3 >>= nDataOption3; + + // 1) #TODO #FIXME need to process DataOption[1..3] not used currently + // 2) #TODO #FIXME need to refactor this ( below ) into an IsSingleCell() method + uno::Reference< table::XColumnRowRange > xColumnRowRange(xRangeCurrent, uno::UNO_QUERY_THROW ); + + // set up defaults + + sal_Int16 nOrder1 = aSortParam.maKeyState[0].bAscending ? excel::XlSortOrder::xlAscending : excel::XlSortOrder::xlDescending; + sal_Int16 nOrder2 = aSortParam.maKeyState[1].bAscending ? excel::XlSortOrder::xlAscending : excel::XlSortOrder::xlDescending; + sal_Int16 nOrder3 = aSortParam.maKeyState[2].bAscending ? excel::XlSortOrder::xlAscending : excel::XlSortOrder::xlDescending; + + sal_Int16 nCustom = aSortParam.nUserIndex; + sal_Int16 nSortMethod = excel::XlSortMethod::xlPinYin; + bool bMatchCase = aSortParam.bCaseSens; + + // seems to work opposite to expected, see below + sal_Int16 nOrientation = aSortParam.bByRow ? excel::XlSortOrientation::xlSortColumns : excel::XlSortOrientation::xlSortRows; + + if ( Orientation.hasValue() ) + { + // Documentation says xlSortRows is default but that doesn't appear to be + // the case. Also it appears that xlSortColumns is the default which + // strangely enough sorts by Row + nOrientation = ::comphelper::getINT16( Orientation ); + // persist new option to be next calls default + if ( nOrientation == excel::XlSortOrientation::xlSortRows ) + aSortParam.bByRow = false; + else + aSortParam.bByRow = true; + + } + + bool bIsSortColumns=false; // sort by row + + if ( nOrientation == excel::XlSortOrientation::xlSortRows ) + bIsSortColumns = true; + sal_Int16 nHeader = aSortParam.nCompatHeader; + bool bContainsHeader = false; + + if ( Header.hasValue() ) + { + nHeader = ::comphelper::getINT16( Header ); + aSortParam.nCompatHeader = nHeader; + } + + if ( nHeader == excel::XlYesNoGuess::xlGuess ) + { + bool bHasColHeader = rDoc.HasColHeader( static_cast< SCCOL >( thisRangeAddress.StartColumn ), static_cast< SCROW >( thisRangeAddress.StartRow ), static_cast< SCCOL >( thisRangeAddress.EndColumn ), static_cast< SCROW >( thisRangeAddress.EndRow ), static_cast< SCTAB >( thisRangeAddress.Sheet )); + bool bHasRowHeader = rDoc.HasRowHeader( static_cast< SCCOL >( thisRangeAddress.StartColumn ), static_cast< SCROW >( thisRangeAddress.StartRow ), static_cast< SCCOL >( thisRangeAddress.EndColumn ), static_cast< SCROW >( thisRangeAddress.EndRow ), static_cast< SCTAB >( thisRangeAddress.Sheet ) ); + if ( bHasColHeader || bHasRowHeader ) + nHeader = excel::XlYesNoGuess::xlYes; + else + nHeader = excel::XlYesNoGuess::xlNo; + aSortParam.nCompatHeader = nHeader; + } + + if ( nHeader == excel::XlYesNoGuess::xlYes ) + bContainsHeader = true; + + if ( SortMethod.hasValue() ) + { + nSortMethod = ::comphelper::getINT16( SortMethod ); + } + + if ( OrderCustom.hasValue() ) + { + OrderCustom >>= nCustom; + --nCustom; // 0-based in OOo + aSortParam.nUserIndex = nCustom; + } + + if ( MatchCase.hasValue() ) + { + MatchCase >>= bMatchCase; + aSortParam.bCaseSens = bMatchCase; + } + + if ( Order1.hasValue() ) + { + nOrder1 = ::comphelper::getINT16(Order1); + if ( nOrder1 == excel::XlSortOrder::xlAscending ) + aSortParam.maKeyState[0].bAscending = true; + else + aSortParam.maKeyState[0].bAscending = false; + + } + if ( Order2.hasValue() ) + { + nOrder2 = ::comphelper::getINT16(Order2); + if ( nOrder2 == excel::XlSortOrder::xlAscending ) + aSortParam.maKeyState[1].bAscending = true; + else + aSortParam.maKeyState[1].bAscending = false; + } + if ( Order3.hasValue() ) + { + nOrder3 = ::comphelper::getINT16(Order3); + if ( nOrder3 == excel::XlSortOrder::xlAscending ) + aSortParam.maKeyState[2].bAscending = true; + else + aSortParam.maKeyState[2].bAscending = false; + } + + uno::Reference< table::XCellRange > xKey1; + uno::Reference< table::XCellRange > xKey2; + uno::Reference< table::XCellRange > xKey3; + ScDocShell* pDocShell = getScDocShell(); + xKey1 = processKey( Key1, mxContext, pDocShell ); + if ( !xKey1.is() ) + throw uno::RuntimeException("Range::Sort needs a key1 param" ); + + if ( Key2.hasValue() ) + xKey2 = processKey( Key2, mxContext, pDocShell ); + if ( Key3.hasValue() ) + xKey3 = processKey( Key3, mxContext, pDocShell ); + + uno::Reference< util::XSortable > xSort( xRangeCurrent, uno::UNO_QUERY_THROW ); + uno::Sequence< beans::PropertyValue > sortDescriptor = xSort->createSortDescriptor(); + auto psortDescriptor = sortDescriptor.getArray(); + sal_Int32 nTableSortFieldIndex = findSortPropertyIndex( sortDescriptor, "SortFields" ); + + uno::Sequence< table::TableSortField > sTableFields(1); + sal_Int32 nTableIndex = 0; + updateTableSortField( xRangeCurrent, xKey1, nOrder1, sTableFields.getArray()[ nTableIndex++ ], bIsSortColumns, bMatchCase ); + + if ( xKey2.is() ) + { + sTableFields.realloc( sTableFields.getLength() + 1 ); + updateTableSortField( xRangeCurrent, xKey2, nOrder2, sTableFields.getArray()[ nTableIndex++ ], bIsSortColumns, bMatchCase ); + } + if ( xKey3.is() ) + { + sTableFields.realloc( sTableFields.getLength() + 1 ); + updateTableSortField( xRangeCurrent, xKey3, nOrder3, sTableFields.getArray()[ nTableIndex++ ], bIsSortColumns, bMatchCase ); + } + psortDescriptor[ nTableSortFieldIndex ].Value <<= sTableFields; + + sal_Int32 nIndex = findSortPropertyIndex( sortDescriptor, "IsSortColumns" ); + psortDescriptor[ nIndex ].Value <<= bIsSortColumns; + + nIndex = findSortPropertyIndex( sortDescriptor, "ContainsHeader" ); + psortDescriptor[ nIndex ].Value <<= bContainsHeader; + + rDoc.SetSortParam( aSortParam, nTab ); + xSort->sort( sortDescriptor ); + + // #FIXME #TODO + // The SortMethod param is not processed ( not sure what its all about, need to + (void)nSortMethod; +} + +uno::Reference< excel::XRange > SAL_CALL +ScVbaRange::End( ::sal_Int32 Direction ) +{ + if ( m_Areas->getCount() > 1 ) + { + uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW ); + return xRange->End( Direction ); + } + + // #FIXME #TODO + // euch! found my orig implementation sucked, so + // trying this even sucker one (really need to use/expose code in + // around ScTabView::MoveCursorArea(), that's the bit that calculates + // where the cursor should go) + // Main problem with this method is the ultra hacky attempt to preserve + // the ActiveCell, there should be no need to go to these extremes + + // Save ActiveSheet/ActiveCell pos (to restore later) + uno::Any aDft; + uno::Reference< excel::XApplication > xApplication( Application(), uno::UNO_QUERY_THROW ); + uno::Reference< excel::XWorksheet > sActiveSheet = xApplication->getActiveSheet(); + OUString sActiveCell = xApplication->getActiveCell()->Address(aDft, aDft, aDft, aDft, aDft ); + + // position current cell upper left of this range + Cells( uno::Any( sal_Int32(1) ), uno::Any( sal_Int32(1) ) )->Select(); + + uno::Reference< frame::XModel > xModel = getModelFromRange( mxRange ); + + SfxViewFrame* pViewFrame = excel::getViewFrame( xModel ); + if ( pViewFrame ) + { + SfxAllItemSet aArgs( SfxGetpApp()->GetPool() ); + // Hoping this will make sure this slot is called + // synchronously + SfxBoolItem sfxAsync( SID_ASYNCHRON, false ); + aArgs.Put( sfxAsync, sfxAsync.Which() ); + SfxDispatcher* pDispatcher = pViewFrame->GetDispatcher(); + + sal_uInt16 nSID = 0; + + switch( Direction ) + { + case excel::XlDirection::xlDown: + nSID = SID_CURSORBLKDOWN; + break; + case excel::XlDirection::xlUp: + nSID = SID_CURSORBLKUP; + break; + case excel::XlDirection::xlToLeft: + nSID = SID_CURSORBLKLEFT; + break; + case excel::XlDirection::xlToRight: + nSID = SID_CURSORBLKRIGHT; + break; + default: + throw uno::RuntimeException(": Invalid ColumnIndex" ); + } + if ( pDispatcher ) + { + pDispatcher->Execute( nSID, SfxCallMode::SYNCHRON, aArgs ); + } + } + + // result is the ActiveCell + OUString sMoved = xApplication->getActiveCell()->Address(aDft, aDft, aDft, aDft, aDft ); + + uno::Any aVoid; + uno::Reference< excel::XRange > resultCell; + resultCell.set( xApplication->getActiveSheet()->Range( uno::Any( sMoved ), aVoid ), uno::UNO_SET_THROW ); + + // restore old ActiveCell + uno::Reference< excel::XRange > xOldActiveCell( sActiveSheet->Range( uno::Any( sActiveCell ), aVoid ), uno::UNO_SET_THROW ); + xOldActiveCell->Select(); + + + // return result + return resultCell; +} + +bool +ScVbaRange::isSingleCellRange() const +{ + uno::Reference< sheet::XCellRangeAddressable > xAddressable( mxRange, uno::UNO_QUERY ); + if ( xAddressable.is() ) + { + table::CellRangeAddress aRangeAddr = xAddressable->getRangeAddress(); + return ( aRangeAddr.EndColumn == aRangeAddr.StartColumn && aRangeAddr.EndRow == aRangeAddr.StartRow ); + } + return false; +} + +uno::Reference< excel::XCharacters > SAL_CALL +ScVbaRange::characters( const uno::Any& Start, const uno::Any& Length ) +{ + if ( !isSingleCellRange() ) + throw uno::RuntimeException("Can't create Characters property for multicell range " ); + uno::Reference< text::XSimpleText > xSimple(mxRange->getCellByPosition(0,0) , uno::UNO_QUERY_THROW ); + ScDocument& rDoc = getDocumentFromRange(mxRange); + + ScVbaPalette aPalette( rDoc.GetDocumentShell() ); + return new ScVbaCharacters( this, mxContext, aPalette, xSimple, Start, Length ); +} + + void SAL_CALL +ScVbaRange::Delete( const uno::Any& Shift ) +{ + if ( m_Areas->getCount() > 1 ) + { + sal_Int32 nItems = m_Areas->getCount(); + for ( sal_Int32 index=1; index <= nItems; ++index ) + { + uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW ); + xRange->Delete( Shift ); + } + return; + } + sheet::CellDeleteMode mode = sheet::CellDeleteMode_NONE ; + RangeHelper thisRange( mxRange ); + table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); + if ( Shift.hasValue() ) + { + sal_Int32 nShift = 0; + Shift >>= nShift; + switch ( nShift ) + { + case excel::XlDeleteShiftDirection::xlShiftUp: + mode = sheet::CellDeleteMode_UP; + break; + case excel::XlDeleteShiftDirection::xlShiftToLeft: + mode = sheet::CellDeleteMode_LEFT; + break; + default: + throw uno::RuntimeException("Illegal parameter " ); + } + } + else + { + ScDocument& rDoc = getScDocument(); + bool bFullRow = ( thisAddress.StartColumn == 0 && thisAddress.EndColumn == rDoc.MaxCol() ); + sal_Int32 nCols = thisAddress.EndColumn - thisAddress.StartColumn; + sal_Int32 nRows = thisAddress.EndRow - thisAddress.StartRow; + if ( mbIsRows || bFullRow || ( nCols >= nRows ) ) + mode = sheet::CellDeleteMode_UP; + else + mode = sheet::CellDeleteMode_LEFT; + } + uno::Reference< sheet::XCellRangeMovement > xCellRangeMove( thisRange.getSpreadSheet(), uno::UNO_QUERY_THROW ); + xCellRangeMove->removeRange( thisAddress, mode ); + +} + +//XElementAccess +sal_Bool SAL_CALL +ScVbaRange::hasElements() +{ + uno::Reference< table::XColumnRowRange > xColumnRowRange(mxRange, uno::UNO_QUERY ); + if ( xColumnRowRange.is() ) + if ( xColumnRowRange->getRows()->getCount() || + xColumnRowRange->getColumns()->getCount() ) + return true; + return false; +} + +// XEnumerationAccess +uno::Reference< container::XEnumeration > SAL_CALL +ScVbaRange::createEnumeration() +{ + if ( mbIsColumns || mbIsRows ) + { + uno::Reference< table::XColumnRowRange > xColumnRowRange(mxRange, uno::UNO_QUERY ); + uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( sal_Int32(1) ), uno::Any() ), uno::UNO_QUERY_THROW ); + sal_Int32 nElems = 0; + if ( mbIsColumns ) + nElems = xColumnRowRange->getColumns()->getCount(); + else + nElems = xColumnRowRange->getRows()->getCount(); + return new ColumnsRowEnumeration( xRange, nElems ); + + } + return new CellsEnumeration( mxParent, mxContext, m_Areas ); +} + +OUString SAL_CALL +ScVbaRange::getDefaultMethodName( ) +{ + return "Item"; +} + +// returns calc internal col. width ( in points ) +double +ScVbaRange::getCalcColWidth(const table::CellRangeAddress& rAddress) +{ + ScDocument& rDoc = getScDocument(); + sal_uInt16 nWidth = rDoc.GetOriginalWidth( static_cast< SCCOL >( rAddress.StartColumn ), static_cast< SCTAB >( rAddress.Sheet ) ); + double nPoints = lcl_TwipsToPoints( nWidth ); + nPoints = lcl_Round2DecPlaces( nPoints ); + return nPoints; +} + +double +ScVbaRange::getCalcRowHeight(const table::CellRangeAddress& rAddress) +{ + ScDocument& rDoc = getDocumentFromRange( mxRange ); + sal_uInt16 nWidth = rDoc.GetOriginalHeight( rAddress.StartRow, rAddress.Sheet ); + double nPoints = lcl_TwipsToPoints( nWidth ); + nPoints = lcl_Round2DecPlaces( nPoints ); + return nPoints; +} + +// return Char Width in points +static double getDefaultCharWidth( ScDocShell* pDocShell ) +{ + ScDocument& rDoc = pDocShell->GetDocument(); + OutputDevice* pRefDevice = rDoc.GetRefDevice(); + ScPatternAttr* pAttr = rDoc.GetDefPattern(); + vcl::Font aDefFont; + pAttr->GetFont( aDefFont, SC_AUTOCOL_BLACK, pRefDevice ); + pRefDevice->SetFont( aDefFont ); + tools::Long nCharWidth = pRefDevice->GetTextWidth( OUString( '0' ) ); // 1/100th mm + return o3tl::convert<double>(nCharWidth, o3tl::Length::mm100, o3tl::Length::pt); +} + +uno::Any SAL_CALL +ScVbaRange::getColumnWidth() +{ + sal_Int32 nLen = m_Areas->getCount(); + if ( nLen > 1 ) + { + uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( sal_Int32(1) ), uno::Any() ), uno::UNO_QUERY_THROW ); + return xRange->getColumnWidth(); + } + + double nColWidth = 0; + ScDocShell* pShell = getScDocShell(); + if ( pShell ) + { + double defaultCharWidth = getDefaultCharWidth( pShell ); + RangeHelper thisRange( mxRange ); + table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); + sal_Int32 nStartCol = thisAddress.StartColumn; + sal_Int32 nEndCol = thisAddress.EndColumn; + sal_uInt16 nColTwips = 0; + for( sal_Int32 nCol = nStartCol ; nCol <= nEndCol; ++nCol ) + { + thisAddress.StartColumn = nCol; + sal_uInt16 nCurTwips = pShell->GetDocument().GetOriginalWidth( static_cast< SCCOL >( thisAddress.StartColumn ), static_cast< SCTAB >( thisAddress.Sheet ) ); + if ( nCol == nStartCol ) + nColTwips = nCurTwips; + if ( nColTwips != nCurTwips ) + return aNULL(); + } + nColWidth = lcl_TwipsToPoints( nColTwips ); + if ( nColWidth != 0.0 ) + nColWidth = ( nColWidth / defaultCharWidth ) - fExtraWidth; + } + nColWidth = lcl_Round2DecPlaces( nColWidth ); + return uno::Any( nColWidth ); +} + +void SAL_CALL +ScVbaRange::setColumnWidth( const uno::Any& _columnwidth ) +{ + sal_Int32 nLen = m_Areas->getCount(); + if ( nLen > 1 ) + { + for ( sal_Int32 index = 1; index != nLen; ++index ) + { + uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( index ), uno::Any() ), uno::UNO_QUERY_THROW ); + xRange->setColumnWidth( _columnwidth ); + } + return; + } + double nColWidth = 0; + _columnwidth >>= nColWidth; + nColWidth = lcl_Round2DecPlaces( nColWidth ); + ScDocShell* pDocShell = getScDocShell(); + if ( !pDocShell ) + return; + + if ( nColWidth != 0.0 ) + nColWidth = ( nColWidth + fExtraWidth ) * getDefaultCharWidth( pDocShell ); + RangeHelper thisRange( mxRange ); + table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); + sal_uInt16 nTwips = lcl_pointsToTwips( nColWidth ); + + std::vector<sc::ColRowSpan> aColArr(1, sc::ColRowSpan(thisAddress.StartColumn, thisAddress.EndColumn)); + // #163561# use mode SC_SIZE_DIRECT: hide for width 0, show for other values + pDocShell->GetDocFunc().SetWidthOrHeight( + true, aColArr, thisAddress.Sheet, SC_SIZE_DIRECT, nTwips, true, true); +} + +uno::Any SAL_CALL +ScVbaRange::getWidth() +{ + if ( m_Areas->getCount() > 1 ) + { + uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( sal_Int32(1) ), uno::Any() ), uno::UNO_QUERY_THROW ); + return xRange->getWidth(); + } + uno::Reference< table::XColumnRowRange > xColRowRange( mxRange, uno::UNO_QUERY_THROW ); + uno::Reference< container::XIndexAccess > xIndexAccess( xColRowRange->getColumns(), uno::UNO_QUERY_THROW ); + sal_Int32 nElems = xIndexAccess->getCount(); + double nWidth = 0; + for ( sal_Int32 index=0; index<nElems; ++index ) + { + uno::Reference< sheet::XCellRangeAddressable > xAddressable( xIndexAccess->getByIndex( index ), uno::UNO_QUERY_THROW ); + double nTmpWidth = getCalcColWidth( xAddressable->getRangeAddress() ); + nWidth += nTmpWidth; + } + return uno::Any( nWidth ); +} + +uno::Any SAL_CALL +ScVbaRange::Areas( const uno::Any& item) +{ + if ( !item.hasValue() ) + return uno::Any( m_Areas ); + return m_Areas->Item( item, uno::Any() ); +} + +uno::Reference< excel::XRange > +ScVbaRange::getArea( sal_Int32 nIndex ) +{ + if ( !m_Areas.is() ) + throw uno::RuntimeException("No areas available" ); + uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( ++nIndex ), uno::Any() ), uno::UNO_QUERY_THROW ); + return xRange; +} + +uno::Any +ScVbaRange::Borders( const uno::Any& item ) +{ + if ( !item.hasValue() ) + return uno::Any( getBorders() ); + return getBorders()->Item( item, uno::Any() ); +} + +uno::Any SAL_CALL +ScVbaRange::BorderAround( const css::uno::Any& LineStyle, const css::uno::Any& Weight, + const css::uno::Any& ColorIndex, const css::uno::Any& Color ) +{ + sal_Int32 nCount = getBorders()->getCount(); + + for( sal_Int32 i = 0; i < nCount; i++ ) + { + const sal_Int32 nLineType = supportedIndexTable[i]; + switch( nLineType ) + { + case excel::XlBordersIndex::xlEdgeLeft: + case excel::XlBordersIndex::xlEdgeTop: + case excel::XlBordersIndex::xlEdgeBottom: + case excel::XlBordersIndex::xlEdgeRight: + { + uno::Reference< excel::XBorder > xBorder( m_Borders->Item( uno::Any( nLineType ), uno::Any() ), uno::UNO_QUERY_THROW ); + if( LineStyle.hasValue() ) + { + xBorder->setLineStyle( LineStyle ); + } + if( Weight.hasValue() ) + { + xBorder->setWeight( Weight ); + } + if( ColorIndex.hasValue() ) + { + xBorder->setColorIndex( ColorIndex ); + } + if( Color.hasValue() ) + { + xBorder->setColor( Color ); + } + break; + } + case excel::XlBordersIndex::xlInsideVertical: + case excel::XlBordersIndex::xlInsideHorizontal: + case excel::XlBordersIndex::xlDiagonalDown: + case excel::XlBordersIndex::xlDiagonalUp: + break; + default: + return uno::Any( false ); + } + } + return uno::Any( true ); +} + +uno::Any SAL_CALL +ScVbaRange::getRowHeight() +{ + sal_Int32 nLen = m_Areas->getCount(); + if ( nLen > 1 ) + { + uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( sal_Int32(1) ), uno::Any() ), uno::UNO_QUERY_THROW ); + return xRange->getRowHeight(); + } + + // if any row's RowHeight in the + // range is different from any other, then return NULL + RangeHelper thisRange( mxRange ); + table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); + + sal_Int32 nStartRow = thisAddress.StartRow; + sal_Int32 nEndRow = thisAddress.EndRow; + sal_uInt16 nRowTwips = 0; + // #TODO probably possible to use the SfxItemSet (and see if + // SfxItemState::DONTCARE is set) to improve performance +// #CHECKME looks like this is general behaviour not just row Range specific +// if ( mbIsRows ) + ScDocShell* pShell = getScDocShell(); + if ( pShell ) + { + for ( sal_Int32 nRow = nStartRow ; nRow <= nEndRow; ++nRow ) + { + thisAddress.StartRow = nRow; + sal_uInt16 nCurTwips = pShell->GetDocument().GetOriginalHeight( thisAddress.StartRow, thisAddress.Sheet ); + if ( nRow == nStartRow ) + nRowTwips = nCurTwips; + if ( nRowTwips != nCurTwips ) + return aNULL(); + } + } + double nHeight = lcl_Round2DecPlaces( lcl_TwipsToPoints( nRowTwips ) ); + return uno::Any( nHeight ); +} + +void SAL_CALL +ScVbaRange::setRowHeight( const uno::Any& _rowheight) +{ + sal_Int32 nLen = m_Areas->getCount(); + if ( nLen > 1 ) + { + for ( sal_Int32 index = 1; index != nLen; ++index ) + { + uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( index ), uno::Any() ), uno::UNO_QUERY_THROW ); + xRange->setRowHeight( _rowheight ); + } + return; + } + double nHeight = 0; // Incoming height is in points + _rowheight >>= nHeight; + nHeight = lcl_Round2DecPlaces( nHeight ); + RangeHelper thisRange( mxRange ); + table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); + sal_uInt16 nTwips = lcl_pointsToTwips( nHeight ); + + ScDocShell* pDocShell = getDocShellFromRange( mxRange ); + std::vector<sc::ColRowSpan> aRowArr(1, sc::ColRowSpan(thisAddress.StartRow, thisAddress.EndRow)); + pDocShell->GetDocFunc().SetWidthOrHeight( + false, aRowArr, thisAddress.Sheet, SC_SIZE_ORIGINAL, nTwips, true, true); +} + +uno::Any SAL_CALL +ScVbaRange::getPageBreak() +{ + sal_Int32 nPageBreak = excel::XlPageBreak::xlPageBreakNone; + ScDocShell* pShell = getDocShellFromRange( mxRange ); + if ( pShell ) + { + RangeHelper thisRange( mxRange ); + table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); + bool bColumn = false; + + if (thisAddress.StartRow==0) + bColumn = true; + + uno::Reference< frame::XModel > xModel = pShell->GetModel(); + if ( xModel.is() ) + { + ScDocument& rDoc = getDocumentFromRange( mxRange ); + + ScBreakType nBreak = ScBreakType::NONE; + if ( !bColumn ) + nBreak = rDoc.HasRowBreak(thisAddress.StartRow, thisAddress.Sheet); + else + nBreak = rDoc.HasColBreak(thisAddress.StartColumn, thisAddress.Sheet); + + if (nBreak & ScBreakType::Page) + nPageBreak = excel::XlPageBreak::xlPageBreakAutomatic; + + if (nBreak & ScBreakType::Manual) + nPageBreak = excel::XlPageBreak::xlPageBreakManual; + } + } + + return uno::Any( nPageBreak ); +} + +void SAL_CALL +ScVbaRange::setPageBreak( const uno::Any& _pagebreak) +{ + sal_Int32 nPageBreak = 0; + _pagebreak >>= nPageBreak; + + ScDocShell* pShell = getDocShellFromRange( mxRange ); + if ( !pShell ) + return; + + RangeHelper thisRange( mxRange ); + table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); + if ((thisAddress.StartColumn==0) && (thisAddress.StartRow==0)) + return; + bool bColumn = false; + + if (thisAddress.StartRow==0) + bColumn = true; + + ScAddress aAddr( static_cast<SCCOL>(thisAddress.StartColumn), thisAddress.StartRow, thisAddress.Sheet ); + uno::Reference< frame::XModel > xModel = pShell->GetModel(); + if ( xModel.is() ) + { + ScTabViewShell* pViewShell = excel::getBestViewShell( xModel ); + if ( nPageBreak == excel::XlPageBreak::xlPageBreakManual ) + pViewShell->InsertPageBreak( bColumn, true, &aAddr); + else if ( nPageBreak == excel::XlPageBreak::xlPageBreakNone ) + pViewShell->DeletePageBreak( bColumn, true, &aAddr); + } +} + +uno::Any SAL_CALL +ScVbaRange::getHeight() +{ + if ( m_Areas->getCount() > 1 ) + { + uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( sal_Int32(1) ), uno::Any() ), uno::UNO_QUERY_THROW ); + return xRange->getHeight(); + } + + uno::Reference< table::XColumnRowRange > xColRowRange( mxRange, uno::UNO_QUERY_THROW ); + uno::Reference< container::XIndexAccess > xIndexAccess( xColRowRange->getRows(), uno::UNO_QUERY_THROW ); + sal_Int32 nElems = xIndexAccess->getCount(); + double nHeight = 0; + for ( sal_Int32 index=0; index<nElems; ++index ) + { + uno::Reference< sheet::XCellRangeAddressable > xAddressable( xIndexAccess->getByIndex( index ), uno::UNO_QUERY_THROW ); + nHeight += getCalcRowHeight(xAddressable->getRangeAddress() ); + } + return uno::Any( nHeight ); +} + +awt::Point +ScVbaRange::getPosition() const +{ + awt::Point aPoint; + uno::Reference< beans::XPropertySet > xProps; + if ( mxRange.is() ) + xProps.set( mxRange, uno::UNO_QUERY_THROW ); + else + xProps.set( mxRanges, uno::UNO_QUERY_THROW ); + xProps->getPropertyValue( "Position" ) >>= aPoint; + return aPoint; +} +uno::Any SAL_CALL +ScVbaRange::getLeft() +{ + // helperapi returns the first ranges left ( and top below ) + if ( m_Areas->getCount() > 1 ) + return getArea( 0 )->getLeft(); + awt::Point aPoint = getPosition(); + return uno::Any(o3tl::convert<double>(aPoint.X, o3tl::Length::mm100, o3tl::Length::pt)); +} + +uno::Any SAL_CALL +ScVbaRange::getTop() +{ + // helperapi returns the first ranges top + if ( m_Areas->getCount() > 1 ) + return getArea( 0 )->getTop(); + awt::Point aPoint= getPosition(); + return uno::Any(o3tl::convert<double>(aPoint.Y, o3tl::Length::mm100, o3tl::Length::pt)); +} + +static uno::Reference< sheet::XCellRangeReferrer > getNamedRange( const uno::Reference< uno::XInterface >& xIf, const uno::Reference< table::XCellRange >& thisRange ) +{ + uno::Reference< beans::XPropertySet > xProps( xIf, uno::UNO_QUERY_THROW ); + uno::Reference< container::XNameAccess > xNameAccess( xProps->getPropertyValue( "NamedRanges" ), uno::UNO_QUERY_THROW ); + + const uno::Sequence< OUString > sNames = xNameAccess->getElementNames(); +// uno::Reference< table::XCellRange > thisRange( getCellRange(), uno::UNO_QUERY_THROW ); + uno::Reference< sheet::XCellRangeReferrer > xNamedRange; + for ( const auto& rName : sNames ) + { + uno::Reference< sheet::XCellRangeReferrer > xName( xNameAccess->getByName( rName ), uno::UNO_QUERY ); + if ( xName.is() ) + { + if ( thisRange == xName->getReferredCells() ) + { + xNamedRange = xName; + break; + } + } + } + return xNamedRange; +} + +uno::Reference< excel::XName > +ScVbaRange::getName() +{ + uno::Reference< beans::XPropertySet > xProps( getUnoModel(), uno::UNO_QUERY ); + uno::Reference< table::XCellRange > thisRange( getCellRange(), uno::UNO_QUERY_THROW ); + // Application range + uno::Reference< sheet::XCellRangeReferrer > xNamedRange = getNamedRange( xProps, thisRange ); + + if ( !xNamedRange.is() ) + { + // not in application range then assume it might be in + // sheet namedranges + RangeHelper aRange( thisRange ); + uno::Reference< sheet::XSpreadsheet > xSheet = aRange.getSpreadSheet(); + xProps.set( xSheet, uno::UNO_QUERY ); + // impl here + xNamedRange = getNamedRange( xProps, thisRange ); + } + if ( xProps.is() && xNamedRange.is() ) + { + uno::Reference< sheet::XNamedRanges > xNamedRanges( xProps, uno::UNO_QUERY_THROW ); + uno::Reference< sheet::XNamedRange > xName( xNamedRange, uno::UNO_QUERY_THROW ); + return new ScVbaName( mxParent, mxContext, xName, xNamedRanges, getUnoModel() ); + } + return uno::Reference< excel::XName >(); +} + +uno::Reference< excel::XWorksheet > +ScVbaRange::getWorksheet() +{ + // #TODO #FIXME parent should always be set up ( currently that's not + // the case ) + uno::Reference< excel::XWorksheet > xSheet( getParent(), uno::UNO_QUERY ); + if ( !xSheet.is() ) + { + uno::Reference< table::XCellRange > xRange = mxRange; + + if ( mxRanges.is() ) // assign xRange to first range + { + uno::Reference< container::XIndexAccess > xIndex( mxRanges, uno::UNO_QUERY_THROW ); + xRange.set( xIndex->getByIndex( 0 ), uno::UNO_QUERY_THROW ); + } + ScDocShell* pDocShell = getDocShellFromRange(xRange); + RangeHelper rHelper(xRange); + // parent should be Thisworkbook + xSheet.set( new ScVbaWorksheet( uno::Reference< XHelperInterface >(), mxContext,rHelper.getSpreadSheet(),pDocShell->GetModel()) ); + } + return xSheet; +} + +// #TODO remove this ugly application processing +// Process an application Range request e.g. 'Range("a1,b2,a4:b6") +uno::Reference< excel::XRange > +ScVbaRange::ApplicationRange( const uno::Reference< uno::XComponentContext >& xContext, const css::uno::Any &Cell1, const css::uno::Any &Cell2 ) +{ + // Although the documentation seems clear that Range without a + // qualifier then it's a shortcut for ActiveSheet.Range + // however, similarly Application.Range is apparently also a + // shortcut for ActiveSheet.Range + // The is however a subtle behavioural difference I've come across + // wrt to named ranges. + // If a named range "test" exists { Sheet1!$A1 } and the active sheet + // is Sheet2 then the following will fail + // msgbox ActiveSheet.Range("test").Address ' fails + // msgbox WorkSheets("Sheet2").Range("test").Address + // but!!! + // msgbox Range("test").Address ' works + // msgbox Application.Range("test").Address ' works + + // Single param Range + OUString sRangeName; + Cell1 >>= sRangeName; + if ( Cell1.hasValue() && !Cell2.hasValue() && !sRangeName.isEmpty() ) + { + uno::Reference< beans::XPropertySet > xPropSet( getCurrentExcelDoc(xContext), uno::UNO_QUERY_THROW ); + + uno::Reference< container::XNameAccess > xNamed( xPropSet->getPropertyValue( "NamedRanges" ), uno::UNO_QUERY_THROW ); + uno::Reference< sheet::XCellRangeReferrer > xReferrer; + try + { + xReferrer.set ( xNamed->getByName( sRangeName ), uno::UNO_QUERY ); + } + catch( uno::Exception& /*e*/ ) + { + // do nothing + } + if ( xReferrer.is() ) + { + uno::Reference< table::XCellRange > xRange = xReferrer->getReferredCells(); + if ( xRange.is() ) + { + uno::Reference< excel::XRange > xVbRange = new ScVbaRange( excel::getUnoSheetModuleObj( xRange ), xContext, xRange ); + return xVbRange; + } + } + } + + uno::Reference<table::XCellRange> xSheetRange; + + try + { + uno::Reference<sheet::XSpreadsheetView> xView( + getCurrentExcelDoc(xContext)->getCurrentController(), uno::UNO_QUERY_THROW); + + xSheetRange.set(xView->getActiveSheet(), uno::UNO_QUERY_THROW); + } + catch (const uno::Exception&) + { + return uno::Reference<excel::XRange>(); + } + + rtl::Reference<ScVbaRange> pRange = new ScVbaRange( excel::getUnoSheetModuleObj( xSheetRange ), xContext, xSheetRange ); + return pRange->Range( Cell1, Cell2, true ); +} + +// Helper functions for AutoFilter +static ScDBData* lcl_GetDBData_Impl( ScDocShell* pDocShell, sal_Int16 nSheet ) +{ + ScDBData* pRet = nullptr; + if (pDocShell) + { + pRet = pDocShell->GetDocument().GetAnonymousDBData(nSheet); + } + return pRet; +} + +static void lcl_SelectAll( ScDocShell* pDocShell, const ScQueryParam& aParam ) +{ + if ( !pDocShell ) + return; + + ScViewData* pViewData = ScDocShell::GetViewData(); + if ( !pViewData ) + { + ScTabViewShell* pViewSh = pDocShell->GetBestViewShell( true ); + pViewData = pViewSh ? &pViewSh->GetViewData() : nullptr; + } + + if ( pViewData ) + { + pViewData->GetView()->Query( aParam, nullptr, true ); + } +} + +static ScQueryParam lcl_GetQueryParam( ScDocShell* pDocShell, sal_Int16 nSheet ) +{ + ScDBData* pDBData = lcl_GetDBData_Impl( pDocShell, nSheet ); + ScQueryParam aParam; + if (pDBData) + { + pDBData->GetQueryParam( aParam ); + } + return aParam; +} + +static void lcl_SetAllQueryForField( ScDocShell* pDocShell, SCCOLROW nField, sal_Int16 nSheet ) +{ + ScQueryParam aParam = lcl_GetQueryParam( pDocShell, nSheet ); + aParam.RemoveEntryByField(nField); + lcl_SelectAll( pDocShell, aParam ); +} + +// Modifies sCriteria, and nOp depending on the value of sCriteria +static void lcl_setTableFieldsFromCriteria( OUString& sCriteria1, const uno::Reference< beans::XPropertySet >& xDescProps, sheet::TableFilterField2& rFilterField ) +{ + // #TODO make this more efficient and cycle through + // sCriteria1 character by character to pick up <,<>,=, * etc. + // right now I am more concerned with just getting it to work right + + sCriteria1 = sCriteria1.trim(); + // table of translation of criteria text to FilterOperators + // <>searchtext - NOT_EQUAL + // =searchtext - EQUAL + // *searchtext - startwith + // <>*searchtext - doesn't startwith + // *searchtext* - contains + // <>*searchtext* - doesn't contain + // [>|>=|<=|...]searchtext for GREATER_value, GREATER_EQUAL_value etc. + if ( sCriteria1.startsWith( EQUALS ) ) + { + if ( o3tl::make_unsigned(sCriteria1.getLength()) == strlen(EQUALS) ) + rFilterField.Operator = sheet::FilterOperator2::EMPTY; + else + { + rFilterField.Operator = sheet::FilterOperator2::EQUAL; + sCriteria1 = sCriteria1.copy( strlen(EQUALS) ); + sCriteria1 = VBAToRegexp( sCriteria1 ); + // UseRegularExpressions + if ( xDescProps.is() ) + xDescProps->setPropertyValue( "UseRegularExpressions", uno::Any( true ) ); + } + + } + else if ( sCriteria1.startsWith( NOTEQUALS ) ) + { + if ( o3tl::make_unsigned(sCriteria1.getLength()) == strlen(NOTEQUALS) ) + rFilterField.Operator = sheet::FilterOperator2::NOT_EMPTY; + else + { + rFilterField.Operator = sheet::FilterOperator2::NOT_EQUAL; + sCriteria1 = sCriteria1.copy( strlen(NOTEQUALS) ); + sCriteria1 = VBAToRegexp( sCriteria1 ); + // UseRegularExpressions + if ( xDescProps.is() ) + xDescProps->setPropertyValue( "UseRegularExpressions", uno::Any( true ) ); + } + } + else if ( sCriteria1.startsWith( GREATERTHAN ) ) + { + if ( sCriteria1.startsWith( GREATERTHANEQUALS ) ) + { + sCriteria1 = sCriteria1.copy( strlen(GREATERTHANEQUALS) ); + rFilterField.Operator = sheet::FilterOperator2::GREATER_EQUAL; + } + else + { + sCriteria1 = sCriteria1.copy( strlen(GREATERTHAN) ); + rFilterField.Operator = sheet::FilterOperator2::GREATER; + } + + } + else if ( sCriteria1.startsWith( LESSTHAN ) ) + { + if ( sCriteria1.startsWith( LESSTHANEQUALS ) ) + { + sCriteria1 = sCriteria1.copy( strlen(LESSTHANEQUALS) ); + rFilterField.Operator = sheet::FilterOperator2::LESS_EQUAL; + } + else + { + sCriteria1 = sCriteria1.copy( strlen(LESSTHAN) ); + rFilterField.Operator = sheet::FilterOperator2::LESS; + } + + } + else + rFilterField.Operator = sheet::FilterOperator2::EQUAL; + + // tdf#107885 - check if criteria is numeric using locale dependent settings without group separator + // or, if the decimal separator is different from the English locale, without any locale. + sal_Int32 nParseEnd = 0; + rtl_math_ConversionStatus eStatus = rtl_math_ConversionStatus_Ok; + double fValue = ScGlobal::getLocaleData().stringToDouble( sCriteria1, false, &eStatus, &nParseEnd ); + if ( nParseEnd == sCriteria1.getLength() && eStatus == rtl_math_ConversionStatus_Ok ) + { + rFilterField.IsNumeric = true; + rFilterField.NumericValue = fValue; + } + else if ( ScGlobal::getLocaleData().getNumDecimalSep().toChar() != '.' ) + { + eStatus = rtl_math_ConversionStatus_Ok; + fValue = ::rtl::math::stringToDouble( sCriteria1, '.', 0, &eStatus, &nParseEnd ); + if ( nParseEnd == sCriteria1.getLength() && eStatus == rtl_math_ConversionStatus_Ok ) + { + rFilterField.IsNumeric = true; + rFilterField.NumericValue = fValue; + } + } + + rFilterField.StringValue = sCriteria1; +} + +void SAL_CALL +ScVbaRange::AutoFilter( const uno::Any& aField, const uno::Any& Criteria1, const uno::Any& Operator, const uno::Any& Criteria2, const uno::Any& /*VisibleDropDown*/ ) +{ + // Is there an existing autofilter + RangeHelper thisRange( mxRange ); + table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); + sal_Int16 nSheet = thisAddress.Sheet; + ScDocShell* pShell = getScDocShell(); + bool bHasAuto = false; + uno::Reference< sheet::XDatabaseRange > xDataBaseRange = excel::GetAutoFiltRange( pShell, nSheet ); + if ( xDataBaseRange.is() ) + bHasAuto = true; + + if ( !bHasAuto ) + { + if ( m_Areas->getCount() > 1 ) + throw uno::RuntimeException( STR_ERRORMESSAGE_APPLIESTOSINGLERANGEONLY ); + + table::CellRangeAddress autoFiltAddress; + //CurrentRegion() + if ( isSingleCellRange() ) + { + uno::Reference< excel::XRange > xCurrent( CurrentRegion() ); + if ( xCurrent.is() ) + { + ScVbaRange* pRange = getImplementation( xCurrent ); + if ( pRange ) + { + if ( pRange->isSingleCellRange() ) + throw uno::RuntimeException("Can't create AutoFilter" ); + RangeHelper currentRegion( pRange->mxRange ); + autoFiltAddress = currentRegion.getCellRangeAddressable()->getRangeAddress(); + } + } + } + else // multi-cell range + { + RangeHelper multiCellRange( mxRange ); + autoFiltAddress = multiCellRange.getCellRangeAddressable()->getRangeAddress(); + // #163530# Filter box shows only entry of first row + ScDocument* pDocument = ( pShell ? &pShell->GetDocument() : nullptr ); + if ( pDocument ) + { + SCCOL nStartCol = autoFiltAddress.StartColumn; + SCROW nStartRow = autoFiltAddress.StartRow; + SCCOL nEndCol = autoFiltAddress.EndColumn; + SCROW nEndRow = autoFiltAddress.EndRow; + pDocument->GetDataArea( autoFiltAddress.Sheet, nStartCol, nStartRow, nEndCol, nEndRow, true, true ); + autoFiltAddress.StartColumn = nStartCol; + autoFiltAddress.StartRow = nStartRow; + autoFiltAddress.EndColumn = nEndCol; + autoFiltAddress.EndRow = nEndRow; + } + } + + uno::Reference< sheet::XUnnamedDatabaseRanges > xDBRanges = excel::GetUnnamedDataBaseRanges( pShell ); + if ( xDBRanges.is() ) + { + if ( !xDBRanges->hasByTable( nSheet ) ) + xDBRanges->setByTable( autoFiltAddress ); + xDataBaseRange.set( xDBRanges->getByTable(nSheet ), uno::UNO_QUERY_THROW ); + } + if ( !xDataBaseRange.is() ) + throw uno::RuntimeException("Failed to find the autofilter placeholder range" ); + + uno::Reference< beans::XPropertySet > xDBRangeProps( xDataBaseRange, uno::UNO_QUERY_THROW ); + // set autofilter + xDBRangeProps->setPropertyValue( "AutoFilter", uno::Any(true) ); + // set header (autofilter always need column headers) + uno::Reference< beans::XPropertySet > xFiltProps( xDataBaseRange->getFilterDescriptor(), uno::UNO_QUERY_THROW ); + xFiltProps->setPropertyValue( "ContainsHeader", uno::Any( true ) ); + } + + sal_Int32 nField = 0; // *IS* 1 based + sal_Int32 nOperator = excel::XlAutoFilterOperator::xlAnd; + + sheet::FilterConnection nConn = sheet::FilterConnection_AND; + double nCriteria1 = 0; + + bool bHasCritValue = Criteria1.hasValue(); + bool bCritHasNumericValue = false; // not sure if a numeric criteria is possible + if ( bHasCritValue ) + bCritHasNumericValue = ( Criteria1 >>= nCriteria1 ); + + if ( !aField.hasValue() && ( Criteria1.hasValue() || Operator.hasValue() || Criteria2.hasValue() ) ) + throw uno::RuntimeException(); + uno::Any Field( aField ); + if ( !( Field >>= nField ) ) + { + const uno::Reference< script::XTypeConverter >& xConverter = getTypeConverter( mxContext ); + try + { + Field = xConverter->convertTo( aField, cppu::UnoType<sal_Int32>::get() ); + } + catch( uno::Exception& ) + { + } + } + // Use the normal uno api, sometimes e.g. when you want to use ALL as the filter + // we can't use refresh as the uno interface doesn't have a concept of ALL + // in this case we just call the core calc functionality - + if ( Field >>= nField ) + { + uno::Reference< sheet::XSheetFilterDescriptor2 > xDesc( + xDataBaseRange->getFilterDescriptor(), uno::UNO_QUERY ); + if ( xDesc.is() ) + { + OUString sCriteria1; + bool bAcceptCriteria2 = true; + bool bAll = false; + uno::Sequence< sheet::TableFilterField2 > sTabFilts; + sheet::TableFilterField2* pTabFilts = nullptr; + uno::Reference< beans::XPropertySet > xDescProps( xDesc, uno::UNO_QUERY_THROW ); + if ( Criteria1.hasValue() ) + { + sTabFilts.realloc( 1 ); + pTabFilts = sTabFilts.getArray(); + pTabFilts[0].Operator = sheet::FilterOperator2::EQUAL;// sensible default + if ( !bCritHasNumericValue ) + { + Criteria1 >>= sCriteria1; + if ( sCriteria1.isEmpty() ) + { + uno::Sequence< OUString > aCriteria1; + Criteria1 >>= aCriteria1; + sal_uInt16 nLength = aCriteria1.getLength(); + if ( nLength ) + { + // When sequence is provided for Criteria1 don't care about Criteria2 + bAcceptCriteria2 = false; + + auto pCriteria1 = aCriteria1.getArray(); + sTabFilts.realloc( nLength ); + pTabFilts = sTabFilts.getArray(); + for ( sal_uInt16 i = 0; i < nLength; ++i ) + { + lcl_setTableFieldsFromCriteria( pCriteria1[i], xDescProps, pTabFilts[i] ); + pTabFilts[i].Connection = sheet::FilterConnection_OR; + pTabFilts[i].Field = (nField - 1); + } + } + else + bAll = true; + } + else + { + pTabFilts[0].IsNumeric = bCritHasNumericValue; + if ( bHasCritValue && !sCriteria1.isEmpty() ) + lcl_setTableFieldsFromCriteria( sCriteria1, xDescProps, pTabFilts[0] ); + else + bAll = true; + } + } + else // numeric + { + pTabFilts[0].IsNumeric = true; + pTabFilts[0].NumericValue = nCriteria1; + } + } + else // no value specified + bAll = true; + // not sure what the relationship between Criteria1 and Operator is, + // e.g. can you have an Operator without a Criteria? In LibreOffice it + if ( Operator.hasValue() && ( Operator >>= nOperator ) ) + { + // if it's a bottom/top Ten(Percent/Value) and there + // is no value specified for criteria1 set it to 10 + if ( !bCritHasNumericValue && sCriteria1.isEmpty() && ( nOperator != excel::XlAutoFilterOperator::xlOr ) && ( nOperator != excel::XlAutoFilterOperator::xlAnd ) ) + { + pTabFilts[0].IsNumeric = true; + pTabFilts[0].NumericValue = 10; + bAll = false; + } + switch ( nOperator ) + { + case excel::XlAutoFilterOperator::xlBottom10Items: + pTabFilts[0].Operator = sheet::FilterOperator2::BOTTOM_VALUES; + break; + case excel::XlAutoFilterOperator::xlBottom10Percent: + pTabFilts[0].Operator = sheet::FilterOperator2::BOTTOM_PERCENT; + break; + case excel::XlAutoFilterOperator::xlTop10Items: + pTabFilts[0].Operator = sheet::FilterOperator2::TOP_VALUES; + break; + case excel::XlAutoFilterOperator::xlTop10Percent: + pTabFilts[0].Operator = sheet::FilterOperator2::TOP_PERCENT; + break; + case excel::XlAutoFilterOperator::xlOr: + nConn = sheet::FilterConnection_OR; + break; + case excel::XlAutoFilterOperator::xlAnd: + nConn = sheet::FilterConnection_AND; + break; + default: + throw uno::RuntimeException("UnknownOption" ); + + } + + } + if ( !bAll && bAcceptCriteria2 ) + { + pTabFilts[0].Connection = sheet::FilterConnection_AND; + pTabFilts[0].Field = (nField - 1); + + uno::Sequence< OUString > aCriteria2; + if ( Criteria2.hasValue() ) // there is a Criteria2 + { + sTabFilts.realloc(2); + pTabFilts = sTabFilts.getArray(); + pTabFilts[1].Field = sTabFilts[0].Field; + pTabFilts[1].Connection = nConn; + + OUString sCriteria2; + if ( Criteria2 >>= sCriteria2 ) + { + if ( !sCriteria2.isEmpty() ) + { + uno::Reference< beans::XPropertySet > xProps; + lcl_setTableFieldsFromCriteria( sCriteria2, xProps, pTabFilts[1] ); + pTabFilts[1].IsNumeric = false; + } + } + else if ( Criteria2 >>= aCriteria2 ) + { + sal_uInt16 nLength = aCriteria2.getLength(); + if ( nLength ) + { + // For compatibility use only the last value from the sequence + lcl_setTableFieldsFromCriteria( aCriteria2.getArray()[nLength - 1], xDescProps, pTabFilts[1] ); + } + } + else // numeric + { + Criteria2 >>= pTabFilts[1].NumericValue; + pTabFilts[1].IsNumeric = true; + pTabFilts[1].Operator = sheet::FilterOperator2::EQUAL; + } + } + } + + xDesc->setFilterFields2( sTabFilts ); + if ( !bAll ) + { + xDataBaseRange->refresh(); + } + else + // was 0 based now seems to be 1 + lcl_SetAllQueryForField( pShell, nField, nSheet ); + } + } + else + { + // this is just to toggle autofilter on and off ( not to be confused with + // a VisibleDropDown option combined with a field, in that case just the + // button should be disabled ) - currently we don't support that + uno::Reference< beans::XPropertySet > xDBRangeProps( xDataBaseRange, uno::UNO_QUERY_THROW ); + if ( bHasAuto ) + { + // find the any field with the query and select all + ScQueryParam aParam = lcl_GetQueryParam( pShell, nSheet ); + for (SCSIZE i = 0; i< aParam.GetEntryCount(); ++i) + { + ScQueryEntry& rEntry = aParam.GetEntry(i); + if ( rEntry.bDoQuery ) + lcl_SetAllQueryForField( pShell, rEntry.nField, nSheet ); + } + // remove existing filters + uno::Reference< sheet::XSheetFilterDescriptor2 > xSheetFilterDescriptor( + xDataBaseRange->getFilterDescriptor(), uno::UNO_QUERY ); + if( xSheetFilterDescriptor.is() ) + xSheetFilterDescriptor->setFilterFields2( uno::Sequence< sheet::TableFilterField2 >() ); + } + xDBRangeProps->setPropertyValue( "AutoFilter", uno::Any(!bHasAuto) ); + + } +} + +void SAL_CALL +ScVbaRange::Insert( const uno::Any& Shift, const uno::Any& /*CopyOrigin*/ ) +{ + // It appears (from the web) that the undocumented CopyOrigin + // param should contain member of enum XlInsertFormatOrigin + // which can have values xlFormatFromLeftOrAbove or xlFormatFromRightOrBelow + // #TODO investigate resultant behaviour using these constants + // currently just processing Shift + + sheet::CellInsertMode mode = sheet::CellInsertMode_NONE; + if ( Shift.hasValue() ) + { + sal_Int32 nShift = 0; + Shift >>= nShift; + switch ( nShift ) + { + case excel::XlInsertShiftDirection::xlShiftToRight: + mode = sheet::CellInsertMode_RIGHT; + break; + case excel::XlInsertShiftDirection::xlShiftDown: + mode = sheet::CellInsertMode_DOWN; + break; + default: + throw uno::RuntimeException("Illegal parameter " ); + } + } + else + { + if ( getRow() >= getColumn() ) + mode = sheet::CellInsertMode_DOWN; + else + mode = sheet::CellInsertMode_RIGHT; + } + RangeHelper thisRange( mxRange ); + table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); + uno::Reference< sheet::XCellRangeMovement > xCellRangeMove( thisRange.getSpreadSheet(), uno::UNO_QUERY_THROW ); + xCellRangeMove->insertCells( thisAddress, mode ); + + // Paste from clipboard only if the clipboard content was copied via VBA, and not already pasted via VBA again. + // "Insert" behavior should not depend on random clipboard content previously copied by the user. + ScDocShell* pDocShell = getDocShellFromRange( mxRange ); + const ScTransferObj* pClipObj = pDocShell ? ScTransferObj::GetOwnClipboard(pDocShell->GetClipData()) : nullptr; + if ( pClipObj && pClipObj->GetUseInApi() ) + { + // After the insert ( this range ) actually has moved + ScRange aRange( static_cast< SCCOL >( thisAddress.StartColumn ), static_cast< SCROW >( thisAddress.StartRow ), static_cast< SCTAB >( thisAddress.Sheet ), static_cast< SCCOL >( thisAddress.EndColumn ), static_cast< SCROW >( thisAddress.EndRow ), static_cast< SCTAB >( thisAddress.Sheet ) ); + uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( getDocShellFromRange( mxRange ) , aRange ) ); + uno::Reference< excel::XRange > xVbaRange( new ScVbaRange( mxParent, mxContext, xRange, mbIsRows, mbIsColumns ) ); + xVbaRange->PasteSpecial( uno::Any(), uno::Any(), uno::Any(), uno::Any() ); + } +} + +void SAL_CALL +ScVbaRange::Autofit() +{ + sal_Int32 nLen = m_Areas->getCount(); + if ( nLen > 1 ) + { + for ( sal_Int32 index = 1; index != nLen; ++index ) + { + uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( index ), uno::Any() ), uno::UNO_QUERY_THROW ); + xRange->Autofit(); + } + return; + } + + // if the range is a not a row or column range autofit will + // throw an error + if ( !( mbIsColumns || mbIsRows ) ) + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + ScDocShell* pDocShell = getDocShellFromRange( mxRange ); + if ( !pDocShell ) + return; + + RangeHelper thisRange( mxRange ); + table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); + + std::vector<sc::ColRowSpan> aColArr(1, sc::ColRowSpan(thisAddress.StartColumn,thisAddress.EndColumn)); + bool bDirection = true; + if ( mbIsRows ) + { + bDirection = false; + aColArr[0].mnStart = thisAddress.StartRow; + aColArr[0].mnEnd = thisAddress.EndRow; + } + pDocShell->GetDocFunc().SetWidthOrHeight( + bDirection, aColArr, thisAddress.Sheet, SC_SIZE_OPTIMAL, 0, true, true); +} + +uno::Any SAL_CALL +ScVbaRange::Hyperlinks( const uno::Any& aIndex ) +{ + /* The range object always returns a new Hyperlinks object containing a + fixed list of existing hyperlinks in the range. + See vbahyperlinks.hxx for more details. */ + + // get the global hyperlink object of the sheet (sheet should always be the parent of a Range object) + uno::Reference< excel::XWorksheet > xWorksheet( getParent(), uno::UNO_QUERY_THROW ); + uno::Reference< excel::XHyperlinks > xSheetHlinks( xWorksheet->Hyperlinks( uno::Any() ), uno::UNO_QUERY_THROW ); + ScVbaHyperlinksRef xScSheetHlinks( dynamic_cast< ScVbaHyperlinks* >( xSheetHlinks.get() ) ); + if( !xScSheetHlinks.is() ) + throw uno::RuntimeException("Cannot obtain hyperlinks implementation object" ); + + // create a new local hyperlinks object based on the sheet hyperlinks + ScVbaHyperlinksRef xHlinks( new ScVbaHyperlinks( getParent(), mxContext, xScSheetHlinks, getScRangeList() ) ); + if( aIndex.hasValue() ) + return xHlinks->Item( aIndex, uno::Any() ); + return uno::Any( uno::Reference< excel::XHyperlinks >( xHlinks ) ); +} + +css::uno::Reference< excel::XValidation > SAL_CALL +ScVbaRange::getValidation() +{ + if ( !m_xValidation.is() ) + m_xValidation = new ScVbaValidation( this, mxContext, mxRange ); + return m_xValidation; +} + +namespace { + +/// @throws uno::RuntimeException +sal_Unicode lclGetPrefixChar( const uno::Reference< table::XCell >& rxCell ) +{ + /* TODO/FIXME: We need an apostroph-prefix property at the cell to + implement this correctly. For now, return an apostroph for every text + cell. + + TODO/FIXME: When Application.TransitionNavigKeys is supported and true, + this function needs to inspect the cell formatting and return different + prefixes according to the horizontal cell alignment. + */ + return (rxCell->getType() == table::CellContentType_TEXT) ? '\'' : 0; +} + +/// @throws uno::RuntimeException +sal_Unicode lclGetPrefixChar( const uno::Reference< table::XCellRange >& rxRange ) +{ + /* This implementation is able to handle different prefixes (needed if + Application.TransitionNavigKeys is true). The function lclGetPrefixChar + for single cells called from here may return any prefix. If that + function returns an empty prefix (NUL character) or different non-empty + prefixes for two cells, this function returns 0. + */ + sal_Unicode cCurrPrefix = 0; + table::CellRangeAddress aRangeAddr = lclGetRangeAddress( rxRange ); + sal_Int32 nEndCol = aRangeAddr.EndColumn - aRangeAddr.StartColumn; + sal_Int32 nEndRow = aRangeAddr.EndRow - aRangeAddr.StartRow; + for( sal_Int32 nRow = 0; nRow <= nEndRow; ++nRow ) + { + for( sal_Int32 nCol = 0; nCol <= nEndCol; ++nCol ) + { + uno::Reference< table::XCell > xCell( rxRange->getCellByPosition( nCol, nRow ), uno::UNO_SET_THROW ); + sal_Unicode cNewPrefix = lclGetPrefixChar( xCell ); + if( (cNewPrefix == 0) || ((cCurrPrefix != 0) && (cNewPrefix != cCurrPrefix)) ) + return 0; + cCurrPrefix = cNewPrefix; + } + } + // all cells contain the same prefix - return it + return cCurrPrefix; +} + +/// @throws uno::RuntimeException +sal_Unicode lclGetPrefixChar( const uno::Reference< sheet::XSheetCellRangeContainer >& rxRanges ) +{ + sal_Unicode cCurrPrefix = 0; + uno::Reference< container::XEnumerationAccess > xRangesEA( rxRanges, uno::UNO_QUERY_THROW ); + uno::Reference< container::XEnumeration > xRangesEnum( xRangesEA->createEnumeration(), uno::UNO_SET_THROW ); + while( xRangesEnum->hasMoreElements() ) + { + uno::Reference< table::XCellRange > xRange( xRangesEnum->nextElement(), uno::UNO_QUERY_THROW ); + sal_Unicode cNewPrefix = lclGetPrefixChar( xRange ); + if( (cNewPrefix == 0) || ((cCurrPrefix != 0) && (cNewPrefix != cCurrPrefix)) ) + return 0; + cCurrPrefix = cNewPrefix; + } + // all ranges contain the same prefix - return it + return cCurrPrefix; +} + +uno::Any lclGetPrefixVariant( sal_Unicode cPrefixChar ) +{ + return uno::Any( (cPrefixChar == 0) ? OUString() : OUString( cPrefixChar ) ); +} + +} // namespace + +uno::Any SAL_CALL ScVbaRange::getPrefixCharacter() +{ + /* (1) If Application.TransitionNavigKeys is false, this function returns + an apostroph character if the text cell begins with an apostroph + character (formula return values are not taken into account); otherwise + an empty string. + + (2) If Application.TransitionNavigKeys is true, this function returns + an apostroph character, if the cell is left-aligned; a double-quote + character, if the cell is right-aligned; a circumflex character, if the + cell is centered; a backslash character, if the cell is set to filled; + or an empty string, if nothing of the above. + + If a range or a list of ranges contains texts with leading apostroph + character as well as other cells, this function returns an empty + string. + */ + + if( mxRange.is() ) + return lclGetPrefixVariant( lclGetPrefixChar( mxRange ) ); + if( mxRanges.is() ) + return lclGetPrefixVariant( lclGetPrefixChar( mxRanges ) ); + throw uno::RuntimeException("Unexpected empty Range object" ); +} + +uno::Any ScVbaRange::getShowDetail() +{ + // #FIXME, If the specified range is in a PivotTable report + + // In MSO VBA, the specified range must be a single summary column or row in an outline. otherwise throw exception + if( m_Areas->getCount() > 1 ) + throw uno::RuntimeException("Can not get Range.ShowDetail attribute " ); + + RangeHelper helper( mxRange ); + uno::Reference< sheet::XSheetCellCursor > xSheetCellCursor = helper.getSheetCellCursor(); + xSheetCellCursor->collapseToCurrentRegion(); + uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable(xSheetCellCursor, uno::UNO_QUERY_THROW); + table::CellRangeAddress aOutlineAddress = xCellRangeAddressable->getRangeAddress(); + + // check if the specified range is a single summary column or row. + table::CellRangeAddress thisAddress = helper.getCellRangeAddressable()->getRangeAddress(); + if( (thisAddress.StartRow != thisAddress.EndRow || thisAddress.EndRow != aOutlineAddress.EndRow ) && + (thisAddress.StartColumn != thisAddress.EndColumn || thisAddress.EndColumn != aOutlineAddress.EndColumn )) + { + throw uno::RuntimeException("Can not set Range.ShowDetail attribute" ); + } + + bool bColumn = thisAddress.StartRow != thisAddress.EndRow; + ScDocument& rDoc = getDocumentFromRange( mxRange ); + ScOutlineTable* pOutlineTable = rDoc.GetOutlineTable(static_cast<SCTAB>(thisAddress.Sheet), true); + const ScOutlineArray& rOutlineArray = bColumn ? pOutlineTable->GetColArray(): pOutlineTable->GetRowArray(); + SCCOLROW nPos = bColumn ? static_cast<SCCOLROW>(thisAddress.EndColumn-1):static_cast<SCCOLROW>(thisAddress.EndRow-1); + const ScOutlineEntry* pEntry = rOutlineArray.GetEntryByPos( 0, nPos ); + if( pEntry ) + { + const bool bShowDetail = !pEntry->IsHidden(); + return uno::Any( bShowDetail ); + } + + return aNULL(); +} + +void ScVbaRange::setShowDetail(const uno::Any& aShowDetail) +{ + // #FIXME, If the specified range is in a PivotTable report + + // In MSO VBA, the specified range must be a single summary column or row in an outline. otherwise throw exception + if( m_Areas->getCount() > 1 ) + throw uno::RuntimeException("Can not set Range.ShowDetail attribute" ); + + bool bShowDetail = extractBoolFromAny( aShowDetail ); + + RangeHelper helper( mxRange ); + uno::Reference< sheet::XSheetCellCursor > xSheetCellCursor = helper.getSheetCellCursor(); + xSheetCellCursor->collapseToCurrentRegion(); + uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable(xSheetCellCursor, uno::UNO_QUERY_THROW); + table::CellRangeAddress aOutlineAddress = xCellRangeAddressable->getRangeAddress(); + + // check if the specified range is a single summary column or row. + table::CellRangeAddress thisAddress = helper.getCellRangeAddressable()->getRangeAddress(); + if( (thisAddress.StartRow != thisAddress.EndRow || thisAddress.EndRow != aOutlineAddress.EndRow ) && + (thisAddress.StartColumn != thisAddress.EndColumn || thisAddress.EndColumn != aOutlineAddress.EndColumn )) + { + throw uno::RuntimeException("Can not set Range.ShowDetail attribute" ); + } + + // #FIXME, seems there is a different behavior between MSO and OOo. + // In OOo, the showDetail will show all the level entries, while only show the first level entry in MSO + uno::Reference< sheet::XSheetOutline > xSheetOutline( helper.getSpreadSheet(), uno::UNO_QUERY_THROW ); + if( bShowDetail ) + xSheetOutline->showDetail( aOutlineAddress ); + else + xSheetOutline->hideDetail( aOutlineAddress ); + +} + +uno::Reference< excel::XRange > SAL_CALL +ScVbaRange::MergeArea() +{ + uno::Reference< sheet::XSheetCellRange > xMergeShellCellRange(mxRange->getCellRangeByPosition(0,0,0,0), uno::UNO_QUERY_THROW); + uno::Reference< sheet::XSheetCellCursor > xMergeSheetCursor(xMergeShellCellRange->getSpreadsheet()->createCursorByRange( xMergeShellCellRange ), uno::UNO_SET_THROW); + if( xMergeSheetCursor.is() ) + { + xMergeSheetCursor->collapseToMergedArea(); + uno::Reference<sheet::XCellRangeAddressable> xMergeCellAddress(xMergeSheetCursor, uno::UNO_QUERY_THROW); + table::CellRangeAddress aCellAddress = xMergeCellAddress->getRangeAddress(); + if( aCellAddress.StartColumn ==0 && aCellAddress.EndColumn==0 && + aCellAddress.StartRow==0 && aCellAddress.EndRow==0) + { + return new ScVbaRange( mxParent,mxContext,mxRange ); + } + else + { + ScRange refRange( static_cast< SCCOL >( aCellAddress.StartColumn ), static_cast< SCROW >( aCellAddress.StartRow ), static_cast< SCTAB >( aCellAddress.Sheet ), + static_cast< SCCOL >( aCellAddress.EndColumn ), static_cast< SCROW >( aCellAddress.EndRow ), static_cast< SCTAB >( aCellAddress.Sheet ) ); + uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( getScDocShell() , refRange ) ); + return new ScVbaRange( mxParent, mxContext,xRange ); + } + } + return new ScVbaRange( mxParent, mxContext, mxRange ); +} + +void SAL_CALL +ScVbaRange::PrintOut( const uno::Any& From, const uno::Any& To, const uno::Any& Copies, const uno::Any& Preview, const uno::Any& ActivePrinter, const uno::Any& PrintToFile, const uno::Any& Collate, const uno::Any& PrToFileName ) +{ + ScDocShell* pShell = nullptr; + + sal_Int32 nItems = m_Areas->getCount(); + uno::Sequence< table::CellRangeAddress > printAreas( nItems ); + auto printAreasRange = asNonConstRange(printAreas); + uno::Reference< sheet::XPrintAreas > xPrintAreas; + for ( sal_Int32 index=1; index <= nItems; ++index ) + { + uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW ); + + RangeHelper thisRange( xRange->getCellRange() ); + table::CellRangeAddress rangeAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); + if ( index == 1 ) + { + ScVbaRange* pRange = getImplementation( xRange ); + // initialise the doc shell and the printareas + pShell = getDocShellFromRange( pRange->mxRange ); + xPrintAreas.set( thisRange.getSpreadSheet(), uno::UNO_QUERY_THROW ); + } + printAreasRange[ index - 1 ] = rangeAddress; + } + if ( pShell && xPrintAreas.is() ) + { + xPrintAreas->setPrintAreas( printAreas ); + uno::Reference< frame::XModel > xModel = pShell->GetModel(); + PrintOutHelper( excel::getBestViewShell( xModel ), From, To, Copies, Preview, ActivePrinter, PrintToFile, Collate, PrToFileName, true ); + } +} + +void SAL_CALL +ScVbaRange::AutoFill( const uno::Reference< excel::XRange >& Destination, const uno::Any& Type ) +{ + uno::Reference< excel::XRange > xDest( Destination, uno::UNO_SET_THROW ); + ScVbaRange* pRange = getImplementation( xDest ); + RangeHelper destRangeHelper( pRange->mxRange ); + table::CellRangeAddress destAddress = destRangeHelper.getCellRangeAddressable()->getRangeAddress(); + + RangeHelper thisRange( mxRange ); + table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); + ScRange sourceRange; + ScRange destRange; + + ScUnoConversion::FillScRange( destRange, destAddress ); + ScUnoConversion::FillScRange( sourceRange, thisAddress ); + + FillDir eDir = FILL_TO_BOTTOM; + double fStep = 1.0; + + ScRange aRange( destRange ); + ScRange aSourceRange( destRange ); + + // default to include the number of Rows in the source range; + SCCOLROW nSourceCount = ( sourceRange.aEnd.Row() - sourceRange.aStart.Row() ) + 1; + SCCOLROW nCount = 0; + + if ( sourceRange != destRange ) + { + // Find direction of fill, vertical or horizontal + if ( sourceRange.aStart == destRange.aStart ) + { + if ( sourceRange.aEnd.Row() == destRange.aEnd.Row() ) + { + nSourceCount = ( sourceRange.aEnd.Col() - sourceRange.aStart.Col() + 1 ); + aSourceRange.aEnd.SetCol( static_cast<SCCOL>( aSourceRange.aStart.Col() + nSourceCount - 1 ) ); + eDir = FILL_TO_RIGHT; + nCount = aRange.aEnd.Col() - aSourceRange.aEnd.Col(); + } + else if ( sourceRange.aEnd.Col() == destRange.aEnd.Col() ) + { + aSourceRange.aEnd.SetRow( static_cast<SCROW>( aSourceRange.aStart.Row() + nSourceCount ) - 1 ); + nCount = aRange.aEnd.Row() - aSourceRange.aEnd.Row(); + eDir = FILL_TO_BOTTOM; + } + } + + else if ( aSourceRange.aEnd == destRange.aEnd ) + { + if ( sourceRange.aStart.Col() == destRange.aStart.Col() ) + { + aSourceRange.aStart.SetRow( static_cast<SCROW>( aSourceRange.aEnd.Row() - nSourceCount + 1 ) ); + nCount = aSourceRange.aStart.Row() - aRange.aStart.Row(); + eDir = FILL_TO_TOP; + fStep = -fStep; + } + else if ( sourceRange.aStart.Row() == destRange.aStart.Row() ) + { + nSourceCount = ( sourceRange.aEnd.Col() - sourceRange.aStart.Col() ) + 1; + aSourceRange.aStart.SetCol( static_cast<SCCOL>( aSourceRange.aEnd.Col() - nSourceCount + 1 ) ); + nCount = aSourceRange.aStart.Col() - aRange.aStart.Col(); + eDir = FILL_TO_LEFT; + fStep = -fStep; + } + } + } + + FillCmd eCmd = FILL_AUTO; + FillDateCmd eDateCmd = FILL_DAY; + + if ( Type.hasValue() ) + { + sal_Int16 nFillType = excel::XlAutoFillType::xlFillDefault; + Type >>= nFillType; + switch ( nFillType ) + { + case excel::XlAutoFillType::xlFillCopy: + eCmd = FILL_SIMPLE; + fStep = 0.0; + break; + case excel::XlAutoFillType::xlFillDays: + eCmd = FILL_DATE; + break; + case excel::XlAutoFillType::xlFillMonths: + eCmd = FILL_DATE; + eDateCmd = FILL_MONTH; + break; + case excel::XlAutoFillType::xlFillWeekdays: + eCmd = FILL_DATE; + eDateCmd = FILL_WEEKDAY; + break; + case excel::XlAutoFillType::xlFillYears: + eCmd = FILL_DATE; + eDateCmd = FILL_YEAR; + break; + case excel::XlAutoFillType::xlGrowthTrend: + eCmd = FILL_GROWTH; + break; + case excel::XlAutoFillType::xlFillFormats: + throw uno::RuntimeException("xlFillFormat not supported for AutoFill" ); + case excel::XlAutoFillType::xlFillValues: + case excel::XlAutoFillType::xlFillSeries: + case excel::XlAutoFillType::xlLinearTrend: + eCmd = FILL_LINEAR; + break; + case excel::XlAutoFillType::xlFillDefault: + default: + eCmd = FILL_AUTO; + break; + } + } + ScDocShell* pDocSh = getDocShellFromRange( mxRange ); + pDocSh->GetDocFunc().FillAuto( aSourceRange, nullptr, eDir, eCmd, eDateCmd, + nCount, fStep, MAXDOUBLE/*fEndValue*/, true, true ); +} +sal_Bool SAL_CALL +ScVbaRange::GoalSeek( const uno::Any& Goal, const uno::Reference< excel::XRange >& ChangingCell ) +{ + ScDocShell* pDocShell = getScDocShell(); + bool bRes = true; + ScVbaRange* pRange = static_cast< ScVbaRange* >( ChangingCell.get() ); + if ( pDocShell && pRange ) + { + uno::Reference< sheet::XGoalSeek > xGoalSeek( pDocShell->GetModel(), uno::UNO_QUERY_THROW ); + RangeHelper thisRange( mxRange ); + table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); + RangeHelper changingCellRange( pRange->mxRange ); + table::CellRangeAddress changingCellAddr = changingCellRange.getCellRangeAddressable()->getRangeAddress(); + OUString sGoal = getAnyAsString( Goal ); + table::CellAddress thisCell( thisAddress.Sheet, thisAddress.StartColumn, thisAddress.StartRow ); + table::CellAddress changingCell( changingCellAddr.Sheet, changingCellAddr.StartColumn, changingCellAddr.StartRow ); + sheet::GoalResult res = xGoalSeek->seekGoal( thisCell, changingCell, sGoal ); + ChangingCell->setValue( uno::Any( res.Result ) ); + + // openoffice behaves differently, result is 0 if the divergence is too great + // but... if it detects 0 is the value it requires then it will use that + // e.g. divergence & result both = 0.0 does NOT mean there is an error + if ( ( res.Divergence != 0.0 ) && ( res.Result == 0.0 ) ) + bRes = false; + } + else + bRes = false; + return bRes; +} + +void +ScVbaRange::Calculate( ) +{ + getWorksheet()->Calculate(); +} + +uno::Reference< excel::XRange > SAL_CALL +ScVbaRange::Item( const uno::Any& row, const uno::Any& column ) +{ + if ( mbIsRows || mbIsColumns ) + { + if ( column.hasValue() ) + DebugHelper::basicexception(ERRCODE_BASIC_BAD_PARAMETER, {} ); + uno::Reference< excel::XRange > xRange; + if ( mbIsColumns ) + xRange = Columns( row ); + else + xRange = Rows( row ); + return xRange; + } + return Cells( row, column ); +} + +void +ScVbaRange::AutoOutline( ) +{ + // #TODO #FIXME needs to check for summary row/col ( whatever they are ) + // not valid for multi Area Addresses + if ( m_Areas->getCount() > 1 ) + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, STR_ERRORMESSAGE_APPLIESTOSINGLERANGEONLY); + // So needs to either span an entire Row or a just be a single cell + // ( that contains a summary RowColumn ) + // also the Single cell cause doesn't seem to be handled specially in + // this code ( ported from the helperapi RangeImpl.java, + // RangeRowsImpl.java, RangesImpl.java, RangeSingleCellImpl.java + RangeHelper thisRange( mxRange ); + table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); + + if ( isSingleCellRange() || mbIsRows ) + { + uno::Reference< sheet::XSheetOutline > xSheetOutline( thisRange.getSpreadSheet(), uno::UNO_QUERY_THROW ); + xSheetOutline->autoOutline( thisAddress ); + } + else + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); +} + +void SAL_CALL +ScVbaRange:: ClearOutline( ) +{ + if ( m_Areas->getCount() > 1 ) + { + sal_Int32 nItems = m_Areas->getCount(); + for ( sal_Int32 index=1; index <= nItems; ++index ) + { + uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW ); + xRange->ClearOutline(); + } + return; + } + RangeHelper thisRange( mxRange ); + uno::Reference< sheet::XSheetOutline > xSheetOutline( thisRange.getSpreadSheet(), uno::UNO_QUERY_THROW ); + xSheetOutline->clearOutline(); +} + +void +ScVbaRange::groupUnGroup( bool bUnGroup ) +{ + if ( m_Areas->getCount() > 1 ) + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, STR_ERRORMESSAGE_APPLIESTOSINGLERANGEONLY); + table::TableOrientation nOrient = table::TableOrientation_ROWS; + if ( mbIsColumns ) + nOrient = table::TableOrientation_COLUMNS; + RangeHelper thisRange( mxRange ); + table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); + uno::Reference< sheet::XSheetOutline > xSheetOutline( thisRange.getSpreadSheet(), uno::UNO_QUERY_THROW ); + if ( bUnGroup ) + xSheetOutline->ungroup( thisAddress, nOrient ); + else + xSheetOutline->group( thisAddress, nOrient ); +} + +void SAL_CALL +ScVbaRange::Group( ) +{ + groupUnGroup(false); +} +void SAL_CALL +ScVbaRange::Ungroup( ) +{ + groupUnGroup(true); +} + +/// @throws uno::RuntimeException +static void lcl_mergeCellsOfRange( const uno::Reference< table::XCellRange >& xCellRange, bool _bMerge ) +{ + uno::Reference< util::XMergeable > xMergeable( xCellRange, uno::UNO_QUERY_THROW ); + xMergeable->merge(_bMerge); +} +void SAL_CALL +ScVbaRange::Merge( const uno::Any& Across ) +{ + if ( m_Areas->getCount() > 1 ) + { + sal_Int32 nItems = m_Areas->getCount(); + for ( sal_Int32 index=1; index <= nItems; ++index ) + { + uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW ); + xRange->Merge(Across); + } + return; + } + bool bAcross = false; + Across >>= bAcross; + if ( !bAcross ) + lcl_mergeCellsOfRange( mxRange, true ); + else + { + uno::Reference< excel::XRange > oRangeRowsImpl = Rows( uno::Any() ); + // #TODO #FIXME this seems incredibly lame, this can't be right + for (sal_Int32 i=1; i <= oRangeRowsImpl->getCount();i++) + { + oRangeRowsImpl->Cells( uno::Any( i ), uno::Any() )->Merge( uno::Any( false ) ); + } + } +} + +void SAL_CALL +ScVbaRange::UnMerge( ) +{ + if ( m_Areas->getCount() > 1 ) + { + sal_Int32 nItems = m_Areas->getCount(); + for ( sal_Int32 index=1; index <= nItems; ++index ) + { + uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW ); + xRange->UnMerge(); + } + return; + } + lcl_mergeCellsOfRange( mxRange, false); +} + +uno::Any SAL_CALL +ScVbaRange::getStyle() +{ + if ( m_Areas->getCount() > 1 ) + { + uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( sal_Int32( 1 ) ), uno::Any() ), uno::UNO_QUERY_THROW ); + return xRange->getStyle(); + } + uno::Reference< beans::XPropertySet > xProps( mxRange, uno::UNO_QUERY_THROW ); + OUString sStyleName; + xProps->getPropertyValue( CELLSTYLE ) >>= sStyleName; + ScDocShell* pShell = getScDocShell(); + uno::Reference< frame::XModel > xModel( pShell->GetModel() ); + uno::Reference< excel::XStyle > xStyle = new ScVbaStyle( this, mxContext, sStyleName, xModel ); + return uno::Any( xStyle ); +} +void SAL_CALL +ScVbaRange::setStyle( const uno::Any& _style ) +{ + if ( m_Areas->getCount() > 1 ) + { + uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( sal_Int32( 1 ) ), uno::Any() ), uno::UNO_QUERY_THROW ); + xRange->setStyle( _style ); + return; + } + uno::Reference< beans::XPropertySet > xProps( mxRange, uno::UNO_QUERY_THROW ); + uno::Reference< excel::XStyle > xStyle; + _style >>= xStyle; + if ( xStyle.is() ) + xProps->setPropertyValue( CELLSTYLE, uno::Any( xStyle->getName() ) ); +} + +uno::Reference< excel::XRange > +ScVbaRange::PreviousNext( bool bIsPrevious ) +{ + ScMarkData markedRange(getScDocument().GetSheetLimits()); + ScRange refRange; + RangeHelper thisRange( mxRange ); + + ScUnoConversion::FillScRange( refRange, thisRange.getCellRangeAddressable()->getRangeAddress()); + markedRange. SetMarkArea( refRange ); + short nMove = bIsPrevious ? -1 : 1; + + SCCOL nNewX = refRange.aStart.Col(); + SCROW nNewY = refRange.aStart.Row(); + SCTAB nTab = refRange.aStart.Tab(); + + ScDocument& rDoc = getScDocument(); + rDoc.GetNextPos( nNewX,nNewY, nTab, nMove,0, true,true, markedRange ); + refRange.aStart.SetCol( nNewX ); + refRange.aStart.SetRow( nNewY ); + refRange.aStart.SetTab( nTab ); + refRange.aEnd.SetCol( nNewX ); + refRange.aEnd.SetRow( nNewY ); + refRange.aEnd.SetTab( nTab ); + + uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( getScDocShell() , refRange ) ); + + return new ScVbaRange( mxParent, mxContext, xRange ); +} + +uno::Reference< excel::XRange > SAL_CALL +ScVbaRange::Next() +{ + if ( m_Areas->getCount() > 1 ) + { + uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( sal_Int32( 1 ) ), uno::Any() ) , uno::UNO_QUERY_THROW ); + return xRange->Next(); + } + return PreviousNext( false ); +} + +uno::Reference< excel::XRange > SAL_CALL +ScVbaRange::Previous() +{ + if ( m_Areas->getCount() > 1 ) + { + uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( sal_Int32( 1 ) ), uno::Any() ), uno::UNO_QUERY_THROW ); + return xRange->Previous(); + } + return PreviousNext( true ); +} + +uno::Reference< excel::XRange > SAL_CALL +ScVbaRange::SpecialCells( const uno::Any& _oType, const uno::Any& _oValue) +{ + bool bIsSingleCell = isSingleCellRange(); + bool bIsMultiArea = ( m_Areas->getCount() > 1 ); + ScVbaRange* pRangeToUse = this; + uno::Reference< excel::XRange > xUsedRange( getWorksheet()->getUsedRange() ); + sal_Int32 nType = 0; + if ( !( _oType >>= nType ) ) + DebugHelper::basicexception(ERRCODE_BASIC_BAD_PARAMETER, {} ); + switch(nType) + { + case excel::XlCellType::xlCellTypeSameFormatConditions: + case excel::XlCellType::xlCellTypeAllValidation: + case excel::XlCellType::xlCellTypeSameValidation: + DebugHelper::basicexception(ERRCODE_BASIC_NOT_IMPLEMENTED, {}); + break; + case excel::XlCellType::xlCellTypeBlanks: + case excel::XlCellType::xlCellTypeComments: + case excel::XlCellType::xlCellTypeConstants: + case excel::XlCellType::xlCellTypeFormulas: + case excel::XlCellType::xlCellTypeVisible: + case excel::XlCellType::xlCellTypeLastCell: + { + if ( bIsMultiArea ) + { + // need to process each area, gather the results and + // create a new range from those + std::vector< table::CellRangeAddress > rangeResults; + sal_Int32 nItems = m_Areas->getCount() + 1; + for ( sal_Int32 index=1; index <= nItems; ++index ) + { + uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW ); + xRange = xRange->SpecialCells( _oType, _oValue); + ScVbaRange* pRange = getImplementation( xRange ); + if ( xRange.is() && pRange ) + { + sal_Int32 nElems = pRange->m_Areas->getCount() + 1; + for ( sal_Int32 nArea = 1; nArea < nElems; ++nArea ) + { + uno::Reference< excel::XRange > xTmpRange( m_Areas->Item( uno::Any( nArea ), uno::Any() ), uno::UNO_QUERY_THROW ); + RangeHelper rHelper( xTmpRange->getCellRange() ); + rangeResults.push_back( rHelper.getCellRangeAddressable()->getRangeAddress() ); + } + } + } + ScRangeList aCellRanges; + for ( const auto& rRangeResult : rangeResults ) + { + ScRange refRange; + ScUnoConversion::FillScRange( refRange, rRangeResult ); + aCellRanges.push_back( refRange ); + } + // Single range + if ( aCellRanges.size() == 1 ) + { + uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( getScDocShell(), aCellRanges.front() ) ); + return new ScVbaRange( mxParent, mxContext, xRange ); + } + uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( getScDocShell(), aCellRanges ) ); + + return new ScVbaRange( mxParent, mxContext, xRanges ); + } + else if ( bIsSingleCell ) + { + pRangeToUse = static_cast< ScVbaRange* >( xUsedRange.get() ); + } + + break; + } + default: + DebugHelper::basicexception(ERRCODE_BASIC_BAD_PARAMETER, {} ); + break; + } + if ( !pRangeToUse ) + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} ); + return pRangeToUse->SpecialCellsImpl( nType, _oValue ); +} + +/// @throws script::BasicErrorException +static sal_Int32 lcl_getFormulaResultFlags(const uno::Any& aType) +{ + sal_Int32 nType = excel::XlSpecialCellsValue::xlNumbers; + aType >>= nType; + sal_Int32 nRes = sheet::FormulaResult::VALUE; + + switch(nType) + { + case excel::XlSpecialCellsValue::xlErrors: + nRes= sheet::FormulaResult::ERROR; + break; + case excel::XlSpecialCellsValue::xlLogical: + //TODO bc93774: ask NN if this is really an appropriate substitute + nRes = sheet::FormulaResult::VALUE; + break; + case excel::XlSpecialCellsValue::xlNumbers: + nRes = sheet::FormulaResult::VALUE; + break; + case excel::XlSpecialCellsValue::xlTextValues: + nRes = sheet::FormulaResult::STRING; + break; + default: + DebugHelper::basicexception(ERRCODE_BASIC_BAD_PARAMETER, {} ); + } + return nRes; +} + +uno::Reference< excel::XRange > +ScVbaRange::SpecialCellsImpl( sal_Int32 nType, const uno::Any& _oValue) +{ + uno::Reference< excel::XRange > xRange; + try + { + uno::Reference< sheet::XCellRangesQuery > xQuery( mxRange, uno::UNO_QUERY_THROW ); + uno::Reference< sheet::XSheetCellRanges > xLocSheetCellRanges; + switch(nType) + { + case excel::XlCellType::xlCellTypeAllFormatConditions: + case excel::XlCellType::xlCellTypeSameFormatConditions: + case excel::XlCellType::xlCellTypeAllValidation: + case excel::XlCellType::xlCellTypeSameValidation: + // Shouldn't get here ( should be filtered out by + // ScVbaRange::SpecialCells() + DebugHelper::basicexception(ERRCODE_BASIC_NOT_IMPLEMENTED, {}); + break; + case excel::XlCellType::xlCellTypeBlanks: + xLocSheetCellRanges = xQuery->queryEmptyCells(); + break; + case excel::XlCellType::xlCellTypeComments: + xLocSheetCellRanges = xQuery->queryContentCells(sheet::CellFlags::ANNOTATION); + break; + case excel::XlCellType::xlCellTypeConstants: + xLocSheetCellRanges = xQuery->queryContentCells(23); + break; + case excel::XlCellType::xlCellTypeFormulas: + { + sal_Int32 nFormulaResult = lcl_getFormulaResultFlags(_oValue); + xLocSheetCellRanges = xQuery->queryFormulaCells(nFormulaResult); + break; + } + case excel::XlCellType::xlCellTypeLastCell: + xRange = Cells( uno::Any( getCount() ), uno::Any() ); + [[fallthrough]]; //TODO ??? + case excel::XlCellType::xlCellTypeVisible: + xLocSheetCellRanges = xQuery->queryVisibleCells(); + break; + default: + DebugHelper::basicexception(ERRCODE_BASIC_BAD_PARAMETER, {} ); + break; + } + if (xLocSheetCellRanges.is()) + { + xRange = lcl_makeXRangeFromSheetCellRanges( getParent(), mxContext, xLocSheetCellRanges, getScDocShell() ); + } + } + catch (uno::Exception& ) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, u"No cells were found"); + } + return xRange; +} + +void SAL_CALL +ScVbaRange::RemoveSubtotal( ) +{ + uno::Reference< sheet::XSubTotalCalculatable > xSub( mxRange, uno::UNO_QUERY_THROW ); + xSub->removeSubTotals(); +} + +void SAL_CALL +ScVbaRange::Subtotal( ::sal_Int32 _nGroupBy, ::sal_Int32 _nFunction, const uno::Sequence< ::sal_Int32 >& _nTotalList, const uno::Any& aReplace, const uno::Any& PageBreaks, const uno::Any& /*SummaryBelowData*/ ) +{ + try + { + bool bDoReplace = false; + aReplace >>= bDoReplace; + bool bAddPageBreaks = false; + PageBreaks >>= bAddPageBreaks; + + uno::Reference< sheet::XSubTotalCalculatable> xSub(mxRange, uno::UNO_QUERY_THROW ); + uno::Reference< sheet::XSubTotalDescriptor > xSubDesc = xSub->createSubTotalDescriptor(true); + uno::Reference< beans::XPropertySet > xSubDescPropertySet( xSubDesc, uno::UNO_QUERY_THROW ); + xSubDescPropertySet->setPropertyValue("InsertPageBreaks", uno::Any( bAddPageBreaks)); + sal_Int32 nLen = _nTotalList.getLength(); + uno::Sequence< sheet::SubTotalColumn > aColumns( nLen ); + auto aColumnsRange = asNonConstRange(aColumns); + for (int i = 0; i < nLen; i++) + { + aColumnsRange[i].Column = _nTotalList[i] - 1; + switch (_nFunction) + { + case excel::XlConsolidationFunction::xlAverage: + aColumnsRange[i].Function = sheet::GeneralFunction_AVERAGE; + break; + case excel::XlConsolidationFunction::xlCount: + aColumnsRange[i].Function = sheet::GeneralFunction_COUNT; + break; + case excel::XlConsolidationFunction::xlCountNums: + aColumnsRange[i].Function = sheet::GeneralFunction_COUNTNUMS; + break; + case excel::XlConsolidationFunction::xlMax: + aColumnsRange[i].Function = sheet::GeneralFunction_MAX; + break; + case excel::XlConsolidationFunction::xlMin: + aColumnsRange[i].Function = sheet::GeneralFunction_MIN; + break; + case excel::XlConsolidationFunction::xlProduct: + aColumnsRange[i].Function = sheet::GeneralFunction_PRODUCT; + break; + case excel::XlConsolidationFunction::xlStDev: + aColumnsRange[i].Function = sheet::GeneralFunction_STDEV; + break; + case excel::XlConsolidationFunction::xlStDevP: + aColumnsRange[i].Function = sheet::GeneralFunction_STDEVP; + break; + case excel::XlConsolidationFunction::xlSum: + aColumnsRange[i].Function = sheet::GeneralFunction_SUM; + break; + case excel::XlConsolidationFunction::xlUnknown: + aColumnsRange[i].Function = sheet::GeneralFunction_NONE; + break; + case excel::XlConsolidationFunction::xlVar: + aColumnsRange[i].Function = sheet::GeneralFunction_VAR; + break; + case excel::XlConsolidationFunction::xlVarP: + aColumnsRange[i].Function = sheet::GeneralFunction_VARP; + break; + default: + DebugHelper::basicexception(ERRCODE_BASIC_BAD_PARAMETER, {}) ; + return; + } + } + xSubDesc->addNew(aColumns, _nGroupBy - 1); + xSub->applySubTotals(xSubDesc, bDoReplace); + } + catch (const uno::Exception&) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } +} + +OUString +ScVbaRange::getServiceImplName() +{ + return "ScVbaRange"; +} + +uno::Sequence< OUString > +ScVbaRange::getServiceNames() +{ + return { "ooo.vba.excel.Range" }; +} + +sal_Bool SAL_CALL +ScVbaRange::hasError() +{ + double dResult = 0.0; + uno::Reference< excel::XApplication > xApplication( Application(), uno::UNO_QUERY_THROW ); + uno::Reference< script::XInvocation > xInvoc( xApplication->WorksheetFunction(), uno::UNO_QUERY_THROW ); + + uno::Reference< excel::XRange > aRange( this ); + uno::Sequence< uno::Any > Params{ uno::Any(aRange) }; + uno::Sequence< sal_Int16 > OutParamIndex; + uno::Sequence< uno::Any > OutParam; + xInvoc->invoke( "IsError", Params, OutParamIndex, OutParam ) >>= dResult; + return dResult > 0.0; +} + + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +Calc_ScVbaRange_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& args) +{ + return cppu::acquire(new ScVbaRange(args, context)); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbarange.hxx b/sc/source/ui/vba/vbarange.hxx new file mode 100644 index 000000000..118ad044c --- /dev/null +++ b/sc/source/ui/vba/vbarange.hxx @@ -0,0 +1,327 @@ +/* -*- 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 . + */ +#pragma once + +#include <ooo/vba/excel/XRange.hpp> + +#include <com/sun/star/awt/Point.hpp> +#include <com/sun/star/sheet/FillDateMode.hpp> +#include <com/sun/star/sheet/FillMode.hpp> +#include <com/sun/star/sheet/FillDirection.hpp> + +#include "vbaformat.hxx" +#include <address.hxx> +#include <formula/grammar.hxx> + +namespace com::sun::star::sheet { class XSheetCellRangeContainer; } +namespace com::sun::star::table { class XCell; } +namespace com::sun::star::table { class XCellRange; } +namespace com::sun::star::table { struct CellRangeAddress; } +namespace com::sun::star::lang { class XServiceInfo; } +namespace ooo::vba { class XCollection; } +namespace ooo::vba::excel { class XComment; } +namespace ooo::vba::excel { class XFont; } + +class SfxItemSet; +class ScCellRangesBase; +class ScCellRangeObj; +class ScDocShell; +class ScDocument; +class ScRangeList; + +class ArrayVisitor +{ +public: + virtual void visitNode( sal_Int32 x, sal_Int32 y, const css::uno::Reference< css::table::XCell >& xCell ) = 0; + virtual ~ArrayVisitor(){} +}; + +class ValueSetter : public ArrayVisitor +{ +public: + virtual bool processValue( const css::uno::Any& aValue, const css::uno::Reference< css::table::XCell >& xCell ) = 0; + +}; + +class ValueGetter : public ArrayVisitor +{ + +public: + virtual void processValue( const css::uno::Any& aValue ) = 0; + virtual const css::uno::Any& getValue() const = 0; +}; + +typedef ScVbaFormat< ov::excel::XRange > ScVbaRange_BASE; + +class ScVbaRange : public ScVbaRange_BASE +{ + css::uno::Reference< ov::XCollection > m_Areas; + css::uno::Reference< ov::XCollection > m_Borders; + css::uno::Reference< css::table::XCellRange > mxRange; + css::uno::Reference< css::sheet::XSheetCellRangeContainer > mxRanges; + bool mbIsRows; + bool mbIsColumns; + css::uno::Reference< ov::excel::XValidation > m_xValidation; + /// @throws css::uno::RuntimeException + double getCalcColWidth(const css::table::CellRangeAddress&); + /// @throws css::uno::RuntimeException + double getCalcRowHeight(const css::table::CellRangeAddress&); + void visitArray( ArrayVisitor& visitor ); + + /// @throws css::uno::RuntimeException + css::uno::Reference< ov::excel::XRange > getEntireColumnOrRow( bool bColumn ); + + /// @throws css::uno::RuntimeException + void fillSeries( css::sheet::FillDirection nFillDirection, css::sheet::FillMode nFillMode, css::sheet::FillDateMode nFillDateMode, double fStep, double fEndValue ); + + /// @throws css::uno::RuntimeException + void ClearContents( sal_Int32 nFlags, bool bFireEvent ); + + /// @throws css::uno::RuntimeException + css::uno::Any getValue( ValueGetter& rValueGetter ); + /// @throws css::uno::RuntimeException + void setValue( const css::uno::Any& aValue, ValueSetter& setter ); + + /// @throws css::uno::RuntimeException + css::uno::Any getFormulaValue( formula::FormulaGrammar::Grammar ); + /// @throws css::uno::RuntimeException + void setFormulaValue( const css::uno::Any& aValue, formula::FormulaGrammar::Grammar ); + + /// @throws css::uno::RuntimeException + css::uno::Reference< ov::excel::XRange > getArea( sal_Int32 nIndex ); + /// @throws css::uno::RuntimeException + ScCellRangeObj* getCellRangeObj( ); + css::uno::Reference< ov::XCollection >& getBorders(); + /// @throws css::uno::RuntimeException + void groupUnGroup( bool bUnGroup ); + css::uno::Reference< ov::excel::XRange > PreviousNext( bool bIsPrevious ); + /// @throws css::script::BasicErrorException + css::uno::Reference< ov::excel::XRange > SpecialCellsImpl( sal_Int32 nType, const css::uno::Any& _oValue); + /// @throws css::uno::RuntimeException + css::awt::Point getPosition() const; + + /** Fires a Worksheet_Change event for this range or range list. */ + void fireChangeEvent(); + + /// @throws css::uno::RuntimeException + ScRange obtainRangeEvenIfRangeListIsEmpty( const ScRangeList& rCellRanges ) const; + +protected: + virtual ScCellRangesBase* getCellRangesBase() override; + /// @throws css::uno::RuntimeException + SfxItemSet* getCurrentDataSet(); +public: + /// @throws css::lang::IllegalArgumentException + ScVbaRange( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Reference< css::table::XCellRange >& xRange, bool bIsRows = false, bool bIsColumns = false ); + /// @throws css::lang::IllegalArgumentException + /// @throws css::uno::RuntimeException + ScVbaRange( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Reference< css::sheet::XSheetCellRangeContainer >& xRanges, bool bIsRows = false, bool bIsColumns = false ); + /// @throws css::lang::IllegalArgumentException + /// @throws css::uno::RuntimeException + ScVbaRange( css::uno::Sequence< css::uno::Any > const& aArgs, css::uno::Reference< css::uno::XComponentContext >const& xContext ); + + /// @throws css::uno::RuntimeException + ScDocument& getScDocument(); + /// @throws css::uno::RuntimeException + ScDocShell* getScDocShell(); + + /** Returns the ScVbaRange implementation object for the passed VBA Range object. */ + static ScVbaRange* getImplementation( const css::uno::Reference< ov::excel::XRange >& rxRange ); + + /// @throws css::uno::RuntimeException + css::uno::Reference< css::frame::XModel > getUnoModel(); + /// @throws css::uno::RuntimeException + static css::uno::Reference< css::frame::XModel > getUnoModel( const css::uno::Reference< ov::excel::XRange >& rxRange ); + + /// @throws css::uno::RuntimeException + const ScRangeList& getScRangeList(); + /// @throws css::uno::RuntimeException + static const ScRangeList& getScRangeList( const css::uno::Reference< ov::excel::XRange >& rxRange ); + + virtual ~ScVbaRange() override; + virtual css::uno::Reference< ov::XHelperInterface > thisHelperIface() override { return this; } + bool isSingleCellRange() const; + + /// @throws css::uno::RuntimeException + static css::uno::Reference< ov::excel::XRange > getRangeObjectForName( + const css::uno::Reference< css::uno::XComponentContext >& xContext, + const OUString& sRangeName, ScDocShell* pDocSh, + formula::FormulaGrammar::AddressConvention eConv ); + + /// @throws css::uno::RuntimeException + static css::uno::Reference< ov::excel::XRange > CellsHelper( + const ScDocument& rDoc, + const css::uno::Reference< ov::XHelperInterface >& xParent, + const css::uno::Reference< css::uno::XComponentContext >& xContext, + const css::uno::Reference< css::table::XCellRange >& xRange, + const css::uno::Any &nRowIndex, const css::uno::Any &nColumnIndex ); + + // Attributes + virtual css::uno::Any SAL_CALL getValue() override; + virtual void SAL_CALL setValue( const css::uno::Any& aValue ) override; + virtual css::uno::Any SAL_CALL getFormula() override; + virtual void SAL_CALL setFormula( const css::uno::Any& rFormula ) override; + virtual css::uno::Any SAL_CALL getFormulaArray() override; + virtual void SAL_CALL setFormulaArray(const css::uno::Any& rFormula) override; + virtual css::uno::Any SAL_CALL getFormulaR1C1() override; + virtual void SAL_CALL setFormulaR1C1( const css::uno::Any &rFormula ) override; + virtual css::uno::Any SAL_CALL getFormulaLocal() override; + virtual void SAL_CALL setFormulaLocal( const css::uno::Any &rFormula ) override; + virtual css::uno::Any SAL_CALL getFormulaR1C1Local() override; + virtual void SAL_CALL setFormulaR1C1Local( const css::uno::Any &rFormula ) override; + virtual ::sal_Int32 SAL_CALL getCount() override; + virtual ::sal_Int32 SAL_CALL getRow() override; + virtual ::sal_Int32 SAL_CALL getColumn() override; + virtual OUString SAL_CALL getText() override; + using ScVbaRange_BASE::setNumberFormat; + virtual void SAL_CALL setNumberFormat( const css::uno::Any& rNumberFormat ) override; + virtual css::uno::Any SAL_CALL getNumberFormat() override; + virtual void SAL_CALL setMergeCells( const css::uno::Any& bMerge ) override; + virtual css::uno::Any SAL_CALL getMergeCells() override; + virtual void SAL_CALL setWrapText( const css::uno::Any& bIsWrapped ) override; + virtual css::uno::Any SAL_CALL getWrapText() override; + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL getEntireRow() override; + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL getEntireColumn() override; + virtual css::uno::Reference< ov::excel::XComment > SAL_CALL getComment() override; + virtual css::uno::Any SAL_CALL getHidden() override; + virtual void SAL_CALL setHidden( const css::uno::Any& _hidden ) override; + virtual css::uno::Any SAL_CALL getColumnWidth() override; + virtual void SAL_CALL setColumnWidth( const css::uno::Any& _columnwidth ) override; + virtual css::uno::Any SAL_CALL getRowHeight() override; + virtual void SAL_CALL setRowHeight( const css::uno::Any& _rowheight ) override; + virtual css::uno::Any SAL_CALL getWidth() override; + virtual css::uno::Any SAL_CALL getHeight() override; + virtual css::uno::Any SAL_CALL getTop() override; + virtual css::uno::Any SAL_CALL getLeft() override; + + virtual css::uno::Reference< ov::excel::XName > SAL_CALL getName() override; + virtual css::uno::Reference< ov::excel::XWorksheet > SAL_CALL getWorksheet() override; + virtual css::uno::Any SAL_CALL getPageBreak() override; + virtual void SAL_CALL setPageBreak( const css::uno::Any& _pagebreak ) override; + virtual css::uno::Reference< ov::excel::XValidation > SAL_CALL getValidation() override; + virtual css::uno::Any SAL_CALL getPrefixCharacter() override; + virtual css::uno::Any SAL_CALL getShowDetail() override; + virtual void SAL_CALL setShowDetail(const css::uno::Any& aShowDetail) override; + // Methods + virtual css::uno::Reference< ov::excel::XComment > SAL_CALL AddComment( const css::uno::Any& Text ) override; + virtual void SAL_CALL Clear() override; + virtual void SAL_CALL ClearComments() override; + virtual void SAL_CALL ClearContents() override; + virtual void SAL_CALL ClearFormats() override; + virtual css::uno::Any SAL_CALL HasFormula() override; + virtual void SAL_CALL FillLeft() override; + virtual void SAL_CALL FillRight() override; + virtual void SAL_CALL FillUp() override; + virtual void SAL_CALL FillDown() override; + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Offset( const css::uno::Any &nRowOffset, const css::uno::Any &nColOffset ) override; + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL CurrentRegion() override; + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL CurrentArray() override; + virtual OUString SAL_CALL Characters( const css::uno::Any& nIndex, const css::uno::Any& nCount ) override; + + virtual OUString SAL_CALL Address( const css::uno::Any& RowAbsolute, const css::uno::Any& ColumnAbsolute, const css::uno::Any& ReferenceStyle, const css::uno::Any& External, const css::uno::Any& RelativeTo ) override; + + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Cells( const css::uno::Any &nRow, const css::uno::Any &nCol ) override; + virtual void SAL_CALL Select() override; + virtual void SAL_CALL Activate() override; + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Rows( const css::uno::Any& nIndex ) override; + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Columns( const css::uno::Any &nIndex ) override; + virtual void SAL_CALL Copy( const css::uno::Any& Destination ) override; + virtual void SAL_CALL Cut( const css::uno::Any& Destination ) override; + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Resize( const css::uno::Any& RowSize, const css::uno::Any& ColumnSize ) override; + virtual css::uno::Reference< ov::excel::XFont > SAL_CALL Font() override; + virtual css::uno::Reference< ov::excel::XInterior > SAL_CALL Interior( ) override ; + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Range( const css::uno::Any &Cell1, const css::uno::Any &Cell2 ) override; + /// @throws css::uno::RuntimeException + css::uno::Reference< ov::excel::XRange > Range( const css::uno::Any &Cell1, const css::uno::Any &Cell2, bool bForceUseInpuRangeTab ); + virtual css::uno::Any SAL_CALL getCellRange( ) override; + /// @throws css::uno::RuntimeException + static css::uno::Any getCellRange( const css::uno::Reference< ov::excel::XRange >& rxRange ); + virtual void SAL_CALL PasteSpecial( const css::uno::Any& Paste, const css::uno::Any& Operation, const css::uno::Any& SkipBlanks, const css::uno::Any& Transpose ) override; + virtual sal_Bool SAL_CALL Replace( const OUString& What, const OUString& Replacement, const css::uno::Any& LookAt, const css::uno::Any& SearchOrder, const css::uno::Any& MatchCase, const css::uno::Any& MatchByte, const css::uno::Any& SearchFormat, const css::uno::Any& ReplaceFormat ) override; + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Find( const css::uno::Any& What, const css::uno::Any& After, const css::uno::Any& LookIn, const css::uno::Any& LookAt, const css::uno::Any& SearchOrder, const css::uno::Any& SearchDirection, const css::uno::Any& MatchCase, const css::uno::Any& MatchByte, const css::uno::Any& SearchFormat ) override; + virtual void SAL_CALL Sort( const css::uno::Any& Key1, const css::uno::Any& Order1, const css::uno::Any& Key2, const css::uno::Any& Type, const css::uno::Any& Order2, const css::uno::Any& Key3, const css::uno::Any& Order3, const css::uno::Any& Header, const css::uno::Any& OrderCustom, const css::uno::Any& MatchCase, const css::uno::Any& Orientation, const css::uno::Any& SortMethod, const css::uno::Any& DataOption1, const css::uno::Any& DataOption2, const css::uno::Any& DataOption3 ) override; + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL End( ::sal_Int32 Direction ) override; + virtual css::uno::Reference< ov::excel::XCharacters > SAL_CALL characters( const css::uno::Any& Start, const css::uno::Any& Length ) override; + virtual void SAL_CALL Delete( const css::uno::Any& Shift ) override; + virtual css::uno::Any SAL_CALL Areas( const css::uno::Any& ) override; + virtual css::uno::Any SAL_CALL Borders( const css::uno::Any& ) override; + virtual css::uno::Any SAL_CALL BorderAround( const css::uno::Any& LineStyle, + const css::uno::Any& Weight, const css::uno::Any& ColorIndex, const css::uno::Any& Color ) override; + virtual css::uno::Any SAL_CALL Hyperlinks( const css::uno::Any& aIndex ) override; + + virtual void SAL_CALL AutoFilter( const css::uno::Any& Field, const css::uno::Any& Criteria1, const css::uno::Any& Operator, const css::uno::Any& Criteria2, const css::uno::Any& VisibleDropDown ) override; + virtual void SAL_CALL Insert( const css::uno::Any& Shift, const css::uno::Any& CopyOrigin ) override; + virtual void SAL_CALL Autofit() override; + virtual void SAL_CALL PrintOut( const css::uno::Any& From, const css::uno::Any& To, const css::uno::Any& Copies, const css::uno::Any& Preview, const css::uno::Any& ActivePrinter, const css::uno::Any& PrintToFile, const css::uno::Any& Collate, const css::uno::Any& PrToFileName ) override; + virtual void SAL_CALL AutoFill( const css::uno::Reference< ov::excel::XRange >& Destination, const css::uno::Any& Type ) override ; + void SAL_CALL Calculate( ) override; + virtual void SAL_CALL AutoOutline( ) override; + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Item( const css::uno::Any& row, const css::uno::Any& column ) override; + virtual void SAL_CALL ClearOutline( ) override; + virtual void SAL_CALL Ungroup( ) override; + virtual void SAL_CALL Group( ) override; + virtual void SAL_CALL Merge( const css::uno::Any& Across ) override; + virtual void SAL_CALL UnMerge( ) override; + virtual css::uno::Any SAL_CALL getStyle() override; + virtual void SAL_CALL setStyle( const css::uno::Any& _style ) override; + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Next() override; + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Previous() override; + virtual void SAL_CALL RemoveSubtotal( ) override; + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL MergeArea() override; + virtual void SAL_CALL Subtotal( ::sal_Int32 GroupBy, ::sal_Int32 Function, const css::uno::Sequence< ::sal_Int32 >& TotalList, const css::uno::Any& Replace, const css::uno::Any& PageBreaks, const css::uno::Any& SummaryBelowData ) override; + + // XEnumerationAccess + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + // XElementAccess + virtual css::uno::Type SAL_CALL getElementType() override + { + return cppu::UnoType<ov::excel::XRange>::get(); + + } + virtual sal_Bool SAL_CALL hasElements() override; + // XDefaultMethod + OUString SAL_CALL getDefaultMethodName( ) override; + // XDefaultProperty + OUString SAL_CALL getDefaultPropertyName( ) override { return "Value"; } + +// #TODO completely rewrite ScVbaRange, it's become a hackfest +// it needs to be closer to ScCellRangeBase in that the underlying +// object model should probably be a ScRangelst. +// * would be nice to be able to construct a range from an address only +// * or a list of address ( multi-area ) +// * object should be a lightweight as possible +// * we shouldn't need hacks like this below + /// @throws css::uno::RuntimeException + static css::uno::Reference< ov::excel::XRange > ApplicationRange( const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Any &Cell1, const css::uno::Any &Cell2 ); + static bool getCellRangesForAddress(ScRefFlags &rResFlags, std::u16string_view sAddress, ScDocShell* pDocSh, ScRangeList& rCellRanges, formula::FormulaGrammar::AddressConvention eConv, char cDelimiter ); + virtual sal_Bool SAL_CALL GoalSeek( const css::uno::Any& Goal, const css::uno::Reference< ov::excel::XRange >& ChangingCell ) override; + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL SpecialCells( const css::uno::Any& _oType, const css::uno::Any& _oValue) override; + // XErrorQuery + virtual sal_Bool SAL_CALL hasError( ) override; + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/// @throws css::uno::RuntimeException +bool getScRangeListForAddress( const OUString& sName, ScDocShell* pDocSh, const ScRange& refRange, + ScRangeList& aCellRanges, + formula::FormulaGrammar::AddressConvention aConv = formula::FormulaGrammar::CONV_XL_A1 ); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbasheetobject.cxx b/sc/source/ui/vba/vbasheetobject.cxx new file mode 100644 index 000000000..52513095f --- /dev/null +++ b/sc/source/ui/vba/vbasheetobject.cxx @@ -0,0 +1,540 @@ +/* -*- 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 "vbasheetobject.hxx" +#include <com/sun/star/awt/TextAlign.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XIndexContainer.hpp> +#include <com/sun/star/drawing/XControlShape.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/script/ScriptEventDescriptor.hpp> +#include <com/sun/star/script/XEventAttacherManager.hpp> +#include <com/sun/star/style/VerticalAlignment.hpp> +#include <comphelper/documentinfo.hxx> +#include <ooo/vba/excel/Constants.hpp> +#include <ooo/vba/excel/XlOrientation.hpp> +#include <ooo/vba/excel/XlPlacement.hpp> +#include <filter/msfilter/msvbahelper.hxx> +#include "vbafont.hxx" + +using namespace ::com::sun::star; +using namespace ::ooo::vba; + +constexpr OUStringLiteral gaListenerType = u"XActionListener"; +constexpr OUStringLiteral gaEventMethod = u"actionPerformed"; + + +ScVbaButtonCharacters::ScVbaButtonCharacters( + const uno::Reference< XHelperInterface >& rxParent, + const uno::Reference< uno::XComponentContext >& rxContext, + const uno::Reference< beans::XPropertySet >& rxPropSet, + const ScVbaPalette& rPalette, + const uno::Any& rStart, + const uno::Any& rLength ) : + ScVbaButtonCharacters_BASE( rxParent, rxContext ), + maPalette( rPalette ), + mxPropSet( rxPropSet, uno::UNO_SET_THROW ) +{ + // extract optional start parameter (missing or invalid -> from beginning) + if( !(rStart >>= mnStart) || (mnStart < 1) ) + mnStart = 1; + --mnStart; // VBA is 1-based, rtl string is 0-based + + // extract optional length parameter (missing or invalid -> to end) + if( !(rLength >>= mnLength) || (mnLength < 1) ) + mnLength = SAL_MAX_INT32; +} + +ScVbaButtonCharacters::~ScVbaButtonCharacters() +{ +} + +// XCharacters attributes + +OUString SAL_CALL ScVbaButtonCharacters::getCaption() +{ + // ignore invalid mnStart and/or mnLength members + OUString aString = getFullString(); + sal_Int32 nStart = ::std::min( mnStart, aString.getLength() ); + sal_Int32 nLength = ::std::min( mnLength, aString.getLength() - nStart ); + return aString.copy( nStart, nLength ); +} + +void SAL_CALL ScVbaButtonCharacters::setCaption( const OUString& rCaption ) +{ + /* Replace the covered text with the passed text, ignore invalid mnStart + and/or mnLength members. This operation does not affect the mnLength + parameter. If the inserted text is longer than mnLength, the additional + characters are not covered by this object. If the inserted text is + shorter than mnLength, other uncovered characters from the original + string will be covered now, thus may be changed with subsequent + operations. */ + OUString aString = getFullString(); + sal_Int32 nStart = ::std::min( mnStart, aString.getLength() ); + sal_Int32 nLength = ::std::min( mnLength, aString.getLength() - nStart ); + setFullString( aString.replaceAt( nStart, nLength, rCaption ) ); +} + +sal_Int32 SAL_CALL ScVbaButtonCharacters::getCount() +{ + // always return the total length of the caption + return getFullString().getLength(); +} + +OUString SAL_CALL ScVbaButtonCharacters::getText() +{ + // Text attribute same as Caption attribute? + return getCaption(); +} + +void SAL_CALL ScVbaButtonCharacters::setText( const OUString& rText ) +{ + // Text attribute same as Caption attribute? + setCaption( rText ); +} + +uno::Reference< excel::XFont > SAL_CALL ScVbaButtonCharacters::getFont() +{ + return new ScVbaFont( this, mxContext, maPalette, mxPropSet, nullptr, true ); +} + +void SAL_CALL ScVbaButtonCharacters::setFont( const uno::Reference< excel::XFont >& /*rxFont*/ ) +{ + // TODO +} + +// XCharacters methods + +void SAL_CALL ScVbaButtonCharacters::Insert( const OUString& rString ) +{ + /* The Insert() operation is in fact "replace covered characters", at + least for buttons... It seems there is no easy way to really insert a + substring. This operation does not affect the mnLength parameter. */ + setCaption( rString ); +} + +void SAL_CALL ScVbaButtonCharacters::Delete() +{ + /* The Delete() operation is nothing else than "replace with empty string". + This does not affect the mnLength parameter, multiple calls of Delete() + will remove characters as long as there are some more covered by this + object. */ + setCaption( OUString() ); +} + +// XHelperInterface + +VBAHELPER_IMPL_XHELPERINTERFACE( ScVbaButtonCharacters, "ooo.vba.excel.Characters" ) + +// private + +OUString ScVbaButtonCharacters::getFullString() const +{ + return mxPropSet->getPropertyValue( "Label" ).get< OUString >(); +} + +void ScVbaButtonCharacters::setFullString( const OUString& rString ) +{ + mxPropSet->setPropertyValue( "Label", uno::Any( rString ) ); +} + +ScVbaSheetObjectBase::ScVbaSheetObjectBase( + const uno::Reference< XHelperInterface >& rxParent, + const uno::Reference< uno::XComponentContext >& rxContext, + const uno::Reference< frame::XModel >& rxModel, + const uno::Reference< drawing::XShape >& rxShape ) : + ScVbaSheetObject_BASE( rxParent, rxContext ), + maPalette( rxModel ), + mxModel( rxModel, uno::UNO_SET_THROW ), + mxShape( rxShape, uno::UNO_SET_THROW ), + mxShapeProps( rxShape, uno::UNO_QUERY_THROW ) +{ +} + +// XSheetObject attributes + +double SAL_CALL ScVbaSheetObjectBase::getLeft() +{ + return HmmToPoints( mxShape->getPosition().X ); +} + +void SAL_CALL ScVbaSheetObjectBase::setLeft( double fLeft ) +{ + if( fLeft < 0.0 ) + throw uno::RuntimeException(); + mxShape->setPosition( awt::Point( PointsToHmm( fLeft ), mxShape->getPosition().Y ) ); +} + +double SAL_CALL ScVbaSheetObjectBase::getTop() +{ + return HmmToPoints( mxShape->getPosition().Y ); +} + +void SAL_CALL ScVbaSheetObjectBase::setTop( double fTop ) +{ + if( fTop < 0.0 ) + throw uno::RuntimeException(); + mxShape->setPosition( awt::Point( mxShape->getPosition().X, PointsToHmm( fTop ) ) ); +} + +double SAL_CALL ScVbaSheetObjectBase::getWidth() +{ + return HmmToPoints( mxShape->getSize().Width ); +} + +void SAL_CALL ScVbaSheetObjectBase::setWidth( double fWidth ) +{ + if( fWidth <= 0.0 ) + throw uno::RuntimeException(); + mxShape->setSize( awt::Size( PointsToHmm( fWidth ), mxShape->getSize().Height ) ); +} + +double SAL_CALL ScVbaSheetObjectBase::getHeight() +{ + return HmmToPoints( mxShape->getSize().Height ); +} + +void SAL_CALL ScVbaSheetObjectBase::setHeight( double fHeight ) +{ + if( fHeight <= 0.0 ) + throw uno::RuntimeException(); + mxShape->setSize( awt::Size( mxShape->getSize().Width, PointsToHmm( fHeight ) ) ); +} + +OUString SAL_CALL ScVbaSheetObjectBase::getName() +{ + return mxShapeProps->getPropertyValue( "Name" ).get< OUString >(); +} + +void SAL_CALL ScVbaSheetObjectBase::setName( const OUString& rName ) +{ + mxShapeProps->setPropertyValue( "Name", uno::Any( rName ) ); +} + +sal_Int32 SAL_CALL ScVbaSheetObjectBase::getPlacement() +{ + sal_Int32 const nRet = excel::XlPlacement::xlMoveAndSize; +#if 0 // TODO: not working at the moment. + SvxShape* pShape = SdrObject::getSdrObjectFromXShape( mxShape ); + if(pShape) + { + SdrObject* pObj = pShape->GetSdrObject(); + if (pObj) + { + ScAnchorType eType = ScDrawLayer::GetAnchor(pObj); + if (eType == SCA_PAGE) + nRet = excel::XlPlacement::xlFreeFloating; + } + } +#endif + return nRet; +} + +void SAL_CALL ScVbaSheetObjectBase::setPlacement( sal_Int32 /*nPlacement*/ ) +{ +#if 0 // TODO: not working at the moment. + SvxShape* pShape = SdrObject::getSdrObjectFromXShape( mxShape ); + if(pShape) + { + SdrObject* pObj = pShape->GetSdrObject(); + if (pObj) + { + ScAnchorType eType = SCA_CELL; + if ( nPlacement == excel::XlPlacement::xlFreeFloating ) + eType = SCA_PAGE; + + // xlMove is not supported, treated as SCA_CELL (xlMoveAndSize) + + ScDrawLayer::SetAnchor(pObj, eType); + } + } +#endif +} + +sal_Bool SAL_CALL ScVbaSheetObjectBase::getPrintObject() +{ + // not supported + return true; +} + +void SAL_CALL ScVbaSheetObjectBase::setPrintObject( sal_Bool /*bPrintObject*/ ) +{ + // not supported +} + +// private + +void ScVbaSheetObjectBase::setDefaultProperties( sal_Int32 nIndex ) +{ + OUString aName = implGetBaseName() + OUStringChar(' ') + OUString::number( nIndex + 1 ); + setName( aName ); + implSetDefaultProperties(); +} + +void ScVbaSheetObjectBase::implSetDefaultProperties() +{ +} + +ScVbaControlObjectBase::ScVbaControlObjectBase( + const uno::Reference< XHelperInterface >& rxParent, + const uno::Reference< uno::XComponentContext >& rxContext, + const uno::Reference< frame::XModel >& rxModel, + const uno::Reference< container::XIndexContainer >& rxFormIC, + const uno::Reference< drawing::XControlShape >& rxControlShape ) : + ScVbaControlObject_BASE( rxParent, rxContext, rxModel, uno::Reference< drawing::XShape >( rxControlShape, uno::UNO_QUERY_THROW ) ), + mxFormIC( rxFormIC, uno::UNO_SET_THROW ), + mxControlProps( rxControlShape->getControl(), uno::UNO_QUERY_THROW ), + mbNotifyMacroEventRead(false) +{ +} + +// XSheetObject attributes + +OUString SAL_CALL ScVbaControlObjectBase::getName() +{ + return mxControlProps->getPropertyValue( "Name" ).get< OUString >(); +} + +void SAL_CALL ScVbaControlObjectBase::setName( const OUString& rName ) +{ + mxControlProps->setPropertyValue( "Name", uno::Any( rName ) ); +} + +OUString SAL_CALL ScVbaControlObjectBase::getOnAction() +{ + uno::Reference< script::XEventAttacherManager > xEventMgr( mxFormIC, uno::UNO_QUERY_THROW ); + sal_Int32 nIndex = getModelIndexInForm(); + const uno::Sequence< script::ScriptEventDescriptor > aEvents = xEventMgr->getScriptEvents( nIndex ); + if( aEvents.hasElements() ) + { + const script::ScriptEventDescriptor* pEvent = std::find_if(aEvents.begin(), aEvents.end(), + [](const script::ScriptEventDescriptor& rEvent) { + return (rEvent.ListenerType == gaListenerType) + && (rEvent.EventMethod == gaEventMethod) + && (rEvent.ScriptType == "Script"); + }); + if (pEvent != aEvents.end()) + return extractMacroName( pEvent->ScriptCode ); + } + return OUString(); +} + +void ScVbaControlObjectBase::NotifyMacroEventRead() +{ + if (mbNotifyMacroEventRead) + return; + comphelper::DocumentInfo::notifyMacroEventRead(mxModel); + mbNotifyMacroEventRead = true; +} + +void SAL_CALL ScVbaControlObjectBase::setOnAction( const OUString& rMacroName ) +{ + uno::Reference< script::XEventAttacherManager > xEventMgr( mxFormIC, uno::UNO_QUERY_THROW ); + sal_Int32 nIndex = getModelIndexInForm(); + + // first, remove a registered event (try/catch just in case implementation throws) + try { xEventMgr->revokeScriptEvent( nIndex, gaListenerType, gaEventMethod, OUString() ); } catch( uno::Exception& ) {} + + // if a macro name has been passed, try to attach it to the event + if( rMacroName.isEmpty() ) + return; + + MacroResolvedInfo aResolvedMacro = resolveVBAMacro( getSfxObjShell( mxModel ), rMacroName ); + if( !aResolvedMacro.mbFound ) + throw uno::RuntimeException(); + script::ScriptEventDescriptor aDescriptor; + aDescriptor.ListenerType = gaListenerType; + aDescriptor.EventMethod = gaEventMethod; + aDescriptor.ScriptType = "Script"; + aDescriptor.ScriptCode = makeMacroURL( aResolvedMacro.msResolvedMacro ); + NotifyMacroEventRead(); + xEventMgr->registerScriptEvent( nIndex, aDescriptor ); +} + +sal_Bool SAL_CALL ScVbaControlObjectBase::getPrintObject() +{ + return mxControlProps->getPropertyValue( "Printable" ).get<bool>(); +} + +void SAL_CALL ScVbaControlObjectBase::setPrintObject( sal_Bool bPrintObject ) +{ + mxControlProps->setPropertyValue( "Printable", uno::Any( bPrintObject ) ); +} + +// XControlObject attributes + +sal_Bool SAL_CALL ScVbaControlObjectBase::getAutoSize() +{ + // not supported + return false; +} + +void SAL_CALL ScVbaControlObjectBase::setAutoSize( sal_Bool /*bAutoSize*/ ) +{ + // not supported +} + +// private + +sal_Int32 ScVbaControlObjectBase::getModelIndexInForm() const +{ + for( sal_Int32 nIndex = 0, nCount = mxFormIC->getCount(); nIndex < nCount; ++nIndex ) + { + uno::Reference< beans::XPropertySet > xProps( mxFormIC->getByIndex( nIndex ), uno::UNO_QUERY_THROW ); + if( mxControlProps.get() == xProps.get() ) + return nIndex; + } + throw uno::RuntimeException(); +} + +ScVbaButton::ScVbaButton( + const uno::Reference< XHelperInterface >& rxParent, + const uno::Reference< uno::XComponentContext >& rxContext, + const uno::Reference< frame::XModel >& rxModel, + const uno::Reference< container::XIndexContainer >& rxFormIC, + const uno::Reference< drawing::XControlShape >& rxControlShape ) : + ScVbaButton_BASE( rxParent, rxContext, rxModel, rxFormIC, rxControlShape ) +{ +} + +// XButton attributes + +OUString SAL_CALL ScVbaButton::getCaption() +{ + return mxControlProps->getPropertyValue( "Label" ).get< OUString >(); +} + +void SAL_CALL ScVbaButton::setCaption( const OUString& rCaption ) +{ + mxControlProps->setPropertyValue( "Label", uno::Any( rCaption ) ); +} + +uno::Reference< excel::XFont > SAL_CALL ScVbaButton::getFont() +{ + return new ScVbaFont( this, mxContext, maPalette, mxControlProps, nullptr, true ); +} + +void SAL_CALL ScVbaButton::setFont( const uno::Reference< excel::XFont >& /*rxFont*/ ) +{ + // TODO +} + +sal_Int32 SAL_CALL ScVbaButton::getHorizontalAlignment() +{ + switch( mxControlProps->getPropertyValue( "Align" ).get< sal_Int16 >() ) + { + case awt::TextAlign::LEFT: return excel::Constants::xlLeft; + case awt::TextAlign::RIGHT: return excel::Constants::xlRight; + case awt::TextAlign::CENTER: return excel::Constants::xlCenter; + } + return excel::Constants::xlCenter; +} + +void SAL_CALL ScVbaButton::setHorizontalAlignment( sal_Int32 nAlign ) +{ + sal_Int32 nAwtAlign = awt::TextAlign::CENTER; + switch( nAlign ) + { + case excel::Constants::xlLeft: nAwtAlign = awt::TextAlign::LEFT; break; + case excel::Constants::xlRight: nAwtAlign = awt::TextAlign::RIGHT; break; + case excel::Constants::xlCenter: nAwtAlign = awt::TextAlign::CENTER; break; + } + // form controls expect short value + mxControlProps->setPropertyValue( "Align", uno::Any( static_cast< sal_Int16 >( nAwtAlign ) ) ); +} + +sal_Int32 SAL_CALL ScVbaButton::getVerticalAlignment() +{ + switch( mxControlProps->getPropertyValue( "VerticalAlign" ).get< style::VerticalAlignment >() ) + { + case style::VerticalAlignment_TOP: return excel::Constants::xlTop; + case style::VerticalAlignment_BOTTOM: return excel::Constants::xlBottom; + case style::VerticalAlignment_MIDDLE: return excel::Constants::xlCenter; + default:; + } + return excel::Constants::xlCenter; +} + +void SAL_CALL ScVbaButton::setVerticalAlignment( sal_Int32 nAlign ) +{ + style::VerticalAlignment eAwtAlign = style::VerticalAlignment_MIDDLE; + switch( nAlign ) + { + case excel::Constants::xlTop: eAwtAlign = style::VerticalAlignment_TOP; break; + case excel::Constants::xlBottom: eAwtAlign = style::VerticalAlignment_BOTTOM; break; + case excel::Constants::xlCenter: eAwtAlign = style::VerticalAlignment_MIDDLE; break; + } + mxControlProps->setPropertyValue( "VerticalAlign", uno::Any( eAwtAlign ) ); +} + +sal_Int32 SAL_CALL ScVbaButton::getOrientation() +{ + // not supported + return excel::XlOrientation::xlHorizontal; +} + +void SAL_CALL ScVbaButton::setOrientation( sal_Int32 /*nOrientation*/ ) +{ + // not supported +} + +uno::Any SAL_CALL ScVbaButton::getValue() +{ + return mxControlProps->getPropertyValue( "State" ); +} + +void SAL_CALL ScVbaButton::setValue( const uno::Any &nValue ) +{ + return mxControlProps->setPropertyValue( "State", nValue ); +} + +OUString SAL_CALL ScVbaButton::getText() +{ + return mxControlProps->getPropertyValue( "Label" ).get< OUString >(); +} + +void SAL_CALL ScVbaButton::setText( const OUString &aText ) +{ + return mxControlProps->setPropertyValue( "Label", uno::Any( aText ) ); +} + +// XButton methods + +uno::Reference< excel::XCharacters > SAL_CALL ScVbaButton::Characters( const uno::Any& rStart, const uno::Any& rLength ) +{ + return new ScVbaButtonCharacters( this, mxContext, mxControlProps, maPalette, rStart, rLength ); +} + +// XHelperInterface + +VBAHELPER_IMPL_XHELPERINTERFACE( ScVbaButton, "ooo.vba.excel.Button" ) + +// private + +OUString ScVbaButton::implGetBaseName() const +{ + return "Button"; +} + +void ScVbaButton::implSetDefaultProperties() +{ + setCaption( getName() ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbasheetobject.hxx b/sc/source/ui/vba/vbasheetobject.hxx new file mode 100644 index 000000000..d88b15034 --- /dev/null +++ b/sc/source/ui/vba/vbasheetobject.hxx @@ -0,0 +1,209 @@ +/* -*- 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 . + */ + +#pragma once + +#include <ooo/vba/excel/XButton.hpp> +#include <ooo/vba/excel/XControlObject.hpp> +#include <ooo/vba/excel/XSheetObject.hpp> +#include <cppuhelper/implbase.hxx> +#include <vbahelper/vbahelperinterface.hxx> +#include "vbapalette.hxx" + +namespace com::sun::star { + namespace container { class XIndexContainer; } + namespace drawing { class XControlShape; } +} + +typedef InheritedHelperInterfaceWeakImpl< ov::excel::XCharacters > ScVbaButtonCharacters_BASE; + +/** Simple implementation of the Characters symbol for drawing button objects. */ +class ScVbaButtonCharacters : public ScVbaButtonCharacters_BASE +{ +public: + /// @throws css::uno::RuntimeException + explicit ScVbaButtonCharacters( + const css::uno::Reference< ov::XHelperInterface >& rxParent, + const css::uno::Reference< css::uno::XComponentContext >& rxContext, + const css::uno::Reference< css::beans::XPropertySet >& rxPropSet, + const ScVbaPalette& rPalette, + const css::uno::Any& rStart, + const css::uno::Any& rLength ); + virtual ~ScVbaButtonCharacters() override; + + // XCharacters attributes + virtual OUString SAL_CALL getCaption() override; + virtual void SAL_CALL setCaption( const OUString& rCaption ) override; + virtual OUString SAL_CALL getText() override; + virtual void SAL_CALL setText( const OUString& rText ) override; + virtual sal_Int32 SAL_CALL getCount() override; + virtual css::uno::Reference< ov::excel::XFont > SAL_CALL getFont() override; + virtual void SAL_CALL setFont( const css::uno::Reference< ov::excel::XFont >& rxFont ) override; + + // XCharacters methods + virtual void SAL_CALL Insert( const OUString& rString ) override; + virtual void SAL_CALL Delete() override; + + // XHelperInterface + VBAHELPER_DECL_XHELPERINTERFACE + +private: + /// @throws css::uno::RuntimeException + OUString getFullString() const; + /// @throws css::uno::RuntimeException + void setFullString( const OUString& rString ); + +private: + ScVbaPalette maPalette; + css::uno::Reference< css::beans::XPropertySet > mxPropSet; + sal_Int32 mnStart; + sal_Int32 mnLength; +}; + +typedef InheritedHelperInterfaceWeakImpl< ov::excel::XSheetObject > ScVbaSheetObject_BASE; + +/** Base class for drawing objects embedded in sheets. */ +class ScVbaSheetObjectBase : public ScVbaSheetObject_BASE +{ +public: + /// @throws css::uno::RuntimeException + explicit ScVbaSheetObjectBase( + const css::uno::Reference< ov::XHelperInterface >& rxParent, + const css::uno::Reference< css::uno::XComponentContext >& rxContext, + const css::uno::Reference< css::frame::XModel >& rxModel, + const css::uno::Reference< css::drawing::XShape >& rxShape ); + + // XSheetObject attributes + virtual double SAL_CALL getLeft() override; + virtual void SAL_CALL setLeft( double fLeft ) override; + virtual double SAL_CALL getTop() override; + virtual void SAL_CALL setTop( double fTop ) override; + virtual double SAL_CALL getWidth() override; + virtual void SAL_CALL setWidth( double fWidth ) override; + virtual double SAL_CALL getHeight() override; + virtual void SAL_CALL setHeight( double fHeight ) override; + virtual OUString SAL_CALL getName() override; + virtual void SAL_CALL setName( const OUString& rName ) override; + virtual sal_Int32 SAL_CALL getPlacement() override; + virtual void SAL_CALL setPlacement( sal_Int32 nPlacement ) override; + virtual sal_Bool SAL_CALL getPrintObject() override; + virtual void SAL_CALL setPrintObject( sal_Bool bPrintObject ) override; + + /** Sets default properties after a new object has been created. + + @throws css::uno::RuntimeException + */ + void setDefaultProperties( sal_Int32 nIndex ); + +protected: + /** Derived classes return the base name used for new objects. */ + virtual OUString implGetBaseName() const = 0; + /** Derived classes set default properties for new drawing objects. + + @throws css::uno::RuntimeException + */ + virtual void implSetDefaultProperties(); + +protected: + ScVbaPalette maPalette; + css::uno::Reference< css::frame::XModel > mxModel; + css::uno::Reference< css::drawing::XShape > mxShape; + css::uno::Reference< css::beans::XPropertySet > mxShapeProps; +}; + +typedef ::cppu::ImplInheritanceHelper< ScVbaSheetObjectBase, ov::excel::XControlObject > ScVbaControlObject_BASE; + +class ScVbaControlObjectBase : public ScVbaControlObject_BASE +{ +public: + /// @throws css::uno::RuntimeException + explicit ScVbaControlObjectBase( + const css::uno::Reference< ov::XHelperInterface >& rxParent, + const css::uno::Reference< css::uno::XComponentContext >& rxContext, + const css::uno::Reference< css::frame::XModel >& rxModel, + const css::uno::Reference< css::container::XIndexContainer >& rxFormIC, + const css::uno::Reference< css::drawing::XControlShape >& rxControlShape ); + + // XSheetObject attributes + virtual OUString SAL_CALL getName() override; + virtual void SAL_CALL setName( const OUString& rName ) override; + virtual OUString SAL_CALL getOnAction() override; + virtual void SAL_CALL setOnAction( const OUString& rMacroName ) override; + virtual sal_Bool SAL_CALL getPrintObject() override; + virtual void SAL_CALL setPrintObject( sal_Bool bPrintObject ) override; + + // XControlObject attributes + virtual sal_Bool SAL_CALL getAutoSize() override; + virtual void SAL_CALL setAutoSize( sal_Bool bAutoSize ) override; + + /// Notify that the document contains a macro event handler + void NotifyMacroEventRead(); + +protected: + /// @throws css::uno::RuntimeException + sal_Int32 getModelIndexInForm() const; + +protected: + css::uno::Reference< css::container::XIndexContainer > mxFormIC; + css::uno::Reference< css::beans::XPropertySet > mxControlProps; + bool mbNotifyMacroEventRead; +}; + +typedef ::cppu::ImplInheritanceHelper< ScVbaControlObjectBase, ov::excel::XButton > ScVbaButton_BASE; + +class ScVbaButton : public ScVbaButton_BASE +{ +public: + /// @throws css::uno::RuntimeException + explicit ScVbaButton( + const css::uno::Reference< ov::XHelperInterface >& rxParent, + const css::uno::Reference< css::uno::XComponentContext >& rxContext, + const css::uno::Reference< css::frame::XModel >& rxModel, + const css::uno::Reference< css::container::XIndexContainer >& rxFormIC, + const css::uno::Reference< css::drawing::XControlShape >& rxControlShape ); + + // XButton attributes + virtual OUString SAL_CALL getCaption() override; + virtual void SAL_CALL setCaption( const OUString& rCaption ) override; + virtual css::uno::Reference< ov::excel::XFont > SAL_CALL getFont() override; + virtual void SAL_CALL setFont( const css::uno::Reference< ov::excel::XFont >& rxFont ) override; + virtual sal_Int32 SAL_CALL getHorizontalAlignment() override; + virtual void SAL_CALL setHorizontalAlignment( sal_Int32 nAlign ) override; + virtual sal_Int32 SAL_CALL getVerticalAlignment() override; + virtual void SAL_CALL setVerticalAlignment( sal_Int32 nAlign ) override; + virtual sal_Int32 SAL_CALL getOrientation() override; + virtual void SAL_CALL setOrientation( sal_Int32 nOrientation ) override; + virtual css::uno::Any SAL_CALL getValue() override; + virtual void SAL_CALL setValue( const css::uno::Any &nValue ) override; + virtual OUString SAL_CALL getText() override; + virtual void SAL_CALL setText( const OUString &aText ) override; + + // XButton methods + css::uno::Reference< ov::excel::XCharacters > SAL_CALL Characters( + const css::uno::Any& rStart, const css::uno::Any& rLength ) override; + + // XHelperInterface + VBAHELPER_DECL_XHELPERINTERFACE + +protected: + virtual OUString implGetBaseName() const override; + virtual void implSetDefaultProperties() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbasheetobjects.cxx b/sc/source/ui/vba/vbasheetobjects.cxx new file mode 100644 index 000000000..32e025a3c --- /dev/null +++ b/sc/source/ui/vba/vbasheetobjects.cxx @@ -0,0 +1,555 @@ +/* -*- 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 "vbasheetobjects.hxx" +#include <vector> +#include <rtl/math.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XIndexContainer.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/drawing/XControlShape.hpp> +#include <com/sun/star/drawing/XDrawPageSupplier.hpp> +#include <com/sun/star/drawing/XShapes.hpp> +#include <com/sun/star/form/FormComponentType.hpp> +#include <com/sun/star/form/XForm.hpp> +#include <com/sun/star/form/XFormComponent.hpp> +#include <com/sun/star/form/XFormsSupplier.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/sheet/XSpreadsheet.hpp> +#include "vbasheetobject.hxx" +#include <cppuhelper/implbase.hxx> + +using namespace ::com::sun::star; +using namespace ::ooo::vba; + +namespace { + +template< typename Type > +bool lclGetProperty( Type& orValue, const uno::Reference< beans::XPropertySet >& rxPropSet, const OUString& rPropName ) +{ + try + { + return rxPropSet->getPropertyValue( rPropName ) >>= orValue; + } + catch( uno::Exception& ) + { + } + return false; +} + +/** Rounds the passed value to a multiple of 0.75 and converts it to 1/100 mm. + + @throws uno::RuntimeException +*/ +double lclPointsToHmm( const uno::Any& rPoints ) +{ + return PointsToHmm( ::rtl::math::approxFloor( rPoints.get< double >() / 0.75 ) * 0.75 ); +} + +} // namespace + +// Base implementations + +/** Container for a specific type of drawing object in a spreadsheet. + + Derived classes provide all required functionality specific to the type of + shapes covered by the container. + */ +class ScVbaObjectContainer : public ::cppu::WeakImplHelper< container::XIndexAccess > +{ +public: + /// @throws uno::RuntimeException + explicit ScVbaObjectContainer( + const uno::Reference< XHelperInterface >& rxParent, + const uno::Reference< uno::XComponentContext >& rxContext, + const uno::Reference< frame::XModel >& rxModel, + const uno::Reference< sheet::XSpreadsheet >& rxSheet, + const uno::Type& rVbaType ); + + /** Returns the VBA helper interface of the VBA collection object. */ + const uno::Reference< XHelperInterface >& getParent() const { return mxParent; } + /** Returns the component context of the VBA collection object. */ + const uno::Reference< uno::XComponentContext >& getContext() const { return mxContext; } + /** Returns the VBA type information of the objects in this container. */ + const uno::Type& getVbaType() const { return maVbaType; } + + /** Collects all shapes supported by this instance and inserts them into + the internal shape vector. + + @throws uno::RuntimeException + */ + void collectShapes(); + /** Creates and returns a new UNO shape. + + @throws uno::RuntimeException + */ + uno::Reference< drawing::XShape > createShape( const awt::Point& rPos, const awt::Size& rSize ); + /** Inserts the passed shape into the draw page and into this container, and returns its index in the draw page. + + @throws uno::RuntimeException + */ + sal_Int32 insertShape( const uno::Reference< drawing::XShape >& rxShape ); + /** Creates and returns a new VBA implementation object for the passed shape. + + @throws uno::RuntimeException + */ + ::rtl::Reference< ScVbaSheetObjectBase > createVbaObject( const uno::Reference< drawing::XShape >& rxShape ); + /** Creates and returns a new VBA implementation object for the passed shape in an Any. + + @throws uno::RuntimeException + */ + uno::Any createCollectionObject( const uno::Any& rSource ); + /** Returns the VBA implementation object with the specified name. + + @throws uno::RuntimeException + */ + uno::Any getItemByStringIndex( const OUString& rIndex ); + + // XIndexAccess + virtual sal_Int32 SAL_CALL getCount() override; + virtual uno::Any SAL_CALL getByIndex( sal_Int32 nIndex ) override; + + // XElementAccess + virtual uno::Type SAL_CALL getElementType() override; + virtual sal_Bool SAL_CALL hasElements() override; + +protected: + /** Derived classes return true, if the passed shape is supported by the instance. */ + virtual bool implPickShape( const uno::Reference< drawing::XShape >& rxShape ) const = 0; + /** Derived classes create and return a new VBA implementation object for the passed shape. + + @throws uno::RuntimeException + */ + virtual rtl::Reference<ScVbaSheetObjectBase> implCreateVbaObject( const uno::Reference< drawing::XShape >& rxShape ) = 0; + /** Derived classes return the service name of the UNO shape. */ + virtual OUString implGetShapeServiceName() const = 0; + + /** Returns the shape name via 'Name' property of the UNO shape. May be overwritten. + + @throws uno::RuntimeException + */ + virtual OUString implGetShapeName( const uno::Reference< drawing::XShape >& rxShape ) const; + /** Is called when a new UNO shape has been created but not yet inserted into the drawing page. + + @throws uno::RuntimeException + */ + virtual void implOnShapeCreated( const uno::Reference< drawing::XShape >& rxShape ); + +protected: + uno::Reference< XHelperInterface > mxParent; + uno::Reference< uno::XComponentContext > mxContext; + uno::Reference< frame::XModel > mxModel; + uno::Reference< lang::XMultiServiceFactory > mxFactory; + uno::Reference< drawing::XShapes > mxShapes; + +private: + typedef ::std::vector< uno::Reference< drawing::XShape > > ShapeVector; + const uno::Type maVbaType; + ShapeVector maShapes; +}; + +ScVbaObjectContainer::ScVbaObjectContainer( + const uno::Reference< XHelperInterface >& rxParent, + const uno::Reference< uno::XComponentContext >& rxContext, + const uno::Reference< frame::XModel >& rxModel, + const uno::Reference< sheet::XSpreadsheet >& rxSheet, + const uno::Type& rVbaType ) : + mxParent( rxParent ), + mxContext( rxContext ), + mxModel( rxModel, uno::UNO_SET_THROW ), + mxFactory( rxModel, uno::UNO_QUERY_THROW ), + maVbaType( rVbaType ) +{ + uno::Reference< drawing::XDrawPageSupplier > xDrawPageSupp( rxSheet, uno::UNO_QUERY_THROW ); + mxShapes.set( xDrawPageSupp->getDrawPage(), uno::UNO_QUERY_THROW ); +} + +void ScVbaObjectContainer::collectShapes() +{ + maShapes.clear(); + for( sal_Int32 nIndex = 0, nCount = mxShapes->getCount(); nIndex < nCount; ++nIndex ) + { + uno::Reference< drawing::XShape > xShape( mxShapes->getByIndex( nIndex ), uno::UNO_QUERY_THROW ); + if( implPickShape( xShape ) ) + maShapes.push_back( xShape ); + } +} + +uno::Reference< drawing::XShape > ScVbaObjectContainer::createShape( const awt::Point& rPos, const awt::Size& rSize ) +{ + uno::Reference< drawing::XShape > xShape( mxFactory->createInstance( implGetShapeServiceName() ), uno::UNO_QUERY_THROW ); + xShape->setPosition( rPos ); + xShape->setSize( rSize ); + implOnShapeCreated( xShape ); + return xShape; +} + +sal_Int32 ScVbaObjectContainer::insertShape( const uno::Reference< drawing::XShape >& rxShape ) +{ + mxShapes->add( rxShape ); + maShapes.push_back( rxShape ); + return mxShapes->getCount() - 1; +} + +::rtl::Reference< ScVbaSheetObjectBase > ScVbaObjectContainer::createVbaObject( + const uno::Reference< drawing::XShape >& rxShape ) +{ + return implCreateVbaObject( rxShape ); +} + +uno::Any ScVbaObjectContainer::createCollectionObject( const uno::Any& rSource ) +{ + uno::Reference< drawing::XShape > xShape( rSource, uno::UNO_QUERY_THROW ); + uno::Reference< excel::XSheetObject > xSheetObject( implCreateVbaObject( xShape ) ); + return uno::Any( xSheetObject ); +} + +uno::Any ScVbaObjectContainer::getItemByStringIndex( const OUString& rIndex ) +{ + auto aIt = std::find_if(maShapes.begin(), maShapes.end(), + [&rIndex, this](const ShapeVector::value_type& rxShape) { return rIndex == implGetShapeName( rxShape ); }); + if (aIt != maShapes.end()) + return createCollectionObject( uno::Any( *aIt ) ); + throw uno::RuntimeException(); +} + +// XIndexAccess + +sal_Int32 SAL_CALL ScVbaObjectContainer::getCount() +{ + return static_cast< sal_Int32 >( maShapes.size() ); +} + +uno::Any SAL_CALL ScVbaObjectContainer::getByIndex( sal_Int32 nIndex ) +{ + if( (0 <= nIndex) && (nIndex < getCount()) ) + return uno::Any( maShapes[ static_cast< size_t >( nIndex ) ] ); + throw lang::IndexOutOfBoundsException(); +} + +// XElementAccess + +uno::Type SAL_CALL ScVbaObjectContainer::getElementType() +{ + return cppu::UnoType<drawing::XShape>::get(); +} + +sal_Bool SAL_CALL ScVbaObjectContainer::hasElements() +{ + return !maShapes.empty(); +} + +// private + +OUString ScVbaObjectContainer::implGetShapeName( const uno::Reference< drawing::XShape >& rxShape ) const +{ + uno::Reference< beans::XPropertySet > xPropSet( rxShape, uno::UNO_QUERY_THROW ); + return xPropSet->getPropertyValue( "Name" ).get< OUString >(); +} + +void ScVbaObjectContainer::implOnShapeCreated( const uno::Reference< drawing::XShape >& /*rxShape*/ ) +{ +} + +namespace { + +class ScVbaObjectEnumeration : public SimpleEnumerationBase +{ +public: + explicit ScVbaObjectEnumeration( const ScVbaObjectContainerRef& rxContainer ); + virtual uno::Any createCollectionObject( const uno::Any& rSource ) override; + +private: + ScVbaObjectContainerRef mxContainer; +}; + +} + +ScVbaObjectEnumeration::ScVbaObjectEnumeration( const ScVbaObjectContainerRef& rxContainer ) : + SimpleEnumerationBase( rxContainer ), + mxContainer( rxContainer ) +{ +} + +uno::Any ScVbaObjectEnumeration::createCollectionObject( const uno::Any& rSource ) +{ + return mxContainer->createCollectionObject( rSource ); +} + +ScVbaSheetObjectsBase::ScVbaSheetObjectsBase( const ScVbaObjectContainerRef& rxContainer ) : + ScVbaSheetObjects_BASE( rxContainer->getParent(), rxContainer->getContext(), rxContainer ), + mxContainer( rxContainer ) +{ + mxContainer->collectShapes(); +} + +ScVbaSheetObjectsBase::~ScVbaSheetObjectsBase() +{ +} + +void ScVbaSheetObjectsBase::collectShapes() +{ + mxContainer->collectShapes(); +} + +// XEnumerationAccess + +uno::Reference< container::XEnumeration > SAL_CALL ScVbaSheetObjectsBase::createEnumeration() +{ + return new ScVbaObjectEnumeration( mxContainer ); +} + +// XElementAccess + +uno::Type SAL_CALL ScVbaSheetObjectsBase::getElementType() +{ + return mxContainer->getVbaType(); +} + +// ScVbaCollectionBase + +uno::Any ScVbaSheetObjectsBase::createCollectionObject( const uno::Any& rSource ) +{ + return mxContainer->createCollectionObject( rSource ); +} + +uno::Any ScVbaSheetObjectsBase::getItemByStringIndex( const OUString& rIndex ) +{ + return mxContainer->getItemByStringIndex( rIndex ); +} + +// Graphic object containers supporting ooo.vba.excel.XGraphicObject + +ScVbaGraphicObjectsBase::ScVbaGraphicObjectsBase( const ScVbaObjectContainerRef& rxContainer ) : + ScVbaGraphicObjects_BASE( rxContainer ) +{ +} + +// XGraphicObjects + +uno::Any SAL_CALL ScVbaGraphicObjectsBase::Add( const uno::Any& rLeft, const uno::Any& rTop, const uno::Any& rWidth, const uno::Any& rHeight ) +{ + /* Extract double values from passed Anys (the lclPointsToHmm() helper + function will throw a RuntimeException on any error), and convert from + points to 1/100 mm. */ + awt::Point aPos( static_cast<sal_Int32>(lclPointsToHmm( rLeft )), static_cast<sal_Int32>(lclPointsToHmm( rTop )) ); + awt::Size aSize( static_cast<sal_Int32>(lclPointsToHmm( rWidth )), static_cast<sal_Int32>(lclPointsToHmm( rHeight )) ); + // TODO: translate coordinates for RTL sheets + if( (aPos.X < 0) || (aPos.Y < 0) || (aSize.Width <= 0) || (aSize.Height <= 0) ) + throw uno::RuntimeException(); + + // create the UNO shape + uno::Reference< drawing::XShape > xShape( mxContainer->createShape( aPos, aSize ), uno::UNO_SET_THROW ); + sal_Int32 nIndex = mxContainer->insertShape( xShape ); + + // create and return the VBA object + ::rtl::Reference< ScVbaSheetObjectBase > xVbaObject = mxContainer->createVbaObject( xShape ); + xVbaObject->setDefaultProperties( nIndex ); + return uno::Any( uno::Reference< excel::XSheetObject >( xVbaObject ) ); +} + +// Drawing controls + +namespace { + +class ScVbaControlContainer : public ScVbaObjectContainer +{ +public: + /// @throws uno::RuntimeException + explicit ScVbaControlContainer( + const uno::Reference< XHelperInterface >& rxParent, + const uno::Reference< uno::XComponentContext >& rxContext, + const uno::Reference< frame::XModel >& rxModel, + const uno::Reference< sheet::XSpreadsheet >& rxSheet, + const uno::Type& rVbaType, + const OUString& rModelServiceName, + sal_Int16 /* css::form::FormComponentType */ eType ); + +protected: + /// @throws uno::RuntimeException + uno::Reference< container::XIndexContainer > const & createForm(); + + virtual bool implPickShape( const uno::Reference< drawing::XShape >& rxShape ) const override; + virtual OUString implGetShapeServiceName() const override; + virtual bool implCheckProperties( const uno::Reference< beans::XPropertySet >& rxModelProps ) const; + virtual OUString implGetShapeName( const uno::Reference< drawing::XShape >& rxShape ) const override; + virtual void implOnShapeCreated( const uno::Reference< drawing::XShape >& rxShape ) override; + +protected: + uno::Reference< container::XIndexContainer > mxFormIC; + OUString maModelServiceName; + sal_Int16 /* css::form::FormComponentType */ meType; +}; + +} + +ScVbaControlContainer::ScVbaControlContainer( + const uno::Reference< XHelperInterface >& rxParent, + const uno::Reference< uno::XComponentContext >& rxContext, + const uno::Reference< frame::XModel >& rxModel, + const uno::Reference< sheet::XSpreadsheet >& rxSheet, + const uno::Type& rVbaType, + const OUString& rModelServiceName, + sal_Int16 /* css::form::FormComponentType */ eType ) : + ScVbaObjectContainer( rxParent, rxContext, rxModel, rxSheet, rVbaType ), + maModelServiceName( rModelServiceName ), + meType( eType ) +{ +} + +uno::Reference< container::XIndexContainer > const & ScVbaControlContainer::createForm() +{ + if( !mxFormIC.is() ) + { + uno::Reference< form::XFormsSupplier > xFormsSupp( mxShapes, uno::UNO_QUERY_THROW ); + uno::Reference< container::XNameContainer > xFormsNC( xFormsSupp->getForms(), uno::UNO_SET_THROW ); + OUString aFormName = "Standard"; + if( xFormsNC->hasByName( aFormName ) ) + { + mxFormIC.set( xFormsNC->getByName( aFormName ), uno::UNO_QUERY_THROW ); + } + else + { + uno::Reference< form::XForm > xForm( mxFactory->createInstance( "com.sun.star.form.component.Form" ), uno::UNO_QUERY_THROW ); + xFormsNC->insertByName( aFormName, uno::Any( xForm ) ); + mxFormIC.set( xForm, uno::UNO_QUERY_THROW ); + } + } + return mxFormIC; +} + +bool ScVbaControlContainer::implPickShape( const uno::Reference< drawing::XShape >& rxShape ) const +{ + try + { + uno::Reference< drawing::XControlShape > xControlShape( rxShape, uno::UNO_QUERY_THROW ); + uno::Reference< beans::XPropertySet > xModelProps( xControlShape->getControl(), uno::UNO_QUERY_THROW ); + sal_Int16 nClassId = -1; + return lclGetProperty( nClassId, xModelProps, "ClassId" ) && + (nClassId == meType) && implCheckProperties( xModelProps ); + } + catch( uno::Exception& ) + { + } + return false; +} + +OUString ScVbaControlContainer::implGetShapeServiceName() const +{ + return "com.sun.star.drawing.ControlShape"; +} + +bool ScVbaControlContainer::implCheckProperties( const uno::Reference< beans::XPropertySet >& /*rxModelProps*/ ) const +{ + return true; +} + +OUString ScVbaControlContainer::implGetShapeName( const uno::Reference< drawing::XShape >& rxShape ) const +{ + uno::Reference< drawing::XControlShape > xControlShape( rxShape, uno::UNO_QUERY_THROW ); + return uno::Reference< container::XNamed >( xControlShape->getControl(), uno::UNO_QUERY_THROW )->getName(); +} + +void ScVbaControlContainer::implOnShapeCreated( const uno::Reference< drawing::XShape >& rxShape ) +{ + // passed shape must be a control shape + uno::Reference< drawing::XControlShape > xControlShape( rxShape, uno::UNO_QUERY_THROW ); + + // create the UNO control model + uno::Reference< form::XFormComponent > xFormComponent( mxFactory->createInstance( maModelServiceName ), uno::UNO_QUERY_THROW ); + uno::Reference< awt::XControlModel > xControlModel( xFormComponent, uno::UNO_QUERY_THROW ); + + // insert the control model into the form and the shape + createForm(); + mxFormIC->insertByIndex( mxFormIC->getCount(), uno::Any( xFormComponent ) ); + xControlShape->setControl( xControlModel ); +} + +// Push button + +namespace { + +class ScVbaButtonContainer : public ScVbaControlContainer +{ + bool mbOptionButtons; +public: + /// @throws uno::RuntimeException + explicit ScVbaButtonContainer( + const uno::Reference< XHelperInterface >& rxParent, + const uno::Reference< uno::XComponentContext >& rxContext, + const uno::Reference< frame::XModel >& rxModel, + const uno::Reference< sheet::XSpreadsheet >& rxSheet, + bool bOptionButtons); + +protected: + virtual rtl::Reference<ScVbaSheetObjectBase> implCreateVbaObject( const uno::Reference< drawing::XShape >& rxShape ) override; + virtual bool implCheckProperties( const uno::Reference< beans::XPropertySet >& rxModelProps ) const override; +}; + +} + +ScVbaButtonContainer::ScVbaButtonContainer( + const uno::Reference< XHelperInterface >& rxParent, + const uno::Reference< uno::XComponentContext >& rxContext, + const uno::Reference< frame::XModel >& rxModel, + const uno::Reference< sheet::XSpreadsheet >& rxSheet, + bool bOptionButtons ) : + ScVbaControlContainer( + rxParent, rxContext, rxModel, rxSheet, + cppu::UnoType<excel::XButton>::get(), + ( bOptionButtons ? + OUString( "com.sun.star.form.component.RadioButton" ) : + OUString( "com.sun.star.form.component.CommandButton" ) ), + ( bOptionButtons ? + form::FormComponentType::RADIOBUTTON : + form::FormComponentType::COMMANDBUTTON) ), + mbOptionButtons(bOptionButtons) +{ +} + +rtl::Reference<ScVbaSheetObjectBase> ScVbaButtonContainer::implCreateVbaObject( const uno::Reference< drawing::XShape >& rxShape ) +{ + uno::Reference< drawing::XControlShape > xControlShape( rxShape, uno::UNO_QUERY_THROW ); + return new ScVbaButton( mxParent, mxContext, mxModel, createForm(), xControlShape ); +} + +bool ScVbaButtonContainer::implCheckProperties( const uno::Reference< beans::XPropertySet >& rxModelProps ) const +{ + if (mbOptionButtons) + return true; + + // do not insert toggle buttons into the 'Buttons' collection + bool bToggle = false; + return lclGetProperty( bToggle, rxModelProps, "Toggle" ) && !bToggle; +} + +ScVbaButtons::ScVbaButtons( + const uno::Reference< XHelperInterface >& rxParent, + const uno::Reference< uno::XComponentContext >& rxContext, + const uno::Reference< frame::XModel >& rxModel, + const uno::Reference< sheet::XSpreadsheet >& rxSheet, + bool bOptionButtons) : + ScVbaGraphicObjectsBase( new ScVbaButtonContainer( rxParent, rxContext, rxModel, rxSheet, bOptionButtons ) ) +{ +} + +VBAHELPER_IMPL_XHELPERINTERFACE( ScVbaButtons, "ooo.vba.excel.Buttons" ) + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbasheetobjects.hxx b/sc/source/ui/vba/vbasheetobjects.hxx new file mode 100644 index 000000000..38d2d1c8d --- /dev/null +++ b/sc/source/ui/vba/vbasheetobjects.hxx @@ -0,0 +1,102 @@ +/* -*- 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 . + */ + +#pragma once + +#include <cppuhelper/implbase.hxx> +#include <ooo/vba/excel/XGraphicObjects.hpp> +#include <vbahelper/vbacollectionimpl.hxx> +#include <rtl/ref.hxx> + +namespace com::sun::star { + namespace container { class XEnumeration; } + namespace frame { class XModel; } + namespace sheet { class XSpreadsheet; } +} + +class ScVbaObjectContainer; +typedef ::rtl::Reference< ScVbaObjectContainer > ScVbaObjectContainerRef; + +typedef CollTestImplHelper< ov::XCollection > ScVbaSheetObjects_BASE; + +/** Base class for collections containing a specific type of drawing object + embedded in a sheet (worksheet, chart sheet, or dialog sheet). + */ +class ScVbaSheetObjectsBase : public ScVbaSheetObjects_BASE +{ +public: + /// @throws css::uno::RuntimeException + explicit ScVbaSheetObjectsBase( const ScVbaObjectContainerRef& rxContainer ); + virtual ~ScVbaSheetObjectsBase() override; + + /** Updates the collection by fetching all shapes from the draw page. + + @throws css::uno::RuntimeException + */ + void collectShapes(); + + // XEnumerationAccess + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + + // XElementAccess + virtual css::uno::Type SAL_CALL getElementType() override; + + // ScVbaCollectionBase + virtual css::uno::Any createCollectionObject( const css::uno::Any& rSource ) override; + virtual css::uno::Any getItemByStringIndex( const OUString& rIndex ) override; + +protected: + ScVbaObjectContainerRef mxContainer; +}; + +typedef ::cppu::ImplInheritanceHelper< ScVbaSheetObjectsBase, ov::excel::XGraphicObjects > ScVbaGraphicObjects_BASE; + +/** Base class for collections containing a specific type of graphic object + from a sheet. + */ +class ScVbaGraphicObjectsBase : public ScVbaGraphicObjects_BASE +{ +public: + /// @throws css::uno::RuntimeException + explicit ScVbaGraphicObjectsBase( const ScVbaObjectContainerRef& rxContainer ); + + // XGraphicObjects + virtual css::uno::Any SAL_CALL Add( + const css::uno::Any& rLeft, + const css::uno::Any& rTop, + const css::uno::Any& rWidth, + const css::uno::Any& rHeight ) override; +}; + +/** Collection containing all button controls from a sheet (not ActiveX controls). */ +class ScVbaButtons : public ScVbaGraphicObjectsBase +{ +public: + /// @throws css::uno::RuntimeException + explicit ScVbaButtons( + const css::uno::Reference< ov::XHelperInterface >& rxParent, + const css::uno::Reference< css::uno::XComponentContext >& rxContext, + const css::uno::Reference< css::frame::XModel >& rxModel, + const css::uno::Reference< css::sheet::XSpreadsheet >& rxSheet, + bool bOptionButtons); + + VBAHELPER_DECL_XHELPERINTERFACE +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbastyle.cxx b/sc/source/ui/vba/vbastyle.cxx new file mode 100644 index 000000000..ae393804d --- /dev/null +++ b/sc/source/ui/vba/vbastyle.cxx @@ -0,0 +1,183 @@ +/* -*- 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 "vbastyle.hxx" +#include <basic/sberrors.hxx> +#include <com/sun/star/style/XStyleFamiliesSupplier.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +constexpr OUStringLiteral DISPLAYNAME = u"DisplayName"; + +uno::Reference< container::XNameAccess > +ScVbaStyle::getStylesNameContainer( const uno::Reference< frame::XModel >& xModel ) +{ + uno::Reference< style::XStyleFamiliesSupplier > xStyleSupplier( xModel, uno::UNO_QUERY_THROW); + uno::Reference< container::XNameAccess > xStylesAccess( xStyleSupplier->getStyleFamilies()->getByName("CellStyles"), uno::UNO_QUERY_THROW ); + return xStylesAccess; +} + +/// @throws script::BasicErrorException +/// @throws uno::RuntimeException +static uno::Reference< beans::XPropertySet > +lcl_getStyleProps( const OUString& sStyleName, const uno::Reference< frame::XModel >& xModel ) +{ + + uno::Reference< beans::XPropertySet > xStyleProps( ScVbaStyle::getStylesNameContainer( xModel )->getByName( sStyleName ), uno::UNO_QUERY_THROW ); + return xStyleProps; +} + +void ScVbaStyle::initialise() +{ + if (!mxModel.is() ) + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, u"XModel Interface could not be retrieved" ); + uno::Reference< lang::XServiceInfo > xServiceInfo( mxPropertySet, uno::UNO_QUERY_THROW ); + if ( !xServiceInfo->supportsService("com.sun.star.style.CellStyle") ) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} ); + } + mxStyle.set( mxPropertySet, uno::UNO_QUERY_THROW ); + + uno::Reference< style::XStyleFamiliesSupplier > xStyleSupplier( mxModel, uno::UNO_QUERY_THROW ); + mxStyleFamilyNameContainer.set( ScVbaStyle::getStylesNameContainer( mxModel ), uno::UNO_QUERY_THROW ); + +} + +ScVbaStyle::ScVbaStyle( const uno::Reference< ov::XHelperInterface >& xParent, + const uno::Reference< uno::XComponentContext > & xContext, + const OUString& sStyleName, const uno::Reference< frame::XModel >& _xModel ) + : ScVbaStyle_BASE( xParent, xContext, lcl_getStyleProps( sStyleName, _xModel ), _xModel, false ) +{ + try + { + initialise(); + } + catch (const uno::Exception& ) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } +} + +ScVbaStyle::ScVbaStyle( const uno::Reference< XHelperInterface >& xParent, + const uno::Reference< uno::XComponentContext > & xContext, + const uno::Reference< beans::XPropertySet >& _xPropertySet, + const uno::Reference< frame::XModel >& _xModel ) + : ScVbaStyle_BASE( xParent, xContext, _xPropertySet, _xModel, false ) +{ + try + { + initialise(); + } + catch (const uno::Exception& ) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } +} + +sal_Bool SAL_CALL +ScVbaStyle::BuiltIn() +{ + return !mxStyle->isUserDefined(); + +} +void SAL_CALL +ScVbaStyle::setName( const OUString& Name ) +{ + mxStyle->setName(Name); +} + +OUString SAL_CALL +ScVbaStyle::getName() +{ + return mxStyle->getName(); +} + +void SAL_CALL +ScVbaStyle::setNameLocal( const OUString& NameLocal ) +{ + try + { + mxPropertySet->setPropertyValue(DISPLAYNAME, uno::Any( NameLocal ) ); + } + catch (const uno::Exception& e) + { + DebugHelper::basicexception(e); + } +} + +OUString SAL_CALL +ScVbaStyle::getNameLocal() +{ + OUString sName; + try + { + mxPropertySet->getPropertyValue(DISPLAYNAME) >>= sName; + } + catch (const uno::Exception& ) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} ); + } + return sName; +} + +void SAL_CALL +ScVbaStyle::Delete() +{ + try + { + mxStyleFamilyNameContainer->removeByName(mxStyle->getName()); + } + catch (const uno::Exception& ) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } +} + +void SAL_CALL +ScVbaStyle::setMergeCells( const uno::Any& /*MergeCells*/ ) +{ + DebugHelper::basicexception(ERRCODE_BASIC_NOT_IMPLEMENTED, {}); +} + +uno::Any SAL_CALL +ScVbaStyle::getMergeCells( ) +{ + DebugHelper::basicexception(ERRCODE_BASIC_NOT_IMPLEMENTED, {}); + return uno::Any(); +} + +OUString +ScVbaStyle::getServiceImplName() +{ + return "ScVbaStyle"; +} + +uno::Sequence< OUString > +ScVbaStyle::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.XStyle" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbastyle.hxx b/sc/source/ui/vba/vbastyle.hxx new file mode 100644 index 000000000..cc002ce6f --- /dev/null +++ b/sc/source/ui/vba/vbastyle.hxx @@ -0,0 +1,62 @@ +/* -*- 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 . + */ + +#pragma once + +#include <ooo/vba/excel/XStyle.hpp> +#include <com/sun/star/style/XStyle.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include "vbaformat.hxx" + +typedef ScVbaFormat< ov::excel::XStyle > ScVbaStyle_BASE; + +class ScVbaStyle final : public ScVbaStyle_BASE +{ + css::uno::Reference< css::style::XStyle > mxStyle; + css::uno::Reference< css::container::XNameContainer > mxStyleFamilyNameContainer; + /// @throws css::uno::RuntimeException + /// @throws css::script::BasicErrorException + void initialise(); +public: + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + ScVbaStyle( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const OUString& sStyleName, const css::uno::Reference< css::frame::XModel >& _xModel ); + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + ScVbaStyle( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::beans::XPropertySet >& _xPropertySet, const css::uno::Reference< css::frame::XModel >& _xModel ); + /// @throws css::uno::RuntimeException + static css::uno::Reference< css::container::XNameAccess > getStylesNameContainer( const css::uno::Reference< css::frame::XModel >& xModel ); + virtual css::uno::Reference< ov::XHelperInterface > thisHelperIface() override { return this; }; + // XStyle Methods + virtual sal_Bool SAL_CALL BuiltIn() override; + virtual void SAL_CALL setName( const OUString& Name ) override; + virtual OUString SAL_CALL getName() override; + virtual void SAL_CALL setNameLocal( const OUString& NameLocal ) override; + virtual OUString SAL_CALL getNameLocal() override; + virtual void SAL_CALL Delete() override; + // XFormat + virtual void SAL_CALL setMergeCells( const css::uno::Any& MergeCells ) override; + virtual css::uno::Any SAL_CALL getMergeCells( ) override; + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbastyles.cxx b/sc/source/ui/vba/vbastyles.cxx new file mode 100644 index 000000000..c21adf064 --- /dev/null +++ b/sc/source/ui/vba/vbastyles.cxx @@ -0,0 +1,199 @@ +/* -*- 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 "vbastyles.hxx" +#include "vbastyle.hxx" +#include <basic/sberrors.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <ooo/vba/excel/XRange.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +static css::uno::Any +lcl_createAPIStyleToVBAObject( const css::uno::Any& aObject, const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< frame::XModel >& xModel ) +{ + uno::Reference< beans::XPropertySet > xStyleProps( aObject, uno::UNO_QUERY_THROW ); + uno::Reference< excel::XStyle > xStyle( new ScVbaStyle( xParent, xContext, xStyleProps, xModel ) ); + return uno::Any( xStyle ); +} + +ScVbaStyles::ScVbaStyles( const uno::Reference< XHelperInterface >& xParent, + const uno::Reference< css::uno::XComponentContext > & xContext, + const uno::Reference< frame::XModel >& xModel ) +: ScVbaStyles_BASE( xParent, + xContext, + uno::Reference< container::XIndexAccess >( ScVbaStyle::getStylesNameContainer( xModel ), uno::UNO_QUERY_THROW ) ), + mxModel( xModel ) +{ + try + { + mxMSF.set( mxModel, uno::UNO_QUERY_THROW ); + mxNameContainerCellStyles.set( m_xNameAccess, uno::UNO_QUERY_THROW ); + } + catch (uno::Exception& ) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } +} + +uno::Sequence< OUString > +ScVbaStyles::getStyleNames() +{ + return mxNameContainerCellStyles->getElementNames(); +} + +uno::Any +ScVbaStyles::createCollectionObject(const uno::Any& aObject) +{ + return lcl_createAPIStyleToVBAObject( aObject, mxParent, mxContext, mxModel ); +} + +uno::Type SAL_CALL +ScVbaStyles::getElementType() +{ + return cppu::UnoType<excel::XStyle>::get(); +} + +namespace { + +class EnumWrapper : public EnumerationHelper_BASE +{ + uno::Reference<container::XIndexAccess > m_xIndexAccess; + uno::Reference<XHelperInterface > m_xParent; + uno::Reference<uno::XComponentContext > m_xContext; + uno::Reference<frame::XModel > m_xModel; + + sal_Int32 nIndex; +public: + EnumWrapper( const uno::Reference< container::XIndexAccess >& xIndexAccess, const uno::Reference<XHelperInterface >& xParent, const uno::Reference<uno::XComponentContext >& xContext, const uno::Reference<frame::XModel >& xModel ) : m_xIndexAccess( xIndexAccess ), m_xParent( xParent ), m_xContext( xContext ), m_xModel( xModel ), nIndex( 0 ) {} + virtual sal_Bool SAL_CALL hasMoreElements( ) override + { + return ( nIndex < m_xIndexAccess->getCount() ); + } + virtual uno::Any SAL_CALL nextElement( ) override + { + try + { + if ( nIndex < m_xIndexAccess->getCount() ) + return lcl_createAPIStyleToVBAObject( m_xIndexAccess->getByIndex( nIndex++ ), m_xParent, m_xContext, m_xModel ); + } + catch (const container::NoSuchElementException&) + { + throw; + } + catch (const lang::WrappedTargetException&) + { + throw; + } + catch (const uno::RuntimeException&) + { + throw; + } + catch (const uno::Exception& e) + { + css::uno::Any a(cppu::getCaughtException()); + throw css::lang::WrappedTargetException( + "wrapped Exception " + e.Message, + css::uno::Reference<css::uno::XInterface>(), a); + } + throw container::NoSuchElementException(); + } +}; + +} + +uno::Reference< container::XEnumeration > SAL_CALL +ScVbaStyles::createEnumeration() +{ + return new EnumWrapper( m_xIndexAccess, mxParent, mxContext, mxModel ); +} + +uno::Reference< excel::XStyle > SAL_CALL +ScVbaStyles::Add( const OUString& _sName, const uno::Any& _aBasedOn ) +{ + uno::Reference< excel::XStyle > aRet; + try + { + OUString sParentCellStyleName("Default"); + if ( _aBasedOn.hasValue() ) + { + uno::Reference< excel::XRange > oRange; + if ( _aBasedOn >>= oRange) + { + uno::Reference< excel::XStyle > oStyle( oRange->getStyle(), uno::UNO_QUERY_THROW ); + sParentCellStyleName = oStyle->getName(); + } + else + { + DebugHelper::basicexception(ERRCODE_BASIC_BAD_ARGUMENT, {}); + } + } + + uno::Reference< style::XStyle > xStyle( mxMSF->createInstance("com.sun.star.style.CellStyle"), uno::UNO_QUERY_THROW ); + + if (!mxNameContainerCellStyles->hasByName(_sName)) + { + mxNameContainerCellStyles->insertByName(_sName, uno::Any( xStyle) ); + } + if (sParentCellStyleName != "Default") + { + xStyle->setParentStyle( sParentCellStyleName ); + } + aRet.set( Item( uno::Any( _sName ), uno::Any() ), uno::UNO_QUERY_THROW ); + } + catch (const uno::Exception&) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } + return aRet; +} + +void +ScVbaStyles::Delete(const OUString& _sStyleName) +{ + try + { + if (mxNameContainerCellStyles->hasByName( _sStyleName ) ) + mxNameContainerCellStyles->removeByName( _sStyleName ); + } + catch (const uno::Exception&) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } +} + +OUString +ScVbaStyles::getServiceImplName() +{ + return "ScVbaStyles"; +} + +uno::Sequence< OUString > +ScVbaStyles::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.XStyles" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbastyles.hxx b/sc/source/ui/vba/vbastyles.hxx new file mode 100644 index 000000000..78990bca9 --- /dev/null +++ b/sc/source/ui/vba/vbastyles.hxx @@ -0,0 +1,50 @@ +/* -*- 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 . + */ +#pragma once +#include <ooo/vba/excel/XStyles.hpp> +#include <vbahelper/vbacollectionimpl.hxx> + +namespace com::sun::star::lang { class XMultiServiceFactory; } +namespace com::sun::star::container { class XNameContainer; } + +typedef CollTestImplHelper< ov::excel::XStyles > ScVbaStyles_BASE; +class ScVbaStyles: public ScVbaStyles_BASE +{ + css::uno::Reference< css::frame::XModel > mxModel; + css::uno::Reference< css::lang::XMultiServiceFactory > mxMSF; + css::uno::Reference< css::container::XNameContainer > mxNameContainerCellStyles; +public: + /// @throws css::script::BasicErrorException + ScVbaStyles( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::frame::XModel >& xModel ); + /// @throws css::uno::RuntimeException + css::uno::Sequence< OUString > getStyleNames(); + /// @throws css::script::BasicErrorException + void Delete(const OUString& _sStyleName); + // XStyles + virtual css::uno::Reference< ov::excel::XStyle > SAL_CALL Add( const OUString& Name, const css::uno::Any& BasedOn ) override; + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + virtual css::uno::Any createCollectionObject(const css::uno::Any&) override; + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbatextboxshape.cxx b/sc/source/ui/vba/vbatextboxshape.cxx new file mode 100644 index 000000000..66a85e49e --- /dev/null +++ b/sc/source/ui/vba/vbatextboxshape.cxx @@ -0,0 +1,60 @@ +/* -*- 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 "excelvbahelper.hxx" +#include "vbatextboxshape.hxx" +#include "vbacharacters.hxx" +#include <com/sun/star/text/XSimpleText.hpp> +#include <docsh.hxx> + +using namespace com::sun::star; +using namespace ooo::vba; + +ScVbaTextBoxShape::ScVbaTextBoxShape( const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< drawing::XShape >& xShape, const uno::Reference< drawing::XShapes >& xShapes, const uno::Reference< frame::XModel >& xModel ) : TextBoxShapeImpl_BASE( uno::Reference< XHelperInterface >(), xContext, xShape, xShapes, xModel, ScVbaShape::getType( xShape ) ) +{ + m_xTextRange.set( xShape , uno::UNO_QUERY_THROW ); +} + +OUString SAL_CALL +ScVbaTextBoxShape::getText() +{ + return m_xTextRange->getString(); +} + +void SAL_CALL +ScVbaTextBoxShape::setText( const OUString& _text ) +{ + m_xTextRange->setString( _text ); +} + +uno::Reference< excel::XCharacters > SAL_CALL +ScVbaTextBoxShape::characters( const uno::Any& Start, const uno::Any& Length ) +{ + ScDocShell* pDocShell = excel::getDocShell( m_xModel ); + ScDocument* pDoc = pDocShell ? &pDocShell->GetDocument() : nullptr; + + if ( !pDoc ) + throw uno::RuntimeException("Failed to access document from shell" ); + uno::Reference< text::XSimpleText > xSimple( m_xTextRange, uno::UNO_QUERY_THROW ); + + ScVbaPalette aPalette( pDoc->GetDocumentShell() ); + return new ScVbaCharacters( this, mxContext, aPalette, xSimple, Start, Length, true ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbatextboxshape.hxx b/sc/source/ui/vba/vbatextboxshape.hxx new file mode 100644 index 000000000..c97fca8d8 --- /dev/null +++ b/sc/source/ui/vba/vbatextboxshape.hxx @@ -0,0 +1,39 @@ +/* -*- 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 . + */ +#pragma once +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/text/XTextRange.hpp> +#include <ooo/vba/msforms/XTextBoxShape.hpp> +#include <vbahelper/vbashape.hxx> + +typedef cppu::ImplInheritanceHelper< ScVbaShape, ov::msforms::XTextBoxShape > TextBoxShapeImpl_BASE; + +class ScVbaTextBoxShape : public TextBoxShapeImpl_BASE +{ + css::uno::Reference< css::text::XTextRange > m_xTextRange; +public: + ScVbaTextBoxShape( const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Reference< css::drawing::XShape >& xShape, const css::uno::Reference< css::drawing::XShapes >& xShapes, const css::uno::Reference< css::frame::XModel >& xModel ); + + // Attributes + virtual OUString SAL_CALL getText() override; + virtual void SAL_CALL setText( const OUString& _text ) override; + virtual css::uno::Reference< ov::excel::XCharacters > SAL_CALL characters( const css::uno::Any& Start, const css::uno::Any& Length ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbatextframe.cxx b/sc/source/ui/vba/vbatextframe.cxx new file mode 100644 index 000000000..9f921a8fa --- /dev/null +++ b/sc/source/ui/vba/vbatextframe.cxx @@ -0,0 +1,67 @@ +/* -*- 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 <com/sun/star/drawing/XShape.hpp> +#include <sfx2/objsh.hxx> +#include "vbatextframe.hxx" +#include "vbacharacters.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +ScVbaTextFrame::ScVbaTextFrame( uno::Sequence< uno::Any> const & args, uno::Reference< uno::XComponentContext> const & xContext ) : ScVbaTextFrame_BASE( getXSomethingFromArgs< XHelperInterface >( args, 0 ), xContext, getXSomethingFromArgs< drawing::XShape >( args, 1, false ) ) +{ +} + +// Methods +uno::Any SAL_CALL +ScVbaTextFrame::Characters() +{ + uno::Reference< text::XSimpleText > xSimpleText( m_xShape, uno::UNO_QUERY_THROW ); + ScVbaPalette aPalette( SfxObjectShell::Current() ); + uno::Any aStart( sal_Int32( 1 ) ); + uno::Any aLength(sal_Int32( -1 ) ); + return uno::Any( uno::Reference< ov::excel::XCharacters >( new ScVbaCharacters( this, mxContext, aPalette, xSimpleText, aStart, aLength, true ) ) ); +} + +OUString +ScVbaTextFrame::getServiceImplName() +{ + return "ScVbaTextFrame"; +} + +uno::Sequence< OUString > +ScVbaTextFrame::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.TextFrame" + }; + return aServiceNames; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +ScVbaTextFrame_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &arguments) +{ + return cppu::acquire(new ScVbaTextFrame(arguments, context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbatextframe.hxx b/sc/source/ui/vba/vbatextframe.hxx new file mode 100644 index 000000000..eb7a59a93 --- /dev/null +++ b/sc/source/ui/vba/vbatextframe.hxx @@ -0,0 +1,40 @@ +/* -*- 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 . + */ +#pragma once +#include <cppuhelper/implbase.hxx> +#include <ooo/vba/excel/XTextFrame.hpp> +#include <vbahelper/vbatextframe.hxx> + +//typedef InheritedHelperInterfaceWeakImpl< ov::excel::XTextFrame > ScVbaTextFrame_BASE; +typedef cppu::ImplInheritanceHelper<VbaTextFrame, ov::excel::XTextFrame> ScVbaTextFrame_BASE; + +class ScVbaTextFrame : public ScVbaTextFrame_BASE +{ +public: + /// @throws css::lang::IllegalArgumentException + ScVbaTextFrame(css::uno::Sequence<css::uno::Any> const& aArgs, + css::uno::Reference<css::uno::XComponentContext> const& xContext); + // Methods + virtual css::uno::Any SAL_CALL Characters() override; + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbatitle.hxx b/sc/source/ui/vba/vbatitle.hxx new file mode 100644 index 000000000..550be0060 --- /dev/null +++ b/sc/source/ui/vba/vbatitle.hxx @@ -0,0 +1,141 @@ +/* -*- 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 . + */ +#pragma once + +#include <vbahelper/vbahelperinterface.hxx> +#include "vbainterior.hxx" +#include "vbafont.hxx" +#include "vbapalette.hxx" +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/drawing/XShape.hpp> +#include <com/sun/star/script/BasicErrorException.hpp> +#include <basic/sberrors.hxx> +#include <memory> + +template< typename... Ifc > +class TitleImpl : public InheritedHelperInterfaceImpl< Ifc... > +{ +typedef InheritedHelperInterfaceImpl< Ifc... > BaseClass; + + css::uno::Reference< css::drawing::XShape > xTitleShape; + css::uno::Reference< css::beans::XPropertySet > xShapePropertySet; + std::unique_ptr<ov::ShapeHelper> oShapeHelper; + ScVbaPalette m_Palette; +public: + TitleImpl( const css::uno::Reference< ov::XHelperInterface >& xParent, + const css::uno::Reference< css::uno::XComponentContext >& xContext, + const css::uno::Reference< css::drawing::XShape >& _xTitleShape ) + : BaseClass( xParent, xContext ), xTitleShape( _xTitleShape ), m_Palette(nullptr) + { + xShapePropertySet.set( xTitleShape, css::uno::UNO_QUERY_THROW ); + oShapeHelper.reset( new ov::ShapeHelper(xTitleShape) ); + } + css::uno::Reference< ov::excel::XInterior > SAL_CALL Interior( ) override + { + // #TODO find out what the proper parent should be + // leaving as set by the helperapi for the moment + // #TODO we really need the ScDocument to pass to ScVbaInterior + // otherwise attempts to access the palette will fail + return new ScVbaInterior( BaseClass::mxParent, BaseClass::mxContext, xShapePropertySet ); + } + css::uno::Reference< ov::excel::XFont > SAL_CALL Font( ) override + { + // #TODO find out what the proper parent should be + // leaving as set by the helperapi for the moment + return new ScVbaFont( BaseClass::mxParent, BaseClass::mxContext, m_Palette, xShapePropertySet ); + + } + void SAL_CALL setText( const OUString& Text ) override + { + try + { + xShapePropertySet->setPropertyValue("String", css::uno::Any( Text )); + } + catch ( css::uno::Exception& ) + { + throw css::script::BasicErrorException( OUString(), css::uno::Reference< css::uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() ); + } + } + OUString SAL_CALL getText( ) override + { + OUString sText; + try + { + xShapePropertySet->getPropertyValue("String") >>= sText; + } + catch ( css::uno::Exception& ) + { + throw css::script::BasicErrorException( OUString(), css::uno::Reference< css::uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() ); + } + return sText; + } + + void SAL_CALL setTop( double Top ) override + { + oShapeHelper->setTop( Top ); + } + double SAL_CALL getTop( ) override + { + return oShapeHelper->getTop(); + } + void SAL_CALL setLeft( double Left ) override + { + oShapeHelper->setLeft( Left ); + } + double SAL_CALL getLeft( ) override + { + return oShapeHelper->getLeft(); + } + void SAL_CALL setOrientation( ::sal_Int32 _nOrientation ) override + { + try + { + xShapePropertySet->setPropertyValue("TextRotation", css::uno::Any(_nOrientation*100)); + } + catch (css::uno::Exception& ) + { + throw css::script::BasicErrorException( OUString(), css::uno::Reference< css::uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() ); + } + } + ::sal_Int32 SAL_CALL getOrientation( ) override + { + sal_Int32 nSOOrientation = 0; + try + { + xShapePropertySet->getPropertyValue("TextRotation") >>= nSOOrientation; + } + catch (css::uno::Exception& ) + { + throw css::script::BasicErrorException( OUString(), css::uno::Reference< css::uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() ); + } + return static_cast< sal_Int32 >(nSOOrientation / 100) ; + } +// XHelperInterface + OUString getServiceImplName() override + { + return "TitleImpl"; + } + css::uno::Sequence< OUString > getServiceNames() override + { + static const css::uno::Sequence< OUString > aServiceNames{ "ooo.vba.excel.XTitle" }; + return aServiceNames; + } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbavalidation.cxx b/sc/source/ui/vba/vbavalidation.cxx new file mode 100644 index 000000000..a30b43fe7 --- /dev/null +++ b/sc/source/ui/vba/vbavalidation.cxx @@ -0,0 +1,382 @@ +/* -*- 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 "vbavalidation.hxx" +#include "vbaformatcondition.hxx" +#include <com/sun/star/sheet/XSheetCondition.hpp> +#include <com/sun/star/sheet/ValidationType.hpp> +#include <com/sun/star/sheet/ValidationAlertStyle.hpp> +#include <com/sun/star/table/XCellRange.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <ooo/vba/excel/XlDVType.hpp> +#include <ooo/vba/excel/XlDVAlertStyle.hpp> + +#include <unonames.hxx> +#include <rangelst.hxx> +#include "excelvbahelper.hxx" +#include "vbarange.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +static void +lcl_setValidationProps( const uno::Reference< table::XCellRange >& xRange, const uno::Reference< beans::XPropertySet >& xProps ) +{ + uno::Reference< beans::XPropertySet > xRangeProps( xRange, uno::UNO_QUERY_THROW ); + xRangeProps->setPropertyValue( SC_UNONAME_VALIDAT , uno::Any( xProps ) ); +} + +static uno::Reference< beans::XPropertySet > +lcl_getValidationProps( const uno::Reference< table::XCellRange >& xRange ) +{ + uno::Reference< beans::XPropertySet > xProps( xRange, uno::UNO_QUERY_THROW ); + uno::Reference< beans::XPropertySet > xValProps; + xValProps.set( xProps->getPropertyValue( SC_UNONAME_VALIDAT ), uno::UNO_QUERY_THROW ); + return xValProps; +} + +sal_Bool SAL_CALL +ScVbaValidation::getIgnoreBlank() +{ + uno::Reference< beans::XPropertySet > xProps( lcl_getValidationProps( m_xRange ) ); + bool bBlank = false; + xProps->getPropertyValue( SC_UNONAME_IGNOREBL ) >>= bBlank; + return bBlank; +} + +void SAL_CALL +ScVbaValidation::setIgnoreBlank( sal_Bool _ignoreblank ) +{ + uno::Reference< beans::XPropertySet > xProps( lcl_getValidationProps( m_xRange ) ); + xProps->setPropertyValue( SC_UNONAME_IGNOREBL, uno::Any( _ignoreblank ) ); + lcl_setValidationProps( m_xRange, xProps ); +} + +sal_Bool SAL_CALL +ScVbaValidation::getInCellDropdown() +{ + uno::Reference< beans::XPropertySet > xProps = lcl_getValidationProps( m_xRange ); + sal_Int32 nShowList = 0; + xProps->getPropertyValue( SC_UNONAME_SHOWLIST ) >>= nShowList; + return nShowList != 0; +} + +void SAL_CALL +ScVbaValidation::setInCellDropdown( sal_Bool _incelldropdown ) +{ + sal_Int32 nDropDown = 0; + if ( _incelldropdown ) + nDropDown = 1; + uno::Reference< beans::XPropertySet > xProps( lcl_getValidationProps(m_xRange) ); + xProps->setPropertyValue( SC_UNONAME_SHOWLIST, uno::Any( nDropDown ) ); + lcl_setValidationProps( m_xRange, xProps ); +} + +sal_Bool SAL_CALL +ScVbaValidation::getShowInput() +{ + uno::Reference< beans::XPropertySet > xProps = lcl_getValidationProps( m_xRange ); + bool bShowInput = false; + xProps->getPropertyValue( SC_UNONAME_SHOWINP ) >>= bShowInput; + return bShowInput; +} + +void SAL_CALL +ScVbaValidation:: setShowInput( sal_Bool _showinput ) +{ + uno::Reference< beans::XPropertySet > xProps( lcl_getValidationProps(m_xRange) ); + xProps->setPropertyValue( SC_UNONAME_IGNOREBL, uno::Any( _showinput ) ); + lcl_setValidationProps( m_xRange, xProps ); +} + +sal_Bool SAL_CALL +ScVbaValidation::getShowError() +{ + uno::Reference< beans::XPropertySet > xProps = lcl_getValidationProps( m_xRange ); + bool bShowError = false; + xProps->getPropertyValue( SC_UNONAME_SHOWERR ) >>= bShowError; + return bShowError; +} + +void SAL_CALL +ScVbaValidation::setShowError( sal_Bool _showerror ) +{ + uno::Reference< beans::XPropertySet > xProps( lcl_getValidationProps( m_xRange ) ); + xProps->setPropertyValue( SC_UNONAME_SHOWERR, uno::Any( _showerror ) ); + lcl_setValidationProps( m_xRange, xProps ); +} + +OUString SAL_CALL +ScVbaValidation::getErrorTitle() +{ + uno::Reference< beans::XPropertySet > xProps = lcl_getValidationProps( m_xRange ); + OUString sErrorTitle; + xProps->getPropertyValue( SC_UNONAME_ERRTITLE ) >>= sErrorTitle; + return sErrorTitle; +} + +void +ScVbaValidation::setErrorTitle( const OUString& _errormessage ) +{ + uno::Reference< beans::XPropertySet > xProps( lcl_getValidationProps( m_xRange ) ); + xProps->setPropertyValue( SC_UNONAME_ERRTITLE, uno::Any( _errormessage ) ); + lcl_setValidationProps( m_xRange, xProps ); +} + +OUString SAL_CALL +ScVbaValidation::getInputMessage() +{ + uno::Reference< beans::XPropertySet > xProps = lcl_getValidationProps( m_xRange ); + OUString sMsg; + xProps->getPropertyValue( SC_UNONAME_INPMESS ) >>= sMsg; + return sMsg; +} + +void SAL_CALL +ScVbaValidation::setInputMessage( const OUString& _inputmessage ) +{ + uno::Reference< beans::XPropertySet > xProps( lcl_getValidationProps( m_xRange ) ); + xProps->setPropertyValue( SC_UNONAME_INPMESS, uno::Any( _inputmessage ) ); + lcl_setValidationProps( m_xRange, xProps ); +} + +OUString SAL_CALL +ScVbaValidation::getInputTitle() +{ + uno::Reference< beans::XPropertySet > xProps = lcl_getValidationProps( m_xRange ); + OUString sString; + xProps->getPropertyValue( SC_UNONAME_INPTITLE ) >>= sString; + return sString; +} + +void SAL_CALL +ScVbaValidation::setInputTitle( const OUString& _inputtitle ) +{ + uno::Reference< beans::XPropertySet > xProps( lcl_getValidationProps( m_xRange ) ); + xProps->setPropertyValue( SC_UNONAME_INPTITLE, uno::Any( _inputtitle ) ); + lcl_setValidationProps( m_xRange, xProps ); +} + +OUString SAL_CALL +ScVbaValidation::getErrorMessage() +{ + uno::Reference< beans::XPropertySet > xProps = lcl_getValidationProps( m_xRange ); + OUString sString; + xProps->getPropertyValue( SC_UNONAME_ERRMESS ) >>= sString; + return sString; +} + +void SAL_CALL +ScVbaValidation::setErrorMessage( const OUString& _errormessage ) +{ + uno::Reference< beans::XPropertySet > xProps( lcl_getValidationProps( m_xRange ) ); + xProps->setPropertyValue( SC_UNONAME_ERRMESS, uno::Any( _errormessage ) ); + lcl_setValidationProps( m_xRange, xProps ); +} + +void SAL_CALL +ScVbaValidation::Delete( ) +{ + OUString sBlank; + uno::Reference< beans::XPropertySet > xProps( lcl_getValidationProps( m_xRange ) ); + uno::Reference< sheet::XSheetCondition > xCond( xProps, uno::UNO_QUERY_THROW ); + xProps->setPropertyValue( SC_UNONAME_IGNOREBL, uno::Any( true ) ); + xProps->setPropertyValue( SC_UNONAME_SHOWINP, uno::Any( true ) ); + xProps->setPropertyValue( SC_UNONAME_SHOWERR, uno::Any( true ) ); + xProps->setPropertyValue( SC_UNONAME_ERRTITLE, uno::Any( sBlank ) ); + xProps->setPropertyValue( SC_UNONAME_INPMESS, uno::Any( sBlank) ); + xProps->setPropertyValue( SC_UNONAME_ERRALSTY, uno::Any( sheet::ValidationAlertStyle_STOP) ); + xProps->setPropertyValue( SC_UNONAME_TYPE, uno::Any( sheet::ValidationType_ANY ) ); + xCond->setFormula1( sBlank ); + xCond->setFormula2( sBlank ); + xCond->setOperator( sheet::ConditionOperator_NONE ); + + lcl_setValidationProps( m_xRange, xProps ); +} + +// Fix the defect that validation cannot work when the input should be limited between a lower bound and an upper bound +void SAL_CALL +ScVbaValidation::Add( const uno::Any& Type, const uno::Any& AlertStyle, const uno::Any& Operator, const uno::Any& Formula1, const uno::Any& Formula2 ) +{ + uno::Reference< beans::XPropertySet > xProps( lcl_getValidationProps( m_xRange ) ); + uno::Reference< sheet::XSheetCondition > xCond( xProps, uno::UNO_QUERY_THROW ); + + sheet::ValidationType nValType = sheet::ValidationType_ANY; + xProps->getPropertyValue( SC_UNONAME_TYPE ) >>= nValType; + if ( nValType != sheet::ValidationType_ANY ) + throw uno::RuntimeException("validation object already exists" ); + sal_Int32 nType = -1; + if ( !Type.hasValue() || !( Type >>= nType ) ) + throw uno::RuntimeException("missing required param" ); + + Delete(); // set up defaults + OUString sFormula1; + Formula1 >>= sFormula1; + OUString sFormula2; + Formula2 >>= sFormula2; + switch ( nType ) + { + case excel::XlDVType::xlValidateList: + { + // for validate list + // at least formula1 is required + if ( !Formula1.hasValue() ) + throw uno::RuntimeException("missing param" ); + nValType = sheet::ValidationType_LIST; + xProps->setPropertyValue( SC_UNONAME_TYPE, uno::Any(nValType )); + // #TODO validate required params + // #TODO need to correct the ';' delimited formula on get/set + break; + } + case excel::XlDVType::xlValidateWholeNumber: + nValType = sheet::ValidationType_WHOLE; + xProps->setPropertyValue( SC_UNONAME_TYPE, uno::Any(nValType )); + break; + default: + throw uno::RuntimeException("unsupported operation..." ); + } + + sheet::ValidationAlertStyle eStyle = sheet::ValidationAlertStyle_STOP; + sal_Int32 nVbaAlertStyle = excel::XlDVAlertStyle::xlValidAlertStop; + if ( AlertStyle.hasValue() && ( AlertStyle >>= nVbaAlertStyle ) ) + { + switch( nVbaAlertStyle ) + { + case excel::XlDVAlertStyle::xlValidAlertStop: + // yes I know it's already defaulted but safer to assume + // someone probably could change the code above + eStyle = sheet::ValidationAlertStyle_STOP; + break; + case excel::XlDVAlertStyle::xlValidAlertWarning: + eStyle = sheet::ValidationAlertStyle_WARNING; + break; + case excel::XlDVAlertStyle::xlValidAlertInformation: + eStyle = sheet::ValidationAlertStyle_INFO; + break; + default: + throw uno::RuntimeException("bad param..." ); + + } + } + + xProps->setPropertyValue( SC_UNONAME_ERRALSTY, uno::Any( eStyle ) ); + + // i#108860: fix the defect that validation cannot work when the input + // should be limited between a lower bound and an upper bound + if ( Operator.hasValue() ) + { + css::sheet::ConditionOperator conOperator = ScVbaFormatCondition::retrieveAPIOperator( Operator ); + xCond->setOperator( conOperator ); + } + + if ( !sFormula1.isEmpty() ) + xCond->setFormula1( sFormula1 ); + if ( !sFormula2.isEmpty() ) + xCond->setFormula2( sFormula2 ); + + lcl_setValidationProps( m_xRange, xProps ); +} + +OUString SAL_CALL +ScVbaValidation::getFormula1() +{ + uno::Reference< sheet::XSheetCondition > xCond( lcl_getValidationProps( m_xRange ), uno::UNO_QUERY_THROW ); + OUString sString = xCond->getFormula1(); + + ScRefFlags nFlags = ScRefFlags::ZERO; + ScRangeList aCellRanges; + + ScDocShell* pDocSh = excel::GetDocShellFromRange( m_xRange ); + // in calc validation formula is either a range or formula + // that results in range. + // In VBA both formula and address can have a leading '=' + // in result of getFormula1, however it *seems* that a named range or + // real formula has to (or is expected to) have the '=' + if ( pDocSh && !ScVbaRange::getCellRangesForAddress( nFlags, sString, pDocSh, aCellRanges, formula::FormulaGrammar::CONV_XL_A1, 0 ) ) + sString = "=" + sString; + return sString; +} + +OUString SAL_CALL +ScVbaValidation::getFormula2() +{ + uno::Reference< sheet::XSheetCondition > xCond( lcl_getValidationProps( m_xRange ), uno::UNO_QUERY_THROW ); + return xCond->getFormula2(); +} + +sal_Int32 SAL_CALL +ScVbaValidation::getType() +{ + uno::Reference< beans::XPropertySet > xProps( lcl_getValidationProps( m_xRange ) ); + sheet::ValidationType nValType = sheet::ValidationType_ANY; + xProps->getPropertyValue( SC_UNONAME_TYPE ) >>= nValType; + sal_Int32 nExcelType = excel::XlDVType::xlValidateList; // pick a default + if ( xProps.is() ) + { + switch ( nValType ) + { + case sheet::ValidationType_LIST: + nExcelType = excel::XlDVType::xlValidateList; + break; + case sheet::ValidationType_ANY: // not ANY not really a great match for anything I fear:-( + nExcelType = excel::XlDVType::xlValidateInputOnly; + break; + case sheet::ValidationType_CUSTOM: + nExcelType = excel::XlDVType::xlValidateCustom; + break; + case sheet::ValidationType_WHOLE: + nExcelType = excel::XlDVType::xlValidateWholeNumber; + break; + case sheet::ValidationType_DECIMAL: + nExcelType = excel::XlDVType::xlValidateDecimal; + break; + case sheet::ValidationType_DATE: + nExcelType = excel::XlDVType::xlValidateDate; + break; + case sheet::ValidationType_TIME: + nExcelType = excel::XlDVType::xlValidateTime; + break; + case sheet::ValidationType_TEXT_LEN: + nExcelType = excel::XlDVType::xlValidateTextLength; + break; + case sheet::ValidationType::ValidationType_MAKE_FIXED_SIZE: + default: + break; + } + } + return nExcelType; +} + +OUString +ScVbaValidation::getServiceImplName() +{ + return "ScVbaValidation"; +} + +uno::Sequence< OUString > +ScVbaValidation::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.Validation" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbavalidation.hxx b/sc/source/ui/vba/vbavalidation.hxx new file mode 100644 index 000000000..ab16c0533 --- /dev/null +++ b/sc/source/ui/vba/vbavalidation.hxx @@ -0,0 +1,64 @@ +/* -*- 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 . + */ +#pragma once + +#include <ooo/vba/excel/XValidation.hpp> +#include <vbahelper/vbahelperinterface.hxx> + +namespace com::sun::star::table { class XCellRange; } +namespace com::sun::star::uno { class XComponentContext; } + +typedef InheritedHelperInterfaceWeakImpl<ov::excel::XValidation > ValidationImpl_BASE; + +class ScVbaValidation : public ValidationImpl_BASE +{ + css::uno::Reference< css::table::XCellRange > m_xRange; + +public: + ScVbaValidation( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Reference< css::table::XCellRange >& xRange ) : ValidationImpl_BASE( xParent, xContext ), m_xRange( xRange) {} + // Attributes + virtual sal_Bool SAL_CALL getIgnoreBlank() override; + virtual void SAL_CALL setIgnoreBlank( sal_Bool _ignoreblank ) override; + virtual sal_Bool SAL_CALL getInCellDropdown() override; + virtual void SAL_CALL setInCellDropdown( sal_Bool _incelldropdown ) override; + virtual sal_Bool SAL_CALL getShowInput() override; + virtual void SAL_CALL setShowInput( sal_Bool _showinput ) override; + virtual sal_Bool SAL_CALL getShowError() override; + virtual void SAL_CALL setShowError( sal_Bool _showerror ) override; + virtual OUString SAL_CALL getInputTitle() override; + virtual void SAL_CALL setInputTitle( const OUString& _inputtitle ) override; + virtual OUString SAL_CALL getErrorTitle() override; + virtual void SAL_CALL setErrorTitle( const OUString& _errortitle ) override; + virtual OUString SAL_CALL getInputMessage() override; + virtual void SAL_CALL setInputMessage( const OUString& _inputmessage ) override; + virtual OUString SAL_CALL getErrorMessage() override; + virtual void SAL_CALL setErrorMessage( const OUString& _errormessage ) override; + virtual OUString SAL_CALL getFormula1() override ; + virtual OUString SAL_CALL getFormula2() override; + virtual sal_Int32 SAL_CALL getType() override; + // Methods + virtual void SAL_CALL Delete( ) override; + virtual void SAL_CALL Add( const css::uno::Any& Type, const css::uno::Any& AlertStyle, const css::uno::Any& Operator, const css::uno::Any& Formula1, const css::uno::Any& Formula2 ) override; + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbawindow.cxx b/sc/source/ui/vba/vbawindow.cxx new file mode 100644 index 000000000..3e7cc4f56 --- /dev/null +++ b/sc/source/ui/vba/vbawindow.cxx @@ -0,0 +1,868 @@ +/* -*- 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 "excelvbahelper.hxx" +#include "vbawindow.hxx" +#include "vbaworksheets.hxx" +#include "vbaworksheet.hxx" +#include "vbaworkbook.hxx" +#include "vbapane.hxx" +#include <com/sun/star/sheet/XSpreadsheetDocument.hpp> +#include <com/sun/star/sheet/XSpreadsheet.hpp> +#include <com/sun/star/sheet/XViewSplitable.hpp> +#include <com/sun/star/sheet/XViewFreezable.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/view/DocumentZoomType.hpp> +#include <com/sun/star/table/CellRangeAddress.hpp> +#include <o3tl/safeint.hxx> +#include <ooo/vba/excel/XApplication.hpp> +#include <ooo/vba/excel/XlWindowState.hpp> +#include <ooo/vba/excel/XlWindowView.hpp> +#include <basic/sberrors.hxx> +#include <comphelper/sequence.hxx> +#include <cppuhelper/implbase.hxx> + +#include <docsh.hxx> +#include <tabvwsh.hxx> +#include <docuno.hxx> +#include <sc.hrc> +#include <sfx2/viewfrm.hxx> +#include <vcl/wrkwin.hxx> +#include <unonames.hxx> +#include <markdata.hxx> +#include <unordered_map> + +using namespace ::com::sun::star; +using namespace ::ooo::vba; +using namespace ::ooo::vba::excel::XlWindowState; + +typedef std::unordered_map< OUString, +SCTAB > NameIndexHash; + +typedef std::vector< uno::Reference< sheet::XSpreadsheet > > Sheets; + +typedef ::cppu::WeakImplHelper< container::XEnumerationAccess + , css::container::XIndexAccess + , css::container::XNameAccess + > SelectedSheets_BASE; + +namespace { + +class SelectedSheetsEnum : public ::cppu::WeakImplHelper< container::XEnumeration > +{ +public: + uno::Reference< uno::XComponentContext > m_xContext; + Sheets m_sheets; + uno::Reference< frame::XModel > m_xModel; + Sheets::const_iterator m_it; + + /// @throws uno::RuntimeException + SelectedSheetsEnum( const uno::Reference< uno::XComponentContext >& xContext, Sheets&& sheets, const uno::Reference< frame::XModel >& xModel ) + : m_xContext( xContext ), m_sheets( std::move(sheets) ), m_xModel( xModel ) + { + m_it = m_sheets.begin(); + } + // XEnumeration + virtual sal_Bool SAL_CALL hasMoreElements( ) override + { + return m_it != m_sheets.end(); + } + virtual uno::Any SAL_CALL nextElement( ) override + { + if ( !hasMoreElements() ) + { + throw container::NoSuchElementException(); + } + // #FIXME needs ThisWorkbook as parent + return uno::Any( uno::Reference< excel::XWorksheet > ( new ScVbaWorksheet( uno::Reference< XHelperInterface >(), m_xContext, *(m_it++), m_xModel ) ) ); + } + +}; + +class SelectedSheetsEnumAccess : public SelectedSheets_BASE +{ + uno::Reference< uno::XComponentContext > m_xContext; + NameIndexHash namesToIndices; + Sheets sheets; + uno::Reference< frame::XModel > m_xModel; +public: + SelectedSheetsEnumAccess( const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< frame::XModel >& xModel ):m_xContext( xContext ), m_xModel( xModel ) + { + ScModelObj* pModel = static_cast< ScModelObj* >( m_xModel.get() ); + if ( !pModel ) + throw uno::RuntimeException("Cannot obtain current document" ); + ScDocShell* pDocShell = static_cast<ScDocShell*>(pModel->GetEmbeddedObject()); + if ( !pDocShell ) + throw uno::RuntimeException("Cannot obtain docshell" ); + ScTabViewShell* pViewShell = excel::getBestViewShell( m_xModel ); + if ( !pViewShell ) + throw uno::RuntimeException("Cannot obtain view shell" ); + + SCTAB nTabCount = pDocShell->GetDocument().GetTableCount(); + SCTAB nIndex = 0; + const ScMarkData& rMarkData = pViewShell->GetViewData().GetMarkData(); + sheets.reserve( nTabCount ); + uno::Reference <sheet::XSpreadsheetDocument> xSpreadSheet( m_xModel, uno::UNO_QUERY_THROW ); + uno::Reference <container::XIndexAccess> xIndex( xSpreadSheet->getSheets(), uno::UNO_QUERY_THROW ); + for (const auto& rTab : rMarkData) + { + if (rTab >= nTabCount) + break; + uno::Reference< sheet::XSpreadsheet > xSheet( xIndex->getByIndex( rTab ), uno::UNO_QUERY_THROW ); + uno::Reference< container::XNamed > xNamed( xSheet, uno::UNO_QUERY_THROW ); + sheets.push_back( xSheet ); + namesToIndices[ xNamed->getName() ] = nIndex++; + } + + } + + //XEnumerationAccess + virtual uno::Reference< container::XEnumeration > SAL_CALL createEnumeration( ) override + { + return new SelectedSheetsEnum( m_xContext, std::vector(sheets), m_xModel ); + } + // XIndexAccess + virtual ::sal_Int32 SAL_CALL getCount( ) override + { + return sheets.size(); + } + virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override + { + if ( Index < 0 + || o3tl::make_unsigned( Index ) >= sheets.size() ) + throw lang::IndexOutOfBoundsException(); + + return uno::Any( sheets[ Index ] ); + } + + //XElementAccess + virtual uno::Type SAL_CALL getElementType( ) override + { + return cppu::UnoType<excel::XWorksheet>::get(); + } + + virtual sal_Bool SAL_CALL hasElements( ) override + { + return ( !sheets.empty() ); + } + + //XNameAccess + virtual uno::Any SAL_CALL getByName( const OUString& aName ) override + { + NameIndexHash::const_iterator it = namesToIndices.find( aName ); + if ( it == namesToIndices.end() ) + throw container::NoSuchElementException(); + return uno::Any( sheets[ it->second ] ); + + } + + virtual uno::Sequence< OUString > SAL_CALL getElementNames( ) override + { + return comphelper::mapKeysToSequence( namesToIndices ); + } + + virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override + { + NameIndexHash::const_iterator it = namesToIndices.find( aName ); + return (it != namesToIndices.end()); + } + +}; + +} + +ScVbaWindow::ScVbaWindow( + const uno::Reference< XHelperInterface >& xParent, + const uno::Reference< uno::XComponentContext >& xContext, + const uno::Reference< frame::XModel >& xModel, + const uno::Reference< frame::XController >& xController ) : + WindowImpl_BASE( xParent, xContext, xModel, xController ) +{ + init(); +} + +ScVbaWindow::ScVbaWindow( + const uno::Sequence< uno::Any >& args, + const uno::Reference< uno::XComponentContext >& xContext ) : + WindowImpl_BASE( args, xContext ) +{ + init(); +} + +void +ScVbaWindow::init() +{ + /* This method is called from the constructor, thus the own refcount is + still zero. The implementation of ActivePane() uses a UNO reference of + this (to set this window as parent of the pane object). This requires + the own refcount to be non-zero, otherwise this instance will be + destructed immediately! Guard the call to ActivePane() in try/catch to + not miss the decrementation of the reference count on exception. */ + osl_atomic_increment( &m_refCount ); + try + { + m_xPane = ActivePane(); + } + catch( uno::Exception& ) + { + } + osl_atomic_decrement( &m_refCount ); +} + +uno::Reference< beans::XPropertySet > +ScVbaWindow::getControllerProps() const +{ + return uno::Reference< beans::XPropertySet >( getController(), uno::UNO_QUERY_THROW ); +} + +uno::Reference< beans::XPropertySet > +ScVbaWindow::getFrameProps() const +{ + return uno::Reference< beans::XPropertySet >( getController()->getFrame(), uno::UNO_QUERY_THROW ); +} + +uno::Reference< awt::XDevice > +ScVbaWindow::getDevice() const +{ + return uno::Reference< awt::XDevice >( getWindow(), uno::UNO_QUERY_THROW ); +} + +void +ScVbaWindow::Scroll( const uno::Any& Down, const uno::Any& Up, const uno::Any& ToRight, const uno::Any& ToLeft, bool bLargeScroll ) +{ + if( !m_xPane.is() ) + throw uno::RuntimeException(); + if( bLargeScroll ) + m_xPane->LargeScroll( Down, Up, ToRight, ToLeft ); + else + m_xPane->SmallScroll( Down, Up, ToRight, ToLeft ); +} + +void SAL_CALL +ScVbaWindow::SmallScroll( const uno::Any& Down, const uno::Any& Up, const uno::Any& ToRight, const uno::Any& ToLeft ) +{ + Scroll( Down, Up, ToRight, ToLeft, false ); +} + +void SAL_CALL +ScVbaWindow::LargeScroll( const uno::Any& Down, const uno::Any& Up, const uno::Any& ToRight, const uno::Any& ToLeft ) +{ + Scroll( Down, Up, ToRight, ToLeft, true ); +} + +uno::Any SAL_CALL +ScVbaWindow::SelectedSheets( const uno::Any& aIndex ) +{ + uno::Reference< container::XEnumerationAccess > xEnumAccess( new SelectedSheetsEnumAccess( mxContext, m_xModel ) ); + // #FIXME needs a workbook as a parent + uno::Reference< excel::XWorksheets > xSheets( new ScVbaWorksheets( uno::Reference< XHelperInterface >(), mxContext, xEnumAccess, m_xModel ) ); + if ( aIndex.hasValue() ) + { + uno::Reference< XCollection > xColl( xSheets, uno::UNO_QUERY_THROW ); + return xColl->Item( aIndex, uno::Any() ); + } + return uno::Any( xSheets ); +} + +void SAL_CALL +ScVbaWindow::ScrollWorkbookTabs( const uno::Any& /*Sheets*/, const uno::Any& /*Position*/ ) +{ +// #TODO #FIXME need some implementation to scroll through the tabs +// but where is this done? +/* + sal_Int32 nSheets = 0; + sal_Int32 nPosition = 0; + throw uno::RuntimeException("No Implemented" ); + sal_Bool bSheets = ( Sheets >>= nSheets ); + sal_Bool bPosition = ( Position >>= nPosition ); + if ( bSheets || bPosition ) // at least one param specified + if ( bSheets ) + ;// use sheets + else if ( bPosition ) + ; //use position +*/ + +} + +uno::Any SAL_CALL +ScVbaWindow::getCaption() +{ + // tdf#118129 - return only the caption property of the frame + OUString sTitle; + getFrameProps()->getPropertyValue(SC_UNONAME_TITLE) >>= sTitle; + return uno::Any( sTitle ); +} + +void SAL_CALL +ScVbaWindow::setCaption( const uno::Any& _caption ) +{ + getFrameProps()->setPropertyValue( SC_UNONAME_TITLE, _caption ); +} + +uno::Any SAL_CALL +ScVbaWindow::getScrollRow() +{ + sal_Int32 nValue = 0; + // !! TODO !! get view shell from controller + ScTabViewShell* pViewShell = excel::getBestViewShell( m_xModel ); + if ( pViewShell ) + { + ScSplitPos eWhich = pViewShell->GetViewData().GetActivePart(); + nValue = pViewShell->GetViewData().GetPosY(WhichV(eWhich)); + } + + return uno::Any( nValue + 1); +} + +void SAL_CALL +ScVbaWindow::setScrollRow( const uno::Any& _scrollrow ) +{ + // !! TODO !! get view shell from controller + ScTabViewShell* pViewShell = excel::getBestViewShell( m_xModel ); + if ( pViewShell ) + { + sal_Int32 scrollRow = 0; + _scrollrow >>= scrollRow; + ScSplitPos eWhich = pViewShell->GetViewData().GetActivePart(); + sal_Int32 nOldValue = pViewShell->GetViewData().GetPosY(WhichV(eWhich)) + 1; + pViewShell->ScrollLines(0, scrollRow - nOldValue); + } +} + +uno::Any SAL_CALL +ScVbaWindow::getScrollColumn() +{ + sal_Int32 nValue = 0; + // !! TODO !! get view shell from controller + ScTabViewShell* pViewShell = excel::getBestViewShell( m_xModel ); + if ( pViewShell ) + { + ScSplitPos eWhich = pViewShell->GetViewData().GetActivePart(); + nValue = pViewShell->GetViewData().GetPosX(WhichH(eWhich)); + } + + return uno::Any( nValue + 1); +} + +void SAL_CALL +ScVbaWindow::setScrollColumn( const uno::Any& _scrollcolumn ) +{ + // !! TODO !! get view shell from controller + ScTabViewShell* pViewShell = excel::getBestViewShell( m_xModel ); + if ( pViewShell ) + { + sal_Int32 scrollColumn = 0; + _scrollcolumn >>= scrollColumn; + ScSplitPos eWhich = pViewShell->GetViewData().GetActivePart(); + sal_Int32 nOldValue = pViewShell->GetViewData().GetPosX(WhichH(eWhich)) + 1; + pViewShell->ScrollLines(scrollColumn - nOldValue, 0); + } +} + +uno::Any SAL_CALL +ScVbaWindow::getWindowState() +{ + sal_Int32 nwindowState = xlNormal; + // !! TODO !! get view shell from controller + ScTabViewShell* pViewShell = excel::getBestViewShell( m_xModel ); + SfxViewFrame* pViewFrame = pViewShell -> GetViewFrame(); + WorkWindow* pWork = static_cast<WorkWindow*>( pViewFrame->GetFrame().GetSystemWindow() ); + if ( pWork ) + { + if ( pWork -> IsMaximized()) + nwindowState = xlMaximized; + else if (pWork -> IsMinimized()) + nwindowState = xlMinimized; + } + return uno::Any( nwindowState ); +} + +void SAL_CALL +ScVbaWindow::setWindowState( const uno::Any& _windowstate ) +{ + sal_Int32 nwindowState = xlMaximized; + _windowstate >>= nwindowState; + // !! TODO !! get view shell from controller + ScTabViewShell* pViewShell = excel::getBestViewShell( m_xModel ); + SfxViewFrame* pViewFrame = pViewShell -> GetViewFrame(); + WorkWindow* pWork = static_cast<WorkWindow*>( pViewFrame->GetFrame().GetSystemWindow() ); + if ( pWork ) + { + if ( nwindowState == xlMaximized) + pWork -> Maximize(); + else if (nwindowState == xlMinimized) + pWork -> Minimize(); + else if (nwindowState == xlNormal) + pWork -> Restore(); + else + throw uno::RuntimeException("Invalid Parameter" ); + } +} + +void +ScVbaWindow::Activate() +{ + rtl::Reference<ScVbaWorkbook> workbook( new ScVbaWorkbook( uno::Reference< XHelperInterface >( Application(), uno::UNO_QUERY_THROW ), mxContext, m_xModel ) ); + + workbook->Activate(); +} + +void +ScVbaWindow::Close( const uno::Any& SaveChanges, const uno::Any& FileName, const uno::Any& RouteWorkBook ) +{ + rtl::Reference< ScVbaWorkbook > workbook( new ScVbaWorkbook( uno::Reference< XHelperInterface >( Application(), uno::UNO_QUERY_THROW ), mxContext, m_xModel ) ); + workbook->Close(SaveChanges, FileName, RouteWorkBook ); +} + +uno::Reference< excel::XPane > SAL_CALL +ScVbaWindow::ActivePane() +{ + uno::Reference< sheet::XViewPane > xViewPane( getController(), uno::UNO_QUERY_THROW ); + return new ScVbaPane( this, mxContext, m_xModel, xViewPane ); +} + +uno::Reference< excel::XRange > SAL_CALL +ScVbaWindow::ActiveCell( ) +{ + uno::Reference< excel::XApplication > xApplication( Application(), uno::UNO_QUERY_THROW ); + return xApplication->getActiveCell(); +} + +uno::Any SAL_CALL +ScVbaWindow::Selection( ) +{ + uno::Reference< excel::XApplication > xApplication( Application(), uno::UNO_QUERY_THROW ); + return xApplication->getSelection(); +} + +uno::Reference< excel::XRange > SAL_CALL +ScVbaWindow::RangeSelection() +{ + /* TODO / FIXME: According to documentation, this method returns the range + selection even if shapes are selected. */ + return uno::Reference< excel::XRange >( Selection(), uno::UNO_QUERY_THROW ); +} + +sal_Bool SAL_CALL +ScVbaWindow::getDisplayGridlines() +{ + bool bGrid = true; + getControllerProps()->getPropertyValue( SC_UNO_SHOWGRID ) >>= bGrid; + return bGrid; +} + +void SAL_CALL +ScVbaWindow::setDisplayGridlines( sal_Bool _displaygridlines ) +{ + getControllerProps()->setPropertyValue( SC_UNO_SHOWGRID, uno::Any( _displaygridlines )); +} + +sal_Bool SAL_CALL +ScVbaWindow::getDisplayHeadings() +{ + bool bHeading = true; + getControllerProps()->getPropertyValue( SC_UNO_COLROWHDR ) >>= bHeading; + return bHeading; +} + +void SAL_CALL +ScVbaWindow::setDisplayHeadings( sal_Bool _bDisplayHeadings ) +{ + getControllerProps()->setPropertyValue( SC_UNO_COLROWHDR, uno::Any( _bDisplayHeadings )); +} + +sal_Bool SAL_CALL +ScVbaWindow::getDisplayHorizontalScrollBar() +{ + bool bHorizontalScrollBar = true; + getControllerProps()->getPropertyValue( SC_UNO_HORSCROLL ) >>= bHorizontalScrollBar; + return bHorizontalScrollBar; +} + +void SAL_CALL +ScVbaWindow::setDisplayHorizontalScrollBar( sal_Bool _bDisplayHorizontalScrollBar ) +{ + getControllerProps()->setPropertyValue( SC_UNO_HORSCROLL, uno::Any( _bDisplayHorizontalScrollBar )); +} + +sal_Bool SAL_CALL +ScVbaWindow::getDisplayOutline() +{ + bool bOutline = true; + getControllerProps()->getPropertyValue( SC_UNO_OUTLSYMB ) >>= bOutline; + return bOutline; +} + +void SAL_CALL +ScVbaWindow::setDisplayOutline( sal_Bool _bDisplayOutline ) +{ + getControllerProps()->setPropertyValue( SC_UNO_OUTLSYMB, uno::Any( _bDisplayOutline )); +} + +sal_Bool SAL_CALL +ScVbaWindow::getDisplayVerticalScrollBar() +{ + bool bVerticalScrollBar = true; + getControllerProps()->getPropertyValue( SC_UNO_VERTSCROLL ) >>= bVerticalScrollBar; + return bVerticalScrollBar; +} + +void SAL_CALL +ScVbaWindow::setDisplayVerticalScrollBar( sal_Bool _bDisplayVerticalScrollBar ) +{ + getControllerProps()->setPropertyValue( SC_UNO_VERTSCROLL, uno::Any( _bDisplayVerticalScrollBar )); +} + +sal_Bool SAL_CALL +ScVbaWindow::getDisplayWorkbookTabs() +{ + bool bWorkbookTabs = true; + getControllerProps()->getPropertyValue( SC_UNO_SHEETTABS ) >>= bWorkbookTabs; + return bWorkbookTabs; +} + +void SAL_CALL +ScVbaWindow::setDisplayWorkbookTabs( sal_Bool _bDisplayWorkbookTabs ) +{ + getControllerProps()->setPropertyValue( SC_UNO_SHEETTABS, uno::Any( _bDisplayWorkbookTabs )); +} + +sal_Bool SAL_CALL +ScVbaWindow::getFreezePanes() +{ + uno::Reference< sheet::XViewFreezable > xViewFreezable( getController(), uno::UNO_QUERY_THROW ); + return xViewFreezable->hasFrozenPanes(); +} + +void SAL_CALL +ScVbaWindow::setFreezePanes( sal_Bool _bFreezePanes ) +{ + uno::Reference< sheet::XViewPane > xViewPane( getController(), uno::UNO_QUERY_THROW ); + uno::Reference< sheet::XViewSplitable > xViewSplitable( xViewPane, uno::UNO_QUERY_THROW ); + uno::Reference< sheet::XViewFreezable > xViewFreezable( xViewPane, uno::UNO_QUERY_THROW ); + if( _bFreezePanes ) + { + if( xViewSplitable->getIsWindowSplit() ) + { + // if there is a split we freeze at the split + sal_Int32 nColumn = getSplitColumn(); + sal_Int32 nRow = getSplitRow(); + xViewFreezable->freezeAtPosition( nColumn, nRow ); + } + else + { + // otherwise we freeze in the center of the visible sheet + table::CellRangeAddress aCellRangeAddress = xViewPane->getVisibleRange(); + sal_Int32 nColumn = aCellRangeAddress.StartColumn + (( aCellRangeAddress.EndColumn - aCellRangeAddress.StartColumn )/2 ); + sal_Int32 nRow = aCellRangeAddress.StartRow + (( aCellRangeAddress.EndRow - aCellRangeAddress.StartRow )/2 ); + xViewFreezable->freezeAtPosition( nColumn, nRow ); + } + } + else + { + //remove the freeze panes + xViewSplitable->splitAtPosition(0,0); + } +} + +sal_Bool SAL_CALL +ScVbaWindow::getSplit() +{ + uno::Reference< sheet::XViewSplitable > xViewSplitable( getController(), uno::UNO_QUERY_THROW ); + return xViewSplitable->getIsWindowSplit(); +} + +void SAL_CALL +ScVbaWindow::setSplit( sal_Bool _bSplit ) +{ + if( !_bSplit ) + { + uno::Reference< sheet::XViewSplitable > xViewSplitable( getController(), uno::UNO_QUERY_THROW ); + xViewSplitable->splitAtPosition(0,0); + } + else + { + uno::Reference< sheet::XViewFreezable > xViewFreezable( getController(), uno::UNO_QUERY_THROW ); + uno::Reference< excel::XRange > xRange = ActiveCell(); + sal_Int32 nRow = xRange->getRow(); + sal_Int32 nColumn = xRange->getColumn(); + SplitAtDefinedPosition( nColumn-1, nRow-1 ); + } +} + +sal_Int32 SAL_CALL +ScVbaWindow::getSplitColumn() +{ + uno::Reference< sheet::XViewSplitable > xViewSplitable( getController(), uno::UNO_QUERY_THROW ); + return xViewSplitable->getSplitColumn(); +} + +void SAL_CALL +ScVbaWindow::setSplitColumn( sal_Int32 _splitcolumn ) +{ + if( getSplitColumn() != _splitcolumn ) + { + uno::Reference< sheet::XViewFreezable > xViewFreezable( getController(), uno::UNO_QUERY_THROW ); + sal_Int32 nRow = getSplitRow(); + SplitAtDefinedPosition( _splitcolumn, nRow ); + } +} + +double SAL_CALL +ScVbaWindow::getSplitHorizontal() +{ + uno::Reference< sheet::XViewSplitable > xViewSplitable( getController(), uno::UNO_QUERY_THROW ); + return PixelsToPoints( getDevice(), xViewSplitable->getSplitHorizontal(), true ); +} + +void SAL_CALL +ScVbaWindow::setSplitHorizontal( double _splithorizontal ) +{ + uno::Reference< sheet::XViewSplitable > xViewSplitable( getController(), uno::UNO_QUERY_THROW ); + double fHoriPixels = PointsToPixels( getDevice(), _splithorizontal, true ); + xViewSplitable->splitAtPosition( static_cast< sal_Int32 >( fHoriPixels ), 0 ); +} + +sal_Int32 SAL_CALL +ScVbaWindow::getSplitRow() +{ + uno::Reference< sheet::XViewSplitable > xViewSplitable( getController(), uno::UNO_QUERY_THROW ); + return xViewSplitable->getSplitRow(); +} + +void SAL_CALL +ScVbaWindow::setSplitRow( sal_Int32 _splitrow ) +{ + if( getSplitRow() != _splitrow ) + { + uno::Reference< sheet::XViewFreezable > xViewFreezable( getController(), uno::UNO_QUERY_THROW ); + sal_Int32 nColumn = getSplitColumn(); + SplitAtDefinedPosition( nColumn, _splitrow ); + } +} + +double SAL_CALL +ScVbaWindow::getSplitVertical() +{ + uno::Reference< sheet::XViewSplitable > xViewSplitable( getController(), uno::UNO_QUERY_THROW ); + return PixelsToPoints( getDevice(), xViewSplitable->getSplitVertical(), false ); +} + +void SAL_CALL +ScVbaWindow::setSplitVertical(double _splitvertical ) +{ + uno::Reference< sheet::XViewSplitable > xViewSplitable( getController(), uno::UNO_QUERY_THROW ); + double fVertiPixels = PointsToPixels( getDevice(), _splitvertical, false ); + xViewSplitable->splitAtPosition( 0, static_cast<sal_Int32>( fVertiPixels ) ); +} + +void ScVbaWindow::SplitAtDefinedPosition( sal_Int32 nColumns, sal_Int32 nRows ) +{ + uno::Reference< sheet::XViewSplitable > xViewSplitable( getController(), uno::UNO_QUERY_THROW ); + uno::Reference< sheet::XViewFreezable > xViewFreezable( xViewSplitable, uno::UNO_QUERY_THROW ); + // nColumns and nRows means split columns/rows + if( nColumns == 0 && nRows == 0 ) + return; + + sal_Int32 cellColumn = nColumns + 1; + sal_Int32 cellRow = nRows + 1; + + ScTabViewShell* pViewShell = excel::getBestViewShell( m_xModel ); + if ( pViewShell ) + { + //firstly remove the old splitter + xViewSplitable->splitAtPosition(0,0); + + uno::Reference< excel::XApplication > xApplication( Application(), uno::UNO_QUERY_THROW ); + uno::Reference< excel::XWorksheet > xSheet( xApplication->getActiveSheet(), uno::UNO_SET_THROW ); + xSheet->Cells(uno::Any(cellRow), uno::Any(cellColumn))->Select(); + + //pViewShell->FreezeSplitters( FALSE ); + dispatchExecute( pViewShell, SID_WINDOW_SPLIT ); + } +} + +uno::Any SAL_CALL +ScVbaWindow::getZoom() +{ + uno::Reference< beans::XPropertySet > xProps = getControllerProps(); + OUString sName( SC_UNO_ZOOMTYPE ); + sal_Int16 nZoomType = view::DocumentZoomType::PAGE_WIDTH; + xProps->getPropertyValue( sName ) >>= nZoomType; + if( nZoomType == view::DocumentZoomType::PAGE_WIDTH ) + { + return uno::Any( true ); + } + else if( nZoomType == view::DocumentZoomType::BY_VALUE ) + { + sName = SC_UNO_ZOOMVALUE; + sal_Int16 nZoom = 100; + xProps->getPropertyValue( sName ) >>= nZoom; + return uno::Any( nZoom ); + } + return uno::Any(); +} + +void SAL_CALL ScVbaWindow::setZoom(const uno::Any& _zoom) +{ + sal_Int16 nZoom = 100; + _zoom >>= nZoom; + uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( m_xModel, uno::UNO_QUERY_THROW ); + uno::Reference< excel::XWorksheet > xActiveSheet = ActiveSheet(); + SCTAB nTab = 0; + if ( !ScVbaWorksheets::nameExists (xSpreadDoc, xActiveSheet->getName(), nTab) ) + throw uno::RuntimeException(); + std::vector< SCTAB > vTabs { nTab }; + excel::implSetZoom( m_xModel, nZoom, vTabs ); +} + +uno::Reference< excel::XWorksheet > SAL_CALL +ScVbaWindow::ActiveSheet( ) +{ + uno::Reference< excel::XApplication > xApplication( Application(), uno::UNO_QUERY_THROW ); + return xApplication->getActiveSheet(); +} + +uno::Any SAL_CALL +ScVbaWindow::getView() +{ + bool bPageBreak = false; + sal_Int32 nWindowView = excel::XlWindowView::xlNormalView; + + ScTabViewShell* pViewShell = excel::getBestViewShell( m_xModel ); + if (pViewShell) + bPageBreak = pViewShell->GetViewData().IsPagebreakMode(); + + if( bPageBreak ) + nWindowView = excel::XlWindowView::xlPageBreakPreview; + else + nWindowView = excel::XlWindowView::xlNormalView; + + return uno::Any( nWindowView ); +} + +void SAL_CALL +ScVbaWindow::setView( const uno::Any& _view) +{ + sal_Int32 nWindowView = excel::XlWindowView::xlNormalView; + _view >>= nWindowView; + sal_uInt16 nSlot = FID_NORMALVIEWMODE; + switch ( nWindowView ) + { + case excel::XlWindowView::xlNormalView: + nSlot = FID_NORMALVIEWMODE; + break; + case excel::XlWindowView::xlPageBreakPreview: + nSlot = FID_PAGEBREAKMODE; + break; + default: + DebugHelper::runtimeexception(ERRCODE_BASIC_BAD_PARAMETER); + } + // !! TODO !! get view shell from controller + ScTabViewShell* pViewShell = excel::getBestViewShell( m_xModel ); + if ( pViewShell ) + dispatchExecute( pViewShell, nSlot ); +} + +uno::Reference< excel::XRange > SAL_CALL +ScVbaWindow::getVisibleRange() +{ + uno::Reference< container::XIndexAccess > xPanesIA( getController(), uno::UNO_QUERY_THROW ); + uno::Reference< sheet::XViewPane > xTopLeftPane( xPanesIA->getByIndex( 0 ), uno::UNO_QUERY_THROW ); + uno::Reference< excel::XPane > xPane( new ScVbaPane( this, mxContext, m_xModel, xTopLeftPane ) ); + return xPane->getVisibleRange(); +} + +sal_Int32 SAL_CALL +ScVbaWindow::PointsToScreenPixelsX(sal_Int32 _points) +{ + sal_Int32 nHundredthsofOneMillimeters = Millimeter::getInHundredthsOfOneMillimeter( _points ); + double fConvertFactor = getDevice()->getInfo().PixelPerMeterX/100000; + return static_cast<sal_Int32>(fConvertFactor * nHundredthsofOneMillimeters ); +} + +sal_Int32 SAL_CALL +ScVbaWindow::PointsToScreenPixelsY(sal_Int32 _points) +{ + sal_Int32 nHundredthsofOneMillimeters = Millimeter::getInHundredthsOfOneMillimeter( _points ); + double fConvertFactor = getDevice()->getInfo().PixelPerMeterY/100000; + return static_cast<sal_Int32>(fConvertFactor * nHundredthsofOneMillimeters ); +} + +void SAL_CALL +ScVbaWindow::PrintOut( const css::uno::Any& From, const css::uno::Any&To, const css::uno::Any& Copies, const css::uno::Any& Preview, const css::uno::Any& ActivePrinter, const css::uno::Any& PrintToFile, const css::uno::Any& Collate, const css::uno::Any& PrToFileName ) +{ + // need test, print current active sheet + // !! TODO !! get view shell from controller + PrintOutHelper( excel::getBestViewShell( m_xModel ), From, To, Copies, Preview, ActivePrinter, PrintToFile, Collate, PrToFileName, true ); +} + +void SAL_CALL +ScVbaWindow::PrintPreview( const css::uno::Any& EnableChanges ) +{ + // need test, print preview current active sheet + // !! TODO !! get view shell from controller + PrintPreviewHelper( EnableChanges, excel::getBestViewShell( m_xModel ) ); +} + +double SAL_CALL ScVbaWindow::getTabRatio() +{ + ScTabViewShell* pViewShell = excel::getBestViewShell( m_xModel ); + if ( pViewShell && pViewShell->GetViewData().GetView() ) + { + double fRatio = ScTabView::GetRelTabBarWidth(); + if ( fRatio >= 0.0 && fRatio <= 1.0 ) + return fRatio; + } + return 0.0; +} + +void SAL_CALL ScVbaWindow::setTabRatio( double fRatio ) +{ + ScTabViewShell* pViewShell = excel::getBestViewShell( m_xModel ); + if ( pViewShell && pViewShell->GetViewData().GetView() ) + { + if ( fRatio >= 0.0 && fRatio <= 1.0 ) + pViewShell->GetViewData().GetView()->SetRelTabBarWidth( fRatio ); + } +} + +OUString +ScVbaWindow::getServiceImplName() +{ + return "ScVbaWindow"; +} + +uno::Sequence< OUString > +ScVbaWindow::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.Window" + }; + return aServiceNames; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +Calc_ScVbaWindow_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& args) +{ + return cppu::acquire(new ScVbaWindow(args, context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbawindow.hxx b/sc/source/ui/vba/vbawindow.hxx new file mode 100644 index 000000000..c4c0a0bec --- /dev/null +++ b/sc/source/ui/vba/vbawindow.hxx @@ -0,0 +1,126 @@ +/* -*- 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 . + */ +#pragma once + +#include <ooo/vba/excel/XWindow.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <ooo/vba/excel/XPane.hpp> +#include <com/sun/star/awt/XDevice.hpp> +#include <cppuhelper/implbase.hxx> + +#include <vbahelper/vbawindowbase.hxx> + +typedef cppu::ImplInheritanceHelper< VbaWindowBase, ov::excel::XWindow > WindowImpl_BASE; + +class ScVbaWindow : public WindowImpl_BASE +{ +private: + css::uno::Reference< ov::excel::XPane > m_xPane; + + void init(); + /// @throws css::uno::RuntimeException + css::uno::Reference< css::beans::XPropertySet > getControllerProps() const; + /// @throws css::uno::RuntimeException + css::uno::Reference< css::beans::XPropertySet > getFrameProps() const; + /// @throws css::uno::RuntimeException + css::uno::Reference< css::awt::XDevice > getDevice() const; + +protected: + void SplitAtDefinedPosition( sal_Int32 nColumns, sal_Int32 nRows ); + +public: + /// @throws css::uno::RuntimeException + void Scroll( const css::uno::Any& Down, const css::uno::Any& Up, const css::uno::Any& ToRight, const css::uno::Any& ToLeft, bool bLargeScroll ); + +public: + /// @throws css::uno::RuntimeException + ScVbaWindow( + const css::uno::Reference< ov::XHelperInterface >& xParent, + const css::uno::Reference< css::uno::XComponentContext >& xContext, + const css::uno::Reference< css::frame::XModel >& xModel, + const css::uno::Reference< css::frame::XController >& xController ); + /// @throws css::uno::RuntimeException + ScVbaWindow( + const css::uno::Sequence< css::uno::Any >& aArgs, + const css::uno::Reference< css::uno::XComponentContext >& xContext ); + + // XWindow + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL ActiveCell( ) override; + virtual css::uno::Reference< ov::excel::XPane > SAL_CALL ActivePane() override; + virtual css::uno::Reference< ov::excel::XWorksheet > SAL_CALL ActiveSheet( ) override; + virtual void SAL_CALL setCaption( const css::uno::Any& _caption ) override; + virtual css::uno::Any SAL_CALL getCaption() override; + virtual sal_Bool SAL_CALL getDisplayGridlines() override; + virtual void SAL_CALL setDisplayGridlines( sal_Bool _displaygridlines ) override; + virtual sal_Bool SAL_CALL getDisplayHeadings() override; + virtual void SAL_CALL setDisplayHeadings( sal_Bool _bDisplayHeadings ) override; + virtual sal_Bool SAL_CALL getDisplayHorizontalScrollBar() override; + virtual void SAL_CALL setDisplayHorizontalScrollBar( sal_Bool _bDisplayHorizontalScrollBar ) override; + virtual sal_Bool SAL_CALL getDisplayOutline() override; + virtual void SAL_CALL setDisplayOutline( sal_Bool _bDisplayOutline ) override; + virtual sal_Bool SAL_CALL getDisplayVerticalScrollBar() override; + virtual void SAL_CALL setDisplayVerticalScrollBar( sal_Bool _bDisplayVerticalScrollBar ) override; + virtual sal_Bool SAL_CALL getDisplayWorkbookTabs() override; + virtual void SAL_CALL setDisplayWorkbookTabs( sal_Bool _bDisplayWorkbookTabs ) override; + virtual sal_Bool SAL_CALL getFreezePanes() override; + virtual void SAL_CALL setFreezePanes( sal_Bool _bFreezePanes ) override; + virtual sal_Bool SAL_CALL getSplit() override; + virtual void SAL_CALL setSplit( sal_Bool _bSplit ) override; + virtual sal_Int32 SAL_CALL getSplitColumn() override ; + virtual void SAL_CALL setSplitColumn( sal_Int32 _splitcolumn ) override ; + virtual double SAL_CALL getSplitHorizontal() override ; + virtual void SAL_CALL setSplitHorizontal( double _splithorizontal ) override ; + virtual sal_Int32 SAL_CALL getSplitRow() override ; + virtual void SAL_CALL setSplitRow( sal_Int32 _splitrow ) override ; + virtual double SAL_CALL getSplitVertical() override ; + virtual void SAL_CALL setSplitVertical( double _splitvertical ) override ; + virtual css::uno::Any SAL_CALL getScrollRow() override ; + virtual void SAL_CALL setScrollRow( const css::uno::Any& _scrollrow ) override ; + virtual css::uno::Any SAL_CALL getScrollColumn() override ; + virtual void SAL_CALL setScrollColumn( const css::uno::Any& _scrollcolumn ) override ; + virtual css::uno::Any SAL_CALL getView() override; + virtual void SAL_CALL setView( const css::uno::Any& _view ) override; + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL getVisibleRange() override; + virtual css::uno::Any SAL_CALL getWindowState() override; + virtual void SAL_CALL setWindowState( const css::uno::Any& _windowstate ) override; + virtual css::uno::Any SAL_CALL getZoom() override; + virtual void SAL_CALL setZoom(const css::uno::Any& _zoom) override; + virtual double SAL_CALL getTabRatio() override ; + virtual void SAL_CALL setTabRatio( double _tabratio ) override ; + + // Methods + virtual void SAL_CALL SmallScroll( const css::uno::Any& Down, const css::uno::Any& Up, const css::uno::Any& ToRight, const css::uno::Any& ToLeft ) override; + virtual void SAL_CALL LargeScroll( const css::uno::Any& Down, const css::uno::Any& Up, const css::uno::Any& ToRight, const css::uno::Any& ToLeft ) override; + virtual css::uno::Any SAL_CALL SelectedSheets( const css::uno::Any& aIndex ) override; + virtual void SAL_CALL ScrollWorkbookTabs( const css::uno::Any& Sheets, const css::uno::Any& Position ) override; + virtual void SAL_CALL Activate( ) override; + virtual void SAL_CALL Close( const css::uno::Any& SaveChanges, const css::uno::Any& FileName, const css::uno::Any& RouteWorkBook ) override; + virtual css::uno::Any SAL_CALL Selection( ) override; + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL RangeSelection() override; + virtual sal_Int32 SAL_CALL PointsToScreenPixelsX(sal_Int32 _points) override; + virtual sal_Int32 SAL_CALL PointsToScreenPixelsY(sal_Int32 _points) override; + virtual void SAL_CALL PrintOut( const css::uno::Any& From, const css::uno::Any&To, const css::uno::Any& Copies, const css::uno::Any& Preview, const css::uno::Any& ActivePrinter, const css::uno::Any& PrintToFile, const css::uno::Any& Collate, const css::uno::Any& PrToFileName ) override; + virtual void SAL_CALL PrintPreview( const css::uno::Any& EnableChanges ) override; + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbawindows.cxx b/sc/source/ui/vba/vbawindows.cxx new file mode 100644 index 000000000..3a9960378 --- /dev/null +++ b/sc/source/ui/vba/vbawindows.cxx @@ -0,0 +1,249 @@ +/* -*- 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 "vbawindows.hxx" + + +#include <com/sun/star/sheet/XSpreadsheetDocument.hpp> +#include <com/sun/star/frame/Desktop.hpp> +#include <cppuhelper/implbase.hxx> +#include <comphelper/sequence.hxx> +#include <o3tl/safeint.hxx> +#include <rtl/ref.hxx> + +#include "vbawindow.hxx" +#include "vbaworkbook.hxx" + +#include <unordered_map> + +using namespace ::com::sun::star; +using namespace ::ooo::vba; + +typedef std::unordered_map< OUString, +sal_Int32 > NameIndexHash; + +static uno::Reference< XHelperInterface > lcl_createWorkbookHIParent( const uno::Reference< frame::XModel >& xModel, const uno::Reference< uno::XComponentContext >& xContext, const uno::Any& aApplication ) +{ + return new ScVbaWorkbook( uno::Reference< XHelperInterface >( aApplication, uno::UNO_QUERY_THROW ), xContext, xModel ); +} + +static uno::Any ComponentToWindow( const uno::Any& aSource, const uno::Reference< uno::XComponentContext > & xContext, const uno::Any& aApplication ) +{ + uno::Reference< frame::XModel > xModel( aSource, uno::UNO_QUERY_THROW ); + // !! TODO !! iterate over all controllers + uno::Reference< frame::XController > xController( xModel->getCurrentController(), uno::UNO_SET_THROW ); + uno::Reference< excel::XWindow > xWin( new ScVbaWindow( lcl_createWorkbookHIParent( xModel, xContext, aApplication ), xContext, xModel, xController ) ); + return uno::Any( xWin ); +} + +typedef std::vector < uno::Reference< sheet::XSpreadsheetDocument > > Components; + +namespace { + +// #TODO more or less the same as class in workwindows ( code sharing needed ) +class WindowComponentEnumImpl : public EnumerationHelper_BASE +{ +protected: + uno::Reference< uno::XComponentContext > m_xContext; + Components m_components; + Components::const_iterator m_it; + +public: + /// @throws uno::RuntimeException + WindowComponentEnumImpl( const uno::Reference< uno::XComponentContext >& xContext, Components&& components ) + : m_xContext( xContext ), m_components( std::move(components) ) + { + m_it = m_components.begin(); + } + + /// @throws uno::RuntimeException + explicit WindowComponentEnumImpl( const uno::Reference< uno::XComponentContext >& xContext ) : m_xContext( xContext ) + { + uno::Reference< frame::XDesktop2 > xDesktop = frame::Desktop::create(m_xContext); + uno::Reference< container::XEnumeration > xComponents = xDesktop->getComponents()->createEnumeration(); + while( xComponents->hasMoreElements() ) + { + uno::Reference< sheet::XSpreadsheetDocument > xNext( xComponents->nextElement(), uno::UNO_QUERY ); + if ( xNext.is() ) + m_components.push_back( xNext ); + } + m_it = m_components.begin(); + } + // XEnumeration + virtual sal_Bool SAL_CALL hasMoreElements( ) override + { + return m_it != m_components.end(); + } + + virtual uno::Any SAL_CALL nextElement( ) override + { + if ( !hasMoreElements() ) + { + throw container::NoSuchElementException(); + } + return css::uno::Any( *(m_it++) ); + } +}; + +class WindowEnumImpl : public WindowComponentEnumImpl +{ + uno::Any m_aApplication; +public: + WindowEnumImpl( const uno::Reference< uno::XComponentContext >& xContext, const uno::Any& aApplication ): WindowComponentEnumImpl( xContext ), m_aApplication( aApplication ) {} + virtual uno::Any SAL_CALL nextElement( ) override + { + return ComponentToWindow( WindowComponentEnumImpl::nextElement(), m_xContext, m_aApplication ); + } +}; + +} + +typedef ::cppu::WeakImplHelper< container::XEnumerationAccess + , css::container::XIndexAccess + , css::container::XNameAccess + > WindowsAccessImpl_BASE; + +namespace { + +class WindowsAccessImpl : public WindowsAccessImpl_BASE +{ + uno::Reference< uno::XComponentContext > m_xContext; + Components m_windows; + NameIndexHash namesToIndices; +public: + explicit WindowsAccessImpl( const uno::Reference< uno::XComponentContext >& xContext ):m_xContext( xContext ) + { + uno::Reference< container::XEnumeration > xEnum = new WindowComponentEnumImpl( m_xContext ); + sal_Int32 nIndex=0; + while( xEnum->hasMoreElements() ) + { + uno::Reference< sheet::XSpreadsheetDocument > xNext( xEnum->nextElement(), uno::UNO_QUERY ); + if ( xNext.is() ) + { + m_windows.push_back( xNext ); + uno::Reference< frame::XModel > xModel( xNext, uno::UNO_QUERY_THROW ); // that the spreadsheetdocument is a xmodel is a given + // !! TODO !! iterate over all controllers + uno::Reference< frame::XController > xController( xModel->getCurrentController(), uno::UNO_SET_THROW ); + uno::Reference< XHelperInterface > xTemp; // temporary needed for g++ 3.3.5 + rtl::Reference< ScVbaWindow > window( new ScVbaWindow( xTemp, m_xContext, xModel, xController ) ); + OUString sCaption; + window->getCaption() >>= sCaption; + namesToIndices[ sCaption ] = nIndex++; + } + } + + } + + //XEnumerationAccess + virtual uno::Reference< container::XEnumeration > SAL_CALL createEnumeration( ) override + { + return new WindowComponentEnumImpl( m_xContext, std::vector(m_windows) ); + } + // XIndexAccess + virtual ::sal_Int32 SAL_CALL getCount( ) override + { + return m_windows.size(); + } + virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override + { + if ( Index < 0 + || o3tl::make_unsigned( Index ) >= m_windows.size() ) + throw lang::IndexOutOfBoundsException(); + return css::uno::Any( m_windows[ Index ] ); // returns xspreadsheetdoc + } + + //XElementAccess + virtual uno::Type SAL_CALL getElementType( ) override + { + return cppu::UnoType<sheet::XSpreadsheetDocument>::get(); + } + + virtual sal_Bool SAL_CALL hasElements( ) override + { + return ( !m_windows.empty() ); + } + + //XNameAccess + virtual uno::Any SAL_CALL getByName( const OUString& aName ) override + { + NameIndexHash::const_iterator it = namesToIndices.find( aName ); + if ( it == namesToIndices.end() ) + throw container::NoSuchElementException(); + return css::uno::Any( m_windows[ it->second ] ); + + } + + virtual uno::Sequence< OUString > SAL_CALL getElementNames( ) override + { + return comphelper::mapKeysToSequence( namesToIndices ); + } + + virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override + { + NameIndexHash::const_iterator it = namesToIndices.find( aName ); + return (it != namesToIndices.end()); + } + +}; + +} + +ScVbaWindows::ScVbaWindows( const uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext ) : ScVbaWindows_BASE( xParent, xContext, uno::Reference< container::XIndexAccess > ( new WindowsAccessImpl( xContext ) ) ) +{ +} +uno::Reference< container::XEnumeration > +ScVbaWindows::createEnumeration() +{ + return new WindowEnumImpl( mxContext, Application() ); +} + +uno::Any +ScVbaWindows::createCollectionObject( const css::uno::Any& aSource ) +{ + return ComponentToWindow( aSource, mxContext, Application() ); +} + +uno::Type +ScVbaWindows::getElementType() +{ + return cppu::UnoType<excel::XWindows>::get(); +} + +void SAL_CALL +ScVbaWindows::Arrange( ::sal_Int32 /*ArrangeStyle*/, const uno::Any& /*ActiveWorkbook*/, const uno::Any& /*SyncHorizontal*/, const uno::Any& /*SyncVertical*/ ) +{ + //#TODO #FIXME see what can be done for an implementation here +} + +OUString +ScVbaWindows::getServiceImplName() +{ + return "ScVbaWindows"; +} + +css::uno::Sequence<OUString> +ScVbaWindows::getServiceNames() +{ + static uno::Sequence< OUString > const sNames + { + "ooo.vba.excel.Windows" + }; + return sNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbawindows.hxx b/sc/source/ui/vba/vbawindows.hxx new file mode 100644 index 000000000..b827bf7e4 --- /dev/null +++ b/sc/source/ui/vba/vbawindows.hxx @@ -0,0 +1,48 @@ +/* -*- 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 . + */ +#pragma once + +#include <ooo/vba/excel/XWindows.hpp> + +#include <vbahelper/vbacollectionimpl.hxx> + +namespace com::sun::star::uno { class XComponentContext; } + +typedef CollTestImplHelper< ov::excel::XWindows > ScVbaWindows_BASE; + +class ScVbaWindows : public ScVbaWindows_BASE +{ +public: + ScVbaWindows( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext ); + + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + + // XWindows + virtual void SAL_CALL Arrange( ::sal_Int32 ArrangeStyle, const css::uno::Any& ActiveWorkbook, const css::uno::Any& SyncHorizontal, const css::uno::Any& SyncVertical ) override; + // ScVbaCollectionBaseImpl + virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaworkbook.cxx b/sc/source/ui/vba/vbaworkbook.cxx new file mode 100644 index 000000000..23cc523a1 --- /dev/null +++ b/sc/source/ui/vba/vbaworkbook.cxx @@ -0,0 +1,420 @@ +/* -*- 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 <sal/config.h> + +#include <comphelper/propertyvalue.hxx> +#include <tools/urlobj.hxx> + +#include <com/sun/star/util/XProtectable.hpp> +#include <com/sun/star/sheet/XNamedRanges.hpp> +#include <com/sun/star/sheet/XSpreadsheetView.hpp> +#include <com/sun/star/sheet/XSpreadsheetDocument.hpp> +#include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <ooo/vba/excel/XlFileFormat.hpp> +#include <ooo/vba/excel/XApplication.hpp> + +#include "vbaworksheet.hxx" +#include "vbaworksheets.hxx" +#include "vbaworkbook.hxx" +#include "vbawindows.hxx" +#include "vbastyles.hxx" +#include "excelvbahelper.hxx" +#include "vbapalette.hxx" +#include <osl/file.hxx> +#include "vbanames.hxx" +#include <docoptio.hxx> +#include <docsh.hxx> + +// Much of the impl. for the equivalent UNO module is +// sc/source/ui/unoobj/docuno.cxx, viewuno.cxx + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +uno::Sequence< sal_Int32 > ScVbaWorkbook::ColorData; + +void SAL_CALL +ScVbaWorkbook::ResetColors( ) +{ + uno::Reference< container::XIndexAccess > xIndexAccess( ScVbaPalette::getDefaultPalette(), uno::UNO_SET_THROW ); + sal_Int32 nLen = xIndexAccess->getCount(); + ColorData.realloc( nLen ); + + sal_Int32* pDest = ColorData.getArray(); + for ( sal_Int32 index=0; index < nLen; ++pDest, ++index ) + xIndexAccess->getByIndex( index ) >>= *pDest; +} + +::uno::Any SAL_CALL +ScVbaWorkbook::Colors( const ::uno::Any& Index ) +{ + uno::Any aRet; + if ( Index.hasValue() ) + { + sal_Int32 nIndex = 0; + Index >>= nIndex; + aRet <<= XLRGBToOORGB( ColorData[ --nIndex ] ); + } + else + aRet <<= ColorData; + return aRet; +} + +bool ScVbaWorkbook::setFilterPropsFromFormat( sal_Int32 nFormat, uno::Sequence< beans::PropertyValue >& rProps ) +{ + auto [begin, end] = asNonConstRange(rProps); + auto pProp = std::find_if(begin, end, + [](const beans::PropertyValue& rProp) { return rProp.Name == "FilterName"; }); + bool bRes = pProp != end; + if (bRes) + { + switch( nFormat ) + { + case excel::XlFileFormat::xlCSV: + pProp->Value <<= OUString(SC_TEXT_CSV_FILTER_NAME); + break; + case excel::XlFileFormat::xlDBF4: + pProp->Value <<= OUString("DBF"); + break; + case excel::XlFileFormat::xlDIF: + pProp->Value <<= OUString("DIF"); + break; + case excel::XlFileFormat::xlWK3: + pProp->Value <<= OUString("Lotus"); + break; + case excel::XlFileFormat::xlExcel4Workbook: + pProp->Value <<= OUString("MS Excel 4.0"); + break; + case excel::XlFileFormat::xlExcel5: + pProp->Value <<= OUString("MS Excel 5.0/95"); + break; + case excel::XlFileFormat::xlHtml: + pProp->Value <<= OUString("HTML (StarCalc)"); + break; + case excel::XlFileFormat::xlExcel9795: + default: + pProp->Value <<= OUString("MS Excel 97"); + break; + } + } + return bRes; +} + +::sal_Int32 SAL_CALL +ScVbaWorkbook::getFileFormat( ) +{ + sal_Int32 aFileFormat = 0; + OUString aFilterName; + uno::Sequence< beans::PropertyValue > aArgs = getModel()->getArgs(); + + // #FIXME - seems suspect should we not walk through the properties + // to find the FilterName + if ( aArgs[0].Name == "FilterName" ) { + aArgs[0].Value >>= aFilterName; + } else { + aArgs[1].Value >>= aFilterName; + } + + if (aFilterName == SC_TEXT_CSV_FILTER_NAME) { + aFileFormat = excel::XlFileFormat::xlCSV; //xlFileFormat. + } + + if ( aFilterName == "DBF" ) { + aFileFormat = excel::XlFileFormat::xlDBF4; + } + + if ( aFilterName == "DIF" ) { + aFileFormat = excel::XlFileFormat::xlDIF; + } + + if ( aFilterName == "Lotus" ) { + aFileFormat = excel::XlFileFormat::xlWK3; + } + + if ( aFilterName == "MS Excel 4.0" ) { + aFileFormat = excel::XlFileFormat::xlExcel4Workbook; + } + + if ( aFilterName == "MS Excel 5.0/95" ) { + aFileFormat = excel::XlFileFormat::xlExcel5; + } + + if ( aFilterName == "MS Excel 97" ) { + aFileFormat = excel::XlFileFormat::xlExcel9795; + } + + if (aFilterName == "HTML (StarCalc)") { + aFileFormat = excel::XlFileFormat::xlHtml; + } + + if ( aFilterName == "calc_StarOffice_XML_Calc_Template" ) { + aFileFormat = excel::XlFileFormat::xlTemplate; + } + + if (aFilterName == "StarOffice XML (Calc)") { + aFileFormat = excel::XlFileFormat::xlWorkbookNormal; + } + if ( aFilterName == "calc8" ) { + aFileFormat = excel::XlFileFormat::xlWorkbookNormal; + } + + return aFileFormat; +} + +void +ScVbaWorkbook::init() +{ + if ( !ColorData.hasElements() ) + ResetColors(); + uno::Reference< frame::XModel > xModel = getModel(); + if ( xModel.is() ) + excel::getDocShell( xModel )->RegisterAutomationWorkbookObject( this ); +} + +ScVbaWorkbook::ScVbaWorkbook( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext, css::uno::Reference< css::frame::XModel > const & xModel ) : ScVbaWorkbook_BASE( xParent, xContext, xModel ) +{ + init(); +} + +ScVbaWorkbook::ScVbaWorkbook( uno::Sequence< uno::Any> const & args, + uno::Reference< uno::XComponentContext> const & xContext ) : ScVbaWorkbook_BASE( args, xContext ) +{ + init(); +} + +uno::Reference< excel::XWorksheet > +ScVbaWorkbook::getActiveSheet() +{ + uno::Reference< frame::XModel > xModel( getCurrentExcelDoc( mxContext ), uno::UNO_SET_THROW ); + uno::Reference< sheet::XSpreadsheetView > xView( xModel->getCurrentController(), uno::UNO_QUERY_THROW ); + uno::Reference< sheet::XSpreadsheet > xSheet( xView->getActiveSheet(), uno::UNO_SET_THROW ); + // #162503# return the original sheet module wrapper object, instead of a new instance + uno::Reference< excel::XWorksheet > xWorksheet( excel::getUnoSheetModuleObj( xSheet ), uno::UNO_QUERY ); + if( xWorksheet.is() ) return xWorksheet; + // #i116936# excel::getUnoSheetModuleObj() may return null in documents without global VBA mode enabled + return new ScVbaWorksheet( this, mxContext, xSheet, xModel ); +} + +uno::Any SAL_CALL +ScVbaWorkbook::Sheets( const uno::Any& aIndex ) +{ + return Worksheets( aIndex ); +} + +uno::Any SAL_CALL +ScVbaWorkbook::Worksheets( const uno::Any& aIndex ) +{ + uno::Reference< frame::XModel > xModel( getModel() ); + uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( xModel, uno::UNO_QUERY_THROW ); + uno::Reference<container::XIndexAccess > xSheets( xSpreadDoc->getSheets(), uno::UNO_QUERY_THROW ); + uno::Reference< XCollection > xWorkSheets( new ScVbaWorksheets( this, mxContext, xSheets, xModel ) ); + if ( aIndex.getValueTypeClass() == uno::TypeClass_VOID ) + { + return uno::Any( xWorkSheets ); + } + // pass on to collection + return xWorkSheets->Item( aIndex, uno::Any() ); +} +uno::Any SAL_CALL +ScVbaWorkbook::Windows( const uno::Any& aIndex ) +{ + + uno::Reference< excel::XWindows > xWindows( new ScVbaWindows( getParent(), mxContext ) ); + if ( aIndex.getValueTypeClass() == uno::TypeClass_VOID ) + return uno::Any( xWindows ); + return xWindows->Item( aIndex, uno::Any() ); +} + +void SAL_CALL +ScVbaWorkbook::Activate() +{ + VbaDocumentBase::Activate(); +} + +void +ScVbaWorkbook::Protect( const uno::Any &aPassword ) +{ + VbaDocumentBase::Protect( aPassword ); +} + +sal_Bool +ScVbaWorkbook::getProtectStructure() +{ + uno::Reference< util::XProtectable > xProt( getModel(), uno::UNO_QUERY_THROW ); + return xProt->isProtected(); +} + +sal_Bool SAL_CALL ScVbaWorkbook::getPrecisionAsDisplayed() +{ + uno::Reference< frame::XModel > xModel( getModel(), uno::UNO_SET_THROW ); + ScDocument& rDoc = excel::getDocShell( xModel )->GetDocument(); + return rDoc.GetDocOptions().IsCalcAsShown(); +} + +void SAL_CALL ScVbaWorkbook::setPrecisionAsDisplayed( sal_Bool _precisionAsDisplayed ) +{ + uno::Reference< frame::XModel > xModel( getModel(), uno::UNO_SET_THROW ); + ScDocument& rDoc = excel::getDocShell( xModel )->GetDocument(); + ScDocOptions aOpt = rDoc.GetDocOptions(); + aOpt.SetCalcAsShown( _precisionAsDisplayed ); + rDoc.SetDocOptions( aOpt ); +} + +OUString SAL_CALL ScVbaWorkbook::getAuthor() +{ + uno::Reference<document::XDocumentPropertiesSupplier> xDPS( getModel(), uno::UNO_QUERY ); + if (!xDPS.is()) + return "?"; + uno::Reference<document::XDocumentProperties> xDocProps = xDPS->getDocumentProperties(); + return xDocProps->getAuthor(); +} + +void SAL_CALL ScVbaWorkbook::setAuthor( const OUString& _author ) +{ + uno::Reference<document::XDocumentPropertiesSupplier> xDPS( getModel(), uno::UNO_QUERY ); + if (!xDPS.is()) + return; + uno::Reference<document::XDocumentProperties> xDocProps = xDPS->getDocumentProperties(); + xDocProps->setAuthor( _author ); +} + +void +ScVbaWorkbook::SaveCopyAs( const OUString& sFileName ) +{ + OUString aURL; + osl::FileBase::getFileURLFromSystemPath( sFileName, aURL ); + uno::Reference< frame::XStorable > xStor( getModel(), uno::UNO_QUERY_THROW ); + uno::Sequence< beans::PropertyValue > storeProps{ comphelper::makePropertyValue( + "FilterName", OUString( "MS Excel 97" )) }; + xStor->storeToURL( aURL, storeProps ); +} + +void SAL_CALL +ScVbaWorkbook::SaveAs( const uno::Any& FileName, const uno::Any& FileFormat, const uno::Any& /*Password*/, const uno::Any& /*WriteResPassword*/, const uno::Any& /*ReadOnlyRecommended*/, const uno::Any& /*CreateBackup*/, const uno::Any& /*AccessMode*/, const uno::Any& /*ConflictResolution*/, const uno::Any& /*AddToMru*/, const uno::Any& /*TextCodepage*/, const uno::Any& /*TextVisualLayout*/, const uno::Any& /*Local*/ ) +{ + OUString sFileName; + FileName >>= sFileName; + OUString sURL; + osl::FileBase::getFileURLFromSystemPath( sFileName, sURL ); + // detect if there is no path then we need + // to use the current folder + INetURLObject aURL( sURL ); + sURL = aURL.GetMainURL( INetURLObject::DecodeMechanism::ToIUri ); + if( sURL.isEmpty() ) + { + // need to add cur dir ( of this workbook ) or else the 'Work' dir + sURL = getModel()->getURL(); + + if ( sURL.isEmpty() ) + { + // not path available from 'this' document + // need to add the 'document'/work directory then + uno::Reference< excel::XApplication > xApplication ( Application(),uno::UNO_QUERY_THROW ); + OUString sWorkPath = xApplication->getDefaultFilePath(); + OUString sWorkURL; + osl::FileBase::getFileURLFromSystemPath( sWorkPath, sWorkURL ); + aURL.SetURL( sWorkURL ); + } + else + { + aURL.SetURL( sURL ); + aURL.Append( sFileName ); + } + sURL = aURL.GetMainURL( INetURLObject::DecodeMechanism::ToIUri ); + + } + + sal_Int32 nFileFormat = excel::XlFileFormat::xlExcel9795; + FileFormat >>= nFileFormat; + + uno::Sequence storeProps{ comphelper::makePropertyValue("FilterName", uno::Any()) }; + setFilterPropsFromFormat( nFileFormat, storeProps ); + + uno::Reference< frame::XStorable > xStor( getModel(), uno::UNO_QUERY_THROW ); + xStor->storeAsURL( sURL, storeProps ); +} + +css::uno::Any SAL_CALL +ScVbaWorkbook::Styles( const uno::Any& Item ) +{ + // quick look and Styles object doesn't seem to have a valid parent + // or a least the object browser just shows an object that has no + // variables ( therefore... leave as NULL for now ) + uno::Reference< XCollection > dStyles = new ScVbaStyles( uno::Reference< XHelperInterface >(), mxContext, getModel() ); + if ( Item.hasValue() ) + return dStyles->Item( Item, uno::Any() ); + return uno::Any( dStyles ); +} + +uno::Any SAL_CALL +ScVbaWorkbook::Names( const uno::Any& aIndex ) +{ + uno::Reference< frame::XModel > xModel( getModel(), uno::UNO_SET_THROW ); + uno::Reference< beans::XPropertySet > xProps( xModel, uno::UNO_QUERY_THROW ); + uno::Reference< sheet::XNamedRanges > xNamedRanges( xProps->getPropertyValue("NamedRanges"), uno::UNO_QUERY_THROW ); + uno::Reference< XCollection > xNames( new ScVbaNames( this, mxContext, xNamedRanges, xModel ) ); + if ( aIndex.hasValue() ) + return xNames->Item( aIndex, uno::Any() ); + return uno::Any( xNames ); +} + +OUString +ScVbaWorkbook::getServiceImplName() +{ + return "ScVbaWorkbook"; +} + +uno::Sequence< OUString > +ScVbaWorkbook::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.Workbook" + }; + return aServiceNames; +} + +OUString SAL_CALL +ScVbaWorkbook::getCodeName() +{ + uno::Reference< beans::XPropertySet > xModelProp( getModel(), uno::UNO_QUERY_THROW ); + return xModelProp->getPropertyValue("CodeName").get< OUString >(); +} + +sal_Int64 +ScVbaWorkbook::getSomething(const uno::Sequence<sal_Int8 >& rId ) +{ + if (comphelper::isUnoTunnelId<ScVbaWorksheet>(rId)) // ??? + { + return comphelper::getSomething_cast(this); + } + return 0; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +Calc_ScVbaWorkbook_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& args) +{ + return cppu::acquire(new ScVbaWorkbook(args, context)); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaworkbook.hxx b/sc/source/ui/vba/vbaworkbook.hxx new file mode 100644 index 000000000..886f771bf --- /dev/null +++ b/sc/source/ui/vba/vbaworkbook.hxx @@ -0,0 +1,73 @@ +/* -*- 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 . + */ +#pragma once + +#include <com/sun/star/frame/XModel.hpp> +#include <ooo/vba/excel/XWorkbook.hpp> +#include <cppuhelper/implbase.hxx> +#include <vbahelper/vbadocumentbase.hxx> + +typedef cppu::ImplInheritanceHelper< VbaDocumentBase, ov::excel::XWorkbook > ScVbaWorkbook_BASE; + +class ScVbaWorkbook : public ScVbaWorkbook_BASE +{ + static css::uno::Sequence< sal_Int32 > ColorData; + static bool setFilterPropsFromFormat( sal_Int32 nFormat, css::uno::Sequence< css::beans::PropertyValue >& rProps ); + void init(); + +public: + ScVbaWorkbook( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext, + css::uno::Reference< css::frame::XModel > const & xModel ); + ScVbaWorkbook( css::uno::Sequence< css::uno::Any > const& aArgs, css::uno::Reference< css::uno::XComponentContext >const& xContext ); + + // Attributes + virtual sal_Bool SAL_CALL getProtectStructure() override; + virtual css::uno::Reference< ov::excel::XWorksheet > SAL_CALL getActiveSheet() override; + virtual sal_Bool SAL_CALL getPrecisionAsDisplayed() override; + virtual void SAL_CALL setPrecisionAsDisplayed( sal_Bool _precisionAsDisplayed ) override; + virtual OUString SAL_CALL getAuthor() override; + virtual void SAL_CALL setAuthor( const OUString& _author ) override; + + // Methods + virtual css::uno::Any SAL_CALL Worksheets( const css::uno::Any& aIndex ) override; + virtual css::uno::Any SAL_CALL Sheets( const css::uno::Any& aIndex ) override; + virtual css::uno::Any SAL_CALL Windows( const css::uno::Any& aIndex ) override; + virtual void SAL_CALL Activate() override; + virtual void SAL_CALL Protect( const css::uno::Any & aPassword ) override; + virtual void SAL_CALL SaveAs( const css::uno::Any& FileName, const css::uno::Any& FileFormat, const css::uno::Any& Password, const css::uno::Any& WriteResPassword, const css::uno::Any& ReadOnlyRecommended, const css::uno::Any& CreateBackup, const css::uno::Any& AccessMode, const css::uno::Any& ConflictResolution, const css::uno::Any& AddToMru, const css::uno::Any& TextCodepage, const css::uno::Any& TextVisualLayout, const css::uno::Any& Local ) override; + virtual css::uno::Any SAL_CALL Names( const css::uno::Any& aIndex ) override; + + virtual css::uno::Any SAL_CALL Styles( const css::uno::Any& Item ) override; + virtual void SAL_CALL ResetColors( ) override; + virtual css::uno::Any SAL_CALL Colors( const css::uno::Any& Index ) override; + virtual ::sal_Int32 SAL_CALL getFileFormat( ) override; + virtual void SAL_CALL SaveCopyAs( const OUString& Filename ) override; + + // code name + virtual OUString SAL_CALL getCodeName() override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; + + // XUnoTunnel + virtual ::sal_Int64 SAL_CALL getSomething(const css::uno::Sequence<sal_Int8 >& rId ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaworkbooks.cxx b/sc/source/ui/vba/vbaworkbooks.cxx new file mode 100644 index 000000000..e3b608b33 --- /dev/null +++ b/sc/source/ui/vba/vbaworkbooks.cxx @@ -0,0 +1,291 @@ +/* -*- 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 <com/sun/star/sheet/XSpreadsheetDocument.hpp> +#include <com/sun/star/container/XEnumerationAccess.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/document/XTypeDetection.hpp> + +#include <tools/urlobj.hxx> + +#include "excelvbahelper.hxx" +#include "vbaworkbook.hxx" +#include "vbaworkbooks.hxx" +#include <vbahelper/vbahelper.hxx> + +#include <comphelper/propertyvalue.hxx> +#include <o3tl/string_view.hxx> +#include <osl/file.hxx> +#include <rtl/ref.hxx> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +const sal_Int16 CUSTOM_CHAR = 5; + +static uno::Any +getWorkbook( const uno::Reference< uno::XComponentContext >& xContext, + const uno::Reference< sheet::XSpreadsheetDocument > &xDoc, + const uno::Reference< XHelperInterface >& xParent ) +{ + // FIXME: fine as long as ScVbaWorkbook is stateless ... + uno::Reference< frame::XModel > xModel( xDoc, uno::UNO_QUERY ); + if( !xModel.is() ) + return uno::Any(); + + uno::Reference< excel::XWorkbook > xWb( getVBADocument( xModel ), uno::UNO_QUERY ); + if ( xWb.is() ) + { + return uno::Any( xWb ); + } + + rtl::Reference<ScVbaWorkbook> pWb = new ScVbaWorkbook( xParent, xContext, xModel ); + return uno::Any( uno::Reference< excel::XWorkbook > (pWb) ); +} + +namespace { + +class WorkBookEnumImpl : public EnumerationHelperImpl +{ +public: + /// @throws uno::RuntimeException + WorkBookEnumImpl( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< container::XEnumeration >& xEnumeration ) : EnumerationHelperImpl( xParent, xContext, xEnumeration ) {} + + virtual uno::Any SAL_CALL nextElement( ) override + { + uno::Reference< sheet::XSpreadsheetDocument > xDoc( m_xEnumeration->nextElement(), uno::UNO_QUERY_THROW ); + return getWorkbook( m_xContext, xDoc, m_xParent ); + } + +}; + +} + +ScVbaWorkbooks::ScVbaWorkbooks( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< css::uno::XComponentContext >& xContext ) : ScVbaWorkbooks_BASE( xParent, xContext, VbaDocumentsBase::EXCEL_DOCUMENT ) +{ +} +// XEnumerationAccess +uno::Type +ScVbaWorkbooks::getElementType() +{ + return cppu::UnoType<excel::XWorkbook>::get(); +} +uno::Reference< container::XEnumeration > +ScVbaWorkbooks::createEnumeration() +{ + // #FIXME it's possible the WorkBookEnumImpl here doesn't reflect + // the state of this object ( although it should ) would be + // safer to create an enumeration based on this objects state + // rather than one effectively based of the desktop component + uno::Reference< container::XEnumerationAccess > xEnumerationAccess( m_xIndexAccess, uno::UNO_QUERY_THROW ); + return new WorkBookEnumImpl( mxParent, mxContext, xEnumerationAccess->createEnumeration() ); +} + +uno::Any +ScVbaWorkbooks::createCollectionObject( const css::uno::Any& aSource ) +{ + uno::Reference< sheet::XSpreadsheetDocument > xDoc( aSource, uno::UNO_QUERY_THROW ); + return getWorkbook( mxContext, xDoc, mxParent ); +} + +uno::Any SAL_CALL +ScVbaWorkbooks::Add( const uno::Any& Template ) +{ + uno::Reference< sheet::XSpreadsheetDocument > xSpreadDoc; + sal_Int32 nWorkbookType = 0; + OUString aTemplateFileName; + if( Template >>= nWorkbookType ) + { + // nWorkbookType is a constant from XlWBATemplate (added in Excel 2007) + // TODO: create chart-sheet if supported by Calc + + xSpreadDoc.set( createDocument(), uno::UNO_QUERY_THROW ); + // create a document with one sheet only + uno::Reference< sheet::XSpreadsheets > xSheets( xSpreadDoc->getSheets(), uno::UNO_SET_THROW ); + uno::Reference< container::XIndexAccess > xSheetsIA( xSheets, uno::UNO_QUERY_THROW ); + while( xSheetsIA->getCount() > 1 ) + { + uno::Reference< container::XNamed > xSheetName( xSheetsIA->getByIndex( xSheetsIA->getCount() - 1 ), uno::UNO_QUERY_THROW ); + xSheets->removeByName( xSheetName->getName() ); + } + } + else if( Template >>= aTemplateFileName ) + { + // TODO: create document from template + xSpreadDoc.set( createDocument(), uno::UNO_QUERY_THROW ); + } + else if( !Template.hasValue() ) + { + // regular spreadsheet document with configured number of sheets + xSpreadDoc.set( createDocument(), uno::UNO_QUERY_THROW ); + } + else + { + // illegal argument + throw uno::RuntimeException(); + } + + // need to set up the document modules ( and vba mode ) here + excel::setUpDocumentModules( xSpreadDoc ); + if (!xSpreadDoc.is()) + return uno::Any(); + + uno::Any aRet = getWorkbook( mxContext, xSpreadDoc, mxParent ); + uno::Reference< excel::XWorkbook > xWBook( aRet, uno::UNO_QUERY ); + if (xWBook.is()) + xWBook->Activate(); + return aRet; +} + +void SAL_CALL +ScVbaWorkbooks::Close() +{ +} + +bool +ScVbaWorkbooks::isTextFile( std::u16string_view sType ) +{ + // will return true if the file is + // a) a variant of a text file + // b) a csv file + // c) unknown + // returning true basically means treat this like a csv file + return sType == u"generic_Text" || sType.empty(); +} + +bool +ScVbaWorkbooks::isSpreadSheetFile( std::u16string_view sType ) +{ + // include calc_QPro etc. ? ( not for the moment anyway ) + return o3tl::starts_with( sType, u"calc_MS" ) + || o3tl::starts_with( sType, u"MS Excel" ) + || o3tl::starts_with( sType, u"calc8" ) + || o3tl::starts_with( sType, u"calc_StarOffice" ); +} + +OUString +ScVbaWorkbooks::getFileFilterType( const OUString& rFileName ) +{ + uno::Reference< document::XTypeDetection > xTypeDetect( mxContext->getServiceManager()->createInstanceWithContext("com.sun.star.document.TypeDetection", mxContext), uno::UNO_QUERY_THROW ); + uno::Sequence aMediaDesc{ comphelper::makePropertyValue("URL", rFileName) }; + OUString sType = xTypeDetect->queryTypeByDescriptor( aMediaDesc, true ); + return sType; +} + +// #TODO# #FIXME# can any of the unused params below be used? +uno::Any SAL_CALL +ScVbaWorkbooks::Open( const OUString& rFileName, const uno::Any& /*UpdateLinks*/, const uno::Any& ReadOnly, const uno::Any& Format, const uno::Any& /*Password*/, const uno::Any& /*WriteResPassword*/, const uno::Any& /*IgnoreReadOnlyRecommended*/, const uno::Any& /*Origin*/, const uno::Any& Delimiter, const uno::Any& /*Editable*/, const uno::Any& /*Notify*/, const uno::Any& /*Converter*/, const uno::Any& /*AddToMru*/ ) +{ + // we need to detect if this is a URL, if not then assume it's a file path + OUString aURL; + INetURLObject aObj; + aObj.SetURL( rFileName ); + bool bIsURL = aObj.GetProtocol() != INetProtocol::NotValid; + if ( bIsURL ) + aURL = rFileName; + else + osl::FileBase::getFileURLFromSystemPath( rFileName, aURL ); + + uno::Sequence< beans::PropertyValue > sProps; + + OUString sType = getFileFilterType( aURL ); + // A text file means it needs to be processed as a csv file + if ( isTextFile( sType ) ) + { + // Values for format + // 1 Tabs + // 2 Commas + // 3 Spaces + // 4 Semicolons + // 5 Nothing + // 6 Custom character (see the Delimiter argument + // no format means use the current delimiter + sal_Int16 const delims[] { 0 /*default not used*/, 9/*tab*/, 44/*comma*/, 32/*space*/, 59/*semicolon*/ }; + + OUString sFormat; + sal_Int16 nFormat = 0; // default indicator + + if ( Format.hasValue() ) + { + Format >>= nFormat; // val of nFormat overwritten if extracted + // validate param + if ( nFormat < 1 || nFormat > 6 ) + throw uno::RuntimeException("Illegal value for Format" ); + } + + sal_Int16 nDelim = getCurrentDelim(); + + if ( nFormat > 0 && nFormat < CUSTOM_CHAR ) + { + nDelim = delims[ nFormat ]; + } + else if ( nFormat > CUSTOM_CHAR ) + { + // Need to check Delimiter param + if ( !Delimiter.hasValue() ) + throw uno::RuntimeException("Expected value for Delimiter" ); + OUString sStr; + Delimiter >>= sStr; + if ( sStr.isEmpty() ) + throw uno::RuntimeException("Incorrect value for Delimiter" ); + + nDelim = sStr[0]; + + } + + getCurrentDelim() = nDelim; //set new current + + sFormat = OUString::number( nDelim ) + ",34,0,1"; + + sProps = { comphelper::makePropertyValue("FilterOptions", sFormat), + comphelper::makePropertyValue("FilterName", OUString( SC_TEXT_CSV_FILTER_NAME )), + // Ensure WORKAROUND_CSV_TXT_BUG_i60158 gets called in typedetection.cxx so + // csv is forced for deep detected 'writerxxx' types + comphelper::makePropertyValue( + "DocumentService", OUString("com.sun.star.sheet.SpreadsheetDocument")) }; + } + else if ( !isSpreadSheetFile( sType ) ) + throw uno::RuntimeException("Bad Format" ); + + uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( openDocument( rFileName, ReadOnly, sProps ), uno::UNO_QUERY_THROW ); + uno::Any aRet = getWorkbook( mxContext, xSpreadDoc, mxParent ); + uno::Reference< excel::XWorkbook > xWBook( aRet, uno::UNO_QUERY ); + if ( xWBook.is() ) + xWBook->Activate(); + return aRet; +} + +OUString +ScVbaWorkbooks::getServiceImplName() +{ + return "ScVbaWorkbooks"; +} + +css::uno::Sequence<OUString> +ScVbaWorkbooks::getServiceNames() +{ + static uno::Sequence< OUString > const sNames + { + "ooo.vba.excel.Workbooks" + }; + return sNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaworkbooks.hxx b/sc/source/ui/vba/vbaworkbooks.hxx new file mode 100644 index 000000000..45d41757a --- /dev/null +++ b/sc/source/ui/vba/vbaworkbooks.hxx @@ -0,0 +1,56 @@ +/* -*- 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 . + */ +#pragma once + +#include <sal/config.h> + +#include <string_view> + +#include <cppuhelper/implbase.hxx> +#include <ooo/vba/excel/XWorkbooks.hpp> +#include <vbahelper/vbadocumentsbase.hxx> + +typedef cppu::ImplInheritanceHelper< VbaDocumentsBase, ov::excel::XWorkbooks > ScVbaWorkbooks_BASE; + +class ScVbaWorkbooks : public ScVbaWorkbooks_BASE +{ +private: + OUString getFileFilterType( const OUString& rString ); + static bool isTextFile( std::u16string_view rString ); + static bool isSpreadSheetFile( std::u16string_view rString ); + static sal_Int16& getCurrentDelim(){ static sal_Int16 nDelim = 44; return nDelim; } +public: + ScVbaWorkbooks( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext ); + + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + + // ScVbaWorkbooks_BASE + virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override; + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; + + // XWorkbooks + virtual css::uno::Any SAL_CALL Add( const css::uno::Any& Template ) override; + virtual void SAL_CALL Close( ) override; + virtual css::uno::Any SAL_CALL Open( const OUString& Filename, const css::uno::Any& UpdateLinks, const css::uno::Any& ReadOnly, const css::uno::Any& Format, const css::uno::Any& Password, const css::uno::Any& WriteResPassword, const css::uno::Any& IgnoreReadOnlyRecommended, const css::uno::Any& Origin, const css::uno::Any& Delimiter, const css::uno::Any& Editable, const css::uno::Any& Notify, const css::uno::Any& Converter, const css::uno::Any& AddToMru ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaworksheet.cxx b/sc/source/ui/vba/vbaworksheet.cxx new file mode 100644 index 000000000..c51284427 --- /dev/null +++ b/sc/source/ui/vba/vbaworksheet.cxx @@ -0,0 +1,1052 @@ +/* -*- 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 <sal/config.h> + +#include <string_view> + +#include "vbaworksheet.hxx" +#include "vbanames.hxx" + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XIntrospectionAccess.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/util/XProtectable.hpp> +#include <com/sun/star/table/XCellRange.hpp> +#include <com/sun/star/sheet/XSpreadsheetView.hpp> +#include <com/sun/star/sheet/XSpreadsheetDocument.hpp> +#include <com/sun/star/sheet/XCalculatable.hpp> +#include <com/sun/star/sheet/XCellRangeAddressable.hpp> +#include <com/sun/star/sheet/XSheetCellRange.hpp> +#include <com/sun/star/sheet/XSheetCellCursor.hpp> +#include <com/sun/star/sheet/XSheetAnnotationsSupplier.hpp> +#include <com/sun/star/sheet/XUsedAreaCursor.hpp> +#include <com/sun/star/sheet/XSpreadsheets.hpp> +#include <com/sun/star/sheet/XSheetOutline.hpp> +#include <com/sun/star/sheet/XSheetPageBreak.hpp> +#include <com/sun/star/sheet/XDataPilotTablesSupplier.hpp> +#include <com/sun/star/sheet/XNamedRanges.hpp> +#include <com/sun/star/frame/Desktop.hpp> +#include <com/sun/star/table/XTableChartsSupplier.hpp> +#include <com/sun/star/drawing/XDrawPageSupplier.hpp> +#include <com/sun/star/drawing/XControlShape.hpp> +#include <com/sun/star/form/XFormsSupplier.hpp> +#include <ooo/vba/excel/XApplication.hpp> +#include <ooo/vba/excel/XlEnableSelection.hpp> +#include <ooo/vba/excel/XlSheetVisibility.hpp> +#include <ooo/vba/XControlProvider.hpp> + +#include <basic/sberrors.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/servicehelper.hxx> +#include <vbahelper/vbashapes.hxx> + +//zhangyun showdataform +#include <scabstdlg.hxx> +#include <tabvwsh.hxx> + +#include <tabprotection.hxx> +#include "excelvbahelper.hxx" +#include "vbaoutline.hxx" +#include "vbarange.hxx" +#include "vbacomments.hxx" +#include "vbachartobjects.hxx" +#include "vbapivottables.hxx" +#include "vbaoleobjects.hxx" +#include "vbapagesetup.hxx" +#include "vbapagebreaks.hxx" +#include "vbaworksheets.hxx" +#include "vbahyperlinks.hxx" +#include "vbasheetobjects.hxx" +#include <dbdata.hxx> + +#include <attrib.hxx> + +#define STANDARDWIDTH 2267 +#define STANDARDHEIGHT 427 + +using namespace com::sun::star; +using namespace ooo::vba; + +static void getNewSpreadsheetName (OUString &aNewName, std::u16string_view aOldName, const uno::Reference <sheet::XSpreadsheetDocument>& xSpreadDoc ) +{ + if (!xSpreadDoc.is()) + throw lang::IllegalArgumentException( "getNewSpreadsheetName() xSpreadDoc is null", uno::Reference< uno::XInterface >(), 1 ); + static const char aUnderScore[] = "_"; + int currentNum =2; + aNewName = OUString::Concat(aOldName) + aUnderScore + OUString::number(currentNum) ; + SCTAB nTab = 0; + while ( ScVbaWorksheets::nameExists(xSpreadDoc,aNewName, nTab ) ) + { + aNewName = OUString::Concat(aOldName) + aUnderScore + OUString::number(++currentNum); + } +} + +static void removeAllSheets( const uno::Reference <sheet::XSpreadsheetDocument>& xSpreadDoc, const OUString& aSheetName) +{ + if (!xSpreadDoc.is()) + throw lang::IllegalArgumentException( "removeAllSheets() xSpreadDoc is null", uno::Reference< uno::XInterface >(), 1 ); + uno::Reference<sheet::XSpreadsheets> xSheets = xSpreadDoc->getSheets(); + uno::Reference <container::XIndexAccess> xIndex( xSheets, uno::UNO_QUERY ); + + if ( !xIndex.is() ) + return; + + uno::Reference<container::XNameContainer> xNameContainer(xSheets,uno::UNO_QUERY_THROW); + for (sal_Int32 i = xIndex->getCount() -1; i>= 1; i--) + { + uno::Reference< sheet::XSpreadsheet > xSheet(xIndex->getByIndex(i), uno::UNO_QUERY); + uno::Reference< container::XNamed > xNamed( xSheet, uno::UNO_QUERY_THROW ); + xNameContainer->removeByName(xNamed->getName()); + } + + uno::Reference< sheet::XSpreadsheet > xSheet(xIndex->getByIndex(0), uno::UNO_QUERY); + uno::Reference< container::XNamed > xNamed( xSheet, uno::UNO_QUERY_THROW ); + xNamed->setName(aSheetName); +} + +static uno::Reference<frame::XModel> +openNewDoc(const OUString& aSheetName ) +{ + uno::Reference<frame::XModel> xModel; + try + { + uno::Reference< uno::XComponentContext > xContext( + comphelper::getProcessComponentContext() ); + + uno::Reference <frame::XDesktop2 > xComponentLoader = frame::Desktop::create(xContext); + + uno::Reference<lang::XComponent > xComponent( xComponentLoader->loadComponentFromURL( + "private:factory/scalc", + "_blank", 0, + uno::Sequence < css::beans::PropertyValue >() ) ); + uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( xComponent, uno::UNO_QUERY_THROW ); + removeAllSheets(xSpreadDoc,aSheetName); + xModel.set(xSpreadDoc,uno::UNO_QUERY_THROW); + } + catch ( uno::Exception & /*e*/ ) + { + } + return xModel; +} + +ScVbaWorksheet::ScVbaWorksheet(const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, + const uno::Reference< sheet::XSpreadsheet >& xSheet, + const uno::Reference< frame::XModel >& xModel ) : WorksheetImpl_BASE( xParent, xContext ), mxSheet( xSheet ), mxModel(xModel), mbVeryHidden( false ) +{ +} + +ScVbaWorksheet::ScVbaWorksheet( uno::Sequence< uno::Any> const & args, + uno::Reference< uno::XComponentContext> const & xContext ) : WorksheetImpl_BASE( getXSomethingFromArgs< XHelperInterface >( args, 0 ), xContext ), mxModel( getXSomethingFromArgs< frame::XModel >( args, 1 ) ), mbVeryHidden( false ) +{ + if ( args.getLength() < 3 ) + throw lang::IllegalArgumentException(); + + OUString sSheetName; + args[2] >>= sSheetName; + + uno::Reference< sheet::XSpreadsheetDocument > xSpreadDoc( mxModel, uno::UNO_QUERY_THROW ); + uno::Reference< container::XNameAccess > xNameAccess( xSpreadDoc->getSheets(), uno::UNO_QUERY_THROW ); + mxSheet.set( xNameAccess->getByName( sSheetName ), uno::UNO_QUERY_THROW ); +} + +ScVbaWorksheet::~ScVbaWorksheet() +{ +} + +const uno::Sequence<sal_Int8>& ScVbaWorksheet::getUnoTunnelId() +{ + static const comphelper::UnoIdInit theScVbaWorksheetUnoTunnelId; + return theScVbaWorksheetUnoTunnelId.getSeq(); +} + +uno::Reference< ov::excel::XWorksheet > +ScVbaWorksheet::createSheetCopyInNewDoc(const OUString& aCurrSheetName) +{ + uno::Reference< sheet::XSheetCellCursor > xSheetCellCursor = getSheet()->createCursor( ); + uno::Reference<sheet::XUsedAreaCursor> xUsedCursor(xSheetCellCursor,uno::UNO_QUERY_THROW); + uno::Reference<excel::XRange> xRange = new ScVbaRange( this, mxContext, xSheetCellCursor); + if (xRange.is()) + xRange->Select(); + excel::implnCopy(mxModel); + uno::Reference<frame::XModel> xModel = openNewDoc(aCurrSheetName); + if (xModel.is()) + { + excel::implnPaste(xModel); + } + uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( xModel, uno::UNO_QUERY_THROW ); + excel::setUpDocumentModules(xSpreadDoc); + uno::Reference <sheet::XSpreadsheets> xSheets( xSpreadDoc->getSheets(), uno::UNO_SET_THROW ); + uno::Reference <container::XIndexAccess> xIndex( xSheets, uno::UNO_QUERY_THROW ); + uno::Reference< sheet::XSpreadsheet > xSheet(xIndex->getByIndex(0), uno::UNO_QUERY_THROW); + + ScDocShell* pShell = excel::getDocShell( xModel ); + OUString aCodeName; + pShell->GetDocument().GetCodeName( 0, aCodeName ); + return uno::Reference< excel::XWorksheet >( getUnoDocModule( aCodeName, pShell ), uno::UNO_QUERY_THROW ); +} + +css::uno::Reference< ov::excel::XWorksheet > +ScVbaWorksheet::createSheetCopy(uno::Reference<excel::XWorksheet> const & xSheet, bool bAfter) +{ + OUString aCurrSheetName = getName(); + ScVbaWorksheet* pDestSheet = excel::getImplFromDocModuleWrapper<ScVbaWorksheet>( xSheet ); + + uno::Reference <sheet::XSpreadsheetDocument> xDestDoc( pDestSheet->getModel(), uno::UNO_QUERY ); + uno::Reference <sheet::XSpreadsheetDocument> xSrcDoc( getModel(), uno::UNO_QUERY ); + + SCTAB nDest = 0; + SCTAB nSrc = 0; + OUString aSheetName = xSheet->getName(); + bool bSameDoc = ( pDestSheet->getModel() == getModel() ); + bool bDestSheetExists = ScVbaWorksheets::nameExists (xDestDoc, aSheetName, nDest ); + bool bSheetExists = ScVbaWorksheets::nameExists (xSrcDoc, aCurrSheetName, nSrc ); + + // set sheet name to be newSheet name + aSheetName = aCurrSheetName; + if ( bSheetExists && bDestSheetExists ) + { + SCTAB nDummy=0; + if(bAfter) + nDest++; + uno::Reference<sheet::XSpreadsheets> xSheets = xDestDoc->getSheets(); + if ( bSameDoc || ScVbaWorksheets::nameExists( xDestDoc, aCurrSheetName, nDummy ) ) + getNewSpreadsheetName(aSheetName,aCurrSheetName,xDestDoc); + if ( bSameDoc ) + xSheets->copyByName(aCurrSheetName,aSheetName,nDest); + else + { + ScDocShell* pDestDocShell = excel::getDocShell( pDestSheet->getModel() ); + ScDocShell* pSrcDocShell = excel::getDocShell( getModel() ); + if ( pDestDocShell && pSrcDocShell ) + pDestDocShell->TransferTab( *pSrcDocShell, nSrc, nDest, true, true ); + } + } + // return new sheet + uno::Reference< excel::XApplication > xApplication( Application(), uno::UNO_QUERY_THROW ); + uno::Reference< excel::XWorksheet > xNewSheet( xApplication->Worksheets( uno::Any( aSheetName ) ), uno::UNO_QUERY_THROW ); + return xNewSheet; +} + +OUString +ScVbaWorksheet::getName() +{ + uno::Reference< container::XNamed > xNamed( getSheet(), uno::UNO_QUERY_THROW ); + return xNamed->getName(); +} + +void +ScVbaWorksheet::setName(const OUString &rName ) +{ + uno::Reference< container::XNamed > xNamed( getSheet(), uno::UNO_QUERY_THROW ); + xNamed->setName( rName ); +} + +sal_Int32 +ScVbaWorksheet::getVisible() +{ + uno::Reference< beans::XPropertySet > xProps( getSheet(), uno::UNO_QUERY_THROW ); + bool bVisible = false; + xProps->getPropertyValue( "IsVisible" ) >>= bVisible; + using namespace ::ooo::vba::excel::XlSheetVisibility; + return bVisible ? xlSheetVisible : (mbVeryHidden ? xlSheetVeryHidden : xlSheetHidden); +} + +void +ScVbaWorksheet::setVisible( sal_Int32 nVisible ) +{ + using namespace ::ooo::vba::excel::XlSheetVisibility; + bool bVisible = true; + switch( nVisible ) + { + case xlSheetVisible: case 1: // Excel accepts -1 and 1 for visible sheets + bVisible = true; + mbVeryHidden = false; + break; + case xlSheetHidden: + bVisible = false; + mbVeryHidden = false; + break; + case xlSheetVeryHidden: + bVisible = false; + mbVeryHidden = true; + break; + default: + throw uno::RuntimeException(); + } + uno::Reference< beans::XPropertySet > xProps( getSheet(), uno::UNO_QUERY_THROW ); + xProps->setPropertyValue( "IsVisible", uno::Any( bVisible ) ); +} + +sal_Int16 +ScVbaWorksheet::getIndex() +{ + return getSheetID() + 1; +} + +sal_Int32 +ScVbaWorksheet::getEnableSelection() +{ + uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( getModel(), uno::UNO_QUERY_THROW ); + SCTAB nTab = 0; + if ( !ScVbaWorksheets::nameExists(xSpreadDoc, getName(), nTab) ) + throw uno::RuntimeException("Sheet Name does not exist." ); + + uno::Reference< frame::XModel > xModel( getModel(), uno::UNO_SET_THROW ); + ScDocument& rDoc = excel::getDocShell( xModel )->GetDocument(); + const ScTableProtection* pProtect = rDoc.GetTabProtection(nTab); + bool bLockedCells = false; + bool bUnlockedCells = false; + if( pProtect ) + { + bLockedCells = pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS); + bUnlockedCells = pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS); + } + if( bLockedCells ) + return excel::XlEnableSelection::xlNoRestrictions; + if( bUnlockedCells ) + return excel::XlEnableSelection::xlUnlockedCells; + return excel::XlEnableSelection::xlNoSelection; + +} + +void +ScVbaWorksheet::setEnableSelection( sal_Int32 nSelection ) +{ + if( (nSelection != excel::XlEnableSelection::xlNoRestrictions) && + (nSelection != excel::XlEnableSelection::xlUnlockedCells) && + (nSelection != excel::XlEnableSelection::xlNoSelection) ) + { + DebugHelper::runtimeexception(ERRCODE_BASIC_BAD_PARAMETER); + } + + uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( getModel(), uno::UNO_QUERY_THROW ); + SCTAB nTab = 0; + if ( !ScVbaWorksheets::nameExists(xSpreadDoc, getName(), nTab) ) + throw uno::RuntimeException("Sheet Name does not exist." ); + + uno::Reference< frame::XModel > xModel( getModel(), uno::UNO_SET_THROW ); + ScDocument& rDoc = excel::getDocShell( xModel )->GetDocument(); + const ScTableProtection* pProtect = rDoc.GetTabProtection(nTab); + // default is xlNoSelection + bool bLockedCells = false; + bool bUnlockedCells = false; + if( nSelection == excel::XlEnableSelection::xlNoRestrictions ) + { + bLockedCells = true; + bUnlockedCells = true; + } + else if( nSelection == excel::XlEnableSelection::xlUnlockedCells ) + { + bUnlockedCells = true; + } + if( pProtect ) + { + ScTableProtection aNewProtect(*pProtect); + aNewProtect.setOption(ScTableProtection::SELECT_LOCKED_CELLS, bLockedCells); + aNewProtect.setOption(ScTableProtection::SELECT_UNLOCKED_CELLS, bUnlockedCells); + rDoc.SetTabProtection(nTab, &aNewProtect); + } + + +} + +sal_Bool SAL_CALL ScVbaWorksheet::getAutoFilterMode() +{ + uno::Reference< frame::XModel > xModel( getModel(), uno::UNO_SET_THROW ); + ScDocument& rDoc = excel::getDocShell( xModel )->GetDocument(); + ScDBData* pDBData = rDoc.GetAnonymousDBData(getSheetID()); + if (pDBData) + return pDBData->HasAutoFilter(); + return false; +} + +void SAL_CALL ScVbaWorksheet::setAutoFilterMode( sal_Bool bAutoFilterMode ) +{ + uno::Reference< frame::XModel > xModel( getModel(), uno::UNO_SET_THROW ); + ScDocShell* pDocShell = excel::getDocShell( xModel ); + ScDocument& rDoc = pDocShell->GetDocument(); + ScDBData* pDBData = rDoc.GetAnonymousDBData(getSheetID()); + if (!pDBData) + return; + + pDBData->SetAutoFilter(bAutoFilterMode); + ScRange aRange; + pDBData->GetArea(aRange); + if (bAutoFilterMode) + rDoc.ApplyFlagsTab( aRange.aStart.Col(), aRange.aStart.Row(), + aRange.aEnd.Col(), aRange.aStart.Row(), + aRange.aStart.Tab(), ScMF::Auto ); + else if (!bAutoFilterMode) + rDoc.RemoveFlagsTab(aRange.aStart.Col(), aRange.aStart.Row(), + aRange.aEnd.Col(), aRange.aStart.Row(), + aRange.aStart.Tab(), ScMF::Auto ); + ScRange aPaintRange(aRange.aStart, aRange.aEnd); + aPaintRange.aEnd.SetRow(aPaintRange.aStart.Row()); + pDocShell->PostPaint(aPaintRange, PaintPartFlags::Grid); +} + +uno::Reference< excel::XRange > +ScVbaWorksheet::getUsedRange() +{ + uno::Reference< sheet::XSheetCellRange > xSheetCellRange(getSheet(), uno::UNO_QUERY_THROW ); + uno::Reference< sheet::XSheetCellCursor > xSheetCellCursor( getSheet()->createCursorByRange( xSheetCellRange ), uno::UNO_SET_THROW ); + uno::Reference<sheet::XUsedAreaCursor> xUsedCursor(xSheetCellCursor,uno::UNO_QUERY_THROW); + xUsedCursor->gotoStartOfUsedArea( false ); + xUsedCursor->gotoEndOfUsedArea( true ); + return new ScVbaRange(this, mxContext, xSheetCellCursor); +} + +uno::Reference< excel::XOutline > +ScVbaWorksheet::Outline( ) +{ + uno::Reference<sheet::XSheetOutline> xOutline(getSheet(),uno::UNO_QUERY_THROW); + return new ScVbaOutline( this, mxContext, xOutline); +} + +uno::Reference< excel::XPageSetup > +ScVbaWorksheet::PageSetup( ) +{ + return new ScVbaPageSetup( this, mxContext, getSheet(), getModel() ); +} + +uno::Any +ScVbaWorksheet::HPageBreaks( const uno::Any& aIndex ) +{ + uno::Reference< sheet::XSheetPageBreak > xSheetPageBreak(getSheet(),uno::UNO_QUERY_THROW); + uno::Reference< excel::XHPageBreaks > xHPageBreaks( new ScVbaHPageBreaks( this, mxContext, xSheetPageBreak)); + if ( aIndex.hasValue() ) + return xHPageBreaks->Item( aIndex, uno::Any()); + return uno::Any( xHPageBreaks ); +} + +uno::Any +ScVbaWorksheet::VPageBreaks( const uno::Any& aIndex ) +{ + uno::Reference< sheet::XSheetPageBreak > xSheetPageBreak( getSheet(), uno::UNO_QUERY_THROW ); + uno::Reference< excel::XVPageBreaks > xVPageBreaks( new ScVbaVPageBreaks( this, mxContext, xSheetPageBreak ) ); + if( aIndex.hasValue() ) + return xVPageBreaks->Item( aIndex, uno::Any()); + return uno::Any( xVPageBreaks ); +} + +sal_Int32 +ScVbaWorksheet::getStandardWidth() +{ + return STANDARDWIDTH ; +} + +sal_Int32 +ScVbaWorksheet::getStandardHeight() +{ + return STANDARDHEIGHT; +} + +sal_Bool +ScVbaWorksheet::getProtectionMode() +{ + return false; +} + +sal_Bool +ScVbaWorksheet::getProtectContents() +{ + uno::Reference<util::XProtectable > xProtectable(getSheet(), uno::UNO_QUERY_THROW); + return xProtectable->isProtected(); +} + +sal_Bool +ScVbaWorksheet::getProtectDrawingObjects() +{ + SCTAB nTab = 0; + OUString aSheetName = getName(); + uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( getModel(), uno::UNO_QUERY_THROW ); + bool bSheetExists = ScVbaWorksheets::nameExists (xSpreadDoc, aSheetName, nTab); + if ( bSheetExists ) + { + uno::Reference< frame::XModel > xModel( getModel(), uno::UNO_SET_THROW ); + ScDocument& rDoc = excel::getDocShell( xModel )->GetDocument(); + const ScTableProtection* pProtect = rDoc.GetTabProtection(nTab); + if ( pProtect ) + return pProtect->isOptionEnabled( ScTableProtection::OBJECTS ); + } + return false; +} + +sal_Bool +ScVbaWorksheet::getProtectScenarios() +{ + return false; +} + +void +ScVbaWorksheet::Activate() +{ + uno::Reference< sheet::XSpreadsheetView > xSpreadsheet( + getModel()->getCurrentController(), uno::UNO_QUERY_THROW ); + xSpreadsheet->setActiveSheet(getSheet()); +} + +void +ScVbaWorksheet::Select() +{ + Activate(); +} + +void +ScVbaWorksheet::Move( const uno::Any& Before, const uno::Any& After ) +{ + uno::Reference<excel::XWorksheet> xSheet; + OUString aCurrSheetName = getName(); + + if (!(Before >>= xSheet) && !(After >>=xSheet)&& !(Before.hasValue()) && !(After.hasValue())) + { + uno::Reference< sheet::XSheetCellCursor > xSheetCellCursor = getSheet()->createCursor( ); + uno::Reference<sheet::XUsedAreaCursor> xUsedCursor(xSheetCellCursor,uno::UNO_QUERY_THROW); + // #FIXME needs worksheet as parent + uno::Reference<excel::XRange> xRange = new ScVbaRange( this, mxContext, xSheetCellCursor); + if (xRange.is()) + xRange->Select(); + excel::implnCopy(mxModel); + uno::Reference<frame::XModel> xModel = openNewDoc(aCurrSheetName); + if (xModel.is()) + { + excel::implnPaste(xModel); + Delete(); + } + return ; + } + + uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( getModel(), uno::UNO_QUERY_THROW ); + SCTAB nDest = 0; + if ( ScVbaWorksheets::nameExists (xSpreadDoc, xSheet->getName(), nDest) ) + { + bool bAfter = After.hasValue(); + if (bAfter) + nDest++; + uno::Reference<sheet::XSpreadsheets> xSheets = xSpreadDoc->getSheets(); + xSheets->moveByName(aCurrSheetName,nDest); + } +} + +void +ScVbaWorksheet::Copy( const uno::Any& Before, const uno::Any& After ) +{ + uno::Reference<excel::XWorksheet> xSheet; + if (!(Before >>= xSheet) && !(After >>=xSheet)&& !(Before.hasValue()) && !(After.hasValue())) + { + createSheetCopyInNewDoc(getName()); + return; + } + + uno::Reference<excel::XWorksheet> xNewSheet = createSheetCopy(xSheet, After.hasValue()); + xNewSheet->Activate(); +} + +void +ScVbaWorksheet::Paste( const uno::Any& Destination, const uno::Any& /*Link*/ ) +{ + // #TODO# #FIXME# Link is not used + uno::Reference<excel::XRange> xRange( Destination, uno::UNO_QUERY ); + if ( xRange.is() ) + xRange->Select(); + excel::implnPaste( mxModel ); +} + +void +ScVbaWorksheet::Delete() +{ + uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( getModel(), uno::UNO_QUERY_THROW ); + OUString aSheetName = getName(); + SCTAB nTab = 0; + if (!ScVbaWorksheets::nameExists(xSpreadDoc, aSheetName, nTab )) + { + return; + } + uno::Reference<sheet::XSpreadsheets> xSheets = xSpreadDoc->getSheets(); + uno::Reference<container::XNameContainer> xNameContainer(xSheets,uno::UNO_QUERY_THROW); + xNameContainer->removeByName(aSheetName); + mxSheet.clear(); +} + +uno::Reference< excel::XWorksheet > +ScVbaWorksheet::getSheetAtOffset(SCTAB offset) +{ + uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( getModel(), uno::UNO_QUERY_THROW ); + uno::Reference <sheet::XSpreadsheets> xSheets( xSpreadDoc->getSheets(), uno::UNO_SET_THROW ); + uno::Reference <container::XIndexAccess> xIndex( xSheets, uno::UNO_QUERY_THROW ); + + SCTAB nIdx = 0; + if ( !ScVbaWorksheets::nameExists (xSpreadDoc, getName(), nIdx ) ) + return uno::Reference< excel::XWorksheet >(); + nIdx = nIdx + offset; + uno::Reference< sheet::XSpreadsheet > xSheet(xIndex->getByIndex(nIdx), uno::UNO_QUERY_THROW); + // parent will be the parent of 'this' worksheet + return new ScVbaWorksheet (getParent(), mxContext, xSheet, getModel()); +} + +uno::Reference< excel::XWorksheet > +ScVbaWorksheet::getNext() +{ + return getSheetAtOffset(static_cast<SCTAB>(1)); +} + +uno::Reference< excel::XWorksheet > +ScVbaWorksheet::getPrevious() +{ + return getSheetAtOffset(-1); +} + +void +ScVbaWorksheet::Protect( const uno::Any& Password, const uno::Any& /*DrawingObjects*/, const uno::Any& /*Contents*/, const uno::Any& /*Scenarios*/, const uno::Any& /*UserInterfaceOnly*/ ) +{ + // #TODO# #FIXME# is there anything we can do with the unused param + // can the implementation use anything else here + uno::Reference<util::XProtectable > xProtectable(getSheet(), uno::UNO_QUERY_THROW); + OUString aPasswd; + Password >>= aPasswd; + xProtectable->protect( aPasswd ); +} + +void +ScVbaWorksheet::Unprotect( const uno::Any& Password ) +{ + uno::Reference<util::XProtectable > xProtectable(getSheet(), uno::UNO_QUERY_THROW); + OUString aPasswd; + Password >>= aPasswd; + xProtectable->unprotect( aPasswd ); +} + +void +ScVbaWorksheet::Calculate() +{ + uno::Reference <sheet::XCalculatable> xReCalculate(getModel(), uno::UNO_QUERY_THROW); + xReCalculate->calculate(); +} + +uno::Reference< excel::XRange > +ScVbaWorksheet::Range( const ::uno::Any& Cell1, const ::uno::Any& Cell2 ) +{ + uno::Reference< excel::XRange > xSheetRange( new ScVbaRange( this, mxContext +, uno::Reference< table::XCellRange >( getSheet(), uno::UNO_QUERY_THROW ) ) ); + return xSheetRange->Range( Cell1, Cell2 ); +} + +void +ScVbaWorksheet::CheckSpelling( const uno::Any& /*CustomDictionary*/,const uno::Any& /*IgnoreUppercase*/,const uno::Any& /*AlwaysSuggest*/, const uno::Any& /*SpellingLang*/ ) +{ + // #TODO# #FIXME# unused params above, can we do anything with those + uno::Reference< frame::XModel > xModel( getModel() ); + dispatchRequests(xModel,".uno:SpellDialog"); +} + +uno::Reference< excel::XRange > +ScVbaWorksheet::getSheetRange() +{ + uno::Reference< table::XCellRange > xRange( getSheet(),uno::UNO_QUERY_THROW ); + return uno::Reference< excel::XRange >( new ScVbaRange( this, mxContext, xRange ) ); +} + +// These are hacks - we prolly (somehow) need to inherit +// the vbarange functionality here ... +uno::Reference< excel::XRange > +ScVbaWorksheet::Cells( const ::uno::Any &nRow, const ::uno::Any &nCol ) +{ + // Performance optimization for often-called Cells method: + // Use a common helper method instead of creating a new ScVbaRange object + uno::Reference< table::XCellRange > xRange( getSheet(), uno::UNO_QUERY_THROW ); + uno::Reference< frame::XModel > xModel( getModel(), uno::UNO_SET_THROW ); + ScDocument& rDoc = excel::getDocShell( xModel )->GetDocument(); + return ScVbaRange::CellsHelper( rDoc, this, mxContext, xRange, nRow, nCol ); +} + +uno::Reference< excel::XRange > +ScVbaWorksheet::Rows(const uno::Any& aIndex ) +{ + return getSheetRange()->Rows( aIndex ); +} + +uno::Reference< excel::XRange > +ScVbaWorksheet::Columns( const uno::Any& aIndex ) +{ + return getSheetRange()->Columns( aIndex ); +} + +uno::Any SAL_CALL +ScVbaWorksheet::ChartObjects( const uno::Any& Index ) +{ + if ( !mxCharts.is() ) + { + uno::Reference< table::XTableChartsSupplier > xChartSupplier( getSheet(), uno::UNO_QUERY_THROW ); + uno::Reference< table::XTableCharts > xTableCharts = xChartSupplier->getCharts(); + + uno::Reference< drawing::XDrawPageSupplier > xDrawPageSupplier( mxSheet, uno::UNO_QUERY_THROW ); + mxCharts = new ScVbaChartObjects( this, mxContext, xTableCharts, xDrawPageSupplier ); + } + if ( Index.hasValue() ) + { + uno::Reference< XCollection > xColl( mxCharts, uno::UNO_QUERY_THROW ); + return xColl->Item( Index, uno::Any() ); + } + else + return uno::Any( mxCharts ); + +} + +uno::Any SAL_CALL +ScVbaWorksheet::PivotTables( const uno::Any& Index ) +{ + uno::Reference< css::sheet::XSpreadsheet > xSheet = getSheet(); + uno::Reference< sheet::XDataPilotTablesSupplier > xTables(xSheet, uno::UNO_QUERY_THROW ) ; + uno::Reference< container::XIndexAccess > xIndexAccess( xTables->getDataPilotTables(), uno::UNO_QUERY_THROW ); + + uno::Reference< XCollection > xColl( new ScVbaPivotTables( this, mxContext, xIndexAccess ) ); + if ( Index.hasValue() ) + return xColl->Item( Index, uno::Any() ); + return uno::Any( xColl ); +} + +uno::Any SAL_CALL +ScVbaWorksheet::Comments( const uno::Any& Index ) +{ + uno::Reference< css::sheet::XSpreadsheet > xSheet = getSheet(); + uno::Reference< sheet::XSheetAnnotationsSupplier > xAnnosSupp( xSheet, uno::UNO_QUERY_THROW ); + uno::Reference< sheet::XSheetAnnotations > xAnnos( xAnnosSupp->getAnnotations(), uno::UNO_SET_THROW ); + uno::Reference< container::XIndexAccess > xIndexAccess( xAnnos, uno::UNO_QUERY_THROW ); + uno::Reference< XCollection > xColl( new ScVbaComments( this, mxContext, mxModel, xIndexAccess ) ); + if ( Index.hasValue() ) + return xColl->Item( Index, uno::Any() ); + return uno::Any( xColl ); +} + +uno::Any SAL_CALL +ScVbaWorksheet::Hyperlinks( const uno::Any& aIndex ) +{ + /* The worksheet always returns the same Hyperlinks object. + See vbahyperlinks.hxx for more details. */ + if( !mxHlinks.is() ) + mxHlinks.set( new ScVbaHyperlinks( this, mxContext ) ); + if( aIndex.hasValue() ) + return uno::Reference< XCollection >( mxHlinks, uno::UNO_QUERY_THROW )->Item( aIndex, uno::Any() ); + return uno::Any( mxHlinks ); +} + +uno::Any SAL_CALL +ScVbaWorksheet::Names( const css::uno::Any& aIndex ) +{ + css::uno::Reference<css::beans::XPropertySet> xProps(getSheet(), css::uno::UNO_QUERY_THROW); + uno::Reference< sheet::XNamedRanges > xNamedRanges( xProps->getPropertyValue("NamedRanges"), uno::UNO_QUERY_THROW ); + uno::Reference< XCollection > xNames( new ScVbaNames( this, mxContext, xNamedRanges, mxModel ) ); + if ( aIndex.hasValue() ) + return xNames->Item( aIndex, uno::Any() ); + return uno::Any( xNames ); +} + +uno::Any SAL_CALL +ScVbaWorksheet::OLEObjects( const uno::Any& Index ) +{ + uno::Reference< sheet::XSpreadsheet > xSpreadsheet( getSheet(), uno::UNO_SET_THROW ); + uno::Reference< drawing::XDrawPageSupplier > xDrawPageSupplier( xSpreadsheet, uno::UNO_QUERY_THROW ); + uno::Reference< drawing::XDrawPage > xDrawPage( xDrawPageSupplier->getDrawPage(), uno::UNO_SET_THROW ); + uno::Reference< container::XIndexAccess > xIndexAccess( xDrawPage, uno::UNO_QUERY_THROW ); + + uno::Reference< excel::XOLEObjects >xOleObjects( new ScVbaOLEObjects( this, mxContext, xIndexAccess ) ); + if( Index.hasValue() ) + return xOleObjects->Item( Index, uno::Any() ); + return uno::Any( xOleObjects ); +} + +uno::Any SAL_CALL +ScVbaWorksheet::Shapes( const uno::Any& aIndex ) +{ + uno::Reference< sheet::XSpreadsheet > xSpreadsheet( getSheet(), uno::UNO_SET_THROW ); + uno::Reference< drawing::XDrawPageSupplier > xDrawPageSupplier( xSpreadsheet, uno::UNO_QUERY_THROW ); + uno::Reference< drawing::XShapes > xShapes( xDrawPageSupplier->getDrawPage(), uno::UNO_QUERY_THROW ); + uno::Reference< container::XIndexAccess > xIndexAccess( xShapes, uno::UNO_QUERY_THROW ); + + uno::Reference< msforms::XShapes> xVbaShapes( new ScVbaShapes( this, mxContext, xIndexAccess, getModel() ) ); + if ( aIndex.hasValue() ) + return xVbaShapes->Item( aIndex, uno::Any() ); + return uno::Any( xVbaShapes ); +} + +uno::Any +ScVbaWorksheet::getButtons( const uno::Any &rIndex, bool bOptionButtons ) +{ + ::rtl::Reference< ScVbaSheetObjectsBase > &rxButtons = bOptionButtons ? mxButtons[0] : mxButtons[1]; + + if( !rxButtons.is() ) + rxButtons.set( new ScVbaButtons( this, mxContext, mxModel, mxSheet, bOptionButtons ) ); + else + rxButtons->collectShapes(); + if( rIndex.hasValue() ) + return rxButtons->Item( rIndex, uno::Any() ); + return uno::Any( uno::Reference< XCollection >( rxButtons ) ); +} + +uno::Any SAL_CALL +ScVbaWorksheet::Buttons( const uno::Any& rIndex ) +{ + return getButtons( rIndex, false ); +} + +uno::Any SAL_CALL +ScVbaWorksheet::CheckBoxes( const uno::Any& /*rIndex*/ ) +{ + throw uno::RuntimeException(); +} + +uno::Any SAL_CALL +ScVbaWorksheet::DropDowns( const uno::Any& /*rIndex*/ ) +{ + throw uno::RuntimeException(); +} + +uno::Any SAL_CALL +ScVbaWorksheet::GroupBoxes( const uno::Any& /*rIndex*/ ) +{ + throw uno::RuntimeException(); +} + +uno::Any SAL_CALL +ScVbaWorksheet::Labels( const uno::Any& /*rIndex*/ ) +{ + throw uno::RuntimeException(); +} + +uno::Any SAL_CALL +ScVbaWorksheet::ListBoxes( const uno::Any& /*rIndex*/ ) +{ + throw uno::RuntimeException(); +} + +uno::Any SAL_CALL +ScVbaWorksheet::OptionButtons( const uno::Any& rIndex ) +{ + return getButtons( rIndex, true ); +} + +uno::Any SAL_CALL +ScVbaWorksheet::ScrollBars( const uno::Any& /*rIndex*/ ) +{ + throw uno::RuntimeException(); +} + +uno::Any SAL_CALL +ScVbaWorksheet::Spinners( const uno::Any& /*rIndex*/ ) +{ + throw uno::RuntimeException(); +} + +void SAL_CALL +ScVbaWorksheet::ShowDataForm( ) +{ + uno::Reference< frame::XModel > xModel( getModel(), uno::UNO_SET_THROW ); + ScTabViewShell* pTabViewShell = excel::getBestViewShell( xModel ); + + ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create(); + + ScopedVclPtr<AbstractScDataFormDlg> pDlg(pFact->CreateScDataFormDlg(pTabViewShell->GetFrameWeld(), + pTabViewShell)); + + pDlg->Execute(); +} + +uno::Any SAL_CALL +ScVbaWorksheet::Evaluate( const OUString& Name ) +{ + // #TODO Evaluate allows other things to be evaluated, e.g. functions + // I think ( like SIN(3) etc. ) need to investigate that + // named Ranges also? e.g. [MyRange] if so need a list of named ranges + uno::Any aVoid; + return uno::Any( Range( uno::Any( Name ), aVoid ) ); +} + +uno::Reference< beans::XIntrospectionAccess > SAL_CALL +ScVbaWorksheet::getIntrospection( ) +{ + return uno::Reference< beans::XIntrospectionAccess >(); +} + +uno::Any SAL_CALL +ScVbaWorksheet::invoke( const OUString& /*aFunctionName*/, const uno::Sequence< uno::Any >& /*aParams*/, uno::Sequence< ::sal_Int16 >& /*aOutParamIndex*/, uno::Sequence< uno::Any >& /*aOutParam*/ ) +{ + throw uno::RuntimeException("Unsupported"); // unsupported operation +} + +void SAL_CALL +ScVbaWorksheet::setValue( const OUString& aPropertyName, const uno::Any& aValue ) +{ + setDefaultPropByIntrospection( getValue( aPropertyName ), aValue ); +} +uno::Any SAL_CALL +ScVbaWorksheet::getValue( const OUString& aPropertyName ) +{ + uno::Reference< drawing::XControlShape > xControlShape( getControlShape( aPropertyName ), uno::UNO_QUERY_THROW ); + + uno::Reference<lang::XMultiComponentFactory > xServiceManager( mxContext->getServiceManager(), uno::UNO_SET_THROW ); + uno::Reference< XControlProvider > xControlProvider( xServiceManager->createInstanceWithContext("ooo.vba.ControlProvider", mxContext ), uno::UNO_QUERY_THROW ); + uno::Reference< msforms::XControl > xControl( xControlProvider->createControl( xControlShape, getModel() ) ); + return uno::Any( xControl ); +} + +sal_Bool SAL_CALL +ScVbaWorksheet::hasMethod( const OUString& /*aName*/ ) +{ + return false; +} + +uno::Reference< container::XNameAccess > +ScVbaWorksheet::getFormControls() const +{ + uno::Reference< container::XNameAccess > xFormControls; + try + { + uno::Reference< sheet::XSpreadsheet > xSpreadsheet( getSheet(), uno::UNO_SET_THROW ); + uno::Reference< drawing::XDrawPageSupplier > xDrawPageSupplier( xSpreadsheet, uno::UNO_QUERY_THROW ); + uno::Reference< form::XFormsSupplier > xFormSupplier( xDrawPageSupplier->getDrawPage(), uno::UNO_QUERY_THROW ); + uno::Reference< container::XIndexAccess > xIndexAccess( xFormSupplier->getForms(), uno::UNO_QUERY_THROW ); + // get the www-standard container ( maybe we should access the + // 'www-standard' by name rather than index, this seems an + // implementation detail + if( xIndexAccess->hasElements() ) + xFormControls.set( xIndexAccess->getByIndex(0), uno::UNO_QUERY ); + + } + catch( uno::Exception& ) + { + } + return xFormControls; + + } +sal_Bool SAL_CALL +ScVbaWorksheet::hasProperty( const OUString& aName ) +{ + uno::Reference< container::XNameAccess > xFormControls( getFormControls() ); + if ( xFormControls.is() ) + return xFormControls->hasByName( aName ); + return false; +} + +uno::Any +ScVbaWorksheet::getControlShape( std::u16string_view sName ) +{ + // ideally we would get an XControl object but it appears an XControl + // implementation only exists for a Control implementation obtained from the + // view ( e.g. in basic you would get this from + // thiscomponent.currentcontroller.getControl( controlModel ) ) + // and the thing to realise is that it is only possible to get an XControl + // for a currently displayed control :-( often we would want to modify + // a control not on the active sheet. But... you can always access the + // XControlShape from the DrawPage whether that is the active drawpage or not + + uno::Reference< drawing::XDrawPageSupplier > xDrawPageSupplier( getSheet(), uno::UNO_QUERY_THROW ); + uno::Reference< container::XIndexAccess > xIndexAccess( xDrawPageSupplier->getDrawPage(), uno::UNO_QUERY_THROW ); + + sal_Int32 nCount = xIndexAccess->getCount(); + for( int index = 0; index < nCount; index++ ) + { + uno::Any aUnoObj = xIndexAccess->getByIndex( index ); + // It seems there are some drawing objects that can not query into Control shapes? + uno::Reference< drawing::XControlShape > xControlShape( aUnoObj, uno::UNO_QUERY ); + if( xControlShape.is() ) + { + uno::Reference< container::XNamed > xNamed( xControlShape->getControl(), uno::UNO_QUERY_THROW ); + if( sName == xNamed->getName() ) + { + return aUnoObj; + } + } + } + return uno::Any(); +} + +OUString +ScVbaWorksheet::getServiceImplName() +{ + return "ScVbaWorksheet"; +} + +void SAL_CALL +ScVbaWorksheet::setEnableCalculation( sal_Bool bEnableCalculation ) +{ + uno::Reference <sheet::XCalculatable> xCalculatable(getModel(), uno::UNO_QUERY_THROW); + xCalculatable->enableAutomaticCalculation( bEnableCalculation); +} +sal_Bool SAL_CALL +ScVbaWorksheet::getEnableCalculation( ) +{ + uno::Reference <sheet::XCalculatable> xCalculatable(getModel(), uno::UNO_QUERY_THROW); + return xCalculatable->isAutomaticCalculationEnabled(); +} + +uno::Sequence< OUString > +ScVbaWorksheet::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.Worksheet" + }; + return aServiceNames; +} + +OUString SAL_CALL +ScVbaWorksheet::getCodeName() +{ + uno::Reference< beans::XPropertySet > xSheetProp( mxSheet, uno::UNO_QUERY_THROW ); + return xSheetProp->getPropertyValue("CodeName").get< OUString >(); +} + +sal_Int16 +ScVbaWorksheet::getSheetID() const +{ + uno::Reference< sheet::XCellRangeAddressable > xAddressable( mxSheet, uno::UNO_QUERY_THROW ); // if ActiveSheet, mxSheet is null. + return xAddressable->getRangeAddress().Sheet; +} + +void SAL_CALL +ScVbaWorksheet::PrintOut( const uno::Any& From, const uno::Any& To, const uno::Any& Copies, const uno::Any& Preview, const uno::Any& ActivePrinter, const uno::Any& PrintToFile, const uno::Any& Collate, const uno::Any& PrToFileName, const uno::Any& ) +{ + sal_Int32 nTo = 0; + sal_Int32 nFrom = 0; + bool bSelection = false; + From >>= nFrom; + To >>= nTo; + + if ( !( nFrom || nTo ) ) + bSelection = true; + + uno::Reference< frame::XModel > xModel( getModel(), uno::UNO_SET_THROW ); + PrintOutHelper( excel::getBestViewShell( xModel ), From, To, Copies, Preview, ActivePrinter, PrintToFile, Collate, PrToFileName, bSelection ); +} + +sal_Int64 SAL_CALL +ScVbaWorksheet::getSomething(const uno::Sequence<sal_Int8 > & rId) +{ + return comphelper::getSomethingImpl(rId, this); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +Calc_ScVbaWorksheet_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& args) +{ + return cppu::acquire(new ScVbaWorksheet(args, context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaworksheet.hxx b/sc/source/ui/vba/vbaworksheet.hxx new file mode 100644 index 000000000..5eee3df4a --- /dev/null +++ b/sc/source/ui/vba/vbaworksheet.hxx @@ -0,0 +1,167 @@ +/* -*- 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 . + */ +#pragma once + +#include <ooo/vba/excel/XWorksheet.hpp> +#include <rtl/ref.hxx> + +#include <vbahelper/vbahelperinterface.hxx> +#include <types.hxx> + +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::sheet { class XSpreadsheet; } +namespace com::sun::star::uno { class XComponentContext; } +namespace ooo::vba::excel { class XOutline; } +namespace ooo::vba::excel { class XPageSetup; } +namespace ooo::vba::excel { class XRange; } + +namespace ooo::vba::excel { + class XChartObjects; + class XHyperlinks; +} + +class ScVbaSheetObjectsBase; + +typedef InheritedHelperInterfaceWeakImpl< ov::excel::XWorksheet > WorksheetImpl_BASE; + +class ScVbaWorksheet : public WorksheetImpl_BASE +{ + css::uno::Reference< css::sheet::XSpreadsheet > mxSheet; + css::uno::Reference< css::frame::XModel > mxModel; + css::uno::Reference< ov::excel::XChartObjects > mxCharts; + css::uno::Reference< ov::excel::XHyperlinks > mxHlinks; + ::rtl::Reference< ScVbaSheetObjectsBase > mxButtons[2]; + bool mbVeryHidden; + + /// @throws css::uno::RuntimeException + css::uno::Reference< ov::excel::XWorksheet > getSheetAtOffset(SCTAB offset); + /// @throws css::uno::RuntimeException + css::uno::Reference< ov::excel::XRange > getSheetRange(); + + css::uno::Reference< css::container::XNameAccess > getFormControls() const; + css::uno::Any getControlShape( std::u16string_view sName ); + + css::uno::Any getButtons( const css::uno::Any &rIndex, bool bOptionButtons ); + +public: + /// @throws css::uno::RuntimeException + ScVbaWorksheet( const css::uno::Reference< ov::XHelperInterface >& xParent, + const css::uno::Reference< css::uno::XComponentContext >& xContext, + const css::uno::Reference< css::sheet::XSpreadsheet >& xSheet, + const css::uno::Reference< css::frame::XModel >& xModel ) ; + /// @throws css::lang::IllegalArgumentException + /// @throws css::uno::RuntimeException + ScVbaWorksheet( css::uno::Sequence< css::uno::Any > const& aArgs, css::uno::Reference< css::uno::XComponentContext >const& xContext ); + + virtual ~ScVbaWorksheet() override; + + const css::uno::Reference< css::frame::XModel >& getModel() const + { return mxModel; } + const css::uno::Reference< css::sheet::XSpreadsheet >& getSheet() const + { return mxSheet; } + static const css::uno::Sequence<sal_Int8>& getUnoTunnelId(); + css::uno::Reference< ov::excel::XWorksheet > createSheetCopyInNewDoc( const OUString& ); + css::uno::Reference< ov::excel::XWorksheet > createSheetCopy(css::uno::Reference< ov::excel::XWorksheet> const & xSheet, bool bAfter); + + // Attributes + virtual OUString SAL_CALL getName() override; + virtual void SAL_CALL setName( const OUString &rName ) override; + virtual sal_Int32 SAL_CALL getVisible() override; + virtual void SAL_CALL setVisible( sal_Int32 nVisible ) override; + virtual ::sal_Int32 SAL_CALL getStandardWidth() override; + virtual ::sal_Int32 SAL_CALL getStandardHeight() override; + virtual sal_Bool SAL_CALL getProtectionMode() override; + virtual sal_Bool SAL_CALL getProtectContents() override; + virtual sal_Bool SAL_CALL getProtectDrawingObjects() override; + virtual sal_Bool SAL_CALL getProtectScenarios() override; + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL getUsedRange() override ; + virtual css::uno::Any SAL_CALL ChartObjects( const css::uno::Any& Index ) override; + virtual css::uno::Reference< ov::excel::XOutline > SAL_CALL Outline( ) override; + virtual css::uno::Reference< ov::excel::XPageSetup > SAL_CALL PageSetup( ) override; + virtual css::uno::Any SAL_CALL HPageBreaks( const css::uno::Any& aIndex ) override; + virtual css::uno::Any SAL_CALL VPageBreaks( const css::uno::Any& aIndex ) override; + virtual css::uno::Reference< ov::excel::XWorksheet > SAL_CALL getNext() override; + virtual css::uno::Reference< ov::excel::XWorksheet > SAL_CALL getPrevious() override; + virtual sal_Int16 SAL_CALL getIndex() override; + virtual sal_Int32 SAL_CALL getEnableSelection() override; + virtual void SAL_CALL setEnableSelection( sal_Int32 nSelection ) override; + virtual sal_Bool SAL_CALL getAutoFilterMode() override; + virtual void SAL_CALL setAutoFilterMode( sal_Bool bAutoFilterMode ) override; + + // Methods + virtual void SAL_CALL Activate() override; + virtual void SAL_CALL Select() override; + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Range( const css::uno::Any& Cell1, const css::uno::Any& Cell2 ) override; + virtual void SAL_CALL Move( const css::uno::Any& Before, const css::uno::Any& After ) override ; + virtual void SAL_CALL Copy( const css::uno::Any& Before, const css::uno::Any& After ) override; + virtual void SAL_CALL Paste( const css::uno::Any& Destination, const css::uno::Any& Link ) override; + virtual void SAL_CALL Delete( ) override; + virtual void SAL_CALL Protect( const css::uno::Any& Password, const css::uno::Any& DrawingObjects, const css::uno::Any& Contents, const css::uno::Any& Scenarios, const css::uno::Any& UserInterfaceOnly ) override; + virtual void SAL_CALL Unprotect( const css::uno::Any& Password ) override; + + virtual void SAL_CALL Calculate( ) override; + virtual void SAL_CALL CheckSpelling( const css::uno::Any& CustomDictionary,const css::uno::Any& IgnoreUppercase,const css::uno::Any& AlwaysSuggest, const css::uno::Any& SpellingLang ) override; + // Hacks (?) + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Cells( const css::uno::Any &nRow, const css::uno::Any &nCol ) override; + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Rows(const css::uno::Any& aIndex ) override; + virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Columns(const css::uno::Any& aIndex ) override; + + virtual css::uno::Any SAL_CALL Evaluate( const OUString& Name ) override; + virtual css::uno::Any SAL_CALL PivotTables( const css::uno::Any& Index ) override; + virtual css::uno::Any SAL_CALL Comments( const css::uno::Any& Index ) override; + virtual css::uno::Any SAL_CALL Hyperlinks( const css::uno::Any& aIndex ) override; + virtual css::uno::Any SAL_CALL Names( const css::uno::Any& aIndex ) override; + + virtual css::uno::Any SAL_CALL OLEObjects( const css::uno::Any& Index ) override; + virtual css::uno::Any SAL_CALL Shapes( const css::uno::Any& aIndex ) override; + + virtual css::uno::Any SAL_CALL Buttons( const css::uno::Any& rIndex ) override; + virtual css::uno::Any SAL_CALL CheckBoxes( const css::uno::Any& rIndex ) override; + virtual css::uno::Any SAL_CALL DropDowns( const css::uno::Any& rIndex ) override; + virtual css::uno::Any SAL_CALL GroupBoxes( const css::uno::Any& rIndex ) override; + virtual css::uno::Any SAL_CALL Labels( const css::uno::Any& rIndex ) override; + virtual css::uno::Any SAL_CALL ListBoxes( const css::uno::Any& rIndex ) override; + virtual css::uno::Any SAL_CALL OptionButtons( const css::uno::Any& rIndex ) override; + virtual css::uno::Any SAL_CALL ScrollBars( const css::uno::Any& rIndex ) override; + virtual css::uno::Any SAL_CALL Spinners( const css::uno::Any& rIndex ) override; + + virtual void SAL_CALL setEnableCalculation( sal_Bool EnableCalculation ) override; + virtual sal_Bool SAL_CALL getEnableCalculation( ) override; + virtual void SAL_CALL ShowDataForm( ) override; + // XInvocation + virtual css::uno::Reference< css::beans::XIntrospectionAccess > SAL_CALL getIntrospection( ) override; + virtual css::uno::Any SAL_CALL invoke( const OUString& aFunctionName, const css::uno::Sequence< css::uno::Any >& aParams, css::uno::Sequence< ::sal_Int16 >& aOutParamIndex, css::uno::Sequence< css::uno::Any >& aOutParam ) override; + virtual void SAL_CALL setValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override; + virtual css::uno::Any SAL_CALL getValue( const OUString& aPropertyName ) override; + virtual sal_Bool SAL_CALL hasMethod( const OUString& aName ) override; + virtual sal_Bool SAL_CALL hasProperty( const OUString& aName ) override; + // CodeName + virtual OUString SAL_CALL getCodeName() override; + /// @throws css::uno::RuntimeException + sal_Int16 getSheetID() const; + + virtual void SAL_CALL PrintOut( const css::uno::Any& From, const css::uno::Any& To, const css::uno::Any& Copies, const css::uno::Any& Preview, const css::uno::Any& ActivePrinter, const css::uno::Any& PrintToFile, const css::uno::Any& Collate, const css::uno::Any& PrToFileName, const css::uno::Any& IgnorePrintAreas ) override; + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; + // XUnoTunnel + virtual ::sal_Int64 SAL_CALL getSomething(const css::uno::Sequence<sal_Int8 >& rId ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaworksheets.cxx b/sc/source/ui/vba/vbaworksheets.cxx new file mode 100644 index 000000000..5df1bc622 --- /dev/null +++ b/sc/source/ui/vba/vbaworksheets.cxx @@ -0,0 +1,535 @@ +/* -*- 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 "vbaworksheets.hxx" + +#include <sfx2/viewfrm.hxx> + +#include <cppuhelper/implbase.hxx> + +#include <com/sun/star/sheet/XSpreadsheetDocument.hpp> +#include <com/sun/star/container/XEnumerationAccess.hpp> +#include <com/sun/star/sheet/XSpreadsheet.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/script/XTypeConverter.hpp> + +#include <ooo/vba/excel/XApplication.hpp> +#include <tabvwsh.hxx> + +#include "excelvbahelper.hxx" +#include "vbaworksheet.hxx" +#include <markdata.hxx> + +#include <vector> +#include <prevwsh.hxx> +#include <preview.hxx> +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +// a map ( or hashmap ) won't do as we need also to preserve the order +// (as added ) of the items +typedef std::vector< uno::Reference< sheet::XSpreadsheet > > SheetMap; + +// #FIXME #TODO the implementation of the Sheets collections sucks, +// e.g. there is no support for tracking sheets added/removed from the collection + +namespace { + +class WorkSheetsEnumeration : public ::cppu::WeakImplHelper< container::XEnumeration > +{ + SheetMap mSheetMap; + SheetMap::iterator mIt; +public: + explicit WorkSheetsEnumeration( SheetMap&& sMap ) : mSheetMap( std::move(sMap) ), mIt( mSheetMap.begin() ) {} + virtual sal_Bool SAL_CALL hasMoreElements( ) override + { + return ( mIt != mSheetMap.end() ); + } + virtual uno::Any SAL_CALL nextElement( ) override + { + if ( !hasMoreElements() ) + throw container::NoSuchElementException(); + uno::Reference< sheet::XSpreadsheet > xSheet( *mIt++ ); + return uno::Any( xSheet ) ; + } +}; + +class SheetCollectionHelper : public ::cppu::WeakImplHelper< container::XNameAccess, + container::XIndexAccess, + container::XEnumerationAccess > +{ + SheetMap mSheetMap; + SheetMap::iterator cachePos; +public: + explicit SheetCollectionHelper( SheetMap&& sMap ) : mSheetMap( std::move(sMap) ), cachePos(mSheetMap.begin()) {} + // XElementAccess + virtual uno::Type SAL_CALL getElementType( ) override { return cppu::UnoType<sheet::XSpreadsheet>::get(); } + virtual sal_Bool SAL_CALL hasElements( ) override { return ( !mSheetMap.empty() ); } + // XNameAccess + virtual uno::Any SAL_CALL getByName( const OUString& aName ) override + { + if ( !hasByName(aName) ) + throw container::NoSuchElementException(); + return uno::Any( *cachePos ); + } + virtual uno::Sequence< OUString > SAL_CALL getElementNames( ) override + { + uno::Sequence< OUString > sNames( mSheetMap.size() ); + OUString* pString = sNames.getArray(); + + for ( const auto& rItem : mSheetMap ) + { + uno::Reference< container::XNamed > xName( rItem, uno::UNO_QUERY_THROW ); + *pString = xName->getName(); + ++pString; + } + return sNames; + } + virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override + { + cachePos = mSheetMap.begin(); + SheetMap::iterator it_end = mSheetMap.end(); + for ( ; cachePos != it_end; ++cachePos ) + { + uno::Reference< container::XNamed > xName( *cachePos, uno::UNO_QUERY_THROW ); + if ( aName == xName->getName() ) + break; + } + return ( cachePos != it_end ); + } + + // XElementAccess + virtual ::sal_Int32 SAL_CALL getCount( ) override { return mSheetMap.size(); } + virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override + { + if ( Index < 0 || Index >= getCount() ) + throw lang::IndexOutOfBoundsException(); + + return uno::Any( mSheetMap[ Index ] ); + + } + // XEnumerationAccess + virtual uno::Reference< container::XEnumeration > SAL_CALL createEnumeration( ) override + { + return new WorkSheetsEnumeration( std::vector(mSheetMap) ); + } +}; + +class SheetsEnumeration : public EnumerationHelperImpl +{ + uno::Reference< frame::XModel > m_xModel; +public: + /// @throws uno::RuntimeException + SheetsEnumeration( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< container::XEnumeration >& xEnumeration, const uno::Reference< frame::XModel >& xModel ) : EnumerationHelperImpl( xParent, xContext, xEnumeration ), m_xModel( xModel ) {} + + virtual uno::Any SAL_CALL nextElement( ) override + { + uno::Reference< sheet::XSpreadsheet > xSheet( m_xEnumeration->nextElement(), uno::UNO_QUERY_THROW ); + uno::Reference< XHelperInterface > xIf = excel::getUnoSheetModuleObj( xSheet ); + uno::Any aRet; + if ( !xIf.is() ) + { + // if the Sheet is in a document created by the api unfortunately ( at the + // moment, it actually won't have the special Document modules + uno::Reference< excel::XWorksheet > xNewSheet( new ScVbaWorksheet( m_xParent, m_xContext, xSheet, m_xModel ) ); + aRet <<= xNewSheet; + } + else + aRet <<= xIf; + return aRet; + } + +}; + +} + +ScVbaWorksheets::ScVbaWorksheets( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< css::uno::XComponentContext > & xContext, const uno::Reference< container::XIndexAccess >& xSheets, const uno::Reference< frame::XModel >& xModel ): ScVbaWorksheets_BASE( xParent, xContext, xSheets ), mxModel( xModel ), m_xSheets( uno::Reference< sheet::XSpreadsheets >( xSheets, uno::UNO_QUERY ) ) +{ +} + +ScVbaWorksheets::ScVbaWorksheets( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< css::uno::XComponentContext > & xContext, const uno::Reference< container::XEnumerationAccess >& xEnumAccess, const uno::Reference< frame::XModel >& xModel ): ScVbaWorksheets_BASE( xParent, xContext, uno::Reference< container::XIndexAccess >( xEnumAccess, uno::UNO_QUERY ) ), mxModel(xModel) +{ +} + +// XEnumerationAccess +uno::Type +ScVbaWorksheets::getElementType() +{ + return cppu::UnoType<excel::XWorksheet>::get(); +} + +uno::Reference< container::XEnumeration > +ScVbaWorksheets::createEnumeration() +{ + if ( !m_xSheets.is() ) + { + uno::Reference< container::XEnumerationAccess > xAccess( m_xIndexAccess, uno::UNO_QUERY_THROW ); + return xAccess->createEnumeration(); + } + uno::Reference< container::XEnumerationAccess > xEnumAccess( m_xSheets, uno::UNO_QUERY_THROW ); + return new SheetsEnumeration( this, mxContext, xEnumAccess->createEnumeration(), mxModel ); +} + +uno::Any +ScVbaWorksheets::createCollectionObject( const uno::Any& aSource ) +{ + uno::Reference< sheet::XSpreadsheet > xSheet( aSource, uno::UNO_QUERY ); + uno::Reference< XHelperInterface > xIf = excel::getUnoSheetModuleObj( xSheet ); + uno::Any aRet; + if ( !xIf.is() ) + { + // if the Sheet is in a document created by the api unfortunately ( at the + // moment, it actually won't have the special Document modules + uno::Reference< excel::XWorksheet > xNewSheet( new ScVbaWorksheet( getParent(), mxContext, xSheet, mxModel ) ); + aRet <<= xNewSheet; + } + else + aRet <<= xIf; + return aRet; +} + +// XWorksheets +uno::Any +ScVbaWorksheets::Add( const uno::Any& Before, const uno::Any& After, + const uno::Any& Count, const uno::Any& Type ) +{ + if ( isSelectedSheets() ) + return uno::Any(); // or should we throw? + + OUString aStringSheet; + bool bBefore(true); + SCTAB nSheetIndex = 0; + SCTAB nNewSheets = 1, nType = 0; + Count >>= nNewSheets; + Type >>= nType; + SCTAB nCount = 0; + + uno::Reference< excel::XWorksheet > xBeforeAfterSheet; + + if ( Before.hasValue() ) + { + if ( Before >>= xBeforeAfterSheet ) + aStringSheet = xBeforeAfterSheet->getName(); + else + Before >>= aStringSheet; + } + + if (aStringSheet.isEmpty() && After.hasValue() ) + { + if ( After >>= xBeforeAfterSheet ) + aStringSheet = xBeforeAfterSheet->getName(); + else + After >>= aStringSheet; + bBefore = false; + } + if (aStringSheet.isEmpty()) + { + uno::Reference< excel::XApplication > xApplication( Application(), uno::UNO_QUERY_THROW ); + aStringSheet = xApplication->getActiveWorkbook()->getActiveSheet()->getName(); + bBefore = true; + } + nCount = static_cast< SCTAB >( m_xIndexAccess->getCount() ); + for (SCTAB i=0; i < nCount; i++) + { + uno::Reference< sheet::XSpreadsheet > xSheet(m_xIndexAccess->getByIndex(i), uno::UNO_QUERY); + uno::Reference< container::XNamed > xNamed( xSheet, uno::UNO_QUERY_THROW ); + if (xNamed->getName() == aStringSheet) + { + nSheetIndex = i; + break; + } + } + + if(!bBefore) + nSheetIndex++; + + SCTAB nSheetName = nCount + 1; + OUString aStringBase( "Sheet" ); + uno::Any result; + for (SCTAB i=0; i < nNewSheets; i++, nSheetName++) + { + OUString aStringName = aStringBase + OUString::number(nSheetName); + while (m_xNameAccess->hasByName(aStringName)) + { + nSheetName++; + aStringName = aStringBase + OUString::number(nSheetName); + } + m_xSheets->insertNewByName(aStringName, nSheetIndex + i); + result = getItemByStringIndex( aStringName ); + } + uno::Reference< excel::XWorksheet > xNewSheet( result, uno::UNO_QUERY ); + if ( xNewSheet.is() ) + xNewSheet->Activate(); + return result; +} + +void +ScVbaWorksheets::Delete() +{ + // #TODO #INVESTIGATE + // mmm this method could be trouble if the underlying + // uno objects ( the m_xIndexAccess etc ) aren't aware of the + // contents that are deleted + sal_Int32 nElems = getCount(); + for ( sal_Int32 nItem = 1; nItem <= nElems; ++nItem ) + { + uno::Reference< excel::XWorksheet > xSheet( Item( uno::Any( nItem ), uno::Any() ), uno::UNO_QUERY_THROW ); + xSheet->Delete(); + } +} + +bool +ScVbaWorksheets::isSelectedSheets() const +{ + return !m_xSheets.is(); +} + +void SAL_CALL +ScVbaWorksheets::PrintOut( const uno::Any& From, const uno::Any& To, const uno::Any& Copies, const uno::Any& Preview, const uno::Any& ActivePrinter, const uno::Any& PrintToFile, const uno::Any& Collate, const uno::Any& PrToFileName ) +{ + sal_Int32 nTo = 0; + sal_Int32 nFrom = 0; + bool bSelection = false; + From >>= nFrom; + To >>= nTo; + + if ( !( nFrom || nTo ) ) + if ( isSelectedSheets() ) + bSelection = true; + + PrintOutHelper( excel::getBestViewShell( mxModel ), From, To, Copies, Preview, ActivePrinter, PrintToFile, Collate, PrToFileName, bSelection ); +} + +uno::Any SAL_CALL +ScVbaWorksheets::getVisible() +{ + bool bVisible = true; + uno::Reference< container::XEnumeration > xEnum( createEnumeration(), uno::UNO_SET_THROW ); + while ( xEnum->hasMoreElements() ) + { + uno::Reference< excel::XWorksheet > xSheet( xEnum->nextElement(), uno::UNO_QUERY_THROW ); + if ( xSheet->getVisible() == 0 ) + { + bVisible = false; + break; + } + } + return uno::Any( bVisible ); +} + +void SAL_CALL +ScVbaWorksheets::setVisible( const uno::Any& _visible ) +{ + bool bState = false; + if ( !(_visible >>= bState) ) + throw uno::RuntimeException("Visible property doesn't support non boolean #FIXME" ); + + uno::Reference< container::XEnumeration > xEnum( createEnumeration(), uno::UNO_SET_THROW ); + while ( xEnum->hasMoreElements() ) + { + uno::Reference< excel::XWorksheet > xSheet( xEnum->nextElement(), uno::UNO_QUERY_THROW ); + xSheet->setVisible( bState ? 1 : 0 ); + } + +} + +void SAL_CALL +ScVbaWorksheets::Select( const uno::Any& Replace ) +{ + ScTabViewShell* pViewShell = excel::getBestViewShell( mxModel ); + if ( !pViewShell ) + throw uno::RuntimeException("Cannot obtain view shell" ); + + ScMarkData& rMarkData = pViewShell->GetViewData().GetMarkData(); + bool bReplace = true; + Replace >>= bReplace; + // Replace is defaulted to True, meaning this current collection + // becomes the Selection, if it were false then the current selection would + // be extended + bool bSelectSingle = bReplace; + sal_Int32 nElems = getCount(); + for ( sal_Int32 nItem = 1; nItem <= nElems; ++nItem ) + { + uno::Reference< excel::XWorksheet > xSheet( Item( uno::Any( nItem ), uno::Any() ), uno::UNO_QUERY_THROW ); + ScVbaWorksheet* pSheet = excel::getImplFromDocModuleWrapper<ScVbaWorksheet>( xSheet ); + if ( bSelectSingle ) + { + rMarkData.SelectOneTable( static_cast< SCTAB >( pSheet->getSheetID() ) ); + bSelectSingle = false; + } + else + rMarkData.SelectTable( static_cast< SCTAB >( pSheet->getSheetID() ), true ); + } + +} + +void SAL_CALL +ScVbaWorksheets::Copy ( const uno::Any& Before, const uno::Any& After) +{ + uno::Reference<excel::XWorksheet> xSheet; + sal_Int32 nElems = getCount(); + bool bAfter = After.hasValue(); + std::vector< uno::Reference< excel::XWorksheet > > Sheets; + sal_Int32 nItem = 0; + + for ( nItem = 1; nItem <= nElems; ++nItem) + { + uno::Reference<excel::XWorksheet> xWorksheet(Item( uno::Any( nItem ), uno::Any() ), uno::UNO_QUERY_THROW ); + Sheets.push_back(xWorksheet); + } + bool bNewDoc = (!(Before >>= xSheet) && !(After >>=xSheet)&& !(Before.hasValue()) && !(After.hasValue())); + + uno::Reference< excel::XWorksheet > xSrcSheet; + if ( bNewDoc ) + { + bAfter = true; + xSrcSheet = Sheets.at(0); + ScVbaWorksheet* pSrcSheet = excel::getImplFromDocModuleWrapper<ScVbaWorksheet>( xSrcSheet ); + xSheet = pSrcSheet->createSheetCopyInNewDoc(xSrcSheet->getName()); + nItem = 1; + } + else + { + nItem=0; + } + + for (; nItem < nElems; ++nItem ) + { + xSrcSheet = Sheets[nItem]; + ScVbaWorksheet* pSrcSheet = excel::getImplFromDocModuleWrapper<ScVbaWorksheet>( xSrcSheet ); + if ( bAfter ) + xSheet = pSrcSheet->createSheetCopy(xSheet, bAfter); + else + pSrcSheet->createSheetCopy(xSheet, bAfter); + } +} + +//ScVbaCollectionBaseImpl +uno::Any SAL_CALL +ScVbaWorksheets::Item(const uno::Any& Index, const uno::Any& Index2) +{ + if ( Index.getValueTypeClass() == uno::TypeClass_SEQUENCE ) + { + const uno::Reference< script::XTypeConverter >& xConverter = getTypeConverter(mxContext); + uno::Any aConverted = xConverter->convertTo( Index, cppu::UnoType<uno::Sequence< uno::Any >>::get() ); + SheetMap aSheets; + uno::Sequence< uno::Any > sIndices; + aConverted >>= sIndices; + for( const auto& rIndex : std::as_const(sIndices) ) + { + uno::Reference< excel::XWorksheet > xWorkSheet( ScVbaWorksheets_BASE::Item( rIndex, Index2 ), uno::UNO_QUERY_THROW ); + ScVbaWorksheet* pWorkSheet = excel::getImplFromDocModuleWrapper<ScVbaWorksheet>( xWorkSheet ); + uno::Reference< sheet::XSpreadsheet > xSheet( pWorkSheet->getSheet() , uno::UNO_SET_THROW ); + uno::Reference< container::XNamed > xName( xSheet, uno::UNO_QUERY_THROW ); + aSheets.push_back( xSheet ); + } + uno::Reference< container::XIndexAccess > xIndexAccess = new SheetCollectionHelper( std::move(aSheets) ); + uno::Reference< XCollection > xSelectedSheets( new ScVbaWorksheets( getParent(), mxContext, xIndexAccess, mxModel ) ); + return uno::Any( xSelectedSheets ); + } + return ScVbaWorksheets_BASE::Item( Index, Index2 ); +} + +OUString +ScVbaWorksheets::getServiceImplName() +{ + return "ScVbaWorksheets"; +} + +css::uno::Sequence<OUString> +ScVbaWorksheets::getServiceNames() +{ + static uno::Sequence< OUString > const sNames + { + "ooo.vba.excel.Worksheets" + }; + return sNames; +} + +bool ScVbaWorksheets::nameExists( const uno::Reference <sheet::XSpreadsheetDocument>& xSpreadDoc, std::u16string_view name, SCTAB& nTab ) +{ + if (!xSpreadDoc.is()) + throw lang::IllegalArgumentException( "nameExists() xSpreadDoc is null", uno::Reference< uno::XInterface >(), 1 ); + uno::Reference <container::XIndexAccess> xIndex( xSpreadDoc->getSheets(), uno::UNO_QUERY ); + if ( xIndex.is() ) + { + SCTAB nCount = static_cast< SCTAB >( xIndex->getCount() ); + for (SCTAB i=0; i < nCount; i++) + { + uno::Reference< container::XNamed > xNamed( xIndex->getByIndex(i), uno::UNO_QUERY_THROW ); + if (xNamed->getName() == name) + { + nTab = i; + return true; + } + } + } + return false; +} + +void ScVbaWorksheets::PrintPreview( const css::uno::Any& /*EnableChanges*/ ) +{ + // need test, print preview current active sheet + // !! TODO !! get view shell from controller + ScTabViewShell* pViewShell = excel::getBestViewShell( mxModel ); + SfxViewFrame* pViewFrame = nullptr; + if ( pViewShell ) + pViewFrame = pViewShell->GetViewFrame(); + if ( !pViewFrame ) + return; + + if ( pViewFrame->GetFrame().IsInPlace() ) + return; + + dispatchExecute( pViewShell, SID_VIEWSHELL1 ); + SfxViewShell* pShell = SfxViewShell::Get( pViewFrame->GetFrame().GetFrameInterface()->getController() ); + + ScPreviewShell* pPrvShell = dynamic_cast< ScPreviewShell* >( pShell ); + if ( !pPrvShell ) + return; + + ScPreview* pPrvView = pPrvShell->GetPreview(); + const ScDocument& rDoc = pViewShell->GetViewData().GetDocument(); + ScMarkData aMarkData(rDoc.GetSheetLimits()); + sal_Int32 nElems = getCount(); + for ( sal_Int32 nItem = 1; nItem <= nElems; ++nItem ) + { + uno::Reference< excel::XWorksheet > xSheet( Item( uno::Any( nItem ), uno::Any() ), uno::UNO_QUERY_THROW ); + ScVbaWorksheet* pSheet = excel::getImplFromDocModuleWrapper<ScVbaWorksheet>( xSheet ); + if ( pSheet ) + aMarkData.SelectTable(static_cast< SCTAB >( pSheet->getSheetID() ), true ); + } + // save old selection, setting the selectedtabs in the preview + // can affect the current selection when preview has been + // closed + ScMarkData::MarkedTabsType aOldTabs = pPrvView->GetSelectedTabs(); + pPrvView->SetSelectedTabs( aMarkData ); + // force update + pPrvView->DataChanged(false); + // set sensible first page + tools::Long nPage = pPrvView->GetFirstPage( 1 ); + pPrvView->SetPageNo( nPage ); + WaitUntilPreviewIsClosed( pViewFrame ); + // restore old tab selection + pViewShell = excel::getBestViewShell( mxModel ); + pViewShell->GetViewData().GetMarkData().SetSelectedTabs(aOldTabs); + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbaworksheets.hxx b/sc/source/ui/vba/vbaworksheets.hxx new file mode 100644 index 000000000..b795fbf5a --- /dev/null +++ b/sc/source/ui/vba/vbaworksheets.hxx @@ -0,0 +1,68 @@ +/* -*- 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 . + */ +#pragma once + +#include <ooo/vba/excel/XWorksheets.hpp> + +#include <vbahelper/vbacollectionimpl.hxx> + +#include <types.hxx> + +namespace com::sun::star::container { class XEnumerationAccess; } +namespace com::sun::star::sheet { class XSpreadsheetDocument; } +namespace com::sun::star::sheet { class XSpreadsheets; } +namespace com::sun::star::uno { class XComponentContext; } + +typedef CollTestImplHelper< ov::excel::XWorksheets > ScVbaWorksheets_BASE; + +class ScVbaWorksheets : public ScVbaWorksheets_BASE +{ + css::uno::Reference< css::frame::XModel > mxModel; + css::uno::Reference< css::sheet::XSpreadsheets > m_xSheets; +public: + ScVbaWorksheets( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::container::XIndexAccess >& xSheets, const css::uno::Reference< css::frame::XModel >& xModel ); + ScVbaWorksheets( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::container::XEnumerationAccess >& xEnum, const css::uno::Reference< css::frame::XModel >& xModel ); + + bool isSelectedSheets() const; + + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + + // XWorksheets + virtual css::uno::Any SAL_CALL getVisible() override; + virtual void SAL_CALL setVisible( const css::uno::Any& _visible ) override; + virtual css::uno::Any SAL_CALL Add( const css::uno::Any& Before, const css::uno::Any& After, const css::uno::Any& Count, const css::uno::Any& Type ) override; + virtual void SAL_CALL Delete( ) override; + virtual void SAL_CALL PrintOut( const css::uno::Any& From, const css::uno::Any& To, const css::uno::Any& Copies, const css::uno::Any& Preview, const css::uno::Any& ActivePrinter, const css::uno::Any& PrintToFile, const css::uno::Any& Collate, const css::uno::Any& PrToFileName ) override; + virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override; + virtual void SAL_CALL Select( const css::uno::Any& Replace ) override; + virtual void SAL_CALL Copy ( const css::uno::Any& Before, const css::uno::Any& After) override; + virtual void SAL_CALL PrintPreview( const css::uno::Any& EnableChanges ) override; + // ScVbaWorksheets_BASE + virtual css::uno::Any SAL_CALL Item( const css::uno::Any& Index1, const css::uno::Any& Index2 ) override; + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; + + /// @throws css::lang::IllegalArgumentException + /// @throws css::uno::RuntimeException + static bool nameExists( const css::uno::Reference <css::sheet::XSpreadsheetDocument>& xSpreadDoc, std::u16string_view name, SCTAB& nTab ); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbawsfunction.cxx b/sc/source/ui/vba/vbawsfunction.cxx new file mode 100644 index 000000000..6af173223 --- /dev/null +++ b/sc/source/ui/vba/vbawsfunction.cxx @@ -0,0 +1,298 @@ +/* -*- 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 <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/table/XCellRange.hpp> +#include <com/sun/star/beans/XIntrospectionAccess.hpp> +#include <com/sun/star/sheet/XFunctionAccess.hpp> +#include <com/sun/star/sheet/XCellRangeAddressable.hpp> +#include <ooo/vba/excel/XRange.hpp> + +#include "vbawsfunction.hxx" +#include <compiler.hxx> + +using namespace com::sun::star; +using namespace ooo::vba; + +namespace { + +void lclConvertDoubleToBoolean( uno::Any& rAny ) +{ + if( rAny.has< double >() ) + { + double fValue = rAny.get< double >(); + if( fValue == 0.0 ) + rAny <<= false; + else if( fValue == 1.0 ) + rAny <<= true; + // do nothing for other values or types + } +} + +void lclConvertBooleanToDouble( uno::Any& rAny ) +{ + bool bValue( false ); + if ( rAny >>= bValue ) + { + if ( bValue ) + rAny <<= 1.0; + else + rAny <<= 0.0; + } +} + +} // namespace + +ScVbaWSFunction::ScVbaWSFunction( const uno::Reference< XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext ) : + ScVbaWSFunction_BASE( xParent, xContext ) +{ +} + +uno::Reference< beans::XIntrospectionAccess > +ScVbaWSFunction::getIntrospection() +{ + return uno::Reference<beans::XIntrospectionAccess>(); +} + +uno::Any SAL_CALL +ScVbaWSFunction::invoke(const OUString& FunctionName, const uno::Sequence< uno::Any >& Params, uno::Sequence< sal_Int16 >& /*OutParamIndex*/, uno::Sequence< uno::Any >& /*OutParam*/) +{ + // create copy of parameters, replace Excel range objects with UNO range objects + uno::Sequence< uno::Any > aParamTemp( Params ); + if( aParamTemp.hasElements() ) + { + for( uno::Any & rArray : asNonConstRange(aParamTemp) ) + { + switch( rArray.getValueType().getTypeClass() ) + { + case uno::TypeClass_BOOLEAN: + lclConvertBooleanToDouble( rArray ); + break; + case uno::TypeClass_INTERFACE: + { + uno::Reference< excel::XRange > myRange( rArray, uno::UNO_QUERY ); + if( myRange.is() ) + rArray = myRange->getCellRange(); + } + break; + case uno::TypeClass_SEQUENCE: + { + // the sheet.FunctionAccess service doesn't deal with Sequences, only Sequences of Sequence + uno::Type aType = rArray.getValueType(); + if ( aType.equals( cppu::UnoType<uno::Sequence<sal_Int16>>::get() ) ) + { + uno::Sequence< uno::Sequence< sal_Int16 > > aTmp(1); + rArray >>= aTmp.getArray()[ 0 ]; + rArray <<= aTmp; + } + else if ( aType.equals( cppu::UnoType<uno::Sequence<sal_Int32>>::get() ) ) + { + uno::Sequence< uno::Sequence< sal_Int32 > > aTmp(1); + rArray >>= aTmp.getArray()[ 0 ]; + rArray <<= aTmp; + } + else if ( aType.equals( cppu::UnoType<uno::Sequence<double>>::get() ) ) + { + uno::Sequence< uno::Sequence< double > > aTmp(1); + rArray >>= aTmp.getArray()[ 0 ]; + rArray <<= aTmp; + } + else if ( aType.equals( cppu::UnoType<uno::Sequence<OUString>>::get() ) ) + { + uno::Sequence< uno::Sequence< OUString > > aTmp(1); + rArray >>= aTmp.getArray()[ 0 ]; + rArray <<= aTmp; + } + else if ( aType.equals( cppu::UnoType<uno::Sequence<uno::Any>>::get() ) ) + { + uno::Sequence< uno::Sequence<uno::Any > > aTmp(1); + rArray >>= aTmp.getArray()[ 0 ]; + rArray <<= aTmp; + } + } + break; + default: + break; + } + } + } + + uno::Any aRet; + bool bAsArray = true; + + // special handing for some functions that don't work correctly in FunctionAccess + formula::FormulaCompiler aCompiler; + OpCode eOpCode = aCompiler.GetEnglishOpCode( FunctionName.toAsciiUpperCase() ); + switch( eOpCode ) + { + // ISLOGICAL does not work in array formula mode + case ocIsLogical: + { + if( aParamTemp.getLength() != 1 ) + throw lang::IllegalArgumentException(); + const uno::Any& rParam = aParamTemp[ 0 ]; + if( rParam.has< bool >() ) + { + aRet <<= true; + } + else if( rParam.has< uno::Reference< table::XCellRange > >() ) try + { + uno::Reference< sheet::XCellRangeAddressable > xRangeAddr( rParam, uno::UNO_QUERY_THROW ); + table::CellRangeAddress aRangeAddr = xRangeAddr->getRangeAddress(); + bAsArray = (aRangeAddr.StartColumn != aRangeAddr.EndColumn) || (aRangeAddr.StartRow != aRangeAddr.EndRow); + } + catch( uno::Exception& ) + { + } + } + break; + default:; + } + + if( !aRet.hasValue() ) + { + uno::Reference< lang::XMultiComponentFactory > xSMgr( mxContext->getServiceManager(), uno::UNO_SET_THROW ); + uno::Reference< sheet::XFunctionAccess > xFunctionAccess( xSMgr->createInstanceWithContext( + "com.sun.star.sheet.FunctionAccess", mxContext ), + uno::UNO_QUERY_THROW ); + uno::Reference< beans::XPropertySet > xPropSet( xFunctionAccess, uno::UNO_QUERY_THROW ); + xPropSet->setPropertyValue("IsArrayFunction", uno::Any( bAsArray ) ); + aRet = xFunctionAccess->callFunction( FunctionName, aParamTemp ); + } + + /* Convert return value from double to Boolean for some functions that + return Booleans. */ + typedef uno::Sequence< uno::Sequence< uno::Any > > AnySeqSeq; + if( (eOpCode == ocIsEmpty) || (eOpCode == ocIsString) || (eOpCode == ocIsNonString) || (eOpCode == ocIsLogical) || + (eOpCode == ocIsRef) || (eOpCode == ocIsValue) || (eOpCode == ocIsFormula) || (eOpCode == ocIsNA) || + (eOpCode == ocIsErr) || (eOpCode == ocIsError) || (eOpCode == ocIsEven) || (eOpCode == ocIsOdd) || + (eOpCode == ocAnd) || (eOpCode == ocOr) || (eOpCode == ocXor) || (eOpCode == ocNot) || (eOpCode == ocTrue) || (eOpCode == ocFalse) ) + { + if( aRet.has< AnySeqSeq >() ) + { + AnySeqSeq aAnySeqSeq = aRet.get< AnySeqSeq >(); + for( auto& rAnySeq : asNonConstRange(aAnySeqSeq) ) + for( auto& rAny : asNonConstRange(rAnySeq) ) + lclConvertDoubleToBoolean( rAny ); + aRet <<= aAnySeqSeq; + } + else + { + lclConvertDoubleToBoolean( aRet ); + } + } + + /* Hack/workaround (?): shorten single-row matrix to simple array, shorten + 1x1 matrix to single value. */ + if( aRet.has< AnySeqSeq >() ) + { + AnySeqSeq aAnySeqSeq = aRet.get< AnySeqSeq >(); + if( aAnySeqSeq.getLength() == 1 ) + { + if( aAnySeqSeq[ 0 ].getLength() == 1 ) + aRet = aAnySeqSeq[ 0 ][ 0 ]; + else + aRet <<= aAnySeqSeq[ 0 ]; + } + } + +#if 0 + // MATCH function should alwayse return a double value, but currently if the first argument is XCellRange, MATCH function returns an array instead of a double value. Don't know why? + // To fix this issue in safe, current solution is to convert this array to a double value just for MATCH function. + OUString aUpper( FunctionName.toAsciiUpperCase() ); + ScCompiler aCompiler( NULL, ScAddress() ); + OpCode eOp = aCompiler.GetEnglishOpCode( aUpper ); + if( eOp == ocMatch ) + { + double fVal = 0.0; + if( aRet >>= fVal ) + return aRet; + uno::Sequence< uno::Sequence< uno::Any > > aSequence; + if( !( ( aRet >>= aSequence ) && ( aSequence.getLength() > 0 ) && + ( aSequence[0].getLength() > 0 ) && ( aSequence[0][0] >>= fVal ) ) ) + throw uno::RuntimeException(); + aRet <<= fVal; + } +#endif + + return aRet; +} + +void SAL_CALL +ScVbaWSFunction::setValue(const OUString& /*PropertyName*/, const uno::Any& /*Value*/) +{ + throw beans::UnknownPropertyException(); +} + +uno::Any SAL_CALL +ScVbaWSFunction::getValue(const OUString& /*PropertyName*/) +{ + throw beans::UnknownPropertyException(); +} + +sal_Bool SAL_CALL +ScVbaWSFunction::hasMethod(const OUString& Name) +{ + bool bIsFound = false; + try + { + // the function name contained in the com.sun.star.sheet.FunctionDescription service is alwayse localized. + // but the function name used in WorksheetFunction is a programmatic name (seems English). + // So m_xNameAccess->hasByName( Name ) may fail to find name when a function name has a localized name. + if( ScCompiler::IsEnglishSymbol( Name ) ) + bIsFound = true; + } + catch( uno::Exception& /*e*/ ) + { + // failed to find name + } + return bIsFound; +} + +sal_Bool SAL_CALL +ScVbaWSFunction::hasProperty(const OUString& /*Name*/) +{ + return false; +} + +OUString SAL_CALL +ScVbaWSFunction::getExactName( const OUString& aApproximateName ) +{ + OUString sName = aApproximateName.toAsciiUpperCase(); + if ( !hasMethod( sName ) ) + return OUString(); + return sName; +} + +OUString +ScVbaWSFunction::getServiceImplName() +{ + return "ScVbaWSFunction"; +} + +uno::Sequence< OUString > +ScVbaWSFunction::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.excel.WorksheetFunction" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/vba/vbawsfunction.hxx b/sc/source/ui/vba/vbawsfunction.hxx new file mode 100644 index 000000000..9a5dd821f --- /dev/null +++ b/sc/source/ui/vba/vbawsfunction.hxx @@ -0,0 +1,45 @@ +/* -*- 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 . + */ +#pragma once + +#include <ooo/vba/excel/XWorksheetFunction.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <vbahelper/vbahelperinterface.hxx> + +typedef InheritedHelperInterfaceWeakImpl< ov::excel::XWorksheetFunction > ScVbaWSFunction_BASE; + +class ScVbaWSFunction : public ScVbaWSFunction_BASE +{ +public: + ScVbaWSFunction( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext); + + virtual css::uno::Reference< css::beans::XIntrospectionAccess > SAL_CALL getIntrospection() override; + virtual css::uno::Any SAL_CALL invoke(const OUString& FunctionName, const css::uno::Sequence< css::uno::Any >& Params, css::uno::Sequence< sal_Int16 >& OutParamIndex, css::uno::Sequence< css::uno::Any >& OutParam) override; + virtual void SAL_CALL setValue(const OUString& PropertyName, const css::uno::Any& Value) override; + virtual css::uno::Any SAL_CALL getValue(const OUString& PropertyName) override; + virtual sal_Bool SAL_CALL hasMethod(const OUString& Name) override; + virtual sal_Bool SAL_CALL hasProperty(const OUString& Name) override; + virtual OUString SAL_CALL getExactName( const OUString& aApproximateName ) override; + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |