LibreOffice Module vbahelper (master) 1
vbadocumentsbase.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <utility>
22
26#include <com/sun/star/container/XEnumerationAccess.hpp>
27#include <com/sun/star/lang/XComponent.hpp>
28#include <com/sun/star/frame/Desktop.hpp>
29#include <com/sun/star/frame/XModel.hpp>
30#include <com/sun/star/frame/XFrame.hpp>
31#include <com/sun/star/frame/FrameSearchFlag.hpp>
32#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
33#include <com/sun/star/document/MacroExecMode.hpp>
34#include <com/sun/star/lang/XServiceInfo.hpp>
35#include <tools/urlobj.hxx>
36#include <o3tl/safeint.hxx>
37#include <osl/file.hxx>
38#include <unordered_map>
39
41#include <ooo/vba/XApplicationBase.hpp>
42
43using namespace ::ooo::vba;
44using namespace ::com::sun::star;
45
46typedef std::unordered_map< OUString,
47 sal_Int32 > NameIndexHash;
48
49typedef std::vector < uno::Reference< frame::XModel > > Documents;
50
51// #FIXME clearly this is a candidate for some sort of helper base class as
52// this is a copy of SelectedSheetsEnum ( vbawindow.cxx )
53
54namespace {
55
56class DocumentsEnumImpl : public ::cppu::WeakImplHelper< container::XEnumeration >
57{
58 uno::Reference< uno::XComponentContext > m_xContext;
59 Documents m_documents;
60 Documents::const_iterator m_it;
61
62public:
64 DocumentsEnumImpl( uno::Reference< uno::XComponentContext > xContext, Documents&& docs ) : m_xContext(std::move( xContext )), m_documents( std::move(docs) )
65 {
66 m_it = m_documents.begin();
67 }
69 explicit DocumentsEnumImpl( uno::Reference< uno::XComponentContext > xContext ) : m_xContext(std::move( xContext ))
70 {
71 uno::Reference< frame::XDesktop2 > xDesktop = frame::Desktop::create( m_xContext );
72 uno::Reference< container::XEnumeration > xComponents = xDesktop->getComponents()->createEnumeration();
73 while( xComponents->hasMoreElements() )
74 {
75 uno::Reference< frame::XModel > xNext( xComponents->nextElement(), uno::UNO_QUERY );
76 if ( xNext.is() )
77 m_documents.push_back( xNext );
78 }
79 m_it = m_documents.begin();
80 }
81 // XEnumeration
82 virtual sal_Bool SAL_CALL hasMoreElements( ) override
83 {
84 return m_it != m_documents.end();
85 }
86
87 virtual uno::Any SAL_CALL nextElement( ) override
88 {
89 if ( !hasMoreElements() )
90 {
91 throw container::NoSuchElementException();
92 }
93 return css::uno::Any( *(m_it++) );
94 }
95};
96
97}
98
99// #FIXME clearly this is also a candidate for some sort of helper base class as
100// a very similar one is used in vbawindow ( SelectedSheetsEnumAccess )
101// Maybe a template base class that does all of the operations on the hashmap
102// and vector only, and the sub-class does everything else
103// => ctor, createEnumeration & factory method need be defined ( to be called
104// by getByIndex, getByName )
105typedef ::cppu::WeakImplHelper< container::XEnumerationAccess
106 , css::container::XIndexAccess
107 , css::container::XNameAccess
109
110namespace {
111
112class DocumentsAccessImpl : public DocumentsAccessImpl_BASE
113{
114 uno::Reference< uno::XComponentContext > m_xContext;
115 Documents m_documents;
116 NameIndexHash namesToIndices;
117public:
119 DocumentsAccessImpl( uno::Reference< uno::XComponentContext > xContext, VbaDocumentsBase::DOCUMENT_TYPE eDocType ) :m_xContext(std::move( xContext ))
120 {
121 uno::Reference< container::XEnumeration > xEnum = new DocumentsEnumImpl( m_xContext );
122 sal_Int32 nIndex=0;
123 while( xEnum->hasMoreElements() )
124 {
125 uno::Reference< lang::XServiceInfo > xServiceInfo( xEnum->nextElement(), uno::UNO_QUERY );
126 if ( xServiceInfo.is()
127 && ( ( xServiceInfo->supportsService( "com.sun.star.sheet.SpreadsheetDocument" ) && eDocType == VbaDocumentsBase::EXCEL_DOCUMENT )
128 || ( xServiceInfo->supportsService( "com.sun.star.text.TextDocument" ) && eDocType == VbaDocumentsBase::WORD_DOCUMENT ) ) )
129 {
130 uno::Reference< frame::XModel > xModel( xServiceInfo, uno::UNO_QUERY_THROW ); // that the spreadsheetdocument is a xmodel is a given
131 m_documents.push_back( xModel );
133 namesToIndices[ sName ] = nIndex++;
134 }
135 }
136
137 }
138
139 //XEnumerationAccess
140 virtual uno::Reference< container::XEnumeration > SAL_CALL createEnumeration( ) override
141 {
142 return new DocumentsEnumImpl( m_xContext, std::vector(m_documents) );
143 }
144 // XIndexAccess
145 virtual ::sal_Int32 SAL_CALL getCount( ) override
146 {
147 return m_documents.size();
148 }
149 virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override
150 {
151 if ( Index < 0
152 || o3tl::make_unsigned(Index) >= m_documents.size() )
153 throw lang::IndexOutOfBoundsException();
154 return css::uno::Any( m_documents[ Index ] ); // returns xspreadsheetdoc
155 }
156
157 //XElementAccess
158 virtual uno::Type SAL_CALL getElementType( ) override
159 {
161 }
162
163 virtual sal_Bool SAL_CALL hasElements( ) override
164 {
165 return (!m_documents.empty());
166 }
167
168 //XNameAccess
169 virtual uno::Any SAL_CALL getByName( const OUString& aName ) override
170 {
171 NameIndexHash::const_iterator it = namesToIndices.find( aName );
172 if ( it == namesToIndices.end() )
173 throw container::NoSuchElementException();
174 return css::uno::Any( m_documents[ it->second ] );
175
176 }
177
178 virtual uno::Sequence< OUString > SAL_CALL getElementNames( ) override
179 {
180 return comphelper::mapKeysToSequence( namesToIndices );
181 }
182
183 virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override
184 {
185 NameIndexHash::const_iterator it = namesToIndices.find( aName );
186 return (it != namesToIndices.end());
187 }
188
189};
190
191}
192
193VbaDocumentsBase::VbaDocumentsBase( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< css::uno::XComponentContext >& xContext, DOCUMENT_TYPE eDocType ) : VbaDocumentsBase_BASE( xParent, xContext, uno::Reference< container::XIndexAccess >( new DocumentsAccessImpl( xContext, eDocType ) ) ), meDocType( eDocType )
194{
195}
196
197namespace {
198
199void lclSetupComponent( const uno::Reference< lang::XComponent >& rxComponent, bool bScreenUpdating, bool bInteractive )
200{
201 if( !bScreenUpdating ) try
202 {
203 uno::Reference< frame::XModel >( rxComponent, uno::UNO_QUERY_THROW )->lockControllers();
204 }
205 catch( uno::Exception& )
206 {
207 }
208
209 if( !bInteractive ) try
210 {
211 uno::Reference< frame::XModel > xModel( rxComponent, uno::UNO_QUERY_THROW );
212 uno::Reference< frame::XController > xController( xModel->getCurrentController(), uno::UNO_SET_THROW );
213 uno::Reference< frame::XFrame > xFrame( xController->getFrame(), uno::UNO_SET_THROW );
214 uno::Reference< awt::XWindow >( xFrame->getContainerWindow(), uno::UNO_SET_THROW )->setEnable( false );
215 }
216 catch( uno::Exception& )
217 {
218 }
219}
220
221} // namespace
222
224{
225 // #163808# determine state of Application.ScreenUpdating and Application.Interactive symbols (before new document is opened)
226 uno::Reference< XApplicationBase > xApplication( Application(), uno::UNO_QUERY );
227 bool bScreenUpdating = !xApplication.is() || xApplication->getScreenUpdating();
228 bool bInteractive = true;
229
230 try
231 {
232 bInteractive = !xApplication.is() || xApplication->getInteractive();
233 }
234 catch( const uno::Exception& )
235 {
236 }
237
238 uno::Reference< frame::XDesktop2 > xLoader = frame::Desktop::create(mxContext);
239 OUString sURL;
240 if( meDocType == WORD_DOCUMENT )
241 sURL = "private:factory/swriter";
242 else if( meDocType == EXCEL_DOCUMENT )
243 sURL = "private:factory/scalc";
244 else
245 throw uno::RuntimeException( "Not implemented" );
246
247 // prepare the media descriptor
248 utl::MediaDescriptor aMediaDesc;
249 aMediaDesc[ utl::MediaDescriptor::PROP_MACROEXECUTIONMODE ] <<= document::MacroExecMode::USE_CONFIG;
250 aMediaDesc.setComponentDataEntry( "ApplyFormDesignMode" , uno::Any( false ) );
251
252 // create the new document
253 uno::Reference< lang::XComponent > xComponent = xLoader->loadComponentFromURL(
254 sURL , "_blank", 0,
255 aMediaDesc.getAsConstPropertyValueList() );
256
257 // #163808# lock document controllers and container window if specified by application
258 lclSetupComponent( xComponent, bScreenUpdating, bInteractive );
259
260 return uno::Any( xComponent );
261}
262
263// #TODO# #FIXME# can any of the unused params below be used?
264uno::Any VbaDocumentsBase::openDocument( const OUString& rFileName, const uno::Any& ReadOnly, const uno::Sequence< beans::PropertyValue >& rProps )
265{
266 // #163808# determine state of Application.ScreenUpdating and Application.Interactive symbols (before new document is opened)
267 uno::Reference< XApplicationBase > xApplication( Application(), uno::UNO_QUERY );
268 bool bScreenUpdating = !xApplication.is() || xApplication->getScreenUpdating();
269 bool bInteractive = true;
270
271 try
272 {
273 bInteractive = !xApplication.is() || xApplication->getInteractive();
274 }
275 catch( const uno::Exception& )
276 {
277 }
278
279 // we need to detect if this is a URL, if not then assume it's a file path
280 OUString aURL;
281 INetURLObject aObj;
282 aObj.SetURL( rFileName );
283 bool bIsURL = aObj.GetProtocol() != INetProtocol::NotValid;
284 if ( bIsURL )
285 aURL = rFileName;
286 else
287 osl::FileBase::getFileURLFromSystemPath( rFileName, aURL );
288 uno::Reference< frame::XDesktop2 > xDesktop = frame::Desktop::create( mxContext );
289
290 uno::Sequence< beans::PropertyValue > sProps( rProps );
291 sProps.realloc( sProps.getLength() + 1 );
292 auto pProps = sProps.getArray();
293 pProps[ sProps.getLength() - 1 ].Name = "MacroExecutionMode";
294 pProps[ sProps.getLength() - 1 ].Value <<= document::MacroExecMode::ALWAYS_EXECUTE_NO_WARN;
295
296 if ( ReadOnly.hasValue() )
297 {
298 bool bIsReadOnly = false;
299 ReadOnly >>= bIsReadOnly;
300 if ( bIsReadOnly )
301 {
302 sProps.realloc( sProps.getLength() + 1 );
303 pProps = sProps.getArray();
304 pProps[ sProps.getLength() - 1 ].Name = "ReadOnly";
305 pProps[ sProps.getLength() - 1 ].Value <<= true;
306 }
307 }
308
309 uno::Reference< lang::XComponent > xComponent = xDesktop->loadComponentFromURL( aURL,
310 "_default" ,
311 frame::FrameSearchFlag::CREATE,
312 sProps);
313
314 // #163808# lock document controllers and container window if specified by application
315 lclSetupComponent( xComponent, bScreenUpdating, bInteractive );
316
317 return uno::Any( xComponent );
318}
319
320/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
struct _ADOIndex Index
Reference< XComponentContext > m_xContext
INetProtocol GetProtocol() const
bool SetURL(std::u16string_view rTheAbsURIRef, EncodeMechanism eMechanism=EncodeMechanism::WasEncoded, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8)
css::uno::Reference< css::uno::XComponentContext > mxContext
virtual css::uno::Any SAL_CALL Application() override
static OUString getNameFromModel(const css::uno::Reference< css::frame::XModel > &xModel)
DOCUMENT_TYPE meDocType
VbaDocumentsBase(const css::uno::Reference< ov::XHelperInterface > &xParent, const css::uno::Reference< css::uno::XComponentContext > &xContext, DOCUMENT_TYPE eDocType)
css::uno::Any openDocument(const OUString &Filename, const css::uno::Any &ReadOnly, const css::uno::Sequence< css::beans::PropertyValue > &rProps)
css::uno::Any createDocument()
css::uno::Type const & get()
void setComponentDataEntry(const OUString &rName, const css::uno::Any &rValue)
static constexpr OUStringLiteral PROP_MACROEXECUTIONMODE
URL aURL
OUString sName
sal_Int32 nIndex
OUString aName
std::vector< DocumentDescriptor > Documents
css::uno::Sequence< typename M::key_type > mapKeysToSequence(M const &map)
Reference
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
Reference< XController > xController
Reference< XFrame > xFrame
Reference< XModel > xModel
unsigned char sal_Bool
::cppu::WeakImplHelper< container::XEnumerationAccess, css::container::XIndexAccess, css::container::XNameAccess > DocumentsAccessImpl_BASE
std::unordered_map< OUString, sal_Int32 > NameIndexHash
std::vector< uno::Reference< frame::XModel > > Documents
std::unordered_map< OUString, SCTAB > NameIndexHash