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