1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <sal/macros.h>
24 #include <fmPropBrw.hxx>
25 #include <svx/strings.hrc>
26 #include <fmservs.hxx>
27 #include <fmshimp.hxx>
28 #include <fmpgeimp.hxx>
30 #include <svx/dialmgr.hxx>
31 #include <svx/fmpage.hxx>
32 #include <svx/fmshell.hxx>
33 #include <svx/fmview.hxx>
34 #include <svx/sdrpagewindow.hxx>
35 #include <svx/svdpagv.hxx>
36 #include <svx/svxids.hrc>
38 #include <com/sun/star/awt/XControlContainer.hpp>
39 #include <com/sun/star/beans/XPropertySet.hpp>
40 #include <com/sun/star/form/XForm.hpp>
41 #include <com/sun/star/form/FormComponentType.hpp>
42 #include <com/sun/star/form/inspection/DefaultFormComponentInspectorModel.hpp>
43 #include <com/sun/star/frame/Frame.hpp>
44 #include <com/sun/star/inspection/ObjectInspector.hpp>
45 #include <com/sun/star/inspection/XObjectInspectorUI.hpp>
46 #include <com/sun/star/inspection/DefaultHelpProvider.hpp>
47 #include <com/sun/star/lang/XServiceInfo.hpp>
48 #include <com/sun/star/util/VetoException.hpp>
50 #include <comphelper/processfactory.hxx>
51 #include <comphelper/property.hxx>
52 #include <comphelper/sequence.hxx>
53 #include <comphelper/types.hxx>
54 #include <cppuhelper/component_context.hxx>
55 #include <o3tl/deleter.hxx>
56 #include <sfx2/bindings.hxx>
57 #include <sfx2/childwin.hxx>
58 #include <sfx2/objitem.hxx>
59 #include <sfx2/objsh.hxx>
60 #include <comphelper/diagnose_ex.hxx>
61 #include <unotools/confignode.hxx>
62 #include <vcl/stdtext.hxx>
63 #include <vcl/svapp.hxx>
64 #include <vcl/weld.hxx>
65 #include <vcl/weldutils.hxx>
67 using namespace ::com::sun::star
;
68 using namespace ::com::sun::star::beans
;
69 using namespace ::com::sun::star::container
;
70 using namespace ::com::sun::star::form
;
71 using namespace ::com::sun::star::form::inspection
;
72 using namespace ::com::sun::star::frame
;
73 using namespace ::com::sun::star::inspection
;
74 using namespace ::com::sun::star::lang
;
75 using namespace ::com::sun::star::uno
;
76 using namespace ::com::sun::star::util
;
77 using namespace ::svxform
;
78 using ::com::sun::star::awt::XWindow
;
81 SFX_IMPL_MODELESSDIALOGCONTOLLER(FmPropBrwMgr
, SID_FM_SHOW_PROPERTIES
)
83 FmPropBrwMgr::FmPropBrwMgr( vcl::Window
* _pParent
, sal_uInt16 _nId
,
84 SfxBindings
* _pBindings
, const SfxChildWinInfo
* _pInfo
)
85 :SfxChildWindow(_pParent
, _nId
)
87 std::shared_ptr
<FmPropBrw
> xControl(new FmPropBrw(::comphelper::getProcessComponentContext(), _pBindings
,
88 this, _pParent
->GetFrameWeld(), _pInfo
), o3tl::default_delete
<FmPropBrw
>());
89 SetController(std::move(xControl
));
90 static_cast<FmPropBrw
*>(GetController().get())->Initialize( _pInfo
);
93 static OUString
GetUIHeadlineName(sal_Int16 nClassId
, const Any
& aUnoObj
)
95 TranslateId pClassNameResourceId
;
99 case FormComponentType::TEXTFIELD
:
101 Reference
< XInterface
> xIFace
;
103 pClassNameResourceId
= RID_STR_PROPTITLE_EDIT
;
105 { // we have a chance to check if it's a formatted field model
106 Reference
< XServiceInfo
> xInfo(xIFace
, UNO_QUERY
);
107 if (xInfo
.is() && (xInfo
->supportsService(FM_SUN_COMPONENT_FORMATTEDFIELD
)))
108 pClassNameResourceId
= RID_STR_PROPTITLE_FORMATTED
;
109 else if (!xInfo
.is())
111 // couldn't distinguish between formatted and edit with the service name, so try with the properties
112 Reference
< XPropertySet
> xProps(xIFace
, UNO_QUERY
);
115 Reference
< XPropertySetInfo
> xPropsInfo
= xProps
->getPropertySetInfo();
116 if (xPropsInfo
.is() && xPropsInfo
->hasPropertyByName(FM_PROP_FORMATSSUPPLIER
))
117 pClassNameResourceId
= RID_STR_PROPTITLE_FORMATTED
;
124 case FormComponentType::COMMANDBUTTON
:
125 pClassNameResourceId
= RID_STR_PROPTITLE_PUSHBUTTON
; break;
126 case FormComponentType::RADIOBUTTON
:
127 pClassNameResourceId
= RID_STR_PROPTITLE_RADIOBUTTON
; break;
128 case FormComponentType::CHECKBOX
:
129 pClassNameResourceId
= RID_STR_PROPTITLE_CHECKBOX
; break;
130 case FormComponentType::LISTBOX
:
131 pClassNameResourceId
= RID_STR_PROPTITLE_LISTBOX
; break;
132 case FormComponentType::COMBOBOX
:
133 pClassNameResourceId
= RID_STR_PROPTITLE_COMBOBOX
; break;
134 case FormComponentType::GROUPBOX
:
135 pClassNameResourceId
= RID_STR_PROPTITLE_GROUPBOX
; break;
136 case FormComponentType::IMAGEBUTTON
:
137 pClassNameResourceId
= RID_STR_PROPTITLE_IMAGEBUTTON
; break;
138 case FormComponentType::FIXEDTEXT
:
139 pClassNameResourceId
= RID_STR_PROPTITLE_FIXEDTEXT
; break;
140 case FormComponentType::GRIDCONTROL
:
141 pClassNameResourceId
= RID_STR_PROPTITLE_DBGRID
; break;
142 case FormComponentType::FILECONTROL
:
143 pClassNameResourceId
= RID_STR_PROPTITLE_FILECONTROL
; break;
144 case FormComponentType::DATEFIELD
:
145 pClassNameResourceId
= RID_STR_PROPTITLE_DATEFIELD
; break;
146 case FormComponentType::TIMEFIELD
:
147 pClassNameResourceId
= RID_STR_PROPTITLE_TIMEFIELD
; break;
148 case FormComponentType::NUMERICFIELD
:
149 pClassNameResourceId
= RID_STR_PROPTITLE_NUMERICFIELD
; break;
150 case FormComponentType::CURRENCYFIELD
:
151 pClassNameResourceId
= RID_STR_PROPTITLE_CURRENCYFIELD
; break;
152 case FormComponentType::PATTERNFIELD
:
153 pClassNameResourceId
= RID_STR_PROPTITLE_PATTERNFIELD
; break;
154 case FormComponentType::IMAGECONTROL
:
155 pClassNameResourceId
= RID_STR_PROPTITLE_IMAGECONTROL
; break;
156 case FormComponentType::HIDDENCONTROL
:
157 pClassNameResourceId
= RID_STR_PROPTITLE_HIDDEN
; break;
158 case FormComponentType::SCROLLBAR
:
159 pClassNameResourceId
= RID_STR_PROPTITLE_SCROLLBAR
; break;
160 case FormComponentType::SPINBUTTON
:
161 pClassNameResourceId
= RID_STR_PROPTITLE_SPINBUTTON
; break;
162 case FormComponentType::NAVIGATIONBAR
:
163 pClassNameResourceId
= RID_STR_PROPTITLE_NAVBAR
; break;
164 case FormComponentType::CONTROL
:
166 pClassNameResourceId
= RID_STR_CONTROL
; break;
169 return SvxResId(pClassNameResourceId
);
172 FmPropBrw::FmPropBrw(const Reference
< XComponentContext
>& _xORB
, SfxBindings
* _pBindings
,
173 SfxChildWindow
* _pMgr
, weld::Window
* _pParent
, const SfxChildWinInfo
* _pInfo
)
174 : SfxModelessDialogController(_pBindings
, _pMgr
, _pParent
, "svx/ui/formpropertydialog.ui", "FormPropertyDialog")
175 , SfxControllerItem(SID_FM_PROPERTY_CONTROL
, *_pBindings
)
176 , m_bInitialStateChange(true)
177 , m_pParent(_pParent
)
178 , m_nAsyncGetFocusId(nullptr)
179 , m_xDialogBox(m_xBuilder
->weld_box("dialog-vbox1"))
180 , m_xContainer(m_xBuilder
->weld_container("container"))
183 m_xContainer
->set_size_request(m_xContainer
->get_approximate_digit_width() * 72, m_xContainer
->get_text_height() * 20);
187 // create a frame wrapper for myself
188 m_xMeAsFrame
= Frame::create(m_xORB
);
190 // transport the container area of this dialog to be the container window of the frame
191 css::uno::Reference
<css::awt::XWindow
> xFrameContainerWindow(new weld::TransportAsXWindow(m_xContainer
.get()));
192 m_xMeAsFrame
->initialize(xFrameContainerWindow
);
193 m_xMeAsFrame
->setName("form property browser");
195 catch (const Exception
&)
197 OSL_FAIL("FmPropBrw::FmPropBrw: could not create/initialize my frame!");
198 m_xMeAsFrame
.clear();
202 m_sLastActivePage
= _pInfo
->aExtraString
;
205 FmPropBrw::~FmPropBrw()
207 if (m_nAsyncGetFocusId
)
209 Application::RemoveUserEvent(m_nAsyncGetFocusId
);
210 m_nAsyncGetFocusId
= nullptr;
213 if (m_xBrowserController
.is())
214 implDetachController();
217 // remove our own properties from the component context. We cannot ensure that the component context
218 // is freed (there might be refcount problems :-\), so at least ensure the context itself
219 // does hold the objects anymore
220 Reference
<XNameContainer
> xName(m_xInspectorContext
,uno::UNO_QUERY
);
223 const OUString pProps
[] = { OUString( "ContextDocument" )
224 , OUString( "DialogParentWindow" )
225 , OUString( "ControlContext" )
226 , OUString( "ControlShapeAccess" ) };
227 for (const auto & i
: pProps
)
228 xName
->removeByName( i
);
231 catch (const Exception
& )
233 DBG_UNHANDLED_EXCEPTION("svx");
235 ::SfxControllerItem::dispose();
238 OUString
FmPropBrw::getCurrentPage() const
240 OUString sCurrentPage
;
243 if ( m_xBrowserController
.is() )
245 OSL_VERIFY( m_xBrowserController
->getViewData() >>= sCurrentPage
);
248 if ( sCurrentPage
.isEmpty() )
249 sCurrentPage
= m_sLastActivePage
;
251 catch( const Exception
& )
253 TOOLS_WARN_EXCEPTION("svx.form", "caught an exception while retrieving the current page!");
258 void FmPropBrw::implDetachController()
260 m_sLastActivePage
= getCurrentPage();
262 implSetNewSelection( InterfaceBag() );
264 if ( m_xMeAsFrame
.is() )
268 m_xMeAsFrame
->setComponent(nullptr, nullptr);
270 catch( const Exception
& )
272 TOOLS_WARN_EXCEPTION("svx.form", "caught an exception while resetting the component!");
276 // we attached a frame to the controller manually, so we need to manually tell it that it's detached, too
277 if ( m_xBrowserController
.is() )
279 m_xBrowserController
->attachFrame( nullptr );
282 m_xBrowserController
.clear();
283 m_xInspectorModel
.clear();
284 m_xMeAsFrame
.clear();
287 void FmPropBrw::Close()
289 // suspend the controller (it is allowed to veto)
290 if ( m_xMeAsFrame
.is() )
294 Reference
< XController
> xController( m_xMeAsFrame
->getController() );
295 if ( xController
.is() && !xController
->suspend( true ) )
298 catch( const Exception
& )
300 TOOLS_WARN_EXCEPTION("svx.form", "caught an exception while asking the controller!");
304 implDetachController();
306 // remember our bindings: while we're closed, we're deleted, too, so accessing the bindings after this
308 // 10/19/00 - 79321 - FS
309 SfxBindings
& rBindings
= SfxControllerItem::GetBindings();
311 SfxModelessDialogController::Close();
313 rBindings
.Invalidate(SID_FM_CTL_PROPERTIES
);
314 rBindings
.Invalidate(SID_FM_PROPERTIES
);
317 bool FmPropBrw::implIsReadOnlyModel() const
321 if ( m_xInspectorModel
.is() )
322 return m_xInspectorModel
->getIsReadOnly();
325 catch( const Exception
& )
327 DBG_UNHANDLED_EXCEPTION("svx");
333 void FmPropBrw::implSetNewSelection( const InterfaceBag
& _rSelection
)
335 if ( !m_xBrowserController
.is() )
340 Reference
< XObjectInspector
> xInspector( m_xBrowserController
, UNO_QUERY_THROW
);
342 // tell it the objects to inspect
343 xInspector
->inspect( comphelper::containerToSequence(_rSelection
) );
345 catch( const VetoException
& )
349 catch( const Exception
& )
351 TOOLS_WARN_EXCEPTION("svx.form", "");
355 // set the new title according to the selected object
358 if ( _rSelection
.empty() )
360 sTitle
= SvxResId(RID_STR_NO_PROPERTIES
);
362 else if ( _rSelection
.size() > 1 )
364 // no form component and (no form or no name) -> Multiselection
365 sTitle
= SvxResId(RID_STR_PROPERTIES_CONTROL
) +
366 SvxResId(RID_STR_PROPTITLE_MULTISELECT
);
370 Reference
< XPropertySet
> xSingleSelection( *_rSelection
.begin(), UNO_QUERY
);
371 if ( ::comphelper::hasProperty( FM_PROP_CLASSID
, xSingleSelection
) )
373 sal_Int16 nClassID
= FormComponentType::CONTROL
;
374 xSingleSelection
->getPropertyValue( FM_PROP_CLASSID
) >>= nClassID
;
376 sTitle
= SvxResId(RID_STR_PROPERTIES_CONTROL
) +
377 GetUIHeadlineName(nClassID
, Any(xSingleSelection
));
379 else if ( Reference
< XForm
>( xSingleSelection
, UNO_QUERY
).is() )
380 sTitle
= SvxResId(RID_STR_PROPERTIES_FORM
);
383 if ( implIsReadOnlyModel() )
384 sTitle
+= SvxResId(RID_STR_READONLY_VIEW
);
386 m_xDialog
->set_title(sTitle
);
389 void FmPropBrw::FillInfo( SfxChildWinInfo
& rInfo
) const
391 rInfo
.bVisible
= false;
392 rInfo
.aExtraString
= getCurrentPage();
395 IMPL_LINK_NOARG( FmPropBrw
, OnAsyncGetFocus
, void*, void )
397 m_xDialogBox
->child_grab_focus();
398 m_nAsyncGetFocusId
= nullptr;
403 bool lcl_shouldEnableHelpSection( const Reference
< XComponentContext
>& _rxContext
)
405 ::utl::OConfigurationTreeRoot
aConfiguration(
406 ::utl::OConfigurationTreeRoot::createWithComponentContext(
408 "/org.openoffice.Office.Common/Forms/PropertyBrowser/" ) );
410 bool bEnabled
= false;
411 OSL_VERIFY( aConfiguration
.getNodeValue( "DirectHelp" ) >>= bEnabled
);
416 void FmPropBrw::impl_createPropertyBrowser_throw( FmFormShell
* _pFormShell
)
418 // the document in which we live
419 Reference
< XInterface
> xDocument
;
420 if ( _pFormShell
&& _pFormShell
->GetObjectShell() )
421 xDocument
= _pFormShell
->GetObjectShell()->GetModel();
423 // the context of the controls in our document
424 Reference
< awt::XControlContainer
> xControlContext
;
425 if ( _pFormShell
&& _pFormShell
->GetFormView() )
427 SdrPageView
* pPageView
= _pFormShell
->GetFormView()->GetSdrPageView();
431 SdrPageWindow
* pPageWindow
= pPageView
->GetPageWindow(0);
435 xControlContext
= pPageWindow
->GetControlContainer();
440 // the default parent window for message boxes
441 Reference
< XWindow
> xParentWindow(m_xDialog
->GetXWindow());
443 // the mapping from control models to control shapes
444 Reference
< XMap
> xControlMap
;
445 FmFormPage
* pFormPage
= _pFormShell
? _pFormShell
->GetCurPage() : nullptr;
447 xControlMap
= pFormPage
->GetImpl().getControlToShapeMap();
449 // our own component context
451 // a ComponentContext for the
452 ::cppu::ContextEntry_Init aHandlerContextInfo
[] =
454 ::cppu::ContextEntry_Init( "ContextDocument", Any( xDocument
) ),
455 ::cppu::ContextEntry_Init( "DialogParentWindow", Any( xParentWindow
) ),
456 ::cppu::ContextEntry_Init( "ControlContext", Any( xControlContext
) ),
457 ::cppu::ContextEntry_Init( "ControlShapeAccess", Any( xControlMap
) )
459 m_xInspectorContext
.set(
460 ::cppu::createComponentContext( aHandlerContextInfo
, SAL_N_ELEMENTS( aHandlerContextInfo
),
463 bool bEnableHelpSection
= lcl_shouldEnableHelpSection( m_xORB
);
465 // an object inspector model
468 ? DefaultFormComponentInspectorModel::createWithHelpSection( m_xInspectorContext
, 3, 5 )
469 : DefaultFormComponentInspectorModel::createDefault( m_xInspectorContext
);
471 // an object inspector
472 m_xBrowserController
=
473 ObjectInspector::createWithModel(
474 m_xInspectorContext
, m_xInspectorModel
477 if ( !m_xBrowserController
.is() )
479 ShowServiceNotAvailableError(m_pParent
, u
"com.sun.star.inspection.ObjectInspector", true);
483 m_xBrowserController
->attachFrame( Reference
<XFrame
>(m_xMeAsFrame
,UNO_QUERY_THROW
) );
486 if ( bEnableHelpSection
)
488 Reference
< XObjectInspector
> xInspector( m_xBrowserController
, UNO_QUERY_THROW
);
489 Reference
< XObjectInspectorUI
> xInspectorUI( xInspector
->getInspectorUI() );
490 DefaultHelpProvider::create( m_xInspectorContext
, xInspectorUI
);
495 void FmPropBrw::impl_ensurePropertyBrowser_nothrow( FmFormShell
* _pFormShell
)
497 // the document in which we live
498 Reference
< XInterface
> xDocument
;
499 SfxObjectShell
* pObjectShell
= _pFormShell
? _pFormShell
->GetObjectShell() : nullptr;
501 xDocument
= pObjectShell
->GetModel();
502 if ( ( xDocument
== m_xLastKnownDocument
) && m_xBrowserController
.is() )
508 // clean up any previous instances of the object inspector
509 if ( m_xMeAsFrame
.is() )
510 m_xMeAsFrame
->setComponent( nullptr, nullptr );
512 ::comphelper::disposeComponent( m_xBrowserController
);
513 m_xBrowserController
.clear();
514 m_xInspectorModel
.clear();
516 // and create a new one
517 impl_createPropertyBrowser_throw( _pFormShell
);
519 catch( const Exception
& )
521 DBG_UNHANDLED_EXCEPTION("svx");
523 m_xLastKnownDocument
= xDocument
;
527 void FmPropBrw::StateChangedAtToolBoxControl(sal_uInt16 nSID
, SfxItemState eState
, const SfxPoolItem
* pState
)
529 if (!pState
|| SID_FM_PROPERTY_CONTROL
!= nSID
)
534 if (eState
>= SfxItemState::DEFAULT
)
536 FmFormShell
* pShell
= dynamic_cast<FmFormShell
*>( static_cast<const SfxObjectItem
*>(pState
)->GetShell() );
537 InterfaceBag aSelection
;
539 pShell
->GetImpl()->getCurrentSelection_Lock(aSelection
);
541 impl_ensurePropertyBrowser_nothrow( pShell
);
543 // set the new object to inspect
544 implSetNewSelection( aSelection
);
546 // if this is the first time we're here, some additional things need to be done ...
547 if ( m_bInitialStateChange
)
549 // if we're just newly created, we want to have the focus
550 m_nAsyncGetFocusId
= Application::PostUserEvent(LINK(this, FmPropBrw
, OnAsyncGetFocus
));
552 // and additionally, we want to show the page which was active during
553 // our previous incarnation
554 if ( !m_sLastActivePage
.isEmpty() )
558 if ( m_xBrowserController
.is() )
559 m_xBrowserController
->restoreViewData( Any( m_sLastActivePage
) );
561 catch( const Exception
& )
563 TOOLS_WARN_EXCEPTION("svx.form",
564 "caught an exception while setting the initial page!");
568 m_bInitialStateChange
= false;
574 implSetNewSelection( InterfaceBag() );
579 TOOLS_WARN_EXCEPTION("svx.form", "");
583 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */