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 
20 #include <memory>
21 #include <unotools/viewoptions.hxx>
22 #include <com/sun/star/frame/XController.hpp>
23 #include <com/sun/star/frame/XFrame.hpp>
24 #include <com/sun/star/util/XCloseable.hpp>
25 #include <com/sun/star/beans/NamedValue.hpp>
26 #include <comphelper/string.hxx>
27 #include <cppuhelper/implbase.hxx>
28 #include <osl/diagnose.h>
29 #include <sal/log.hxx>
30 #include <tools/debug.hxx>
31 
32 #include <vcl/svapp.hxx>
33 #include <sfx2/childwin.hxx>
34 #include <sfx2/app.hxx>
35 #include <sfx2/bindings.hxx>
36 #include <sfx2/module.hxx>
37 #include <sfx2/dockwin.hxx>
38 #include <sfx2/dispatch.hxx>
39 #include <workwin.hxx>
40 #include <childwinimpl.hxx>
41 
42 const sal_uInt16 nVersion = 2;
43 
SfxChildWinFactory(SfxChildWinCtor pTheCtor,sal_uInt16 nID,sal_uInt16 n)44 SfxChildWinFactory::SfxChildWinFactory( SfxChildWinCtor pTheCtor, sal_uInt16 nID,
45         sal_uInt16 n )
46     : pCtor(pTheCtor)
47     , nId( nID )
48     , nPos(n)
49 {}
50 
~SfxChildWinFactory()51 SfxChildWinFactory::~SfxChildWinFactory()
52 {
53 }
54 
55 struct SfxChildWindow_Impl
56 {
57     css::uno::Reference< css::frame::XFrame >             xFrame;
58     css::uno::Reference< css::lang::XEventListener >      xListener;
59     SfxChildWinFactory* pFact;
60     bool                bHideNotDelete;
61     bool                bVisible;
62     bool                bWantsFocus;
63     SfxWorkWindow*      pWorkWin;
64 };
65 
66 namespace {
67 
68 class DisposeListener : public ::cppu::WeakImplHelper< css::lang::XEventListener >
69 {
70     public:
DisposeListener(SfxChildWindow * pOwner,SfxChildWindow_Impl * pData)71         DisposeListener( SfxChildWindow*      pOwner ,
72                          SfxChildWindow_Impl* pData  )
73             :   m_pOwner( pOwner )
74             ,   m_pData ( pData  )
75         {}
76 
disposing(const css::lang::EventObject & aSource)77         virtual void SAL_CALL disposing( const css::lang::EventObject& aSource ) override
78         {
79             css::uno::Reference< css::lang::XEventListener > xSelfHold( this );
80 
81             css::uno::Reference< css::lang::XComponent > xComp( aSource.Source, css::uno::UNO_QUERY );
82             if( xComp.is() )
83                 xComp->removeEventListener( this );
84 
85             if( !m_pOwner || !m_pData )
86                 return;
87 
88             m_pData->xListener.clear();
89 
90             if ( m_pData->pWorkWin )
91             {
92                 // m_pOwner and m_pData will be killed
93                 m_pData->xFrame.clear();
94                 m_pData->pWorkWin->GetBindings().Execute( m_pOwner->GetType() );
95             }
96             else
97             {
98                 delete m_pOwner;
99             }
100 
101             m_pOwner = nullptr;
102             m_pData  = nullptr;
103         }
104 
105     private:
106         SfxChildWindow*      m_pOwner;
107         SfxChildWindow_Impl* m_pData ;
108 };
109 
110 }
111 
GetPosSizeFromString(const OUString & rStr,Point & rPos,Size & rSize)112 bool GetPosSizeFromString( const OUString& rStr, Point& rPos, Size& rSize )
113 {
114     if ( comphelper::string::getTokenCount(rStr, '/') != 4 )
115         return false;
116 
117     sal_Int32 nIdx = 0;
118     rPos.setX( rStr.getToken(0, '/', nIdx).toInt32() );
119     rPos.setY( rStr.getToken(0, '/', nIdx).toInt32() );
120     rSize.setWidth( rStr.getToken(0, '/', nIdx).toInt32() );
121     rSize.setHeight( rStr.getToken(0, '/', nIdx).toInt32() );
122 
123     // negative sizes are invalid
124     return rSize.Width() >= 0 && rSize.Height() >= 0;
125 }
126 
GetSplitSizeFromString(const OUString & rStr,Size & rSize)127 bool GetSplitSizeFromString( const OUString& rStr, Size& rSize )
128 {
129     sal_Int32 nIndex = rStr.indexOf( ',' );
130     if ( nIndex != -1 )
131     {
132         OUString aStr = rStr.copy( nIndex+1 );
133 
134         sal_Int32 nCount = comphelper::string::getTokenCount(aStr, ';');
135         if ( nCount != 2 )
136             return false;
137 
138         sal_Int32 nIdx{ 0 };
139         rSize.setWidth( aStr.getToken(0, ';', nIdx ).toInt32() );
140         rSize.setHeight( aStr.getToken(0, ';', nIdx ).toInt32() );
141 
142         // negative sizes are invalid
143         return rSize.Width() >= 0 && rSize.Height() >= 0;
144     }
145 
146     return false;
147 }
148 
SfxChildWindow(vcl::Window * pParentWindow,sal_uInt16 nId)149 SfxChildWindow::SfxChildWindow(vcl::Window *pParentWindow, sal_uInt16 nId)
150     : pParent(pParentWindow)
151     , nType(nId)
152     , eChildAlignment(SfxChildAlignment::NOALIGNMENT)
153     , pImpl(new SfxChildWindow_Impl)
154 {
155     pImpl->pFact = nullptr;
156     pImpl->bHideNotDelete = false;
157     pImpl->bWantsFocus = true;
158     pImpl->bVisible = true;
159     pImpl->pWorkWin = nullptr;
160 }
161 
Destroy()162 void SfxChildWindow::Destroy()
163 {
164     if ( GetFrame().is() )
165     {
166         ClearWorkwin();
167         try
168         {
169             css::uno::Reference < css::util::XCloseable > xClose( GetFrame(), css::uno::UNO_QUERY );
170             if ( xClose.is() )
171                 xClose->close( true );
172             else
173                 GetFrame()->dispose();
174         }
175         catch (const css::uno::Exception&)
176         {
177         }
178     }
179     else
180         delete this;
181 }
182 
ClearWorkwin()183 void SfxChildWindow::ClearWorkwin()
184 {
185     if (pImpl->pWorkWin)
186     {
187         if (pImpl->pWorkWin->GetActiveChild_Impl() == pWindow)
188             pImpl->pWorkWin->SetActiveChild_Impl(nullptr);
189         pImpl->pWorkWin = nullptr;
190     }
191 }
192 
~SfxChildWindow()193 SfxChildWindow::~SfxChildWindow()
194 {
195     ClearWorkwin();
196     if (xController)
197     {
198         xController->ChildWinDispose();
199         xController.reset();
200     }
201     pWindow.disposeAndClear();
202 }
203 
CreateChildWindow(sal_uInt16 nId,vcl::Window * pParent,SfxBindings * pBindings,SfxChildWinInfo const & rInfo)204 std::unique_ptr<SfxChildWindow> SfxChildWindow::CreateChildWindow( sal_uInt16 nId,
205         vcl::Window *pParent, SfxBindings* pBindings, SfxChildWinInfo const & rInfo)
206 {
207     std::unique_ptr<SfxChildWindow> pChild;
208     SfxChildWinFactory* pFact=nullptr;
209     SystemWindowFlags nOldMode = Application::GetSystemWindowMode();
210 
211     // First search for ChildWindow in SDT; Overlay windows are realized
212     // by using ChildWindowContext
213     SfxApplication *pApp = SfxGetpApp();
214     {
215         SfxChildWinFactArr_Impl &rFactories = pApp->GetChildWinFactories_Impl();
216         for ( size_t nFactory = 0; nFactory < rFactories.size(); ++nFactory )
217         {
218             pFact = &rFactories[nFactory];
219             if ( pFact->nId == nId )
220             {
221                 SfxChildWinInfo& rFactInfo = pFact->aInfo;
222                 if ( rInfo.bVisible )
223                 {
224                     if ( pBindings )
225                         pBindings->ENTERREGISTRATIONS();
226                     SfxChildWinInfo aInfo = rFactInfo;
227                     Application::SetSystemWindowMode( SystemWindowFlags::NOAUTOMODE );
228                     pChild = pFact->pCtor( pParent, nId, pBindings, &aInfo );
229                     Application::SetSystemWindowMode( nOldMode );
230                     if ( pBindings )
231                         pBindings->LEAVEREGISTRATIONS();
232                 }
233 
234                 break;
235             }
236         }
237     }
238 
239     SfxDispatcher *pDisp = pBindings ? pBindings->GetDispatcher_Impl() : nullptr;
240     SfxModule *pMod = pDisp ? SfxModule::GetActiveModule( pDisp->GetFrame() ) : nullptr;
241     if (!pChild && pMod)
242     {
243         SfxChildWinFactArr_Impl *pFactories = pMod->GetChildWinFactories_Impl();
244         if ( pFactories )
245         {
246             SfxChildWinFactArr_Impl &rFactories = *pFactories;
247             for ( size_t nFactory = 0; nFactory < rFactories.size(); ++nFactory )
248             {
249                 pFact = &rFactories[nFactory];
250                 if ( pFact->nId == nId )
251                 {
252                     SfxChildWinInfo& rFactInfo = pFact->aInfo;
253                     if ( rInfo.bVisible )
254                     {
255                         if ( pBindings )
256                             pBindings->ENTERREGISTRATIONS();
257                         SfxChildWinInfo aInfo = rFactInfo;
258                         Application::SetSystemWindowMode( SystemWindowFlags::NOAUTOMODE );
259                         pChild = pFact->pCtor( pParent, nId, pBindings, &aInfo );
260                         Application::SetSystemWindowMode( nOldMode );
261                         if ( pBindings )
262                             pBindings->LEAVEREGISTRATIONS();
263                     }
264 
265                     break;
266                 }
267             }
268         }
269     }
270 
271     if ( pChild )
272         pChild->SetFactory_Impl( pFact );
273 
274     DBG_ASSERT(pFact && (pChild || !rInfo.bVisible), "ChildWindow-Typ not registered!");
275 
276     if (pChild && (!pChild->pWindow && !pChild->xController))
277     {
278         pChild.reset();
279         SAL_INFO("sfx.appl", "ChildWindow has no Window!");
280     }
281 
282     return pChild;
283 }
284 
285 
SaveStatus(const SfxChildWinInfo & rInfo)286 void SfxChildWindow::SaveStatus(const SfxChildWinInfo& rInfo)
287 {
288     sal_uInt16 nID = GetType();
289 
290     OUString aInfoVisible = rInfo.bVisible ? OUString("V") : OUString("H");
291 
292     OUString aWinData = "V"
293                       + OUString::number(static_cast<sal_Int32>(nVersion))
294                       + ","
295                       + aInfoVisible
296                       + ","
297                       + OUString::number(static_cast<sal_Int32>(rInfo.nFlags));
298 
299     if ( !rInfo.aExtraString.isEmpty() )
300         aWinData += "," + rInfo.aExtraString;
301 
302     OUString sName(OUString::number(nID));
303     //Try and save window state per-module, e.g. sidebar on in one application
304     //but off in another
305     if (!rInfo.aModule.isEmpty())
306         sName = rInfo.aModule + "/" + sName;
307     SvtViewOptions aWinOpt(EViewType::Window, sName);
308     aWinOpt.SetWindowState(OStringToOUString(rInfo.aWinState, RTL_TEXTENCODING_UTF8));
309 
310     css::uno::Sequence < css::beans::NamedValue > aSeq
311         { { "Data", css::uno::makeAny(aWinData) } };
312     aWinOpt.SetUserData( aSeq );
313 
314     // ... but save status at runtime!
315     pImpl->pFact->aInfo = rInfo;
316 }
317 
SetAlignment(SfxChildAlignment eAlign)318 void SfxChildWindow::SetAlignment(SfxChildAlignment eAlign)
319 {
320     eChildAlignment = eAlign;
321 }
322 
GetInfo() const323 SfxChildWinInfo SfxChildWindow::GetInfo() const
324 {
325     SfxChildWinInfo aInfo(pImpl->pFact->aInfo);
326     if (xController)
327     {
328         weld::Dialog* pDialog = xController->getDialog();
329         aInfo.aPos  = pDialog->get_position();
330         aInfo.aSize = pDialog->get_size();
331         WindowStateMask nMask = WindowStateMask::Pos | WindowStateMask::State;
332         if (pDialog->get_resizable())
333             nMask |= WindowStateMask::Width | WindowStateMask::Height;
334         aInfo.aWinState = pDialog->get_window_state(nMask);
335     }
336     else if (pWindow)
337     {
338         aInfo.aPos  = pWindow->GetPosPixel();
339         aInfo.aSize = pWindow->GetSizePixel();
340         if ( pWindow->IsSystemWindow() )
341         {
342             WindowStateMask nMask = WindowStateMask::Pos | WindowStateMask::State;
343             if ( pWindow->GetStyle() & WB_SIZEABLE )
344                 nMask |= WindowStateMask::Width | WindowStateMask::Height;
345             aInfo.aWinState = static_cast<SystemWindow*>(pWindow.get())->GetWindowState( nMask );
346         }
347         else if (DockingWindow* pDockingWindow = dynamic_cast<DockingWindow*>(pWindow.get()))
348         {
349             if (pDockingWindow->GetFloatingWindow())
350                 aInfo.aWinState = pDockingWindow->GetFloatingWindow()->GetWindowState();
351             else if (SfxDockingWindow* pSfxDockingWindow = dynamic_cast<SfxDockingWindow*>(pDockingWindow))
352             {
353                 SfxChildWinInfo aTmpInfo;
354                 pSfxDockingWindow->FillInfo( aTmpInfo );
355                 aInfo.aExtraString = aTmpInfo.aExtraString;
356             }
357         }
358     }
359 
360     aInfo.bVisible = pImpl->bVisible;
361     aInfo.nFlags = SfxChildWindowFlags::NONE;
362     return aInfo;
363 }
364 
GetPosition() const365 sal_uInt16 SfxChildWindow::GetPosition() const
366 {
367     return pImpl->pFact->nPos;
368 }
369 
InitializeChildWinFactory_Impl(sal_uInt16 nId,SfxChildWinInfo & rInfo)370 void SfxChildWindow::InitializeChildWinFactory_Impl(sal_uInt16 nId, SfxChildWinInfo& rInfo)
371 {
372     // load configuration
373 
374     std::unique_ptr<SvtViewOptions> xWinOpt;
375     // first see if a module specific id exists
376     if (rInfo.aModule.getLength())
377         xWinOpt.reset(new SvtViewOptions(EViewType::Window, rInfo.aModule + "/" + OUString::number(nId)));
378 
379     // if not then try the generic id
380     if (!xWinOpt || !xWinOpt->Exists())
381         xWinOpt.reset(new SvtViewOptions(EViewType::Window, OUString::number(nId)));
382 
383     if (xWinOpt->Exists() && xWinOpt->HasVisible() )
384         rInfo.bVisible  = xWinOpt->IsVisible(); // set state from configuration. Can be overwritten by UserData, see below
385 
386     css::uno::Sequence < css::beans::NamedValue > aSeq = xWinOpt->GetUserData();
387 
388     OUString aTmp;
389     if ( aSeq.hasElements() )
390         aSeq[0].Value >>= aTmp;
391 
392     OUString aWinData( aTmp );
393     rInfo.aWinState = OUStringToOString(xWinOpt->GetWindowState(), RTL_TEXTENCODING_UTF8);
394 
395     if ( aWinData.isEmpty() )
396         return;
397 
398     // Search for version ID
399     if ( aWinData[0] != 0x0056 ) // 'V' = 56h
400         // A version ID, so do not use
401         return;
402 
403     // Delete 'V'
404     aWinData = aWinData.copy(1);
405 
406     // Read version
407     char cToken = ',';
408     sal_Int32 nPos = aWinData.indexOf( cToken );
409     sal_uInt16 nActVersion = static_cast<sal_uInt16>(aWinData.copy( 0, nPos + 1 ).toInt32());
410     if ( nActVersion != nVersion )
411         return;
412 
413     aWinData = aWinData.copy(nPos+1);
414 
415     // Load Visibility: is coded as a char
416     rInfo.bVisible = (aWinData[0] == 0x0056); // 'V' = 56h
417     aWinData = aWinData.copy(1);
418     nPos = aWinData.indexOf( cToken );
419     if (nPos == -1)
420         return;
421 
422     sal_Int32 nNextPos = aWinData.indexOf( cToken, 2 );
423     if ( nNextPos != -1 )
424     {
425         // there is extra information
426         rInfo.nFlags = static_cast<SfxChildWindowFlags>(static_cast<sal_uInt16>(aWinData.copy( nPos+1, nNextPos - nPos - 1 ).toInt32()));
427         aWinData = aWinData.replaceAt( nPos, nNextPos-nPos+1, "" );
428         rInfo.aExtraString = aWinData;
429     }
430     else
431         rInfo.nFlags = static_cast<SfxChildWindowFlags>(static_cast<sal_uInt16>(aWinData.copy( nPos+1 ).toInt32()));
432 }
433 
ParentIsFloatingWindow(vcl::Window * pParent)434 bool ParentIsFloatingWindow(vcl::Window *pParent)
435 {
436     if (!pParent)
437         return false;
438     if (pParent->GetType() == WindowType::DOCKINGWINDOW || pParent->GetType() == WindowType::TOOLBOX)
439         return static_cast<DockingWindow*>(pParent)->GetFloatingWindow() != nullptr;
440     if (pParent->GetType() == WindowType::FLOATINGWINDOW)
441         return true;
442     return false;
443 }
444 
SetFactory_Impl(SfxChildWinFactory * pF)445 void SfxChildWindow::SetFactory_Impl( SfxChildWinFactory *pF )
446 {
447     pImpl->pFact = pF;
448 }
449 
SetHideNotDelete(bool bOn)450 void SfxChildWindow::SetHideNotDelete( bool bOn )
451 {
452     pImpl->bHideNotDelete = bOn;
453 }
454 
IsHideNotDelete() const455 bool SfxChildWindow::IsHideNotDelete() const
456 {
457     return pImpl->bHideNotDelete;
458 }
459 
SetWantsFocus(bool bSet)460 void SfxChildWindow::SetWantsFocus( bool bSet )
461 {
462     pImpl->bWantsFocus = bSet;
463 }
464 
WantsFocus() const465 bool SfxChildWindow::WantsFocus() const
466 {
467     return pImpl->bWantsFocus;
468 }
469 
GetExtraData_Impl(SfxChildAlignment * pAlign) const470 bool SfxChildWinInfo::GetExtraData_Impl
471 (
472     SfxChildAlignment   *pAlign
473 )   const
474 {
475     // invalid?
476     if ( aExtraString.isEmpty() )
477         return false;
478     OUString aStr;
479     sal_Int32 nPos = aExtraString.indexOf("AL:");
480     if ( nPos == -1 )
481         return false;
482 
483     // Try to read the alignment string "ALIGN :(...)", but if
484     // it is not present, then use an older version
485     sal_Int32 n1 = aExtraString.indexOf('(', nPos);
486     if ( n1 != -1 )
487     {
488         sal_Int32 n2 = aExtraString.indexOf(')', n1);
489         if ( n2 != -1 )
490         {
491             // Cut out Alignment string
492             aStr = aExtraString.copy(nPos, n2 - nPos + 1);
493             aStr = aStr.replaceAt(nPos, n1-nPos+1, "");
494         }
495     }
496 
497     // First extract the Alignment
498     if ( aStr.isEmpty() )
499         return false;
500     if ( pAlign )
501         *pAlign = static_cast<SfxChildAlignment>(static_cast<sal_uInt16>(aStr.toInt32()));
502 
503     // then the LastAlignment
504     nPos = aStr.indexOf(',');
505     if ( nPos == -1 )
506         return false;
507     aStr = aStr.copy(nPos+1);
508 
509     // Then the splitting information
510     nPos = aStr.indexOf(',');
511     if ( nPos == -1 )
512         // No docking in a Splitwindow
513         return true;
514     aStr = aStr.copy(nPos+1);
515     Point aChildPos;
516     Size aChildSize;
517     return GetPosSizeFromString( aStr, aChildPos, aChildSize );
518 }
519 
IsVisible() const520 bool SfxChildWindow::IsVisible() const
521 {
522     return pImpl->bVisible;
523 }
524 
SetVisible_Impl(bool bVis)525 void SfxChildWindow::SetVisible_Impl( bool bVis )
526 {
527     pImpl->bVisible = bVis;
528 }
529 
Hide()530 void SfxChildWindow::Hide()
531 {
532     if (xController)
533         xController->EndDialog();
534     else
535         pWindow->Hide();
536 }
537 
Show(ShowFlags nFlags)538 void SfxChildWindow::Show( ShowFlags nFlags )
539 {
540     if (xController)
541     {
542         if (!xController->getDialog()->get_visible())
543         {
544             weld::DialogController::runAsync(xController,
545                 [this](sal_Int32 /*nResult*/){ xController->Close(); });
546         }
547     }
548     else
549         pWindow->Show(true, nFlags);
550 }
551 
SetWorkWindow_Impl(SfxWorkWindow * pWin)552 void SfxChildWindow::SetWorkWindow_Impl( SfxWorkWindow* pWin )
553 {
554     pImpl->pWorkWin = pWin;
555     if (pWin)
556     {
557         if ( (xController && xController->getDialog()->has_toplevel_focus()) ||
558              (pWindow && pWindow->HasChildPathFocus()) )
559         {
560             pImpl->pWorkWin->SetActiveChild_Impl( pWindow );
561         }
562     }
563 }
564 
Activate_Impl()565 void SfxChildWindow::Activate_Impl()
566 {
567     if(pImpl->pWorkWin!=nullptr)
568         pImpl->pWorkWin->SetActiveChild_Impl( pWindow );
569 }
570 
QueryClose()571 bool SfxChildWindow::QueryClose()
572 {
573     bool bAllow = true;
574 
575     if ( pImpl->xFrame.is() )
576     {
577         css::uno::Reference< css::frame::XController >  xCtrl = pImpl->xFrame->getController();
578         if ( xCtrl.is() )
579             bAllow = xCtrl->suspend( true );
580     }
581 
582     if ( bAllow )
583     {
584         if (GetController())
585         {
586             weld::Dialog* pDialog = GetController()->getDialog();
587             bAllow = !pDialog->get_visible() || !pDialog->get_modal();
588         }
589         else if (GetWindow())
590             bAllow = !GetWindow()->IsInModalMode();
591     }
592 
593     return bAllow;
594 }
595 
GetFrame() const596 const css::uno::Reference< css::frame::XFrame >&  SfxChildWindow::GetFrame() const
597 {
598     return pImpl->xFrame;
599 }
600 
SetFrame(const css::uno::Reference<css::frame::XFrame> & rFrame)601 void SfxChildWindow::SetFrame( const css::uno::Reference< css::frame::XFrame > & rFrame )
602 {
603     // Do nothing if nothing will be changed ...
604     if( pImpl->xFrame == rFrame )
605         return;
606 
607     // ... but stop listening on old frame, if connection exist!
608     if( pImpl->xFrame.is() )
609         pImpl->xFrame->removeEventListener( pImpl->xListener );
610 
611     // If new frame is not NULL -> we must guarantee valid listener for disposing events.
612     // Use already existing or create new one.
613     if( rFrame.is() )
614         if( !pImpl->xListener.is() )
615             pImpl->xListener.set( new DisposeListener( this, pImpl.get() ) );
616 
617     // Set new frame in data container
618     // and build new listener connection, if necessary.
619     pImpl->xFrame = rFrame;
620     if( pImpl->xFrame.is() )
621         pImpl->xFrame->addEventListener( pImpl->xListener );
622 }
623 
RegisterChildWindow(SfxModule * pMod,std::unique_ptr<SfxChildWinFactory> pFact)624 void SfxChildWindow::RegisterChildWindow(SfxModule* pMod, std::unique_ptr<SfxChildWinFactory> pFact)
625 {
626     SfxGetpApp()->RegisterChildWindow_Impl( pMod, std::move(pFact) );
627 }
628 
629 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
630