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_extensions.hxx"
30 #include "sqlcommanddesign.hxx"
31 #include "formstrings.hxx"
32 #ifndef _EXTENSIONS_FORMCTRLR_PROPRESID_HRC_
33 #include "formresid.hrc"
34 #endif
35 #ifndef _EXTENSIONS_PROPCTRLR_MODULEPRC_HXX_
36 #include "modulepcr.hxx"
37 #endif
38 #include "unourl.hxx"
39 
40 /** === begin UNO includes === **/
41 #include <com/sun/star/awt/XWindow.hpp>
42 #include <com/sun/star/awt/XTopWindow.hpp>
43 #include <com/sun/star/uno/Sequence.hxx>
44 #include <com/sun/star/frame/XTitle.hpp>
45 #include <com/sun/star/frame/XComponentLoader.hpp>
46 #include <com/sun/star/frame/XController.hpp>
47 #include <com/sun/star/lang/NullPointerException.hpp>
48 #include <com/sun/star/lang/DisposedException.hpp>
49 #include <com/sun/star/frame/FrameSearchFlag.hpp>
50 #include <com/sun/star/frame/XFramesSupplier.hpp>
51 #include <com/sun/star/sdbc/XConnection.hpp>
52 #include <com/sun/star/util/XCloseable.hpp>
53 #include <com/sun/star/frame/XDispatchProvider.hpp>
54 #include <com/sun/star/beans/XPropertySetInfo.hpp>
55 #include <com/sun/star/sdb/CommandType.hpp>
56 /** === end UNO includes === **/
57 
58 #include <svtools/localresaccess.hxx>
59 #include <tools/diagnose_ex.h>
60 #include <osl/diagnose.h>
61 
62 //........................................................................
63 namespace pcr
64 {
65 //........................................................................
66 
67     /** === begin UNO using === **/
68     using ::com::sun::star::uno::Reference;
69     using ::com::sun::star::lang::XMultiComponentFactory;
70     using ::com::sun::star::beans::PropertyChangeEvent;
71     using ::com::sun::star::uno::RuntimeException;
72     using ::com::sun::star::frame::XFrame;
73     using ::com::sun::star::awt::XTopWindow;
74     using ::com::sun::star::awt::XWindow;
75     using ::com::sun::star::uno::Exception;
76     using ::com::sun::star::uno::UNO_QUERY_THROW;
77     using ::com::sun::star::uno::UNO_QUERY;
78     using ::com::sun::star::beans::PropertyValue;
79     using ::com::sun::star::uno::Sequence;
80     using ::com::sun::star::lang::XComponent;
81     using ::com::sun::star::frame::XComponentLoader;
82     using ::com::sun::star::beans::XPropertySet;
83     using ::com::sun::star::beans::XPropertySetInfo;
84     using ::com::sun::star::frame::XController;
85     using ::com::sun::star::frame::XTitle;
86     using ::com::sun::star::lang::EventObject;
87     using ::com::sun::star::lang::NullPointerException;
88     using ::com::sun::star::lang::DisposedException;
89     using ::com::sun::star::uno::makeAny;
90     using ::com::sun::star::uno::XComponentContext;
91     using ::com::sun::star::frame::XFramesSupplier;
92     using ::com::sun::star::frame::XFrames;
93     using ::com::sun::star::util::XCloseable;
94     using ::com::sun::star::uno::TypeClass_STRING;
95     using ::com::sun::star::lang::XMultiServiceFactory;
96     using ::com::sun::star::frame::XDispatchProvider;
97     using ::com::sun::star::frame::XDispatch;
98     using ::com::sun::star::uno::Any;
99     /** === end UNO using === **/
100     namespace FrameSearchFlag = ::com::sun::star::frame::FrameSearchFlag;
101     namespace CommandType = ::com::sun::star::sdb::CommandType;
102 
103 	//====================================================================
104 	//= ISQLCommandAdapter
105 	//====================================================================
106 	//--------------------------------------------------------------------
107     ISQLCommandAdapter::~ISQLCommandAdapter()
108     {
109     }
110 
111     //====================================================================
112 	//= SQLCommandDesigner
113 	//====================================================================
114 	//--------------------------------------------------------------------
115     SQLCommandDesigner::SQLCommandDesigner( const Reference< XComponentContext >& _rxContext,
116             const ::rtl::Reference< ISQLCommandAdapter >& _rxPropertyAdapter,
117             const ::dbtools::SharedConnection& _rConnection, const Link& _rCloseLink )
118         :m_xContext( _rxContext )
119         ,m_xConnection( _rConnection )
120         ,m_xObjectAdapter( _rxPropertyAdapter )
121         ,m_aCloseLink( _rCloseLink )
122     {
123         if ( m_xContext.is() )
124             m_xORB = m_xContext->getServiceManager();
125         if ( !m_xORB.is() || !_rxPropertyAdapter.is() || !m_xConnection.is() )
126             throw NullPointerException();
127 
128         impl_doOpenDesignerFrame_nothrow();
129     }
130 
131 	//--------------------------------------------------------------------
132     SQLCommandDesigner::~SQLCommandDesigner()
133     {
134     }
135 
136     //--------------------------------------------------------------------
137     void SAL_CALL SQLCommandDesigner::propertyChange( const PropertyChangeEvent& Event ) throw (RuntimeException)
138     {
139         OSL_ENSURE( m_xDesigner.is() && ( Event.Source == m_xDesigner ), "SQLCommandDesigner::propertyChange: where did this come from?" );
140 
141         if ( m_xDesigner.is() && ( Event.Source == m_xDesigner ) )
142         {
143             try
144             {
145                 if ( PROPERTY_ACTIVECOMMAND == Event.PropertyName )
146                 {
147                     ::rtl::OUString sCommand;
148                     OSL_VERIFY( Event.NewValue >>= sCommand );
149                     m_xObjectAdapter->setSQLCommand( sCommand );
150                 }
151                 else if ( PROPERTY_ESCAPE_PROCESSING == Event.PropertyName )
152                 {
153                     sal_Bool bEscapeProcessing( sal_False );
154                     OSL_VERIFY( Event.NewValue >>= bEscapeProcessing );
155                     m_xObjectAdapter->setEscapeProcessing( bEscapeProcessing );
156                 }
157             }
158             catch( const RuntimeException& ) { throw; }
159             catch( const Exception& )
160             {
161                 // not allowed to leave, so silence it
162                 DBG_UNHANDLED_EXCEPTION();
163             }
164         }
165     }
166 
167     //--------------------------------------------------------------------
168     void SAL_CALL SQLCommandDesigner::disposing( const EventObject& Source ) throw (RuntimeException)
169     {
170         if ( m_xDesigner.is() && ( Source.Source == m_xDesigner ) )
171         {
172             impl_designerClosed_nothrow();
173             m_xDesigner.clear();
174         }
175     }
176 
177     //--------------------------------------------------------------------
178     void SQLCommandDesigner::dispose()
179     {
180         if ( impl_isDisposed() )
181             return;
182 
183         if ( isActive() )
184             impl_closeDesigner_nothrow();
185 
186         m_xConnection.clear();
187         m_xContext.clear();
188         m_xORB.clear();
189     }
190 
191     //--------------------------------------------------------------------
192     void SQLCommandDesigner::impl_checkDisposed_throw() const
193     {
194         if ( impl_isDisposed() )
195             throw DisposedException();
196     }
197 
198     //--------------------------------------------------------------------
199     void SQLCommandDesigner::raise() const
200     {
201         impl_checkDisposed_throw();
202         impl_raise_nothrow();
203     }
204 
205 	//------------------------------------------------------------------------
206     bool SQLCommandDesigner::suspend() const
207     {
208         impl_checkDisposed_throw();
209         return impl_trySuspendDesigner_nothrow();
210     }
211 
212     //--------------------------------------------------------------------
213     void SQLCommandDesigner::impl_raise_nothrow() const
214     {
215         OSL_PRECOND( isActive(), "SQLCommandDesigner::impl_raise_nothrow: not active!" );
216         if ( !isActive() )
217             return;
218 
219         try
220         {
221             // activate the frame for this component
222             Reference< XFrame >     xFrame( m_xDesigner->getFrame(), UNO_QUERY_THROW );
223             Reference< XWindow >    xWindow( xFrame->getContainerWindow(), UNO_QUERY_THROW );
224             Reference< XTopWindow > xTopWindow( xWindow, UNO_QUERY_THROW );
225 
226             xTopWindow->toFront();
227             xWindow->setFocus();
228         }
229         catch( const Exception& )
230         {
231             DBG_UNHANDLED_EXCEPTION();
232         }
233     }
234 
235     //--------------------------------------------------------------------
236     void SQLCommandDesigner::impl_doOpenDesignerFrame_nothrow()
237     {
238         OSL_PRECOND( !isActive(),
239             "SQLCommandDesigner::impl_doOpenDesignerFrame_nothrow: already active!" );
240         OSL_PRECOND( m_xConnection.is(), "SQLCommandDesigner::impl_doOpenDesignerFrame_nothrow: this will crash!" );
241         osl_incrementInterlockedCount(&m_refCount);
242 
243         try
244         {
245             // for various reasons, we don't want the new frame to appear in the desktop's frame list
246             // thus, we create a blank frame at the desktop, remove it from the desktop's frame list
247             // immediately, and then load the component into this blank (and now parent-less) frame
248 			Reference< XComponentLoader > xLoader( impl_createEmptyParentlessTask_nothrow(), UNO_QUERY_THROW );
249             Sequence< PropertyValue > aArgs( 5 );
250             aArgs[0].Name = PROPERTY_ACTIVE_CONNECTION;
251             aArgs[0].Value <<= m_xConnection.getTyped();
252 
253             aArgs[1].Name  = PROPERTY_COMMAND;
254             aArgs[1].Value <<= m_xObjectAdapter->getSQLCommand();
255             aArgs[2].Name  = PROPERTY_COMMANDTYPE;
256             aArgs[2].Value <<= (sal_Int32)CommandType::COMMAND;
257             aArgs[3].Name  = PROPERTY_ESCAPE_PROCESSING;
258             aArgs[3].Value <<= m_xObjectAdapter->getEscapeProcessing();
259 
260             aArgs[4].Name  = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "GraphicalDesign" ) );
261             aArgs[4].Value <<= m_xObjectAdapter->getEscapeProcessing();
262 
263 			Reference< XComponent > xQueryDesign = xLoader->loadComponentFromURL(
264                 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ".component:DB/QueryDesign" ) ),
265 				::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "_self" ) ),
266 				FrameSearchFlag::TASKS | FrameSearchFlag::CREATE,
267 				aArgs
268 			);
269 
270             // remember this newly loaded component - we need to care for it e.g. when we're suspended
271             m_xDesigner = m_xDesigner.query( xQueryDesign );
272             OSL_ENSURE( m_xDesigner.is() || !xQueryDesign.is(), "SQLCommandDesigner::impl_doOpenDesignerFrame_nothrow: the component is expected to be a controller!" );
273             if ( m_xDesigner.is() )
274             {
275                 Reference< XPropertySet > xQueryDesignProps( m_xDesigner, UNO_QUERY );
276                 OSL_ENSURE( xQueryDesignProps.is(), "SQLCommandDesigner::impl_doOpenDesignerFrame_nothrow: the controller should have properties!" );
277                 if ( xQueryDesignProps.is() )
278                 {
279                     xQueryDesignProps->addPropertyChangeListener( PROPERTY_ACTIVECOMMAND, this );
280                     xQueryDesignProps->addPropertyChangeListener( PROPERTY_ESCAPE_PROCESSING, this );
281                 }
282             }
283 
284             // get the frame which we just opened and set it's title
285             Reference< XTitle> xTitle(xQueryDesign,UNO_QUERY);
286             if ( xTitle.is() )
287             {
288                 ::svt::OLocalResourceAccess aEnumStrings( PcrRes( RID_RSC_ENUM_COMMAND_TYPE ), RSC_RESOURCE );
289 	            ::rtl::OUString sDisplayName = String( PcrRes( CommandType::COMMAND + 1 ) );
290     	        xTitle->setTitle( sDisplayName );
291             }
292         }
293         catch( const Exception& )
294         {
295             DBG_UNHANDLED_EXCEPTION();
296             m_xDesigner.clear();
297         }
298         osl_decrementInterlockedCount(&m_refCount);
299     }
300 
301 	//------------------------------------------------------------------------
302     Reference< XFrame > SQLCommandDesigner::impl_createEmptyParentlessTask_nothrow( ) const
303     {
304         OSL_PRECOND( m_xORB.is(), "SQLCommandDesigner::impl_createEmptyParentlessTask_nothrow: this will crash!" );
305 
306         Reference< XFrame > xFrame;
307         try
308         {
309             Reference< XInterface      > xDesktop          ( m_xORB->createInstanceWithContext( SERVICE_DESKTOP, m_xContext ) );
310             Reference< XFrame          > xDesktopFrame     ( xDesktop,      UNO_QUERY_THROW );
311             Reference< XFramesSupplier > xSuppDesktopFrames( xDesktopFrame, UNO_QUERY_THROW );
312 
313             Reference< XFrames > xDesktopFramesCollection( xSuppDesktopFrames->getFrames(), UNO_QUERY_THROW );
314             xFrame = xDesktopFrame->findFrame( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "_blank" ) ), FrameSearchFlag::CREATE );
315             OSL_ENSURE( xFrame.is(), "SQLCommandDesigner::impl_createEmptyParentlessTask_nothrow: could not create an empty frame!" );
316             xDesktopFramesCollection->remove( xFrame );
317         }
318         catch( const Exception& )
319         {
320             DBG_UNHANDLED_EXCEPTION();
321         }
322         return xFrame;
323     }
324 
325 	//------------------------------------------------------------------------
326     void SQLCommandDesigner::impl_designerClosed_nothrow()
327     {
328         if ( m_aCloseLink.IsSet() )
329             m_aCloseLink.Call( this );
330     }
331 
332 	//------------------------------------------------------------------------
333     void SQLCommandDesigner::impl_closeDesigner_nothrow()
334     {
335         OSL_PRECOND( isActive(), "SQLCommandDesigner::impl_closeDesigner_nothrow: invalid calle!" );
336         // close it
337         try
338         {
339             // do not listen anymore ....
340             Reference< XPropertySet > xProps( m_xDesigner, UNO_QUERY );
341             if ( xProps.is() )
342                 xProps->removePropertyChangeListener( PROPERTY_ACTIVECOMMAND, this );
343 
344             // we need to close the frame via the "user interface", by dispatching a close command,
345             // instead of calling XCloseable::close directly. The latter method would also close
346             // the frame, but not care for things like shutting down the office when the last
347             // frame is gone ...
348             const UnoURL aCloseURL( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ".uno:CloseDoc" ) ),
349                 Reference< XMultiServiceFactory >( m_xORB, UNO_QUERY ) );
350 
351             Reference< XDispatchProvider > xProvider( m_xDesigner->getFrame(), UNO_QUERY_THROW );
352             Reference< XDispatch > xDispatch( xProvider->queryDispatch( aCloseURL, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "_top" ) ), FrameSearchFlag::SELF ) );
353             OSL_ENSURE( xDispatch.is(), "SQLCommandDesigner::impl_closeDesigner_nothrow: no dispatcher for the CloseDoc command!" );
354             if ( xDispatch.is() )
355             {
356                 xDispatch->dispatch( aCloseURL, Sequence< PropertyValue >( ) );
357             }
358             else
359             {
360                 // fallback: use the XCloseable::close (with all possible disadvantages)
361                 Reference< XCloseable > xClose( m_xDesigner->getFrame(), UNO_QUERY );
362                 if ( xClose.is() )
363                     xClose->close( sal_True );
364             }
365         }
366         catch( const Exception& )
367         {
368             DBG_UNHANDLED_EXCEPTION();
369         }
370 
371         m_xDesigner.clear();
372     }
373 
374 	//------------------------------------------------------------------------
375     bool SQLCommandDesigner::impl_trySuspendDesigner_nothrow() const
376     {
377         OSL_PRECOND( isActive(), "SQLCommandDesigner::impl_trySuspendDesigner_nothrow: no active designer, this will crash!" );
378         sal_Bool bAllow = sal_True;
379         try
380         {
381             bAllow = m_xDesigner->suspend( sal_True );
382         }
383         catch( const Exception& )
384         {
385             DBG_UNHANDLED_EXCEPTION();
386         }
387         return bAllow;
388     }
389 
390 //........................................................................
391 } // namespace pcr
392 //........................................................................
393 
394