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 #ifndef EXTENSIONS_SOURCE_PROPCTRLR_FORMCOMPONENTHANDLER_HXX
29 #define EXTENSIONS_SOURCE_PROPCTRLR_FORMCOMPONENTHANDLER_HXX
30 
31 #include "propertyhandler.hxx"
32 #include "sqlcommanddesign.hxx"
33 #include "pcrcommon.hxx"
34 #include <comphelper/uno3.hxx>
35 #include <comphelper/proparrhlp.hxx>
36 #include <comphelper/propertycontainer.hxx>
37 /** === begin UNO includes === **/
38 #include <com/sun/star/frame/XModel.hpp>
39 #include <com/sun/star/beans/XPropertyState.hpp>
40 #include <com/sun/star/sdbc/XRowSet.hpp>
41 #include <com/sun/star/awt/XControlContainer.hpp>
42 #include <com/sun/star/form/XForm.hpp>
43 /** === end UNO includes === **/
44 #include <tools/fldunit.hxx>
45 #include <vcl/waitobj.hxx>
46 #include <connectivity/dbtools.hxx>
47 
48 #include <set>
49 
50 //........................................................................
51 namespace pcr
52 {
53 //........................................................................
54 
55 	//====================================================================
56 	//= ComponentClassification
57 	//====================================================================
58     enum ComponentClassification
59     {
60         eFormControl,
61         eDialogControl,
62         eUnknown
63     };
64 
65 	//====================================================================
66 	//= FormComponentPropertyHandler
67 	//====================================================================
68     class FormComponentPropertyHandler;
69     typedef HandlerComponentBase< FormComponentPropertyHandler > FormComponentPropertyHandler_Base;
70     typedef ::comphelper::OPropertyArrayUsageHelper<FormComponentPropertyHandler> FormComponentPropertyHandler_PROP;
71     /** default ->XPropertyHandler for all form components.
72     */
73     class FormComponentPropertyHandler :    public FormComponentPropertyHandler_Base,
74                                             public ::comphelper::OPropertyContainer,
75                                             public FormComponentPropertyHandler_PROP
76 	{
77     private:
78         /// access to property states
79         ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyState >             m_xPropertyState;
80         /// the parent of our component
81 		::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > 				    m_xObjectParent;
82 
83         /// the database connection. Owned by us if and only if we created it ourself.
84         mutable ::dbtools::SharedConnection                                                     m_xRowSetConnection;
85         ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XRowSet >                     m_xRowSet;
86         /** helper component encapsulating the handling for the QueryDesign component for
87             interactively designing an SQL command
88         */
89         ::rtl::Reference< SQLCommandDesigner >                                                  m_xCommandDesigner;
90         ::com::sun::star::uno::Reference< ::com::sun::star::inspection::XObjectInspectorUI >    m_xBrowserUI;
91 
92         /// the string indicating a "default" (VOID) value in list-like controls
93         ::rtl::OUString                 m_sDefaultValueString;
94         /// all properties to whose control's we added ->m_sDefaultValueString
95         ::std::set< ::rtl::OUString >   m_aPropertiesWithDefListEntry;
96         /// type of our component
97         ComponentClassification         m_eComponentClass;
98         /// is our component a (database) sub form?
99         bool                            m_bComponentIsSubForm : 1;
100         /// our component has a "ListSource" property
101         bool                            m_bHaveListSource : 1;
102         /// our component has a "Command" property
103         bool                            m_bHaveCommand : 1;
104 		/// the class id of the component - if appliable
105 		sal_Int16				        m_nClassId;
106 
107     public:
108         FormComponentPropertyHandler(
109             const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext >& _rxContext
110         );
111 
112         DECLARE_XINTERFACE( )
113 
114         // XPropertySet
115         virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo(  ) throw(::com::sun::star::uno::RuntimeException);
116 
117         static ::rtl::OUString SAL_CALL getImplementationName_static(  ) throw (::com::sun::star::uno::RuntimeException);
118         static ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames_static(  ) throw (::com::sun::star::uno::RuntimeException);
119 
120     protected:
121         ~FormComponentPropertyHandler();
122 
123     protected:
124         virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const;
125 		virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper();
126         // XPropertyHandler overridables
127         virtual ::com::sun::star::uno::Any                          SAL_CALL getPropertyValue( const ::rtl::OUString& _rPropertyName ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException);
128         virtual void                                                SAL_CALL setPropertyValue( const ::rtl::OUString& _rPropertyName, const ::com::sun::star::uno::Any& _rValue ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException);
129         virtual ::com::sun::star::uno::Any                          SAL_CALL convertToPropertyValue( const ::rtl::OUString& _rPropertyName, const ::com::sun::star::uno::Any& _rControlValue ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException);
130         virtual ::com::sun::star::uno::Any                          SAL_CALL convertToControlValue( const ::rtl::OUString& _rPropertyName, const ::com::sun::star::uno::Any& _rPropertyValue, const ::com::sun::star::uno::Type& _rControlValueType ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException);
131         virtual ::com::sun::star::beans::PropertyState              SAL_CALL getPropertyState( const ::rtl::OUString& _rPropertyName ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException);
132         virtual void                                                SAL_CALL addPropertyChangeListener( const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& _rxListener ) throw (::com::sun::star::uno::RuntimeException);
133         virtual void                                                SAL_CALL removePropertyChangeListener( const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& _rxListener ) throw (::com::sun::star::uno::RuntimeException);
134         virtual ::com::sun::star::uno::Sequence< ::rtl::OUString >  SAL_CALL getSupersededProperties() throw (::com::sun::star::uno::RuntimeException);
135         virtual ::com::sun::star::uno::Sequence< ::rtl::OUString >  SAL_CALL getActuatingProperties() throw (::com::sun::star::uno::RuntimeException);
136         virtual ::com::sun::star::inspection::LineDescriptor        SAL_CALL describePropertyLine( const ::rtl::OUString& _rPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::inspection::XPropertyControlFactory >& _rxControlFactory ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::NullPointerException, ::com::sun::star::uno::RuntimeException);
137         virtual ::com::sun::star::inspection::InteractiveSelectionResult
138                                                                     SAL_CALL onInteractivePropertySelection( const ::rtl::OUString& _rPropertyName, sal_Bool _bPrimary, ::com::sun::star::uno::Any& _rData, const ::com::sun::star::uno::Reference< ::com::sun::star::inspection::XObjectInspectorUI >& _rxInspectorUI ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::NullPointerException, ::com::sun::star::uno::RuntimeException);
139         virtual void                                                SAL_CALL actuatingPropertyChanged( const ::rtl::OUString& _rActuatingPropertyName, const ::com::sun::star::uno::Any& _rNewValue, const ::com::sun::star::uno::Any& _rOldValue, const ::com::sun::star::uno::Reference< ::com::sun::star::inspection::XObjectInspectorUI >& _rxInspectorUI, sal_Bool _bFirstTimeInit ) throw (::com::sun::star::lang::NullPointerException, ::com::sun::star::uno::RuntimeException);
140         virtual sal_Bool                                            SAL_CALL suspend( sal_Bool _bSuspend ) throw (::com::sun::star::uno::RuntimeException);
141 
142         // XComponent
143         virtual void                                                SAL_CALL disposing();
144 
145         // PropertyHandler
146         virtual ::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property >
147                                             SAL_CALL doDescribeSupportedProperties() const;
148         virtual void onNewComponent();
149 
150     private:
151         /** initializes some (cached) meta data about the component
152             @throws RuntimeException
153                 if a serious error occurs, for instance if the component does not provide an XPropertySetInfo instance
154         */
155         void    impl_initComponentMetaData_throw();
156 
157         /** classifies our component, in case it's a control model, by ClassId
158 
159             Note that UNO dialog controls are also classified, though they don't have the ClassId property
160         */
161         void    impl_classifyControlModel_throw();
162 
163         /** const-version of ->getPropertyValue
164         */
165         ::com::sun::star::uno::Any impl_getPropertyValue_throw( const ::rtl::OUString& _rPropertyName ) const;
166 
167         // some property values are faked, and not used in the way they're provided by our component
168         void impl_normalizePropertyValue_nothrow( ::com::sun::star::uno::Any& _rValue, PropertyId _nPropId ) const;
169 
170         /** determines whether we should exclude a given property from our "supported properties"
171         */
172         bool impl_shouldExcludeProperty_nothrow( const ::com::sun::star::beans::Property& _rProperty ) const;
173 
174         /** initializes the list of field names, if we're handling a control which supports the
175             DataField property
176         */
177         void impl_initFieldList_nothrow( ::std::vector< ::rtl::OUString >& rFieldNames ) const;
178 
179         /** obtaines the RowSet to which our component belongs
180 
181             If the component is a RowSet itself, it's returned directly. Else, the parent
182             is examined for the XRowSet interface. If the parent is no XRowSet, then
183             a check is made whether our component is a grid control column, and if so,
184             the parent of the grid control is examied for the XRowSet interace.
185 
186             Normally, at least one of those methods should succeed.
187         */
188 	    ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XRowSet > impl_getRowSet_throw( ) const;
189 
190         /** nothrow-version of ->impl_getRowSet_throw
191         */
192         ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XRowSet > impl_getRowSet_nothrow( ) const;
193 
194         /** connects the row set belonging to our introspected data aware form component,
195             and remembers the connection in ->m_xRowSetConnection.
196 
197             If the row set already is connected, ->m_xRowSetConnection will be set, too, but
198             not take the ownership of the connection.
199 
200             If ->m_xRowSetConnection is already set, nothing happens, so if you want to
201             force creation of a connection, you need to clear ->m_xRowSetConnection.
202         */
203 	    bool impl_ensureRowsetConnection_nothrow() const;
204 
205         /** clears ->m_xRowSetConnection
206         */
207         void impl_clearRowsetConnection_nothrow();
208 
209         /** fills an ->LineDescriptor with information to represent a cursor source
210             of our form - that is, a table, a query, or an SQL statement.
211 
212             As an example, if our form has currently a CommandType of TABLE, then the
213             value list in the LineDescriptor will contain a list of all tables
214             of the data source which the form is bound to.
215 
216             @seealso impl_fillTableNames_throw
217             @seealso impl_fillQueryNames_throw
218         */
219         void impl_describeCursorSource_nothrow(
220                 ::com::sun::star::inspection::LineDescriptor& _out_rProperty,
221                 const ::com::sun::star::uno::Reference< ::com::sun::star::inspection::XPropertyControlFactory >& _rxControlFactory
222             ) const;
223 
224         /** describes the UI for selecting a table name
225 
226             @precond
227                 m_xRowSetConnection is not <NULL/>
228         */
229 	    void impl_fillTableNames_throw( ::std::vector< ::rtl::OUString >& _out_rNames ) const;
230 
231         /** describes the UI for selecting a query name
232 
233             @precond
234                 m_xRowSetConnection is not <NULL/>
235         */
236 	    void impl_fillQueryNames_throw( ::std::vector< ::rtl::OUString >& _out_rNames ) const;
237 
238         /** describes the UI for selecting a query name
239 
240             @precond
241                 m_xRowSetConnection is not <NULL/>
242         */
243         void impl_fillQueryNames_throw( const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess >& _xQueryNames
244                     ,::std::vector< ::rtl::OUString >& _out_rNames
245                     ,const ::rtl::OUString& _sName = ::rtl::OUString() ) const;
246 
247         /** describes the UI for selecting a ListSource (for list-like form controls)
248             @precond
249                 ->m_xRowSetConnection is not <NULL/>
250             @precond
251                 ->m_xComponent is not <NULL/>
252         */
253         void impl_describeListSourceUI_throw(
254                 ::com::sun::star::inspection::LineDescriptor& _out_rDescriptor,
255                 const ::com::sun::star::uno::Reference< ::com::sun::star::inspection::XPropertyControlFactory >& _rxControlFactory
256             ) const;
257 
258         /** displays a datbase-related error to the user
259         */
260         void impl_displaySQLError_nothrow( const ::dbtools::SQLExceptionInfo& _rErrorDescriptor ) const;
261 
262         /** let's the user chose a selection of entries from a string list, and stores this
263             selection in the given property
264             @return
265                 <TRUE/> if and only if the user successfully changed the property
266         */
267         bool impl_dialogListSelection_nothrow( const ::rtl::OUString& _rProperty, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const;
268 
269         /** executes a dialog for chosing a filter or sort criterion for a database form
270             @param _bFilter
271                 <TRUE/> if the Filter property should be used, <FALSE/> if it's the Order
272                 property
273             @param _out_rSelectedClause
274                 the filter or order clause as chosen by the user
275             @precond
276                 we're really inspecting a database form (well, a RowSet at least)
277             @return
278                 <TRUE/> if and only if the user successfully chose a clause
279         */
280         bool impl_dialogFilterOrSort_nothrow( bool _bFilter, ::rtl::OUString& _out_rSelectedClause, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const;
281 
282         /** executes a dialog which allows the user to chose the columns linking
283             a sub to a master form, and sets the respective MasterFields / SlaveFields
284             properties at the form.
285             @precond
286                 we're inspecting (sub) database form
287             @return
288                 <TRUE/> if and only if the user successfully eneter master and slave fields
289         */
290         bool impl_dialogLinkedFormFields_nothrow( ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const;
291 
292         /** executes a dialog which allows the user to modify the FormatKey
293             property of our component, by chosing a (number) format.
294             @precond
295                 Our component actually has a FormatKey property.
296             @param _out_rNewValue
297                 the new property value, if the user chose a new formatting
298             @return
299                 <TRUE/> if and only if a new formatting has been chosen by the user.
300                 In this case, ->_out_rNewValue is filled with the new property value
301         */
302 		bool impl_dialogFormatting_nothrow( ::com::sun::star::uno::Any& _out_rNewValue, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const;
303 
304         /** executes a dialog which allows to the user to change the ImageURL property
305             of our component by browsing for an image file.
306             @precond
307                 our component actually has a ImageURL property
308             @param _out_rNewValue
309                 the new property value, if the user chose a new image url
310             @return
311                 <TRUE/> if and only if a new image URL has been chosen by the user.
312                 In this case, ->_out_rNewValue is filled with the new property value
313         */
314         bool impl_browseForImage_nothrow( ::com::sun::star::uno::Any& _out_rNewValue, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const;
315 
316         /** executes a dialog which allows the user to change the TargetURL property of
317             our component
318             @precond
319                 our component actually has a TargetURL property
320             @param _out_rNewValue
321                 the new property value, if the user chose a new TargetURL
322             @return
323                 <TRUE/> if and only if a new TargetURL has been chosen by the user.
324                 In this case, ->_out_rNewValue is filled with the new property value
325         */
326         bool impl_browseForTargetURL_nothrow( ::com::sun::star::uno::Any& _out_rNewValue, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const;
327 
328         /** executes a dialog which allows the user to change the font, plus related properties,
329             of our component
330             @precond
331                 our component actually has a Font property
332             @param _out_rNewValue
333                 a value desribing the new font, as <code>Sequence&lt; NamedValue &gt;</code>
334             @return
335                 <TRUE/> if and only if the user successfully changed the font of our component
336         */
337 		bool impl_executeFontDialog_nothrow( ::com::sun::star::uno::Any& _out_rNewValue, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const;
338 
339         /** allows the user browsing for a database document
340             @precond
341                 our component actually has a DataSource property
342             @param _out_rNewValue
343                 the new property value, if the user chose a new DataSource
344             @return
345                 <TRUE/> if and only if a new DataSource has been chosen by the user.
346                 In this case, ->_out_rNewValue is filled with the new property value
347         */
348         bool impl_browseForDatabaseDocument_throw( ::com::sun::star::uno::Any& _out_rNewValue, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const;
349 
350         /** raises a dialog which allows the user to choose a color
351             @param  _nColorPropertyId
352                 the ID of the color property
353             @param  _out_rNewValue
354                 the chosen color value
355             @return
356                 <TRUE/> if and only if a color was chosen by the user
357         */
358         bool impl_dialogColorChooser_throw( sal_Int32 _nColorPropertyId, ::com::sun::star::uno::Any& _out_rNewValue, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const;
359 
360         /** raises a dialog which allows the user to choose a label control for our component
361             @param  _out_rNewValue
362                 the chosen label control, if any
363             @return
364                 <TRUE/> if and only if a label control was chosen by the user
365         */
366         bool impl_dialogChooseLabelControl_nothrow( ::com::sun::star::uno::Any& _out_rNewValue, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const;
367 
368         /** raises a dialog which lets the user chose the tab order of controls of a form
369             @precond
370                 we have a view control container in which our controls live
371             @return
372                 <TRUE/> if and only if the user successfully changed the tab order
373             @seealso impl_getContextControlContainer_nothrow
374         */
375         bool impl_dialogChangeTabOrder_nothrow( ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const;
376 
377         /** retrieves the context for controls, whose model(s) we're inspecting
378 
379             If we're inspecting a control model, this is usually part of a set of controls
380             and control models, where the controls live in a certain context (a ->XControlContainer).
381             If we know this context, we can enable additional special functionality.
382 
383             The ->XComponentContext in which we were created is examined for a value
384             named "ControlContext", and this value is returned.
385         */
386         ::com::sun::star::uno::Reference< ::com::sun::star::awt::XControlContainer >
387             impl_getContextControlContainer_nothrow() const;
388 
389         /** opens a query design window for interactively designing the SQL command of a
390             database form
391             @param _rxUIUpdate
392                 access to the property browser UI
393             @param _nDesignForProperty
394                 the ID for the property for which the designer is opened
395             @return
396                 <TRUE/> if the window was successfully opened, or was previously open,
397                 <FALSE/> otherwise
398         */
399         bool impl_doDesignSQLCommand_nothrow(
400             const ::com::sun::star::uno::Reference< ::com::sun::star::inspection::XObjectInspectorUI >& _rxInspectorUI,
401             PropertyId _nDesignForProperty
402         );
403 
404         /** updates a property (UI) whose state depends on more than one other property
405 
406             ->actuatingPropertyChanged is called for certain properties in whose changes
407             we expressed interes (->getActuatingProperty). Now such a property change can
408             result in simple UI updates, for instance another property being enabled or disabled.
409 
410             However, it can also result in a more complex change: The current (UI) state might
411             depend on the value of more than one other property. Those dependent properties (their
412             UI, more precisly) are updated in this method.
413 
414             @param _nPropid
415                 the ->PropertyId of the dependent property whose UI state is to be updated
416 
417             @param _rxInspectorUI
418                 provides access to the property browser UI. Must not be <NULL/>.
419         */
420         void impl_updateDependentProperty_nothrow( PropertyId _nPropId, const ::com::sun::star::uno::Reference< ::com::sun::star::inspection::XObjectInspectorUI >& _rxInspectorUI ) const;
421 
422         /** determines whether the given form has a valid data source signature.
423 
424             Valid here means that the DataSource property denotes an existing data source, and the
425             Command property is not empty. No check is made whether the value of the Command property
426             denotes an existent object, since this would be way too expensive.
427 
428             @param _xFormProperties
429                 the form to check. Must not be <NULL/>.
430             @param _bAllowEmptyDataSourceName
431                 determine whether an empty data source name is allowed (<TRUE/>), and should not
432                 lead to rejection
433         */
434         static bool impl_hasValidDataSourceSignature_nothrow(
435                 const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& _xFormProperties,
436                 bool _bAllowEmptyDataSourceName );
437 
438         /** returns the URL of our context document
439             @return
440         */
441         ::rtl::OUString impl_getDocumentURL_nothrow() const;
442 
443     private:
444         DECL_LINK( OnDesignerClosed, void* );
445 
446     private:
447         FormComponentPropertyHandler();                                                 // never implemented
448         FormComponentPropertyHandler( const FormComponentPropertyHandler& );            // never implemented
449         FormComponentPropertyHandler& operator=( const FormComponentPropertyHandler& ); // never implemented
450 
451     private:
452         using ::comphelper::OPropertyContainer::addPropertyChangeListener;
453         using ::comphelper::OPropertyContainer::removePropertyChangeListener;
454 	};
455 
456 	//====================================================================
457 	//= WaitCursor
458 	//====================================================================
459     /** wrapper around a ->WaitObject which can cope with a NULL window
460     */
461     class WaitCursor
462     {
463     private:
464         ::std::auto_ptr< WaitObject >       m_aWaitObject;
465 
466     public:
467         WaitCursor( Window* _pWindow )
468         {
469             if ( _pWindow )
470                 m_aWaitObject.reset( new WaitObject( _pWindow ) );
471         }
472     };
473 
474 //........................................................................
475 } // namespace pcr
476 //........................................................................
477 
478 #endif // EXTENSIONS_SOURCE_PROPCTRLR_FORMCOMPONENTHANDLER_HXX
479 
480