1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_svtools.hxx"
30 #include <com/sun/star/util/XCloseBroadcaster.hpp>
31 #include <com/sun/star/util/XCloseable.hpp>
32 #include <com/sun/star/lang/DisposedException.hpp>
33 #include <com/sun/star/lang/IllegalArgumentException.hpp>
34 #include <com/sun/star/frame/DoubleInitializationException.hpp>
35 #include <com/sun/star/frame/DoubleInitializationException.hpp>
36 #include <com/sun/star/beans/XPropertySet.hpp>
37 #include <com/sun/star/awt/XVclWindowPeer.hpp>
38 
39 #include <vos/mutex.hxx>
40 #include <vcl/svapp.hxx>
41 #include <vcl/dialog.hxx>
42 #include <tools/link.hxx>
43 #include <toolkit/helper/vclunohelper.hxx>
44 
45 #include "documentcloser.hxx"
46 
47 using namespace ::com::sun::star;
48 
49 
50 // ====================================================================
51 // MainThreadFrameCloserRequest
52 // ====================================================================
53 
54 class MainThreadFrameCloserRequest
55 {
56 	uno::Reference< frame::XFrame > m_xFrame;
57 
58 	public:
59 	    MainThreadFrameCloserRequest( const uno::Reference< frame::XFrame >& xFrame )
60 		: m_xFrame( xFrame )
61 		{}
62 
63 		DECL_STATIC_LINK( MainThreadFrameCloserRequest, worker, MainThreadFrameCloserRequest* );
64 
65 		static void Start( MainThreadFrameCloserRequest* pRequest );
66 };
67 
68 // --------------------------------------------------------
69 void MainThreadFrameCloserRequest::Start( MainThreadFrameCloserRequest* pMTRequest )
70 {
71 	if ( pMTRequest )
72 	{
73 		if ( Application::GetMainThreadIdentifier() == osl_getThreadIdentifier( NULL ) )
74 		{
75 			// this is the main thread
76 			worker( NULL, pMTRequest );
77 		}
78 		else
79 			Application::PostUserEvent( STATIC_LINK( NULL, MainThreadFrameCloserRequest, worker ), pMTRequest );
80 	}
81 }
82 
83 // --------------------------------------------------------
84 IMPL_STATIC_LINK( MainThreadFrameCloserRequest, worker, MainThreadFrameCloserRequest*, pMTRequest )
85 {
86     (void) pThis; // unused
87 	if ( pMTRequest )
88 	{
89 		if ( pMTRequest->m_xFrame.is() )
90 		{
91 			// this is the main thread, the solar mutex must be locked
92 			::vos::OGuard aGuard( Application::GetSolarMutex() );
93 
94 			try
95 			{
96 				uno::Reference< awt::XWindow > xWindow = pMTRequest->m_xFrame->getContainerWindow();
97 				uno::Reference< awt::XVclWindowPeer > xWinPeer( xWindow, uno::UNO_QUERY_THROW );
98 
99 				xWindow->setVisible( sal_False );
100 
101 				// reparent the window
102 				xWinPeer->setProperty( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PluginParent" ) ),
103 										uno::makeAny( (sal_Int64) 0 ) );
104 
105 				Window* pWindow = VCLUnoHelper::GetWindow( xWindow );
106 				if ( pWindow )
107 					Dialog::EndAllDialogs( pWindow );
108 			}
109 			catch( uno::Exception& )
110 			{
111 				// ignore all the errors
112 			}
113 
114 			try
115 			{
116 				uno::Reference< util::XCloseable > xCloseable( pMTRequest->m_xFrame, uno::UNO_QUERY_THROW );
117 				xCloseable->close( sal_True );
118 			}
119 			catch( uno::Exception& )
120 			{
121 				// ignore all the errors
122 			}
123 		}
124 
125 		delete pMTRequest;
126 	}
127 
128 	return 0;
129 }
130 
131 
132 // ====================================================================
133 // ODocumentCloser
134 // ====================================================================
135 
136 // --------------------------------------------------------
137 ODocumentCloser::ODocumentCloser( const uno::Reference< uno::XComponentContext >& xContext )
138 : m_xContext( xContext )
139 , m_pListenersContainer( NULL )
140 , m_bDisposed( sal_False )
141 , m_bInitialized( sal_False )
142 {
143 }
144 
145 // --------------------------------------------------------
146 ODocumentCloser::~ODocumentCloser()
147 {
148 	if ( m_pListenersContainer )
149 	{
150 		delete m_pListenersContainer;
151 		m_pListenersContainer = NULL;
152 	}
153 }
154 
155 // XComponent
156 // --------------------------------------------------------
157 void SAL_CALL ODocumentCloser::dispose()
158 	throw (uno::RuntimeException)
159 {
160 	::osl::MutexGuard aGuard( m_aMutex );
161 
162 	if ( m_bDisposed )
163 		throw lang::DisposedException();
164 
165    	lang::EventObject aSource( static_cast< ::cppu::OWeakObject* >(this) );
166 	if ( m_pListenersContainer )
167 		m_pListenersContainer->disposeAndClear( aSource );
168 
169 	// TODO: trigger a main thread execution to close the frame
170 	if ( m_xFrame.is() )
171 	{
172 		// the created object will be deleted after thread execution
173 		MainThreadFrameCloserRequest* pCloser = new MainThreadFrameCloserRequest( m_xFrame );
174 		MainThreadFrameCloserRequest::Start( pCloser );
175 	}
176 
177 	m_bDisposed = sal_True;
178 }
179 
180 // --------------------------------------------------------
181 void SAL_CALL ODocumentCloser::addEventListener( const uno::Reference< lang::XEventListener >& xListener )
182 	throw (uno::RuntimeException)
183 {
184 	::osl::MutexGuard aGuard( m_aMutex );
185 	if ( m_bDisposed )
186 		throw lang::DisposedException(); // TODO
187 
188 	if ( !m_pListenersContainer )
189 		m_pListenersContainer = new ::cppu::OInterfaceContainerHelper( m_aMutex );
190 
191 	m_pListenersContainer->addInterface( xListener );
192 }
193 
194 // --------------------------------------------------------
195 void SAL_CALL ODocumentCloser::removeEventListener( const uno::Reference< lang::XEventListener >& xListener )
196 	throw (uno::RuntimeException)
197 {
198 	::osl::MutexGuard aGuard( m_aMutex );
199 	if ( m_pListenersContainer )
200 		m_pListenersContainer->removeInterface( xListener );
201 }
202 
203 // XInitialization
204 // --------------------------------------------------------
205 void SAL_CALL ODocumentCloser::initialize( const uno::Sequence< uno::Any >& aArguments )
206 	throw (uno::Exception, uno::RuntimeException)
207 {
208 	::osl::MutexGuard aGuard( m_aMutex );
209 	if ( m_bInitialized )
210 		throw frame::DoubleInitializationException();
211 
212 	if ( m_bDisposed )
213 		throw lang::DisposedException(); // TODO
214 
215 	if ( !m_refCount )
216 		throw uno::RuntimeException(); // the object must be refcounted already!
217 
218 	sal_Int32 nLen = aArguments.getLength();
219 	if ( nLen != 1 )
220 		throw lang::IllegalArgumentException(
221 						::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Wrong count of parameters!" ) ),
222 						uno::Reference< uno::XInterface >(),
223 						0 );
224 
225 	if ( !( aArguments[0] >>= m_xFrame ) || !m_xFrame.is() )
226 		throw lang::IllegalArgumentException(
227 				::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Nonempty reference is expected as the first argument!" ) ),
228 				uno::Reference< uno::XInterface >(),
229 				0 );
230 
231 	m_bInitialized = sal_True;
232 }
233 
234 
235 // XServiceInfo
236 // --------------------------------------------------------
237 ::rtl::OUString SAL_CALL ODocumentCloser::getImplementationName(  )
238 	throw (uno::RuntimeException)
239 {
240 	return impl_staticGetImplementationName();
241 }
242 
243 // --------------------------------------------------------
244 ::sal_Bool SAL_CALL ODocumentCloser::supportsService( const ::rtl::OUString& ServiceName )
245 	throw (uno::RuntimeException)
246 {
247 	uno::Sequence< ::rtl::OUString > aSeq = impl_staticGetSupportedServiceNames();
248 
249 	for ( sal_Int32 nInd = 0; nInd < aSeq.getLength(); nInd++ )
250     	if ( ServiceName.compareTo( aSeq[nInd] ) == 0 )
251         	return sal_True;
252 
253 	return sal_False;
254 }
255 
256 // --------------------------------------------------------
257 uno::Sequence< ::rtl::OUString > SAL_CALL ODocumentCloser::getSupportedServiceNames()
258 	throw (uno::RuntimeException)
259 {
260 	return impl_staticGetSupportedServiceNames();
261 }
262 
263 // Static methods
264 // --------------------------------------------------------
265 uno::Sequence< ::rtl::OUString > SAL_CALL ODocumentCloser::impl_staticGetSupportedServiceNames()
266 {
267     const rtl::OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.embed.DocumentCloser" ) );
268     return uno::Sequence< rtl::OUString >( &aServiceName, 1 );
269 }
270 
271 // --------------------------------------------------------
272 ::rtl::OUString SAL_CALL ODocumentCloser::impl_staticGetImplementationName()
273 {
274     return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.embed.DocumentCloser" ) );
275 }
276 
277 // --------------------------------------------------------
278 uno::Reference< uno::XInterface > SAL_CALL ODocumentCloser::impl_staticCreateSelfInstance(
279 								const uno::Reference< lang::XMultiServiceFactory >& xServiceManager )
280 {
281     uno::Reference< uno::XComponentContext > xContext;
282     uno::Reference< beans::XPropertySet > xPropSet( xServiceManager, uno::UNO_QUERY );
283     if ( xPropSet.is() )
284         xPropSet->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ) ) ) >>= xContext;
285 
286     if ( !xContext.is() )
287     {
288         throw uno::RuntimeException(
289             rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unable to obtain component context from service manager!" ) ),
290             uno::Reference< uno::XInterface >() );
291     }
292 
293     return static_cast< cppu::OWeakObject * >( new ODocumentCloser( xContext ) );
294 }
295 
296