summaryrefslogtreecommitdiff
path: root/oox/source/xls/excelvbaproject.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'oox/source/xls/excelvbaproject.cxx')
-rwxr-xr-xoox/source/xls/excelvbaproject.cxx214
1 files changed, 214 insertions, 0 deletions
diff --git a/oox/source/xls/excelvbaproject.cxx b/oox/source/xls/excelvbaproject.cxx
new file mode 100755
index 000000000000..fc3caf7e59aa
--- /dev/null
+++ b/oox/source/xls/excelvbaproject.cxx
@@ -0,0 +1,214 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/excelvbaproject.hxx"
+#include <com/sun/star/container/XEnumeration.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/document/XEventsSupplier.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
+#include "properties.hxx"
+#include "oox/helper/helper.hxx"
+#include "oox/helper/propertyset.hxx"
+
+using ::rtl::OUString;
+using ::com::sun::star::container::XEnumeration;
+using ::com::sun::star::container::XEnumerationAccess;
+using ::com::sun::star::document::XEventsSupplier;
+using ::com::sun::star::frame::XModel;
+using ::com::sun::star::lang::XMultiServiceFactory;
+using ::com::sun::star::sheet::XSpreadsheetDocument;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::uno::UNO_SET_THROW;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+VbaProject::VbaProject( const Reference< XMultiServiceFactory >& rxGlobalFactory, const Reference< XSpreadsheetDocument >& rxDocument ) :
+ ::oox::ole::VbaProject( rxGlobalFactory, Reference< XModel >( rxDocument, UNO_QUERY ), CREATE_OUSTRING( "Calc" ) ),
+ mxDocument( rxDocument )
+{
+}
+
+void VbaProject::attachToEvents()
+{
+ // do nothing is code is not executable
+ if( !isImportVbaExecutable() )
+ return;
+
+ // document events
+ PropertySet aDocProp( mxDocument );
+ OUString aCodeName;
+ aDocProp.getProperty( aCodeName, PROP_CodeName );
+ attachToDocumentEvents( aCodeName );
+
+ // sheet events
+ if( mxDocument.is() ) try
+ {
+ Reference< XEnumerationAccess > xSheetsEA( mxDocument->getSheets(), UNO_QUERY_THROW );
+ Reference< XEnumeration > xSheetsEnum( xSheetsEA->createEnumeration(), UNO_SET_THROW );
+ // own try/catch for every sheet
+ while( xSheetsEnum->hasMoreElements() ) try
+ {
+ // TODO: once we have chart sheets we need a switch/case on sheet type
+ Reference< XEventsSupplier > xEventsSupp( xSheetsEnum->nextElement(), UNO_QUERY_THROW );
+ PropertySet aSheetProp( xEventsSupp );
+ aSheetProp.getProperty( aCodeName, PROP_CodeName );
+ attachToSheetEvents( xEventsSupp, aCodeName );
+ }
+ catch( Exception& )
+ {
+ }
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+// private --------------------------------------------------------------------
+
+void VbaProject::attachToDocumentEvents( const OUString& rCodeName )
+{
+ if( (rCodeName.getLength() == 0) || !hasModule( rCodeName ) )
+ return;
+
+ attachMacroToDocumentEvent( CREATE_OUSTRING( "OnLoad" ), rCodeName, CREATE_OUSTRING( "Workbook_Open" ) );
+ attachMacroToDocumentEvent( CREATE_OUSTRING( "OnFocus" ), rCodeName, CREATE_OUSTRING( "Workbook_Activate" ) );
+ attachMacroToDocumentEvent( CREATE_OUSTRING( "OnUnfocus" ), rCodeName, CREATE_OUSTRING( "Workbook_Deactivate" ) );
+ attachMacroToDocumentEvent( CREATE_OUSTRING( "OnSave" ), rCodeName, CREATE_OUSTRING( "Workbook_BeforeSave" ), OUString(), OUString(), CREATE_OUSTRING( "\t$MACRO False, False" ) );
+ attachMacroToDocumentEvent( CREATE_OUSTRING( "OnSaveAs" ), rCodeName, CREATE_OUSTRING( "Workbook_BeforeSave" ), OUString(), OUString(), CREATE_OUSTRING( "\t$MACRO True, False" ) );
+ attachMacroToDocumentEvent( CREATE_OUSTRING( "OnSaveDone" ), rCodeName, CREATE_OUSTRING( "Workbook_AfterSave" ), OUString(), OUString(), CREATE_OUSTRING( "\t$MACRO True" ) );
+ attachMacroToDocumentEvent( CREATE_OUSTRING( "OnSaveAsDone" ), rCodeName, CREATE_OUSTRING( "Workbook_AfterSave" ), OUString(), OUString(), CREATE_OUSTRING( "\t$MACRO True" ) );
+ attachMacroToDocumentEvent( CREATE_OUSTRING( "OnSaveFailed" ), rCodeName, CREATE_OUSTRING( "Workbook_AfterSave" ), OUString(), OUString(), CREATE_OUSTRING( "\t$MACRO False" ) );
+ attachMacroToDocumentEvent( CREATE_OUSTRING( "OnSaveAsFailed" ), rCodeName, CREATE_OUSTRING( "Workbook_AfterSave" ), OUString(), OUString(), CREATE_OUSTRING( "\t$MACRO False" ) );
+ attachMacroToDocumentEvent( CREATE_OUSTRING( "OnPrint" ), rCodeName, CREATE_OUSTRING( "Workbook_BeforePrint" ), OUString(), OUString(), CREATE_OUSTRING( "\t$MACRO False" ) );
+ attachMacroToDocumentEvent( CREATE_OUSTRING( "OnPrepareUnload" ), rCodeName, CREATE_OUSTRING( "Workbook_BeforeClose" ), OUString(), OUString(), CREATE_OUSTRING( "\t$MACRO False" ) );
+}
+
+void VbaProject::attachToSheetEvents( const Reference< XEventsSupplier >& rxEventsSupp, const OUString& rCodeName )
+{
+ if( !rxEventsSupp.is() || (rCodeName.getLength() == 0) || !hasModule( rCodeName ) )
+ return;
+
+ // attach macros to simple sheet events directly
+ attachMacroToEvent( rxEventsSupp, CREATE_OUSTRING( "OnFocus" ), rCodeName, CREATE_OUSTRING( "Worksheet_Activate" ) );
+ attachMacroToEvent( rxEventsSupp, CREATE_OUSTRING( "OnUnfocus" ), rCodeName, CREATE_OUSTRING( "Worksheet_Deactivate" ) );
+ attachMacroToEvent( rxEventsSupp, CREATE_OUSTRING( "OnCalculate" ), rCodeName, CREATE_OUSTRING( "Worksheet_Calculate" ) );
+
+ /* Attach macros to complex sheet events. The events pass a cell range or
+ a collection of cell ranges depending on the event type and sheet
+ selection. The generated proxy macros need to convert these UNO renges
+ to VBA compatible ranges.
+ */
+
+#define VBA_MACRONAME_RANGECONV "Local_GetVbaRangeFromUnoRange"
+#define VBA_MACRONAME_TARGETCONV "Local_GetVbaTargetFromUnoTarget"
+
+ /* If this variable turns to true, the macros that convert UNO cell ranges
+ to VBA Range objects have to be inserted.
+ */
+ bool bNeedsTargetHelper = false;
+
+ /* Insert the proxy macros attached to sheet events that notify something
+ has changed (changed selection and changed cell contents). These events
+ cannot be cancelled. The proxy macro converts the passed UNO cell range
+ or collection of cell ranges to a VBA Range object, and calls the VBA
+ event handler.
+ */
+ OUString aChangeProxyArgs = CREATE_OUSTRING( "ByVal unoTarget As Object" );
+ OUString aChangeProxyCode = CREATE_OUSTRING(
+ "\tDim vbaTarget As Range : Set vbaTarget = " VBA_MACRONAME_TARGETCONV "( unoTarget )\n"
+ "\tIf Not vbaTarget Is Nothing Then $MACRO vbaTarget" );
+ bNeedsTargetHelper |= attachMacroToEvent( rxEventsSupp, CREATE_OUSTRING( "OnChange" ), rCodeName, CREATE_OUSTRING( "Worksheet_Change" ), aChangeProxyArgs, OUString(), aChangeProxyCode );
+ bNeedsTargetHelper |= attachMacroToEvent( rxEventsSupp, CREATE_OUSTRING( "OnSelect" ), rCodeName, CREATE_OUSTRING( "Worksheet_SelectionChange" ), aChangeProxyArgs, OUString(), aChangeProxyCode );
+
+ /* Insert the proxy macros attached to sheet events that notify an ongoing
+ mouse click event (double click and right click). These events can be
+ cancelled by returning false (in VBA: as a Boolean output parameter, in
+ UNO: as return value of the Basic function). The proxy macro converts
+ the passed UNO cell range or collection of cell ranges to a VBA Range
+ object, calls the VBA event handler, and returns the Boolean value
+ provided by the VBA event handler.
+ */
+ OUString aClickProxyArgs = CREATE_OUSTRING( "ByVal unoTarget As Object" );
+ OUString aClickProxyRetT = CREATE_OUSTRING( "Boolean" );
+ OUString aClickProxyCode = CREATE_OUSTRING(
+ "\tDim Cancel As Boolean : Cancel = False\n"
+ "\tDim vbaTarget As Range : Set vbaTarget = " VBA_MACRONAME_TARGETCONV "( unoTarget )\n"
+ "\tIf Not vbaTarget Is Nothing Then $MACRO vbaTarget, Cancel\n"
+ "\t$PROXY = Cancel" );
+ bNeedsTargetHelper |= attachMacroToEvent( rxEventsSupp, CREATE_OUSTRING( "OnDoubleClick" ), rCodeName, CREATE_OUSTRING( "Worksheet_BeforeDoubleClick" ), aClickProxyArgs, aClickProxyRetT, aClickProxyCode );
+ bNeedsTargetHelper |= attachMacroToEvent( rxEventsSupp, CREATE_OUSTRING( "OnRightClick" ), rCodeName, CREATE_OUSTRING( "Worksheet_BeforeRightClick" ), aClickProxyArgs, aClickProxyRetT, aClickProxyCode );
+
+ if( bNeedsTargetHelper )
+ {
+ /* Generate a helper function that converts a
+ com.sun.star.sheet.SheetCellRange object to a VBA Range object.
+ */
+ OUString aRangeConvName = CREATE_OUSTRING( VBA_MACRONAME_RANGECONV );
+ OUString aRangeConvArgs = CREATE_OUSTRING( "ByVal unoRange As com.sun.star.sheet.SheetCellRange" );
+ OUString aRangeConvRetT = CREATE_OUSTRING( "Range" );
+ OUString aRangeConvCode = CREATE_OUSTRING(
+ "\tDim unoAddress As com.sun.star.table.CellRangeAddress : Set unoAddress = unoRange.RangeAddress\n"
+ "\tDim vbaSheet As Worksheet : Set vbaSheet = Application.ThisWorkbook.Sheets( unoAddress.Sheet + 1 )\n"
+ "\tSet $MACRO = vbaSheet.Range( vbaSheet.Cells( unoAddress.StartRow + 1, unoAddress.StartColumn + 1 ), vbaSheet.Cells( unoAddress.EndRow + 1, unoAddress.EndColumn + 1 ) )" );
+ insertMacro( rCodeName, aRangeConvName, aRangeConvArgs, aRangeConvRetT, aRangeConvCode );
+
+ /* Generate a helper function that converts a generic range selection
+ object (com.sun.star.sheet.SheetCellRange or
+ com.sun.star.sheet.SheetCellRanges) to a VBA Range object.
+ */
+ OUString aTargetConvName = CREATE_OUSTRING( VBA_MACRONAME_TARGETCONV );
+ OUString aTargetConvArgs = CREATE_OUSTRING( "ByVal unoTarget As Object" );
+ OUString aTargetConvRetT = CREATE_OUSTRING( "Range" );
+ OUString aTargetConvCode = CREATE_OUSTRING(
+ "\tDim vbaTarget As Range\n"
+ "\tIf unoTarget.supportsService( \"com.sun.star.sheet.SheetCellRange\" ) Then\n"
+ "\t\tSet vbaTarget = " VBA_MACRONAME_RANGECONV "( unoTarget )\n"
+ "\tElseIf unoTarget.supportsService( \"com.sun.star.sheet.SheetCellRanges\" ) Then\n"
+ "\t\tDim unoRangeEnum As Object : Set unoRangeEnum = unoTarget.createEnumeration\n"
+ "\t\tIf unoRangeEnum.hasMoreElements Then Set vbaTarget = " VBA_MACRONAME_RANGECONV "( unoRangeEnum.nextElement )\n"
+ "\t\tWhile unoRangeEnum.hasMoreElements\n"
+ "\t\t\tSet vbaTarget = Application.Union( vbaTarget, " VBA_MACRONAME_RANGECONV "( unoRangeEnum.nextElement ) )\n"
+ "\t\tWend\n"
+ "\tEnd If\n"
+ "\tSet $MACRO = vbaTarget" );
+ insertMacro( rCodeName, aTargetConvName, aTargetConvArgs, aTargetConvRetT, aTargetConvCode );
+ }
+#undef VBA_MACRONAME_RANGECONV
+#undef VBA_MACRONAME_TARGETCONV
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox