xref: /AOO41X/main/vbahelper/source/vbahelper/vbadocumentsbase.cxx (revision e6ed5fbc51cf474df369618b58e945b84a21a167)
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