1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 #include "vbahelper/vbadocumentsbase.hxx"
25
26 #include <comphelper/mediadescriptor.hxx>
27 #include <comphelper/processfactory.hxx>
28 #include <cppuhelper/implbase1.hxx>
29 #include <cppuhelper/implbase3.hxx>
30 #include <com/sun/star/frame/XDesktop.hpp>
31 #include <com/sun/star/container/XEnumerationAccess.hpp>
32 #include <com/sun/star/frame/XComponentLoader.hpp>
33 #include <com/sun/star/lang/XComponent.hpp>
34 #include <com/sun/star/frame/XModel.hpp>
35 #include <com/sun/star/frame/XFrame.hpp>
36 #include <com/sun/star/frame/FrameSearchFlag.hpp>
37 #include <com/sun/star/util/XModifiable.hpp>
38 #include <com/sun/star/frame/XStorable.hpp>
39 #include <com/sun/star/lang/DisposedException.hpp>
40 #include <com/sun/star/beans/PropertyVetoException.hpp>
41 #include <com/sun/star/util/XCloseable.hpp>
42 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
43 #include <com/sun/star/document/XTypeDetection.hpp>
44 #include <com/sun/star/document/MacroExecMode.hpp>
45 #include <com/sun/star/uri/XUriReference.hpp>
46 #include <com/sun/star/uri/XUriReferenceFactory.hpp>
47 #include <com/sun/star/lang/XServiceInfo.hpp>
48 #include <sfx2/objsh.hxx>
49 #include <tools/urlobj.hxx>
50 #include <hash_map>
51 #include <osl/file.hxx>
52
53 #include "vbahelper/vbahelper.hxx"
54 #include "vbahelper/vbaapplicationbase.hxx"
55
56 using namespace ::ooo::vba;
57 using namespace ::com::sun::star;
58
59 static const rtl::OUString sSpreadsheetDocument( rtl::OUString::createFromAscii( "com.sun.star.sheet.SpreadsheetDocument" ) );
60 static const rtl::OUString sTextDocument( rtl::OUString::createFromAscii( "com.sun.star.text.TextDocument" ) );
61
62 typedef std::hash_map< rtl::OUString,
63 sal_Int32, ::rtl::OUStringHash,
64 ::std::equal_to< ::rtl::OUString > > NameIndexHash;
65
66 typedef std::vector < uno::Reference< frame::XModel > > Documents;
67
68 typedef ::cppu::WeakImplHelper1< container::XEnumeration > DocumentsEnumImpl_BASE;
69
70 // #FIXME clearly this is a candidate for some sort of helper base class as
71 // this is a copy of SelectedSheetsEnum ( vbawindow.cxx )
72
73 class DocumentsEnumImpl : public DocumentsEnumImpl_BASE
74 {
75 uno::Reference< uno::XComponentContext > m_xContext;
76 Documents m_documents;
77 Documents::const_iterator m_it;
78
79 public:
DocumentsEnumImpl(const uno::Reference<uno::XComponentContext> & xContext,const Documents & docs)80 DocumentsEnumImpl( const uno::Reference< uno::XComponentContext >& xContext, const Documents& docs ) throw ( uno::RuntimeException ) : m_xContext( xContext ), m_documents( docs )
81 {
82 m_it = m_documents.begin();
83 }
DocumentsEnumImpl(const uno::Reference<uno::XComponentContext> & xContext)84 DocumentsEnumImpl( const uno::Reference< uno::XComponentContext >& xContext ) throw ( uno::RuntimeException ) : m_xContext( xContext )
85 {
86 uno::Reference< lang::XMultiComponentFactory > xSMgr(
87 m_xContext->getServiceManager(), uno::UNO_QUERY_THROW );
88
89 uno::Reference< frame::XDesktop > xDesktop
90 (xSMgr->createInstanceWithContext(::rtl::OUString::createFromAscii("com.sun.star.frame.Desktop"), m_xContext), uno::UNO_QUERY_THROW );
91 uno::Reference< container::XEnumeration > mxComponents = xDesktop->getComponents()->createEnumeration();
92 while( mxComponents->hasMoreElements() )
93 {
94 uno::Reference< frame::XModel > xNext( mxComponents->nextElement(), uno::UNO_QUERY );
95 if ( xNext.is() )
96 m_documents.push_back( xNext );
97 }
98 m_it = m_documents.begin();
99 }
100 // XEnumeration
hasMoreElements()101 virtual ::sal_Bool SAL_CALL hasMoreElements( ) throw (uno::RuntimeException)
102 {
103 return m_it != m_documents.end();
104 }
105
nextElement()106 virtual uno::Any SAL_CALL nextElement( ) throw (container::NoSuchElementException, lang::WrappedTargetException, uno::RuntimeException)
107 {
108 if ( !hasMoreElements() )
109 {
110 throw container::NoSuchElementException();
111 }
112 return makeAny( *(m_it++) );
113 }
114 };
115
116 // #FIXME clearly this is also a candidate for some sort of helper base class as
117 // a very similar one is used in vbawindow ( SelectedSheetsEnumAccess )
118 // Maybe a template base class that does all of the operations on the hashmap
119 // and vector only, and the sub-class does everything else
120 // => ctor, createEnumeration & factory method need be defined ( to be called
121 // by getByIndex, getByName )
122 typedef ::cppu::WeakImplHelper3< container::XEnumerationAccess
123 , com::sun::star::container::XIndexAccess
124 , com::sun::star::container::XNameAccess
125 > DocumentsAccessImpl_BASE;
126
127 class DocumentsAccessImpl : public DocumentsAccessImpl_BASE
128 {
129 uno::Reference< uno::XComponentContext > m_xContext;
130 Documents m_documents;
131 NameIndexHash namesToIndices;
132 VbaDocumentsBase::DOCUMENT_TYPE meDocType;
133 public:
DocumentsAccessImpl(const uno::Reference<uno::XComponentContext> & xContext,VbaDocumentsBase::DOCUMENT_TYPE eDocType)134 DocumentsAccessImpl( const uno::Reference< uno::XComponentContext >& xContext, VbaDocumentsBase::DOCUMENT_TYPE eDocType ) throw (uno::RuntimeException) :m_xContext( xContext ), meDocType( eDocType )
135 {
136 uno::Reference< container::XEnumeration > xEnum = new DocumentsEnumImpl( m_xContext );
137 sal_Int32 nIndex=0;
138 while( xEnum->hasMoreElements() )
139 {
140 uno::Reference< lang::XServiceInfo > xServiceInfo( xEnum->nextElement(), uno::UNO_QUERY );
141 if ( xServiceInfo.is()
142 && ( ( xServiceInfo->supportsService( sSpreadsheetDocument ) && meDocType == VbaDocumentsBase::EXCEL_DOCUMENT )
143 || ( xServiceInfo->supportsService( sTextDocument ) && meDocType == VbaDocumentsBase::WORD_DOCUMENT ) ) )
144 {
145 uno::Reference< frame::XModel > xModel( xServiceInfo, uno::UNO_QUERY_THROW ); // that the spreadsheetdocument is a xmodel is a given
146 m_documents.push_back( xModel );
147 INetURLObject aURL( xModel->getURL() );
148 namesToIndices[ aURL.GetLastName() ] = nIndex++;
149 }
150 }
151
152 }
153
154 //XEnumerationAccess
createEnumeration()155 virtual uno::Reference< container::XEnumeration > SAL_CALL createEnumeration( ) throw (uno::RuntimeException)
156 {
157 return new DocumentsEnumImpl( m_xContext, m_documents );
158 }
159 // XIndexAccess
getCount()160 virtual ::sal_Int32 SAL_CALL getCount( ) throw (uno::RuntimeException)
161 {
162 return m_documents.size();
163 }
getByIndex(::sal_Int32 Index)164 virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) throw ( lang::IndexOutOfBoundsException, lang::WrappedTargetException, uno::RuntimeException)
165 {
166 if ( Index < 0
167 || static_cast< Documents::size_type >(Index) >= m_documents.size() )
168 throw lang::IndexOutOfBoundsException();
169 return makeAny( m_documents[ Index ] ); // returns xspreadsheetdoc
170 }
171
172 //XElementAccess
getElementType()173 virtual uno::Type SAL_CALL getElementType( ) throw (uno::RuntimeException)
174 {
175 return frame::XModel::static_type(0);
176 }
177
hasElements()178 virtual ::sal_Bool SAL_CALL hasElements( ) throw (uno::RuntimeException)
179 {
180 return (m_documents.size() > 0);
181 }
182
183 //XNameAccess
getByName(const::rtl::OUString & aName)184 virtual uno::Any SAL_CALL getByName( const ::rtl::OUString& aName ) throw (container::NoSuchElementException, lang::WrappedTargetException, uno::RuntimeException)
185 {
186 NameIndexHash::const_iterator it = namesToIndices.find( aName );
187 if ( it == namesToIndices.end() )
188 throw container::NoSuchElementException();
189 return makeAny( m_documents[ it->second ] );
190
191 }
192
getElementNames()193 virtual uno::Sequence< ::rtl::OUString > SAL_CALL getElementNames( ) throw (uno::RuntimeException)
194 {
195 uno::Sequence< ::rtl::OUString > names( namesToIndices.size() );
196 ::rtl::OUString* pString = names.getArray();
197 NameIndexHash::const_iterator it = namesToIndices.begin();
198 NameIndexHash::const_iterator it_end = namesToIndices.end();
199 for ( ; it != it_end; ++it, ++pString )
200 *pString = it->first;
201 return names;
202 }
203
hasByName(const::rtl::OUString & aName)204 virtual ::sal_Bool SAL_CALL hasByName( const ::rtl::OUString& aName ) throw (uno::RuntimeException)
205 {
206 NameIndexHash::const_iterator it = namesToIndices.find( aName );
207 return (it != namesToIndices.end());
208 }
209
210 };
211
VbaDocumentsBase(const uno::Reference<XHelperInterface> & xParent,const uno::Reference<css::uno::XComponentContext> & xContext,DOCUMENT_TYPE eDocType)212 VbaDocumentsBase::VbaDocumentsBase( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< css::uno::XComponentContext >& xContext, DOCUMENT_TYPE eDocType ) throw (uno::RuntimeException) : VbaDocumentsBase_BASE( xParent, xContext, uno::Reference< container::XIndexAccess >( new DocumentsAccessImpl( xContext, eDocType ) ) ), meDocType( eDocType )
213 {
214 }
215
216 namespace {
217
lclSetupComponent(const uno::Reference<lang::XComponent> & rxComponent,sal_Bool bScreenUpdating,sal_Bool bInteractive)218 void lclSetupComponent( const uno::Reference< lang::XComponent >& rxComponent, sal_Bool bScreenUpdating, sal_Bool bInteractive )
219 {
220 if( !bScreenUpdating ) try
221 {
222 uno::Reference< frame::XModel >( rxComponent, uno::UNO_QUERY_THROW )->lockControllers();
223 }
224 catch( uno::Exception& )
225 {
226 }
227
228 if( !bInteractive ) try
229 {
230 uno::Reference< frame::XModel > xModel( rxComponent, uno::UNO_QUERY_THROW );
231 uno::Reference< frame::XController > xController( xModel->getCurrentController(), uno::UNO_SET_THROW );
232 uno::Reference< frame::XFrame > xFrame( xController->getFrame(), uno::UNO_SET_THROW );
233 uno::Reference< awt::XWindow >( xFrame->getContainerWindow(), uno::UNO_SET_THROW )->setEnable( sal_False );
234 }
235 catch( uno::Exception& )
236 {
237 }
238 }
239
240 } // namespace
241
createDocument()242 uno::Any VbaDocumentsBase::createDocument() throw (uno::RuntimeException)
243 {
244 // #163808# determine state of Application.ScreenUpdating and Application.Interactive symbols (before new document is opened)
245 uno::Reference< XApplicationBase > xApplication( Application(), uno::UNO_QUERY );
246 sal_Bool bScreenUpdating = !xApplication.is() || xApplication->getScreenUpdating();
247 sal_Bool bInteractive = !xApplication.is() || xApplication->getInteractive();
248
249 uno::Reference< lang::XMultiComponentFactory > xSMgr(
250 mxContext->getServiceManager(), uno::UNO_QUERY_THROW );
251
252 uno::Reference< frame::XComponentLoader > xLoader(
253 xSMgr->createInstanceWithContext(
254 ::rtl::OUString::createFromAscii("com.sun.star.frame.Desktop"),
255 mxContext), uno::UNO_QUERY_THROW );
256 rtl::OUString sURL;
257 if( meDocType == WORD_DOCUMENT )
258 sURL = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("private:factory/swriter") );
259 else if( meDocType == EXCEL_DOCUMENT )
260 sURL = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("private:factory/scalc") );
261 else
262 throw uno::RuntimeException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Not implemented") ), uno::Reference< uno::XInterface >() );
263
264 // prepare the media descriptor
265 ::comphelper::MediaDescriptor aMediaDesc;
266 aMediaDesc[ ::comphelper::MediaDescriptor::PROP_MACROEXECUTIONMODE() ] <<= document::MacroExecMode::USE_CONFIG;
267 aMediaDesc.setComponentDataEntry( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ApplyFormDesignMode" ) ), uno::Any( false ) );
268
269 // craete the new document
270 uno::Reference< lang::XComponent > xComponent = xLoader->loadComponentFromURL(
271 sURL ,
272 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("_blank") ), 0,
273 aMediaDesc.getAsConstPropertyValueList() );
274
275 // #163808# lock document controllers and container window if specified by application
276 lclSetupComponent( xComponent, bScreenUpdating, bInteractive );
277
278 return uno::makeAny( xComponent );
279 }
280
closeDocuments()281 void VbaDocumentsBase::closeDocuments() throw (uno::RuntimeException)
282 {
283 // #FIXME this *MUST* be wrong documents::close surely closes ALL documents
284 // in the collection, use of getCurrentDocument here is totally wrong
285 /*
286 uno::Reference< lang::XMultiComponentFactory > xSMgr(
287 mxContext->getServiceManager(), uno::UNO_QUERY_THROW );
288 uno::Reference< frame::XModel > xModel( getCurrentDocument(), uno::UNO_QUERY_THROW );
289 rtl::OUString url = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ".uno:CloseDoc"));
290 dispatchRequests(xModel,url);
291 */
292 }
293
294 // #TODO# #FIXME# can any of the unused params below be used?
openDocument(const rtl::OUString & rFileName,const uno::Any & ReadOnly,const uno::Sequence<beans::PropertyValue> & rProps)295 uno::Any VbaDocumentsBase::openDocument( const rtl::OUString& rFileName, const uno::Any& ReadOnly, const uno::Sequence< beans::PropertyValue >& rProps ) throw (uno::RuntimeException)
296 {
297 // #163808# determine state of Application.ScreenUpdating and Application.Interactive symbols (before new document is opened)
298 uno::Reference< XApplicationBase > xApplication( Application(), uno::UNO_QUERY );
299 sal_Bool bScreenUpdating = !xApplication.is() || xApplication->getScreenUpdating();
300 sal_Bool bInteractive = !xApplication.is() || xApplication->getInteractive();
301
302 // we need to detect if this is a URL, if not then assume its a file path
303 rtl::OUString aURL;
304 INetURLObject aObj;
305 aObj.SetURL( rFileName );
306 bool bIsURL = aObj.GetProtocol() != INET_PROT_NOT_VALID;
307 if ( bIsURL )
308 aURL = rFileName;
309 else
310 osl::FileBase::getFileURLFromSystemPath( rFileName, aURL );
311 uno::Reference< lang::XMultiComponentFactory > xSMgr(
312 mxContext->getServiceManager(), uno::UNO_QUERY_THROW );
313 uno::Reference< frame::XDesktop > xDesktop
314 (xSMgr->createInstanceWithContext(::rtl::OUString::createFromAscii("com.sun.star.frame.Desktop") , mxContext),
315 uno::UNO_QUERY_THROW );
316 uno::Reference< frame::XComponentLoader > xLoader(
317 xSMgr->createInstanceWithContext(
318 ::rtl::OUString::createFromAscii("com.sun.star.frame.Desktop"),
319 mxContext),
320 uno::UNO_QUERY_THROW );
321
322 uno::Sequence< beans::PropertyValue > sProps( rProps );
323 sProps.realloc( sProps.getLength() + 1 );
324 sProps[ sProps.getLength() - 1 ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("MacroExecutionMode") );
325 sProps[ sProps.getLength() - 1 ].Value <<= document::MacroExecMode::ALWAYS_EXECUTE_NO_WARN;
326
327 if ( ReadOnly.hasValue() )
328 {
329 sal_Bool bIsReadOnly = sal_False; ReadOnly >>= bIsReadOnly;
330 if ( bIsReadOnly )
331 {
332 sProps.realloc( sProps.getLength() + 1 );
333 sProps[ sProps.getLength() - 1 ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ReadOnly") );
334 sProps[ sProps.getLength() - 1 ].Value <<= true;
335 }
336 }
337
338 uno::Reference< lang::XComponent > xComponent = xLoader->loadComponentFromURL( aURL,
339 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("_default") ),
340 frame::FrameSearchFlag::CREATE,
341 sProps);
342
343 // #163808# lock document controllers and container window if specified by application
344 lclSetupComponent( xComponent, bScreenUpdating, bInteractive );
345
346 return uno::makeAny( xComponent );
347 }
348
349