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