1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 #include <memory>
20 #include <propbrw.hxx>
21 #include <RptObject.hxx>
22 #include <ReportController.hxx>
23 #include <cppuhelper/component_context.hxx>
24 #include <strings.hrc>
25 #include <rptui_slotid.hrc>
26 #include <tools/diagnose_ex.h>
27 #include <com/sun/star/awt/XLayoutConstrains.hpp>
28 #include <com/sun/star/beans/PropertyValue.hpp>
29 #include <com/sun/star/frame/Frame.hpp>
30 #include <com/sun/star/inspection/ObjectInspector.hpp>
31 #include <com/sun/star/inspection/DefaultHelpProvider.hpp>
32 #include <com/sun/star/lang/XServiceInfo.hpp>
33 #include <com/sun/star/report/inspection/DefaultComponentInspectorModel.hpp>
34 #include <vcl/stdtext.hxx>
35 #include <vcl/weld.hxx>
36 #include <svx/svditer.hxx>
37 
38 #include <toolkit/helper/vclunohelper.hxx>
39 #include <comphelper/namecontainer.hxx>
40 #include <comphelper/types.hxx>
41 #include <comphelper/sequence.hxx>
42 #include <core_resource.hxx>
43 #include <SectionView.hxx>
44 #include <ReportSection.hxx>
45 #include <strings.hxx>
46 #include <DesignView.hxx>
47 #include <ViewsWindow.hxx>
48 #include <UITools.hxx>
49 #include <unotools/confignode.hxx>
50 
51 namespace rptui
52 {
53 #define STD_WIN_SIZE_X  300
54 #define STD_WIN_SIZE_Y  350
55 
56 using namespace ::com::sun::star;
57 using namespace uno;
58 using namespace lang;
59 using namespace frame;
60 using namespace beans;
61 using namespace container;
62 using namespace ::comphelper;
63 
64 
65 namespace
66 {
lcl_shouldEnableHelpSection(const Reference<XComponentContext> & _rxContext)67     bool lcl_shouldEnableHelpSection( const Reference< XComponentContext >& _rxContext )
68     {
69         ::utl::OConfigurationTreeRoot aConfiguration(
70             ::utl::OConfigurationTreeRoot::createWithComponentContext(
71                 _rxContext, "/org.openoffice.Office.ReportDesign/PropertyBrowser/" ) );
72 
73         bool bEnabled = false;
74         OSL_VERIFY( aConfiguration.getNodeValue( "DirectHelp"  ) >>= bEnabled );
75         return bEnabled;
76     }
77 }
78 
79 
80 // PropBrw
81 
82 
PropBrw(const Reference<XComponentContext> & _xORB,vcl::Window * pParent,ODesignView * _pDesignView)83 PropBrw::PropBrw(const Reference< XComponentContext >& _xORB, vcl::Window* pParent, ODesignView*  _pDesignView)
84     : DockingWindow(pParent,WinBits(WB_STDMODELESS|WB_SIZEABLE|WB_3DLOOK))
85     , m_xContentArea(VclPtr<VclVBox>::Create(this))
86     , m_xORB(_xORB)
87     , m_pDesignView(_pDesignView)
88     , m_pView( nullptr )
89     , m_bInitialStateChange(true)
90 {
91 
92     Size aPropWinSize(STD_WIN_SIZE_X,STD_WIN_SIZE_Y);
93     SetOutputSizePixel(aPropWinSize);
94 
95     // turn off WB_CLIPCHILDREN otherwise the bg won't extend "under"
96     // transparent children of the widget
97     m_xContentArea->SetControlBackground(m_xContentArea->GetSettings().GetStyleSettings().GetWindowColor());
98     m_xContentArea->SetBackground(m_xContentArea->GetControlBackground());
99     m_xContentArea->SetStyle(m_xContentArea->GetStyle() & ~WB_CLIPCHILDREN);
100     m_xContentArea->Show();
101 
102     try
103     {
104         // create a frame wrapper for myself
105         m_xMeAsFrame = Frame::create( m_xORB );
106         m_xMeAsFrame->initialize(VCLUnoHelper::GetInterface(m_xContentArea));
107         m_xMeAsFrame->setName("report property browser");  // change name!
108     }
109     catch (Exception&)
110     {
111         DBG_UNHANDLED_EXCEPTION("reportdesign");
112         OSL_FAIL("PropBrw::PropBrw: could not create/initialize my frame!");
113         m_xMeAsFrame.clear();
114     }
115 
116     if (m_xMeAsFrame.is())
117     {
118         try
119         {
120             ::cppu::ContextEntry_Init aHandlerContextInfo[] =
121             {
122                 ::cppu::ContextEntry_Init( "ContextDocument", makeAny( m_pDesignView->getController().getModel() )),
123                 ::cppu::ContextEntry_Init( "DialogParentWindow", makeAny( VCLUnoHelper::GetInterface ( this ) )),
124                 ::cppu::ContextEntry_Init( "ActiveConnection", makeAny( m_pDesignView->getController().getConnection() ) ),
125             };
126             m_xInspectorContext.set(
127                 ::cppu::createComponentContext( aHandlerContextInfo, SAL_N_ELEMENTS( aHandlerContextInfo ),
128                 m_xORB ) );
129             // create a property browser controller
130             bool bEnableHelpSection = lcl_shouldEnableHelpSection( m_xORB );
131             Reference< inspection::XObjectInspectorModel> xInspectorModel( bEnableHelpSection
132                 ?   report::inspection::DefaultComponentInspectorModel::createWithHelpSection( m_xInspectorContext, 3, 8 )
133                 :   report::inspection::DefaultComponentInspectorModel::createDefault( m_xInspectorContext ) );
134 
135             m_xBrowserController = inspection::ObjectInspector::createWithModel(m_xInspectorContext, xInspectorModel);
136             if ( !m_xBrowserController.is() )
137             {
138                 ShowServiceNotAvailableError(pParent ? pParent->GetFrameWeld() : nullptr, u"com.sun.star.inspection.ObjectInspector", true);
139             }
140             else
141             {
142                 m_xBrowserController->attachFrame( Reference<XFrame>(m_xMeAsFrame, UNO_QUERY_THROW));
143                 if ( bEnableHelpSection )
144                 {
145                     uno::Reference< inspection::XObjectInspector > xInspector( m_xBrowserController, uno::UNO_SET_THROW );
146                     uno::Reference< inspection::XObjectInspectorUI > xInspectorUI( xInspector->getInspectorUI() );
147                     inspection::DefaultHelpProvider::create( m_xInspectorContext, xInspectorUI );
148                 }
149             }
150         }
151         catch (Exception&)
152         {
153             DBG_UNHANDLED_EXCEPTION("reportdesign");
154             OSL_FAIL("PropBrw::PropBrw: could not create/initialize the browser controller!");
155             try
156             {
157                 ::comphelper::disposeComponent(m_xBrowserController);
158             }
159             catch(Exception&) { }
160             m_xBrowserController.clear();
161         }
162     }
163 
164     VclContainer::setLayoutAllocation(*m_xContentArea, Point(0, 0), aPropWinSize);
165     m_xContentArea->Show();
166 
167     ::rptui::notifySystemWindow(pParent,this,::comphelper::mem_fun(&TaskPaneList::AddWindow));
168 }
169 
170 
~PropBrw()171 PropBrw::~PropBrw()
172 {
173     disposeOnce();
174 }
175 
dispose()176 void PropBrw::dispose()
177 {
178     if (m_xBrowserController.is())
179         implDetachController();
180 
181     try
182     {
183         uno::Reference<container::XNameContainer> xName(m_xInspectorContext,uno::UNO_QUERY);
184         if ( xName.is() )
185         {
186             const OUString pProps[] = { OUString( "ContextDocument" )
187                                             ,  OUString( "DialogParentWindow" )
188                                             , OUString( "ActiveConnection" )};
189             for (const auto & i : pProps)
190                 xName->removeByName(i);
191         }
192     }
193     catch(Exception&)
194     {}
195 
196     ::rptui::notifySystemWindow(this,this,::comphelper::mem_fun(&TaskPaneList::RemoveWindow));
197     m_pDesignView.clear();
198     m_xContentArea.disposeAndClear();
199     DockingWindow::dispose();
200 }
201 
setCurrentPage(const OUString & _sLastActivePage)202 void PropBrw::setCurrentPage(const OUString& _sLastActivePage)
203 {
204     m_sLastActivePage = _sLastActivePage;
205 }
206 
207 
implDetachController()208 void PropBrw::implDetachController()
209 {
210     m_sLastActivePage = getCurrentPage();
211     implSetNewObject(  );
212 
213     if ( m_xMeAsFrame.is() )
214         m_xMeAsFrame->setComponent( nullptr, nullptr );
215 
216     if ( m_xBrowserController.is() )
217         m_xBrowserController->attachFrame( nullptr );
218 
219     m_xMeAsFrame.clear();
220     m_xBrowserController.clear();
221 }
222 
getCurrentPage() const223 OUString PropBrw::getCurrentPage() const
224 {
225     OUString sCurrentPage;
226     try
227     {
228         if ( m_xBrowserController.is() )
229         {
230             OSL_VERIFY( m_xBrowserController->getViewData() >>= sCurrentPage );
231         }
232 
233         if ( sCurrentPage.isEmpty() )
234             sCurrentPage = m_sLastActivePage;
235     }
236     catch( const Exception& )
237     {
238         TOOLS_WARN_EXCEPTION( "reportdesign", "PropBrw::getCurrentPage: caught an exception while retrieving the current page!" );
239     }
240     return sCurrentPage;
241 }
242 
Close()243 bool PropBrw::Close()
244 {
245     m_xLastSection.clear();
246     // suspend the controller (it is allowed to veto)
247     if ( m_xMeAsFrame.is() )
248     {
249         try
250         {
251             Reference< XController > xController( m_xMeAsFrame->getController() );
252             if ( xController.is() && !xController->suspend( true ) )
253                 return false;
254         }
255         catch( const Exception& )
256         {
257             TOOLS_WARN_EXCEPTION( "reportdesign", "FmPropBrw::Close: caught an exception while asking the controller!" );
258         }
259     }
260     implDetachController();
261 
262     m_pDesignView->getController().executeUnChecked(SID_PROPERTYBROWSER_LAST_PAGE,uno::Sequence< beans::PropertyValue>());
263 
264     return true;
265 }
266 
CreateCompPropSet(const SdrMarkList & _rMarkList)267 uno::Sequence< Reference<uno::XInterface> > PropBrw::CreateCompPropSet(const SdrMarkList& _rMarkList)
268 {
269     const size_t nMarkCount = _rMarkList.GetMarkCount();
270     ::std::vector< uno::Reference< uno::XInterface> > aSets;
271     aSets.reserve(nMarkCount);
272 
273     for(size_t i=0; i<nMarkCount; ++i)
274     {
275         SdrObject* pCurrent = _rMarkList.GetMark(i)->GetMarkedSdrObj();
276 
277         ::std::unique_ptr<SdrObjListIter> pGroupIterator;
278         if (pCurrent->IsGroupObject())
279         {
280             pGroupIterator.reset(new SdrObjListIter(pCurrent->GetSubList()));
281             pCurrent = pGroupIterator->IsMore() ? pGroupIterator->Next() : nullptr;
282         }
283 
284         while (pCurrent)
285         {
286             OObjectBase* pObj = dynamic_cast<OObjectBase*>(pCurrent);
287             if ( pObj )
288                 aSets.push_back(CreateComponentPair(pObj));
289 
290             // next element
291             pCurrent = pGroupIterator && pGroupIterator->IsMore() ? pGroupIterator->Next() : nullptr;
292         }
293     }
294     return uno::Sequence< Reference<uno::XInterface> >(aSets.data(), aSets.size());
295 }
296 
implSetNewObject(const uno::Sequence<Reference<uno::XInterface>> & _aObjects)297 void PropBrw::implSetNewObject( const uno::Sequence< Reference<uno::XInterface> >& _aObjects )
298 {
299     if ( m_xBrowserController.is() )
300     {
301         try
302         {
303             m_xBrowserController->inspect(uno::Sequence< Reference<uno::XInterface> >());
304             m_xBrowserController->inspect(_aObjects);
305         }
306         catch( const Exception& )
307         {
308             TOOLS_WARN_EXCEPTION( "reportdesign", "FmPropBrw::StateChanged: caught an exception while setting the initial page!" );
309         }
310     }
311     SetText( GetHeadlineName(_aObjects) );
312 }
313 
314 
GetHeadlineName(const uno::Sequence<Reference<uno::XInterface>> & _aObjects)315 OUString PropBrw::GetHeadlineName( const uno::Sequence< Reference<uno::XInterface> >& _aObjects )
316 {
317     OUString aName;
318     if ( !_aObjects.hasElements() )
319     {
320         aName = RptResId(RID_STR_BRWTITLE_NO_PROPERTIES);
321     }
322     else if ( _aObjects.getLength() == 1 )    // single selection
323     {
324         aName = RptResId(RID_STR_BRWTITLE_PROPERTIES);
325 
326         uno::Reference< container::XNameContainer > xNameCont(_aObjects[0],uno::UNO_QUERY);
327         Reference< lang::XServiceInfo > xServiceInfo( xNameCont->getByName("ReportComponent"), UNO_QUERY );
328         if ( xServiceInfo.is() )
329         {
330             const char* pResId;
331             if ( xServiceInfo->supportsService( SERVICE_FIXEDTEXT ) )
332             {
333                 pResId = RID_STR_PROPTITLE_FIXEDTEXT;
334             }
335             else if ( xServiceInfo->supportsService( SERVICE_IMAGECONTROL ) )
336             {
337                 pResId = RID_STR_PROPTITLE_IMAGECONTROL;
338             }
339             else if ( xServiceInfo->supportsService( SERVICE_FORMATTEDFIELD ) )
340             {
341                 pResId = RID_STR_PROPTITLE_FORMATTED;
342             }
343             else if ( xServiceInfo->supportsService( SERVICE_SHAPE ) )
344             {
345                 pResId = RID_STR_PROPTITLE_SHAPE;
346             }
347             else if ( xServiceInfo->supportsService( SERVICE_REPORTDEFINITION ) )
348             {
349                 pResId = RID_STR_PROPTITLE_REPORT;
350             }
351             else if ( xServiceInfo->supportsService( SERVICE_SECTION ) )
352             {
353                 pResId = RID_STR_PROPTITLE_SECTION;
354             }
355             else if ( xServiceInfo->supportsService( SERVICE_FUNCTION ) )
356             {
357                 pResId = RID_STR_PROPTITLE_FUNCTION;
358             }
359             else if ( xServiceInfo->supportsService( SERVICE_GROUP ) )
360             {
361                 pResId = RID_STR_PROPTITLE_GROUP;
362             }
363             else if ( xServiceInfo->supportsService( SERVICE_FIXEDLINE ) )
364             {
365                 pResId = RID_STR_PROPTITLE_FIXEDLINE;
366             }
367             else
368             {
369                 OSL_FAIL("Unknown service name!");
370                 aName += RID_STR_CLASS_FORMATTEDFIELD;
371                 return aName;
372             }
373 
374             aName += RptResId(pResId);
375         }
376     }
377     else    // multiselection
378     {
379         aName = RptResId(RID_STR_BRWTITLE_PROPERTIES)
380             + RptResId(RID_STR_BRWTITLE_MULTISELECT);
381     }
382 
383     return aName;
384 }
385 
CreateComponentPair(OObjectBase * _pObj)386 uno::Reference< uno::XInterface> PropBrw::CreateComponentPair(OObjectBase* _pObj)
387 {
388     _pObj->initializeOle();
389     return CreateComponentPair(_pObj->getAwtComponent(),_pObj->getReportComponent());
390 }
391 
CreateComponentPair(const uno::Reference<uno::XInterface> & _xFormComponent,const uno::Reference<uno::XInterface> & _xReportComponent)392 uno::Reference< uno::XInterface> PropBrw::CreateComponentPair(const uno::Reference< uno::XInterface>& _xFormComponent
393                                                               ,const uno::Reference< uno::XInterface>& _xReportComponent)
394 {
395     uno::Reference< container::XNameContainer > xNameCont = ::comphelper::NameContainer_createInstance(cppu::UnoType<XInterface>::get());
396     xNameCont->insertByName("FormComponent",uno::makeAny(_xFormComponent));
397     xNameCont->insertByName("ReportComponent",uno::makeAny(_xReportComponent));
398     xNameCont->insertByName("RowSet",uno::makeAny(uno::Reference< uno::XInterface>(m_pDesignView->getController().getRowSet())));
399 
400     return xNameCont;
401 }
402 
getMinimumSize() const403 ::Size PropBrw::getMinimumSize() const
404 {
405     ::Size aSize;
406     Reference< awt::XLayoutConstrains > xLayoutConstrains( m_xBrowserController, UNO_QUERY );
407     if( xLayoutConstrains.is() )
408     {
409         awt::Size aMinSize = xLayoutConstrains->getMinimumSize();
410         aMinSize.Height += 4;
411         aMinSize.Width += 4;
412         aSize.setHeight( aMinSize.Height );
413         aSize.setWidth( aMinSize.Width );
414     }
415     return aSize;
416 }
417 
Update(OSectionView * pNewView)418 void PropBrw::Update( OSectionView* pNewView )
419 {
420     try
421     {
422         if ( m_pView )
423         {
424             EndListening( *(m_pView->GetModel()) );
425             m_pView = nullptr;
426         }
427 
428         // set focus on initialization
429         if ( m_bInitialStateChange )
430         {
431             // if we're just newly created, we want to have the focus
432             PostUserEvent( LINK( this, PropBrw, OnAsyncGetFocus ), nullptr, true );
433             m_bInitialStateChange = false;
434             // and additionally, we want to show the page which was active during
435             // our previous incarnation
436             if ( !m_sLastActivePage.isEmpty() && m_xBrowserController.is() )
437             {
438                 try
439                 {
440                     m_xBrowserController->restoreViewData( makeAny( m_sLastActivePage ) );
441                 }
442                 catch( const Exception& )
443                 {
444                     TOOLS_WARN_EXCEPTION( "reportdesign", "FmPropBrw::StateChanged: caught an exception while setting the initial page!" );
445                 }
446             }
447         }
448 
449         if ( !pNewView )
450             return;
451         else
452             m_pView = pNewView;
453 
454         uno::Sequence< Reference<uno::XInterface> > aMarkedObjects;
455         OViewsWindow* pViews = m_pView->getReportSection()->getSectionWindow()->getViewsWindow();
456         const sal_uInt16 nSectionCount = pViews->getSectionCount();
457         for (sal_uInt16 i = 0; i < nSectionCount; ++i)
458         {
459             OSectionWindow* pSectionWindow = pViews->getSectionWindow(i);
460             if ( pSectionWindow )
461             {
462                 const SdrMarkList& rMarkList = pSectionWindow->getReportSection().getSectionView().GetMarkedObjectList();
463                 aMarkedObjects = ::comphelper::concatSequences(aMarkedObjects,CreateCompPropSet( rMarkList ));
464             }
465         }
466 
467         if ( aMarkedObjects.hasElements() ) // multiple selection
468         {
469             m_xLastSection.clear();
470             implSetNewObject( aMarkedObjects );
471         }
472         else if ( m_xLastSection != m_pView->getReportSection()->getSection() )
473         {
474             uno::Reference< uno::XInterface> xTemp(m_pView->getReportSection()->getSection());
475             m_xLastSection = xTemp;
476             uno::Reference< container::XNameContainer > xNameCont = ::comphelper::NameContainer_createInstance(cppu::UnoType<XInterface>::get() );
477             xNameCont->insertByName("ReportComponent",uno::makeAny(xTemp));
478             xTemp = xNameCont;
479 
480             implSetNewObject( uno::Sequence< uno::Reference< uno::XInterface> >(&xTemp,1) );
481         }
482 
483         StartListening( *(m_pView->GetModel()) );
484     }
485     catch ( Exception& )
486     {
487         TOOLS_WARN_EXCEPTION( "reportdesign", "PropBrw::Update" );
488     }
489 }
490 
Update(const uno::Reference<uno::XInterface> & _xReportComponent)491 void PropBrw::Update( const uno::Reference< uno::XInterface>& _xReportComponent)
492 {
493     if ( m_xLastSection == _xReportComponent )
494         return;
495 
496     m_xLastSection = _xReportComponent;
497     try
498     {
499         if ( m_pView )
500         {
501             EndListening( *(m_pView->GetModel()) );
502             m_pView = nullptr;
503         }
504 
505         uno::Reference< uno::XInterface> xTemp(CreateComponentPair(_xReportComponent,_xReportComponent));
506         implSetNewObject( uno::Sequence< uno::Reference< uno::XInterface> >(&xTemp,1) );
507     }
508     catch ( Exception& )
509     {
510         TOOLS_WARN_EXCEPTION( "reportdesign", "PropBrw::Update: Exception occurred!" );
511     }
512 }
513 
IMPL_LINK_NOARG(PropBrw,OnAsyncGetFocus,void *,void)514 IMPL_LINK_NOARG( PropBrw, OnAsyncGetFocus, void*, void )
515 {
516     m_xContentArea->GrabFocus();
517 }
518 
LoseFocus()519 void PropBrw::LoseFocus()
520 {
521     DockingWindow::LoseFocus();
522     if (m_pDesignView)
523         m_pDesignView->getController().InvalidateAll();
524 }
525 
526 }
527 
528 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
529