summaryrefslogtreecommitdiff
path: root/oox
diff options
context:
space:
mode:
Diffstat (limited to 'oox')
-rw-r--r--[-rwxr-xr-x]oox/inc/oox/ole/vbamodule.hxx19
-rw-r--r--oox/inc/oox/ole/vbaproject.hxx21
-rwxr-xr-xoox/inc/oox/xls/excelvbaproject.hxx68
-rw-r--r--oox/prj/build.lst2
-rw-r--r--oox/prj/d.lst1
-rw-r--r--oox/source/ole/vbamodule.cxx79
-rw-r--r--oox/source/ole/vbaproject.cxx107
-rwxr-xr-xoox/source/xls/excelvbaproject.cxx161
-rw-r--r--oox/source/xls/makefile.mk1
-rw-r--r--oox/source/xls/workbookhelper.cxx4
-rw-r--r--oox/source/xls/worksheethelper.cxx134
11 files changed, 524 insertions, 73 deletions
diff --git a/oox/inc/oox/ole/vbamodule.hxx b/oox/inc/oox/ole/vbamodule.hxx
index 3b529ceee129..377c7abc335a 100755..100644
--- a/oox/inc/oox/ole/vbamodule.hxx
+++ b/oox/inc/oox/ole/vbamodule.hxx
@@ -68,11 +68,26 @@ public:
/** Imports all records for this module until the MODULEEND record. */
void importDirRecords( BinaryInputStream& rDirStrm );
- /** Imports the Basic source code into the passed Basic library. */
- void importSourceCode(
+
+ /** Imports the VBA source code into the passed Basic library. */
+ void createAndImportModule(
StorageBase& rVbaStrg,
const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer >& rxBasicLib,
const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess >& rxDocObjectNA ) const;
+ /** Creates an empty Basic module in the passed Basic library. */
+ void createEmptyModule(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer >& rxBasicLib,
+ const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess >& rxDocObjectNA ) const;
+
+private:
+ /** Reads and returns the VBA source code from the passed storage. */
+ ::rtl::OUString readSourceCode( StorageBase& rVbaStrg ) const;
+
+ /** Creates a new Basic module and inserts it into the passed Basic library. */
+ void createModule(
+ const ::rtl::OUString& rVBASourceCode,
+ const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer >& rxBasicLib,
+ const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess >& rxDocObjectNA ) const;
private:
::com::sun::star::uno::Reference< ::com::sun::star::frame::XModel >
diff --git a/oox/inc/oox/ole/vbaproject.hxx b/oox/inc/oox/ole/vbaproject.hxx
index 1d2fca29dbab..e8d9aa7c0f5d 100644
--- a/oox/inc/oox/ole/vbaproject.hxx
+++ b/oox/inc/oox/ole/vbaproject.hxx
@@ -97,6 +97,18 @@ public:
/** Returns true, if the document contains the specified dialog. */
bool hasDialog( const ::rtl::OUString& rDialogName ) const;
+protected:
+ /** Registers a dummy module that will be created when the VBA project is
+ imported. */
+ void addDummyModule( const ::rtl::OUString& rName, sal_Int32 nType );
+ /** Creates all dummy modules in the document. */
+ void createDummyModules();
+
+ /** Called when the import process of the VBA project has been started. */
+ virtual void prepareImport();
+ /** Called when the import process of the VBA project is finished. */
+ virtual void finalizeImport();
+
private:
VbaProject( const VbaProject& );
VbaProject& operator=( const VbaProject& );
@@ -113,12 +125,18 @@ private:
/** Creates and returns the dialog library of the document used for import. */
::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer >
createDialogLibrary();
+
/** Imports the VBA code modules and forms. */
- void importVba( StorageBase& rVbaPrjStrg, const GraphicHelper& rGraphicHelper, bool bDefaultColorBgr );
+ void importVba(
+ StorageBase& rVbaPrjStrg,
+ const GraphicHelper& rGraphicHelper,
+ bool bDefaultColorBgr );
/** Copies the entire VBA project storage to the passed document model. */
void copyStorage( StorageBase& rVbaPrjStrg );
private:
+ typedef ::std::map< ::rtl::OUString, sal_Int32 > DummyModuleMap;
+
::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >
mxGlobalFactory; /// Global service factory.
::com::sun::star::uno::Reference< ::com::sun::star::frame::XModel >
@@ -127,6 +145,7 @@ private:
mxBasicLib; /// The Basic library of the document used for import.
::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer >
mxDialogLib; /// The dialog library of the document used for import.
+ DummyModuleMap maDummyModules; /// Additional empty modules created on import.
const ::rtl::OUString maLibName; /// Name for Basic and dialog library used for import.
};
diff --git a/oox/inc/oox/xls/excelvbaproject.hxx b/oox/inc/oox/xls/excelvbaproject.hxx
new file mode 100755
index 000000000000..121e6a1667cd
--- /dev/null
+++ b/oox/inc/oox/xls/excelvbaproject.hxx
@@ -0,0 +1,68 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_EXCELVBAPROJECT_HXX
+#define OOX_XLS_EXCELVBAPROJECT_HXX
+
+#include "oox/ole/vbaproject.hxx"
+#include "oox/dllapi.h"
+
+namespace com { namespace sun { namespace star {
+ namespace sheet { class XSpreadsheetDocument; }
+} } }
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+/** Special implementation of the VBA project for the Excel filters. */
+class OOX_DLLPUBLIC ExcelVbaProject : public ::oox::ole::VbaProject
+{
+public:
+ explicit ExcelVbaProject(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& rxGlobalFactory,
+ const ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XSpreadsheetDocument >& rxDocument );
+
+ /** Generates VBA modules for sheets that do not specify a codename. */
+ void createMissingModules();
+
+protected:
+ /** Adds dummy modules for sheets without imported code name. */
+ virtual void prepareImport();
+
+private:
+ ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XSpreadsheetDocument >
+ mxDocument;
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
diff --git a/oox/prj/build.lst b/oox/prj/build.lst
index 345c72e00558..03735c73dd11 100644
--- a/oox/prj/build.lst
+++ b/oox/prj/build.lst
@@ -1,4 +1,4 @@
-oox oox : vos cppu cppuhelper comphelper sal offapi sax basegfx xmlscript tools vcl BOOST:boost OPENSSL:openssl NULL
+oox oox : vos cppu cppuhelper comphelper sal offapi sax basegfx xmlscript tools vcl BOOST:boost OPENSSL:openssl LIBXSLT:libxslt NULL
oox oox usr1 - all oox_mkout NULL
oox oox\prj get - all oox_prj NULL
oox oox\source\token nmake - all oox_token NULL
diff --git a/oox/prj/d.lst b/oox/prj/d.lst
index ff13b324d65c..f656056b119e 100644
--- a/oox/prj/d.lst
+++ b/oox/prj/d.lst
@@ -36,6 +36,7 @@ mkdir: %_DEST%\inc%_EXT%\oox\xls
..\inc\oox\ole\vbaproject.hxx %_DEST%\inc%_EXT%\oox\ole\vbaproject.hxx
..\inc\oox\vml\vmldrawing.hxx %_DEST%\inc%_EXT%\oox\vml\vmldrawing.hxx
..\inc\oox\vml\vmlshape.hxx %_DEST%\inc%_EXT%\oox\vml\vmlshape.hxx
+..\inc\oox\xls\excelvbaproject.hxx %_DEST%\inc%_EXT%\oox\xls\excelvbaproject.hxx
dos: sh -c "if test %OS% = MACOSX; then create-bundle %_DEST%\lib%_EXT%\*.dylib; fi"
diff --git a/oox/source/ole/vbamodule.cxx b/oox/source/ole/vbamodule.cxx
index 9886f2cc5968..dbd5c9c02ced 100644
--- a/oox/source/ole/vbamodule.cxx
+++ b/oox/source/ole/vbamodule.cxx
@@ -128,18 +128,56 @@ void VbaModule::importDirRecords( BinaryInputStream& rDirStrm )
OSL_ENSURE( mnOffset < SAL_MAX_UINT32, "VbaModule::importDirRecords - missing module stream offset" );
}
-void VbaModule::importSourceCode( StorageBase& rVbaStrg,
- const Reference< XNameContainer >& rxBasicLib, const Reference< XNameAccess >& rxDocObjectNA ) const
+void VbaModule::createAndImportModule( StorageBase& rVbaStrg, const Reference< XNameContainer >& rxBasicLib,
+ const Reference< XNameAccess >& rxDocObjectNA ) const
{
- if( (maName.getLength() == 0) || (maStreamName.getLength() == 0) || (mnOffset == SAL_MAX_UINT32) )
- return;
+ OUString aVBASourceCode = readSourceCode( rVbaStrg );
+ createModule( aVBASourceCode, rxBasicLib, rxDocObjectNA );
+}
+
+void VbaModule::createEmptyModule( const Reference< XNameContainer >& rxBasicLib, const Reference< XNameAccess >& rxDocObjectNA ) const
+{
+ createModule( OUString(), rxBasicLib, rxDocObjectNA );
+}
- BinaryXInputStream aInStrm( rVbaStrg.openInputStream( maStreamName ), true );
- OSL_ENSURE( !aInStrm.isEof(), "VbaModule::importSourceCode - cannot open module stream" );
- // skip the 'performance cache' stored before the actual source code
- aInStrm.seek( mnOffset );
- // if stream is still valid, load the source code
- if( aInStrm.isEof() )
+// private --------------------------------------------------------------------
+
+OUString VbaModule::readSourceCode( StorageBase& rVbaStrg ) const
+{
+ OUStringBuffer aSourceCode;
+ if( (maStreamName.getLength() > 0) && (mnOffset != SAL_MAX_UINT32) )
+ {
+ BinaryXInputStream aInStrm( rVbaStrg.openInputStream( maStreamName ), true );
+ OSL_ENSURE( !aInStrm.isEof(), "VbaModule::readSourceCode - cannot open module stream" );
+ // skip the 'performance cache' stored before the actual source code
+ aInStrm.seek( mnOffset );
+ // if stream is still valid, load the source code
+ if( !aInStrm.isEof() )
+ {
+ // decompression starts at current stream position of aInStrm
+ VbaInputStream aVbaStrm( aInStrm );
+ // load the source code line-by-line, with some more processing
+ TextInputStream aVbaTextStrm( aVbaStrm, meTextEnc );
+ while( !aVbaTextStrm.isEof() )
+ {
+ OUString aCodeLine = aVbaTextStrm.readLine();
+ if( !aCodeLine.matchAsciiL( RTL_CONSTASCII_STRINGPARAM( "Attribute " ) ) )
+ {
+ // normal source code line
+ if( !mbExecutable )
+ aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "Rem " ) );
+ aSourceCode.append( aCodeLine ).append( sal_Unicode( '\n' ) );
+ }
+ }
+ }
+ }
+ return aSourceCode.makeStringAndClear();
+}
+
+void VbaModule::createModule( const OUString& rVBASourceCode,
+ const Reference< XNameContainer >& rxBasicLib, const Reference< XNameAccess >& rxDocObjectNA ) const
+{
+ if( maName.getLength() == 0 )
return;
// prepare the Basic module
@@ -162,7 +200,7 @@ void VbaModule::importSourceCode( StorageBase& rVbaStrg,
break;
case ModuleType::DOCUMENT:
aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "VBADocumentModule" ) );
- // get the VBA object associated to the document module
+ // get the VBA implementation object associated to the document module
if( rxDocObjectNA.is() ) try
{
aModuleInfo.ModuleObject.set( rxDocObjectNA->getByName( maName ), UNO_QUERY );
@@ -188,21 +226,8 @@ void VbaModule::importSourceCode( StorageBase& rVbaStrg,
append( maName.replace( ' ', '_' ) ).append( sal_Unicode( '\n' ) );
}
- // decompression starts at current stream position of aInStrm
- VbaInputStream aVbaStrm( aInStrm );
- // load the source code line-by-line, with some more processing
- TextInputStream aVbaTextStrm( aVbaStrm, meTextEnc );
- while( !aVbaTextStrm.isEof() )
- {
- OUString aCodeLine = aVbaTextStrm.readLine();
- // skip all 'Attribute' statements
- if( !aCodeLine.matchAsciiL( RTL_CONSTASCII_STRINGPARAM( "Attribute " ) ) )
- {
- if( !mbExecutable )
- aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "Rem " ) );
- aSourceCode.append( aCodeLine ).append( sal_Unicode( '\n' ) );
- }
- }
+ // append passed VBA source code
+ aSourceCode.append( rVBASourceCode );
// close the subroutine named after the module
if( !mbExecutable )
@@ -225,7 +250,7 @@ void VbaModule::importSourceCode( StorageBase& rVbaStrg,
}
catch( Exception& )
{
- OSL_ENSURE( false, "VbaModule::importSourceCode - cannot insert module into library" );
+ OSL_ENSURE( false, "VbaModule::createModule - cannot insert module into library" );
}
}
diff --git a/oox/source/ole/vbaproject.cxx b/oox/source/ole/vbaproject.cxx
index deff066a5ed5..0f7e3cb8612a 100644
--- a/oox/source/ole/vbaproject.cxx
+++ b/oox/source/ole/vbaproject.cxx
@@ -173,6 +173,67 @@ bool VbaProject::hasDialog( const OUString& rDialogName ) const
return mxDialogLib.is() && mxDialogLib->hasByName( rDialogName );
}
+// protected ------------------------------------------------------------------
+
+void VbaProject::addDummyModule( const OUString& rName, sal_Int32 nType )
+{
+ OSL_ENSURE( rName.getLength() > 0, "VbaProject::addDummyModule - missing module name" );
+ maDummyModules[ rName ] = nType;
+}
+
+void VbaProject::createDummyModules()
+{
+ /* !! HACK !! This function is called from old XLS filter only, must be
+ removed when this filter uses the OOX VBA import instead of the old SVX
+ VBA import.
+ */
+
+ // create empty dummy modules
+ typedef RefMap< OUString, VbaModule > VbaModuleMap;
+ VbaModuleMap aDummyModules;
+ for( DummyModuleMap::iterator aIt = maDummyModules.begin(), aEnd = maDummyModules.end(); aIt != aEnd; ++aIt )
+ {
+ OSL_ENSURE( !aDummyModules.has( aIt->first ), "VbaProject::createDummyModules - multiple modules with the same name" );
+ VbaModuleMap::mapped_type& rxModule = aDummyModules[ aIt->first ];
+ rxModule.reset( new VbaModule( mxDocModel, aIt->first, RTL_TEXTENCODING_MS_1252, isImportVbaExecutable() ) );
+ rxModule->setType( aIt->second );
+ }
+
+ if( !aDummyModules.empty() ) try
+ {
+ // get the model factory and the basic library
+ Reference< XMultiServiceFactory > xModelFactory( mxDocModel, UNO_QUERY_THROW );
+ Reference< XNameContainer > xBasicLib( createBasicLibrary(), UNO_SET_THROW );
+
+ // try to get access to document objects related to code modules
+ Reference< XNameAccess > xDocObjectNA;
+ try
+ {
+ xDocObjectNA.set( xModelFactory->createInstance( CREATE_OUSTRING( "ooo.vba.VBAObjectModuleObjectProvider" ) ), UNO_QUERY );
+ }
+ catch( Exception& )
+ {
+ // not all documents support this
+ }
+
+ // create empty dummy modules
+ if( xBasicLib.is() )
+ aDummyModules.forEachMem( &VbaModule::createEmptyModule,
+ ::boost::cref( xBasicLib ), ::boost::cref( xDocObjectNA ) );
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+void VbaProject::prepareImport()
+{
+}
+
+void VbaProject::finalizeImport()
+{
+}
+
// private --------------------------------------------------------------------
Reference< XLibraryContainer > VbaProject::getLibraryContainer( sal_Int32 nPropId )
@@ -231,6 +292,9 @@ void VbaProject::importVba( StorageBase& rVbaPrjStrg, const GraphicHelper& rGrap
if( aDirStrm.isEof() )
return;
+ // virtual call, derived classes may do some preparations
+ prepareImport();
+
// read all records of the directory
rtl_TextEncoding eTextEnc = RTL_TEXTENCODING_MS_1252;
sal_uInt16 nModuleCount = 0;
@@ -345,17 +409,29 @@ void VbaProject::importVba( StorageBase& rVbaPrjStrg, const GraphicHelper& rGrap
}
}
+ // create empty dummy modules
+ VbaModuleMap aDummyModules;
+ for( DummyModuleMap::iterator aIt = maDummyModules.begin(), aEnd = maDummyModules.end(); aIt != aEnd; ++aIt )
+ {
+ OSL_ENSURE( !aModules.has( aIt->first ) && !aDummyModules.has( aIt->first ), "VbaProject::importVba - multiple modules with the same name" );
+ VbaModuleMap::mapped_type& rxModule = aDummyModules[ aIt->first ];
+ rxModule.reset( new VbaModule( mxDocModel, aIt->first, eTextEnc, bExecutable ) );
+ rxModule->setType( aIt->second );
+ }
+
/* Now it is time to load the source code. All modules will be inserted
into the Basic library of the document specified by the 'maLibName'
member. Do not create the Basic library, if there are no modules
specified. */
- if( !aModules.empty() ) try
+ if( !aModules.empty() || !aDummyModules.empty() ) try
{
// get the model factory and the basic library
Reference< XMultiServiceFactory > xModelFactory( mxDocModel, UNO_QUERY_THROW );
Reference< XNameContainer > xBasicLib( createBasicLibrary(), UNO_SET_THROW );
- // set library container to VBA compatibility mode
+ /* Set library container to VBA compatibility mode. This will create
+ the VBA Globals object and store it in the Basic manager of the
+ document. */
try
{
Reference< XVBACompatibility >( getLibraryContainer( PROP_BasicLibraries ), UNO_QUERY_THROW )->setVBACompatibilityMode( sal_True );
@@ -364,15 +440,6 @@ void VbaProject::importVba( StorageBase& rVbaPrjStrg, const GraphicHelper& rGrap
{
}
- // create the VBAGlobals object, the model will store it in the Basic manager
- try
- {
- xModelFactory->createInstance( CREATE_OUSTRING( "ooo.vba.VBAGlobals" ) );
- }
- catch( Exception& )
- {
- }
-
// try to get access to document objects related to code modules
Reference< XNameAccess > xDocObjectNA;
try
@@ -384,10 +451,17 @@ void VbaProject::importVba( StorageBase& rVbaPrjStrg, const GraphicHelper& rGrap
// not all documents support this
}
- // call Basic source code import for each module, boost::[c]ref enforces pass-by-ref
if( xBasicLib.is() )
- aModules.forEachMem( &VbaModule::importSourceCode,
- ::boost::ref( *xVbaStrg ), ::boost::cref( xBasicLib ), ::boost::cref( xDocObjectNA ) );
+ {
+ // call Basic source code import for each module, boost::[c]ref enforces pass-by-ref
+ aModules.forEachMem( &VbaModule::createAndImportModule,
+ ::boost::ref( *xVbaStrg ), ::boost::cref( xBasicLib ),
+ ::boost::cref( xDocObjectNA ) );
+
+ // create empty dummy modules
+ aDummyModules.forEachMem( &VbaModule::createEmptyModule,
+ ::boost::cref( xBasicLib ), ::boost::cref( xDocObjectNA ) );
+ }
}
catch( Exception& )
{
@@ -402,7 +476,7 @@ void VbaProject::importVba( StorageBase& rVbaPrjStrg, const GraphicHelper& rGrap
for( ::std::vector< OUString >::iterator aIt = aElements.begin(), aEnd = aElements.end(); aIt != aEnd; ++aIt )
{
// try to open the element as storage
- if( !aIt->equals( CREATE_OUSTRING( "VBA" ) ) )
+ if( !aIt->equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "VBA" ) ) )
{
StorageRef xSubStrg = rVbaPrjStrg.openSubStorage( *aIt, false );
if( xSubStrg.get() ) try
@@ -425,6 +499,9 @@ void VbaProject::importVba( StorageBase& rVbaPrjStrg, const GraphicHelper& rGrap
}
}
}
+
+ // virtual call, derived classes may do some more processing
+ finalizeImport();
}
void VbaProject::copyStorage( StorageBase& rVbaPrjStrg )
diff --git a/oox/source/xls/excelvbaproject.cxx b/oox/source/xls/excelvbaproject.cxx
new file mode 100755
index 000000000000..ee22dc8398ba
--- /dev/null
+++ b/oox/source/xls/excelvbaproject.cxx
@@ -0,0 +1,161 @@
+/*************************************************************************
+ *
+ * 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 <list>
+#include <set>
+#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/script/ModuleType.hpp>
+#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
+#include <rtl/ustrbuf.hxx>
+#include "oox/helper/helper.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "properties.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::document;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::script;
+using namespace ::com::sun::star::sheet;
+using namespace ::com::sun::star::uno;
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+
+// ============================================================================
+
+ExcelVbaProject::ExcelVbaProject( const Reference< XMultiServiceFactory >& rxGlobalFactory, const Reference< XSpreadsheetDocument >& rxDocument ) :
+ ::oox::ole::VbaProject( rxGlobalFactory, Reference< XModel >( rxDocument, UNO_QUERY ), CREATE_OUSTRING( "Calc" ) ),
+ mxDocument( rxDocument )
+{
+}
+
+void ExcelVbaProject::createMissingModules()
+{
+ /* !! HACK !! This function is called from old XLS filter only, must be
+ removed when this filter uses the OOX VBA import instead of the old SVX
+ VBA import.
+ */
+
+ // collect and register all sheets without codenames
+ prepareImport();
+ // manually create the registered dummy modules
+ createDummyModules();
+}
+
+// protected ------------------------------------------------------------------
+
+namespace {
+
+struct SheetCodeNameInfo
+{
+ PropertySet maSheetProps; /// Property set of the sheet without codename.
+ OUString maPrefix; /// Prefix for the codename to be generated.
+
+ inline explicit SheetCodeNameInfo( PropertySet& rSheetProps, const OUString& rPrefix ) :
+ maSheetProps( rSheetProps ), maPrefix( rPrefix ) {}
+};
+
+typedef ::std::set< OUString > CodeNameSet;
+typedef ::std::list< SheetCodeNameInfo > SheetCodeNameInfoList;
+
+} // namespace
+
+void ExcelVbaProject::prepareImport()
+{
+ /* Check if the sheets have imported codenames. Generate new unused
+ codenames if not. */
+ if( mxDocument.is() ) try
+ {
+ // collect existing codenames (do not use them when creating new codenames)
+ CodeNameSet aUsedCodeNames;
+
+ // collect sheets without codenames
+ SheetCodeNameInfoList aCodeNameInfos;
+
+ // iterate over all imported sheets
+ 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
+ {
+ PropertySet aSheetProp( xSheetsEnum->nextElement() );
+ OUString aCodeName;
+ aSheetProp.getProperty( aCodeName, PROP_CodeName );
+ if( aCodeName.getLength() > 0 )
+ {
+ aUsedCodeNames.insert( aCodeName );
+ }
+ else
+ {
+ // TODO: once we have chart sheets we need a switch/case on sheet type ('SheetNNN' vs. 'ChartNNN')
+ aCodeNameInfos.push_back( SheetCodeNameInfo( aSheetProp, CREATE_OUSTRING( "Sheet" ) ) );
+ }
+ }
+ catch( Exception& )
+ {
+ }
+
+ // create new codenames if sheets do not have one
+ for( SheetCodeNameInfoList::iterator aIt = aCodeNameInfos.begin(), aEnd = aCodeNameInfos.end(); aIt != aEnd; ++aIt )
+ {
+ // search for an unused codename
+ sal_Int32 nCounter = 1;
+ OUString aCodeName;
+ do
+ {
+ aCodeName = OUStringBuffer( aIt->maPrefix ).append( nCounter++ ).makeStringAndClear();
+ }
+ while( aUsedCodeNames.count( aCodeName ) > 0 );
+ aUsedCodeNames.insert( aCodeName );
+
+ // set codename at sheet
+ aIt->maSheetProps.setProperty( PROP_CodeName, aCodeName );
+
+ // tell base class to create a dummy module
+ addDummyModule( aCodeName, ModuleType::DOCUMENT );
+ }
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
diff --git a/oox/source/xls/makefile.mk b/oox/source/xls/makefile.mk
index cdb2e18c262d..b5ede953bbfe 100644
--- a/oox/source/xls/makefile.mk
+++ b/oox/source/xls/makefile.mk
@@ -59,6 +59,7 @@ SLOFILES = \
$(SLO)$/excelchartconverter.obj \
$(SLO)$/excelfilter.obj \
$(SLO)$/excelhandlers.obj \
+ $(SLO)$/excelvbaproject.obj \
$(SLO)$/externallinkbuffer.obj \
$(SLO)$/externallinkfragment.obj \
$(SLO)$/formulabase.obj \
diff --git a/oox/source/xls/workbookhelper.cxx b/oox/source/xls/workbookhelper.cxx
index 5684fbd8ae75..ceba5690004c 100644
--- a/oox/source/xls/workbookhelper.cxx
+++ b/oox/source/xls/workbookhelper.cxx
@@ -43,7 +43,6 @@
#include "properties.hxx"
#include "oox/helper/progressbar.hxx"
#include "oox/helper/propertyset.hxx"
-#include "oox/ole/vbaproject.hxx"
#include "oox/drawingml/theme.hxx"
#include "oox/xls/addressconverter.hxx"
#include "oox/xls/biffinputstream.hxx"
@@ -51,6 +50,7 @@
#include "oox/xls/defnamesbuffer.hxx"
#include "oox/xls/excelchartconverter.hxx"
#include "oox/xls/excelfilter.hxx"
+#include "oox/xls/excelvbaproject.hxx"
#include "oox/xls/externallinkbuffer.hxx"
#include "oox/xls/formulaparser.hxx"
#include "oox/xls/pagesettings.hxx"
@@ -691,7 +691,7 @@ void WorkbookHelper::finalizeWorkbookImport()
StorageRef xVbaPrjStrg = mrBookData.getVbaProjectStorage();
if( xVbaPrjStrg.get() && xVbaPrjStrg->isStorage() )
{
- ::oox::ole::VbaProject aVbaProject( getGlobalFactory(), getBaseFilter().getModel(), CREATE_OUSTRING( "Calc" ) );
+ ExcelVbaProject aVbaProject( getGlobalFactory(), getDocument() );
aVbaProject.importVbaProject( *xVbaPrjStrg, getBaseFilter().getGraphicHelper() );
}
}
diff --git a/oox/source/xls/worksheethelper.cxx b/oox/source/xls/worksheethelper.cxx
index 99c2d844f4b5..d2d42f2be369 100644
--- a/oox/source/xls/worksheethelper.cxx
+++ b/oox/source/xls/worksheethelper.cxx
@@ -404,7 +404,7 @@ public:
Size getCellSize( sal_Int32 nCol, sal_Int32 nRow ) const;
/** Returns the address of the cell that contains the passed point in 1/100 mm. */
- CellAddress getCellAddressFromPosition( const Point& rPosition, const CellAddress* pStartAddr = 0 ) const;
+ CellAddress getCellAddressFromPosition( const Point& rPosition, const Size& rDrawPageSize ) const;
/** Returns the cell range address that contains the passed rectangle in 1/100 mm. */
CellRangeAddress getCellRangeFromRectangle( const Rectangle& rRect ) const;
@@ -795,41 +795,117 @@ Size WorksheetData::getCellSize( sal_Int32 nCol, sal_Int32 nRow ) const
return aSize;
}
-CellAddress WorksheetData::getCellAddressFromPosition( const Point& rPosition, const CellAddress* pStartAddr ) const
+namespace {
+
+inline sal_Int32 lclGetMidAddr( sal_Int32 nBegAddr, sal_Int32 nEndAddr, sal_Int32 nBegPos, sal_Int32 nEndPos, sal_Int32 nSearchPos )
+{
+ // use sal_Int64 to prevent integer overflow
+ return nBegAddr + 1 + static_cast< sal_Int32 >( static_cast< sal_Int64 >( nEndAddr - nBegAddr - 2 ) * (nSearchPos - nBegPos) / (nEndPos - nBegPos) );
+}
+
+bool lclPrepareInterval( sal_Int32 nBegAddr, sal_Int32& rnMidAddr, sal_Int32 nEndAddr,
+ sal_Int32 nBegPos, sal_Int32 nEndPos, sal_Int32 nSearchPos )
{
- // prepare start address for search loop
- sal_Int32 nCol = pStartAddr ? ::std::min< sal_Int32 >( pStartAddr->Column + 1, mrMaxApiPos.Column ) : 1;
- sal_Int32 nRow = pStartAddr ? ::std::min< sal_Int32 >( pStartAddr->Row + 1, mrMaxApiPos.Row ) : 1;
+ // searched position before nBegPos -> use nBegAddr
+ if( nSearchPos <= nBegPos )
+ {
+ rnMidAddr = nBegAddr;
+ return false;
+ }
+
+ // searched position after nEndPos, or begin next to end -> use nEndAddr
+ if( (nSearchPos >= nEndPos) || (nBegAddr + 1 >= nEndAddr) )
+ {
+ rnMidAddr = nEndAddr;
+ return false;
+ }
+
+ /* Otherwise find mid address according to position. lclGetMidAddr() will
+ return an address between nBegAddr and nEndAddr. */
+ rnMidAddr = lclGetMidAddr( nBegAddr, nEndAddr, nBegPos, nEndPos, nSearchPos );
+ return true;
+}
+
+bool lclUpdateInterval( sal_Int32& rnBegAddr, sal_Int32& rnMidAddr, sal_Int32& rnEndAddr,
+ sal_Int32& rnBegPos, sal_Int32 nMidPos, sal_Int32& rnEndPos, sal_Int32 nSearchPos )
+{
+ // nSearchPos < nMidPos: use the interval [begin,mid] in the next iteration
+ if( nSearchPos < nMidPos )
+ {
+ // if rnBegAddr is next to rnMidAddr, the latter is the column/row in question
+ if( rnBegAddr + 1 >= rnMidAddr )
+ return false;
+ // otherwise, set interval end to mid
+ rnEndPos = nMidPos;
+ rnEndAddr = rnMidAddr;
+ rnMidAddr = lclGetMidAddr( rnBegAddr, rnEndAddr, rnBegPos, rnEndPos, nSearchPos );
+ return true;
+ }
+
+ // nSearchPos > nMidPos: use the interval [mid,end] in the next iteration
+ if( nSearchPos > nMidPos )
+ {
+ // if rnMidAddr is next to rnEndAddr, the latter is the column/row in question
+ if( rnMidAddr + 1 >= rnEndAddr )
+ {
+ rnMidAddr = rnEndAddr;
+ return false;
+ }
+ // otherwise, set interval start to mid
+ rnBegPos = nMidPos;
+ rnBegAddr = rnMidAddr;
+ rnMidAddr = lclGetMidAddr( rnBegAddr, rnEndAddr, rnBegPos, rnEndPos, nSearchPos );
+ return true;
+ }
+
+ // nSearchPos == nMidPos: rnMidAddr is the column/row in question, do not loop anymore
+ return false;
+}
+
+} // namespace
+
+CellAddress WorksheetData::getCellAddressFromPosition( const Point& rPosition, const Size& rDrawPageSize ) const
+{
+ // starting cell address and its position in drawing layer (top-left edge)
+ sal_Int32 nBegCol = 0;
+ sal_Int32 nBegRow = 0;
+ Point aBegPos( 0, 0 );
+
+ // end cell address and its position in drawing layer (bottom-right edge)
+ sal_Int32 nEndCol = mrMaxApiPos.Column + 1;
+ sal_Int32 nEndRow = mrMaxApiPos.Row + 1;
+ Point aEndPos( rDrawPageSize.Width, rDrawPageSize.Height );
+
+ // starting point for interval search
+ sal_Int32 nMidCol, nMidRow;
+ bool bLoopCols = lclPrepareInterval( nBegCol, nMidCol, nEndCol, aBegPos.X, aEndPos.X, rPosition.X );
+ bool bLoopRows = lclPrepareInterval( nBegRow, nMidRow, nEndRow, aBegPos.Y, aEndPos.Y, rPosition.Y );
+ Point aMidPos = getCellPosition( nMidCol, nMidRow );
/* The loop will find the column/row index of the cell right of/below
the cell containing the passed point, unless the point is located at
the top or left border of the containing cell. */
- bool bNextCol = true;
- bool bNextRow = true;
- Point aCellPos;
- do
+ while( bLoopCols || bLoopRows )
{
- aCellPos = getCellPosition( nCol, nRow );
- if( bNextCol && ((bNextCol = (aCellPos.X < rPosition.X) && (nCol < mrMaxApiPos.Column)) == true) )
- ++nCol;
- if( bNextRow && ((bNextRow = (aCellPos.Y < rPosition.Y) && (nRow < mrMaxApiPos.Row)) == true) )
- ++nRow;
+ bLoopCols = bLoopCols && lclUpdateInterval( nBegCol, nMidCol, nEndCol, aBegPos.X, aMidPos.X, aEndPos.X, rPosition.X );
+ bLoopRows = bLoopRows && lclUpdateInterval( nBegRow, nMidRow, nEndRow, aBegPos.Y, aMidPos.Y, aEndPos.Y, rPosition.Y );
+ aMidPos = getCellPosition( nMidCol, nMidRow );
}
- while( bNextCol || bNextRow );
/* The cell left of/above the current search position contains the passed
point, unless the point is located on the top/left border of the cell,
or the last column/row of the sheet has been reached. */
- if( aCellPos.X > rPosition.X ) --nCol;
- if( aCellPos.Y > rPosition.Y ) --nRow;
- return CellAddress( getSheetIndex(), nCol, nRow );
+ if( aMidPos.X > rPosition.X ) --nMidCol;
+ if( aMidPos.Y > rPosition.Y ) --nMidRow;
+ return CellAddress( getSheetIndex(), nMidCol, nMidRow );
}
CellRangeAddress WorksheetData::getCellRangeFromRectangle( const Rectangle& rRect ) const
{
- CellAddress aStartAddr = getCellAddressFromPosition( Point( rRect.X, rRect.Y ) );
+ Size aPageSize = getDrawPageSize();
+ CellAddress aStartAddr = getCellAddressFromPosition( Point( rRect.X, rRect.Y ), aPageSize );
Point aBotRight( rRect.X + rRect.Width, rRect.Y + rRect.Height );
- CellAddress aEndAddr = getCellAddressFromPosition( aBotRight );
+ CellAddress aEndAddr = getCellAddressFromPosition( aBotRight, aPageSize );
bool bMultiCols = aStartAddr.Column < aEndAddr.Column;
bool bMultiRows = aStartAddr.Row < aEndAddr.Row;
if( bMultiCols || bMultiRows )
@@ -945,17 +1021,25 @@ void WorksheetData::extendUsedArea( const CellRangeAddress& rRange )
void WorksheetData::extendShapeBoundingBox( const Rectangle& rShapeRect )
{
+ // scale EMUs to 1/100 mm
+ const UnitConverter& rUnitConv = getUnitConverter();
+ Rectangle aShapeRectHmm(
+ rUnitConv.scaleToMm100( rShapeRect.X, UNIT_EMU ),
+ rUnitConv.scaleToMm100( rShapeRect.Y, UNIT_EMU ),
+ rUnitConv.scaleToMm100( rShapeRect.Width, UNIT_EMU ),
+ rUnitConv.scaleToMm100( rShapeRect.Height, UNIT_EMU ) );
+
if( (maShapeBoundingBox.Width == 0) && (maShapeBoundingBox.Height == 0) )
{
// width and height of maShapeBoundingBox are assumed to be zero on first cell
- maShapeBoundingBox = rShapeRect;
+ maShapeBoundingBox = aShapeRectHmm;
}
else
{
- sal_Int32 nEndX = ::std::max( maShapeBoundingBox.X + maShapeBoundingBox.Width, rShapeRect.X + rShapeRect.Width );
- sal_Int32 nEndY = ::std::max( maShapeBoundingBox.Y + maShapeBoundingBox.Height, rShapeRect.Y + rShapeRect.Height );
- maShapeBoundingBox.X = ::std::min( maShapeBoundingBox.X, rShapeRect.X );
- maShapeBoundingBox.Y = ::std::min( maShapeBoundingBox.Y, rShapeRect.Y );
+ sal_Int32 nEndX = ::std::max( maShapeBoundingBox.X + maShapeBoundingBox.Width, aShapeRectHmm.X + aShapeRectHmm.Width );
+ sal_Int32 nEndY = ::std::max( maShapeBoundingBox.Y + maShapeBoundingBox.Height, aShapeRectHmm.Y + aShapeRectHmm.Height );
+ maShapeBoundingBox.X = ::std::min( maShapeBoundingBox.X, aShapeRectHmm.X );
+ maShapeBoundingBox.Y = ::std::min( maShapeBoundingBox.Y, aShapeRectHmm.Y );
maShapeBoundingBox.Width = nEndX - maShapeBoundingBox.X;
maShapeBoundingBox.Height = nEndY - maShapeBoundingBox.Y;
}