LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / sfx2 / source / appl / childwin.cxx
blob263f750f9b12c104e762f4b548f5876e792da17e
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
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>
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>
41 const sal_uInt16 nVersion = 2;
43 SfxChildWinFactory::SfxChildWinFactory( SfxChildWinCtor pTheCtor, sal_uInt16 nID,
44 sal_uInt16 n )
45 : pCtor(pTheCtor)
46 , nId( nID )
47 , nPos(n)
50 struct SfxChildWindow_Impl
52 css::uno::Reference< css::frame::XFrame > xFrame;
53 css::uno::Reference< css::lang::XEventListener > xListener;
54 SfxChildWinFactory aFact = { nullptr, 0, 0 };
55 bool bHideNotDelete;
56 bool bVisible;
57 bool bWantsFocus;
58 SfxWorkWindow* pWorkWin;
61 namespace {
63 class DisposeListener : public ::cppu::WeakImplHelper< css::lang::XEventListener >
65 public:
66 DisposeListener( SfxChildWindow* pOwner ,
67 SfxChildWindow_Impl* pData )
68 : m_pOwner( pOwner )
69 , m_pData ( pData )
72 virtual void SAL_CALL disposing( const css::lang::EventObject& aSource ) override
74 css::uno::Reference< css::lang::XEventListener > xSelfHold( this );
76 css::uno::Reference< css::lang::XComponent > xComp( aSource.Source, css::uno::UNO_QUERY );
77 if( xComp.is() )
78 xComp->removeEventListener( this );
80 if( !m_pOwner || !m_pData )
81 return;
83 m_pData->xListener.clear();
85 if ( m_pData->pWorkWin )
87 // m_pOwner and m_pData will be killed
88 m_pData->xFrame.clear();
89 m_pData->pWorkWin->GetBindings().Execute( m_pOwner->GetType() );
91 else
93 delete m_pOwner;
96 m_pOwner = nullptr;
97 m_pData = nullptr;
100 private:
101 SfxChildWindow* m_pOwner;
102 SfxChildWindow_Impl* m_pData ;
107 bool GetPosSizeFromString( const OUString& rStr, Point& rPos, Size& rSize )
109 if ( comphelper::string::getTokenCount(rStr, '/') != 4 )
110 return false;
112 sal_Int32 nIdx = 0;
113 rPos.setX( rStr.getToken(0, '/', nIdx).toInt32() );
114 rPos.setY( rStr.getToken(0, '/', nIdx).toInt32() );
115 rSize.setWidth( rStr.getToken(0, '/', nIdx).toInt32() );
116 rSize.setHeight( rStr.getToken(0, '/', nIdx).toInt32() );
118 // negative sizes are invalid
119 return rSize.Width() >= 0 && rSize.Height() >= 0;
122 bool GetSplitSizeFromString( const OUString& rStr, Size& rSize )
124 sal_Int32 nIndex = rStr.indexOf( ',' );
125 if ( nIndex != -1 )
127 OUString aStr = rStr.copy( nIndex+1 );
129 sal_Int32 nCount = comphelper::string::getTokenCount(aStr, ';');
130 if ( nCount != 2 )
131 return false;
133 sal_Int32 nIdx{ 0 };
134 rSize.setWidth( aStr.getToken(0, ';', nIdx ).toInt32() );
135 rSize.setHeight( aStr.getToken(0, ';', nIdx ).toInt32() );
137 // negative sizes are invalid
138 return rSize.Width() >= 0 && rSize.Height() >= 0;
141 return false;
144 SfxChildWindow::SfxChildWindow(vcl::Window *pParentWindow, sal_uInt16 nId)
145 : pParent(pParentWindow)
146 , pImpl(new SfxChildWindow_Impl)
147 , eChildAlignment(SfxChildAlignment::NOALIGNMENT)
148 , nType(nId)
150 pImpl->bHideNotDelete = false;
151 pImpl->bWantsFocus = true;
152 pImpl->bVisible = true;
153 pImpl->pWorkWin = nullptr;
156 void SfxChildWindow::Destroy()
158 if ( GetFrame().is() )
160 ClearWorkwin();
163 css::uno::Reference < css::util::XCloseable > xClose( GetFrame(), css::uno::UNO_QUERY );
164 if ( xClose.is() )
165 xClose->close( true );
166 else
167 GetFrame()->dispose();
169 catch (const css::uno::Exception&)
173 else
174 delete this;
177 void SfxChildWindow::ClearWorkwin()
179 if (pImpl->pWorkWin)
181 if (pImpl->pWorkWin->GetActiveChild_Impl() == pWindow)
182 pImpl->pWorkWin->SetActiveChild_Impl(nullptr);
183 pImpl->pWorkWin = nullptr;
187 SfxChildWindow::~SfxChildWindow()
189 ClearWorkwin();
190 if (xController)
192 xController->ChildWinDispose();
193 xController.reset();
195 pWindow.disposeAndClear();
198 std::unique_ptr<SfxChildWindow> SfxChildWindow::CreateChildWindow( sal_uInt16 nId,
199 vcl::Window *pParent, SfxBindings* pBindings, SfxChildWinInfo const & rInfo)
201 std::unique_ptr<SfxChildWindow> pChild;
202 SfxChildWinFactory* pFact=nullptr;
203 SystemWindowFlags nOldMode = Application::GetSystemWindowMode();
205 // First search for ChildWindow in SDT; Overlay windows are realized
206 // by using ChildWindowContext
207 SfxApplication *pApp = SfxGetpApp();
209 pFact = pApp->GetChildWinFactoryById(nId);
210 if ( pFact )
212 SfxChildWinInfo& rFactInfo = pFact->aInfo;
213 if ( rInfo.bVisible )
215 if ( pBindings )
216 pBindings->ENTERREGISTRATIONS();
217 SfxChildWinInfo aInfo = rFactInfo;
218 Application::SetSystemWindowMode( SystemWindowFlags::NOAUTOMODE );
219 pChild = pFact->pCtor( pParent, nId, pBindings, &aInfo );
220 Application::SetSystemWindowMode( nOldMode );
221 if ( pBindings )
222 pBindings->LEAVEREGISTRATIONS();
227 SfxDispatcher *pDisp = pBindings ? pBindings->GetDispatcher_Impl() : nullptr;
228 SfxModule *pMod = pDisp ? SfxModule::GetActiveModule( pDisp->GetFrame() ) : nullptr;
229 if (!pChild && pMod)
231 pFact = pMod->GetChildWinFactoryById(nId);
232 if ( pFact )
234 SfxChildWinInfo& rFactInfo = pFact->aInfo;
235 if ( rInfo.bVisible )
237 if ( pBindings )
238 pBindings->ENTERREGISTRATIONS();
239 SfxChildWinInfo aInfo = rFactInfo;
240 Application::SetSystemWindowMode( SystemWindowFlags::NOAUTOMODE );
241 pChild = pFact->pCtor( pParent, nId, pBindings, &aInfo );
242 Application::SetSystemWindowMode( nOldMode );
243 if ( pBindings )
244 pBindings->LEAVEREGISTRATIONS();
249 if (pChild)
251 assert(pFact && "pChild is returned by a call on pFact, so pFact cannot be null");
252 pChild->SetFactory_Impl( pFact );
255 DBG_ASSERT(pFact && (pChild || !rInfo.bVisible), "ChildWindow-Typ not registered!");
257 if (pChild && (!pChild->pWindow && !pChild->xController))
259 pChild.reset();
260 SAL_INFO("sfx.appl", "ChildWindow has no Window!");
263 return pChild;
267 void SfxChildWindow::SaveStatus(const SfxChildWinInfo& rInfo)
269 sal_uInt16 nID = GetType();
271 OUString aInfoVisible = rInfo.bVisible ? OUString("V") : OUString("H");
273 OUString aWinData = "V"
274 + OUString::number(static_cast<sal_Int32>(nVersion))
275 + ","
276 + aInfoVisible
277 + ","
278 + OUString::number(static_cast<sal_Int32>(rInfo.nFlags));
280 if ( !rInfo.aExtraString.isEmpty() )
281 aWinData += "," + rInfo.aExtraString;
283 OUString sName(OUString::number(nID));
284 //Try and save window state per-module, e.g. sidebar on in one application
285 //but off in another
286 if (!rInfo.aModule.isEmpty())
287 sName = rInfo.aModule + "/" + sName;
288 SvtViewOptions aWinOpt(EViewType::Window, sName);
289 aWinOpt.SetWindowState(OStringToOUString(rInfo.aWinState, RTL_TEXTENCODING_UTF8));
291 css::uno::Sequence < css::beans::NamedValue > aSeq
292 { { "Data", css::uno::makeAny(aWinData) } };
293 aWinOpt.SetUserData( aSeq );
295 // ... but save status at runtime!
296 pImpl->aFact.aInfo = rInfo;
299 void SfxChildWindow::SetAlignment(SfxChildAlignment eAlign)
301 eChildAlignment = eAlign;
304 SfxChildWinInfo SfxChildWindow::GetInfo() const
306 SfxChildWinInfo aInfo(pImpl->aFact.aInfo);
307 if (xController)
309 weld::Dialog* pDialog = xController->getDialog();
310 aInfo.aPos = pDialog->get_position();
311 aInfo.aSize = pDialog->get_size();
312 WindowStateMask nMask = WindowStateMask::Pos | WindowStateMask::State;
313 if (pDialog->get_resizable())
314 nMask |= WindowStateMask::Width | WindowStateMask::Height;
315 aInfo.aWinState = pDialog->get_window_state(nMask);
317 else if (pWindow)
319 aInfo.aPos = pWindow->GetPosPixel();
320 aInfo.aSize = pWindow->GetSizePixel();
321 if ( pWindow->IsSystemWindow() )
323 WindowStateMask nMask = WindowStateMask::Pos | WindowStateMask::State;
324 if ( pWindow->GetStyle() & WB_SIZEABLE )
325 nMask |= WindowStateMask::Width | WindowStateMask::Height;
326 aInfo.aWinState = static_cast<SystemWindow*>(pWindow.get())->GetWindowState( nMask );
328 else if (DockingWindow* pDockingWindow = dynamic_cast<DockingWindow*>(pWindow.get()))
330 if (pDockingWindow->GetFloatingWindow())
331 aInfo.aWinState = pDockingWindow->GetFloatingWindow()->GetWindowState();
332 else if (SfxDockingWindow* pSfxDockingWindow = dynamic_cast<SfxDockingWindow*>(pDockingWindow))
334 SfxChildWinInfo aTmpInfo;
335 pSfxDockingWindow->FillInfo( aTmpInfo );
336 aInfo.aExtraString = aTmpInfo.aExtraString;
341 aInfo.bVisible = pImpl->bVisible;
342 aInfo.nFlags = SfxChildWindowFlags::NONE;
343 return aInfo;
346 sal_uInt16 SfxChildWindow::GetPosition() const
348 return pImpl->aFact.nPos;
351 void SfxChildWindow::InitializeChildWinFactory_Impl(sal_uInt16 nId, SfxChildWinInfo& rInfo)
353 // load configuration
355 std::unique_ptr<SvtViewOptions> xWinOpt;
356 // first see if a module specific id exists
357 if (rInfo.aModule.getLength())
358 xWinOpt.reset(new SvtViewOptions(EViewType::Window, rInfo.aModule + "/" + OUString::number(nId)));
360 // if not then try the generic id
361 if (!xWinOpt || !xWinOpt->Exists())
362 xWinOpt.reset(new SvtViewOptions(EViewType::Window, OUString::number(nId)));
364 if (xWinOpt->Exists() && xWinOpt->HasVisible() )
365 rInfo.bVisible = xWinOpt->IsVisible(); // set state from configuration. Can be overwritten by UserData, see below
367 css::uno::Sequence < css::beans::NamedValue > aSeq = xWinOpt->GetUserData();
369 OUString aTmp;
370 if ( aSeq.hasElements() )
371 aSeq[0].Value >>= aTmp;
373 OUString aWinData( aTmp );
374 rInfo.aWinState = OUStringToOString(xWinOpt->GetWindowState(), RTL_TEXTENCODING_UTF8);
376 if ( aWinData.isEmpty() )
377 return;
379 // Search for version ID
380 if ( aWinData[0] != 0x0056 ) // 'V' = 56h
381 // A version ID, so do not use
382 return;
384 // Delete 'V'
385 aWinData = aWinData.copy(1);
387 // Read version
388 char cToken = ',';
389 sal_Int32 nPos = aWinData.indexOf( cToken );
390 sal_uInt16 nActVersion = static_cast<sal_uInt16>(aWinData.copy( 0, nPos + 1 ).toInt32());
391 if ( nActVersion != nVersion )
392 return;
394 aWinData = aWinData.copy(nPos+1);
396 // Load Visibility: is coded as a char
397 rInfo.bVisible = (aWinData[0] == 0x0056); // 'V' = 56h
398 aWinData = aWinData.copy(1);
399 nPos = aWinData.indexOf( cToken );
400 if (nPos == -1)
401 return;
403 sal_Int32 nNextPos = aWinData.indexOf( cToken, 2 );
404 if ( nNextPos != -1 )
406 // there is extra information
407 rInfo.nFlags = static_cast<SfxChildWindowFlags>(static_cast<sal_uInt16>(aWinData.copy( nPos+1, nNextPos - nPos - 1 ).toInt32()));
408 aWinData = aWinData.replaceAt( nPos, nNextPos-nPos+1, u"" );
409 rInfo.aExtraString = aWinData;
411 else
412 rInfo.nFlags = static_cast<SfxChildWindowFlags>(static_cast<sal_uInt16>(aWinData.copy( nPos+1 ).toInt32()));
415 bool ParentIsFloatingWindow(const vcl::Window *pParent)
417 if (!pParent)
418 return false;
419 if (pParent->GetType() == WindowType::DOCKINGWINDOW || pParent->GetType() == WindowType::TOOLBOX)
420 return static_cast<const DockingWindow*>(pParent)->GetFloatingWindow() != nullptr;
421 if (pParent->GetType() == WindowType::FLOATINGWINDOW)
422 return true;
423 return false;
426 void SfxChildWindow::SetFactory_Impl( const SfxChildWinFactory *pF )
428 pImpl->aFact = *pF;
431 void SfxChildWindow::SetHideNotDelete( bool bOn )
433 pImpl->bHideNotDelete = bOn;
436 bool SfxChildWindow::IsHideNotDelete() const
438 return pImpl->bHideNotDelete;
441 void SfxChildWindow::SetWantsFocus( bool bSet )
443 pImpl->bWantsFocus = bSet;
446 bool SfxChildWindow::WantsFocus() const
448 return pImpl->bWantsFocus;
451 bool SfxChildWinInfo::GetExtraData_Impl
453 SfxChildAlignment *pAlign
454 ) const
456 // invalid?
457 if ( aExtraString.isEmpty() )
458 return false;
459 OUString aStr;
460 sal_Int32 nPos = aExtraString.indexOf("AL:");
461 if ( nPos == -1 )
462 return false;
464 // Try to read the alignment string "ALIGN :(...)", but if
465 // it is not present, then use an older version
466 sal_Int32 n1 = aExtraString.indexOf('(', nPos);
467 if ( n1 != -1 )
469 sal_Int32 n2 = aExtraString.indexOf(')', n1);
470 if ( n2 != -1 )
472 // Cut out Alignment string
473 aStr = aExtraString.copy(nPos, n2 - nPos + 1);
474 aStr = aStr.replaceAt(nPos, n1-nPos+1, u"");
478 // First extract the Alignment
479 if ( aStr.isEmpty() )
480 return false;
481 if ( pAlign )
482 *pAlign = static_cast<SfxChildAlignment>(static_cast<sal_uInt16>(aStr.toInt32()));
484 // then the LastAlignment
485 nPos = aStr.indexOf(',');
486 if ( nPos == -1 )
487 return false;
488 aStr = aStr.copy(nPos+1);
490 // Then the splitting information
491 nPos = aStr.indexOf(',');
492 if ( nPos == -1 )
493 // No docking in a Splitwindow
494 return true;
495 aStr = aStr.copy(nPos+1);
496 Point aChildPos;
497 Size aChildSize;
498 return GetPosSizeFromString( aStr, aChildPos, aChildSize );
501 bool SfxChildWindow::IsVisible() const
503 return pImpl->bVisible;
506 void SfxChildWindow::SetVisible_Impl( bool bVis )
508 pImpl->bVisible = bVis;
511 void SfxChildWindow::Hide()
513 if (xController)
514 xController->EndDialog();
515 else
516 pWindow->Hide();
519 void SfxChildWindow::Show( ShowFlags nFlags )
521 if (xController)
523 if (!xController->getDialog()->get_visible())
525 weld::DialogController::runAsync(xController,
526 [this](sal_Int32 /*nResult*/){ xController->Close(); });
529 else
530 pWindow->Show(true, nFlags);
533 void SfxChildWindow::SetWorkWindow_Impl( SfxWorkWindow* pWin )
535 pImpl->pWorkWin = pWin;
536 if (pWin)
538 if ( (xController && xController->getDialog()->has_toplevel_focus()) ||
539 (pWindow && pWindow->HasChildPathFocus()) )
541 pImpl->pWorkWin->SetActiveChild_Impl( pWindow );
546 void SfxChildWindow::Activate_Impl()
548 if(pImpl->pWorkWin!=nullptr)
549 pImpl->pWorkWin->SetActiveChild_Impl( pWindow );
552 bool SfxChildWindow::QueryClose()
554 bool bAllow = true;
556 if ( pImpl->xFrame.is() )
558 css::uno::Reference< css::frame::XController > xCtrl = pImpl->xFrame->getController();
559 if ( xCtrl.is() )
560 bAllow = xCtrl->suspend( true );
563 if ( bAllow )
565 if (GetController())
567 weld::Dialog* pDialog = GetController()->getDialog();
568 bAllow = !pDialog->get_visible() || !pDialog->get_modal();
570 else if (GetWindow())
571 bAllow = !GetWindow()->IsInModalMode();
574 return bAllow;
577 const css::uno::Reference< css::frame::XFrame >& SfxChildWindow::GetFrame() const
579 return pImpl->xFrame;
582 void SfxChildWindow::SetFrame( const css::uno::Reference< css::frame::XFrame > & rFrame )
584 // Do nothing if nothing will be changed ...
585 if( pImpl->xFrame == rFrame )
586 return;
588 // ... but stop listening on old frame, if connection exist!
589 if( pImpl->xFrame.is() )
590 pImpl->xFrame->removeEventListener( pImpl->xListener );
592 // If new frame is not NULL -> we must guarantee valid listener for disposing events.
593 // Use already existing or create new one.
594 if( rFrame.is() )
595 if( !pImpl->xListener.is() )
596 pImpl->xListener.set( new DisposeListener( this, pImpl.get() ) );
598 // Set new frame in data container
599 // and build new listener connection, if necessary.
600 pImpl->xFrame = rFrame;
601 if( pImpl->xFrame.is() )
602 pImpl->xFrame->addEventListener( pImpl->xListener );
605 void SfxChildWindow::RegisterChildWindow(SfxModule* pMod, const SfxChildWinFactory& rFact)
607 SfxGetpApp()->RegisterChildWindow_Impl( pMod, rFact );
610 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */