nss: upgrade to release 3.73
[LibreOffice.git] / vcl / source / window / dialog.cxx
blob5618af225d4c28bfae6273bb33a048495dad1e5a
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 <config_feature_desktop.h>
22 #ifdef IOS
23 #include <premac.h>
24 #include <UIKit/UIKit.h>
25 #include <postmac.h>
26 #endif
28 #include <com/sun/star/frame/theGlobalEventBroadcaster.hpp>
29 #include <comphelper/lok.hxx>
30 #include <comphelper/scopeguard.hxx>
31 #include <comphelper/processfactory.hxx>
32 #include <officecfg/Office/Common.hxx>
33 #include <osl/diagnose.h>
35 #include <svdata.hxx>
36 #include <window.h>
37 #include <brdwin.hxx>
39 #include <rtl/bootstrap.hxx>
40 #include <rtl/strbuf.hxx>
41 #include <sal/log.hxx>
43 #include <vcl/abstdlg.hxx>
44 #include <vcl/accel.hxx>
45 #include <vcl/builder.hxx>
46 #include <vcl/layout.hxx>
47 #include <vcl/svapp.hxx>
48 #include <vcl/event.hxx>
49 #include <vcl/waitobj.hxx>
50 #include <vcl/wrkwin.hxx>
51 #include <vcl/toolkit/button.hxx>
52 #include <vcl/mnemonic.hxx>
53 #include <vcl/toolkit/dialog.hxx>
54 #include <vcl/dialoghelper.hxx>
55 #include <vcl/settings.hxx>
56 #include <vcl/virdev.hxx>
57 #include <vcl/weld.hxx>
58 #include <vcl/uitest/uiobject.hxx>
59 #include <vcl/uitest/logger.hxx>
60 #include <vcl/IDialogRenderable.hxx>
61 #include <messagedialog.hxx>
62 #include <salframe.hxx>
64 #include <iostream>
65 #include <utility>
67 static OString ImplGetDialogText( Dialog* pDialog )
69 OStringBuffer aErrorStr(OUStringToOString(
70 pDialog->GetText(), RTL_TEXTENCODING_UTF8));
72 OUString sMessage;
73 if (MessageDialog* pMessDialog = dynamic_cast<MessageDialog*>(pDialog))
75 sMessage = pMessDialog->get_primary_text();
78 if (!sMessage.isEmpty())
80 aErrorStr.append(", ");
81 aErrorStr.append(OUStringToOString(
82 sMessage, RTL_TEXTENCODING_UTF8));
84 return aErrorStr.makeStringAndClear();
87 static bool ImplIsMnemonicCtrl( vcl::Window* pWindow )
89 if( ! pWindow->GetSettings().GetStyleSettings().GetAutoMnemonic() )
90 return false;
92 if ( (pWindow->GetType() == WindowType::RADIOBUTTON) ||
93 (pWindow->GetType() == WindowType::CHECKBOX) ||
94 (pWindow->GetType() == WindowType::TRISTATEBOX) ||
95 (pWindow->GetType() == WindowType::PUSHBUTTON) )
96 return true;
98 if ( pWindow->GetType() == WindowType::FIXEDTEXT )
100 FixedText *pText = static_cast<FixedText*>(pWindow);
101 if (pText->get_mnemonic_widget())
102 return true;
103 //This is the legacy pre-layout logic which we retain
104 //until we can be sure we can remove it
105 if (pWindow->GetStyle() & WB_NOLABEL)
106 return false;
107 vcl::Window* pNextWindow = pWindow->GetWindow( GetWindowType::Next );
108 if ( !pNextWindow )
109 return false;
110 pNextWindow = pNextWindow->GetWindow( GetWindowType::Client );
111 return !(!(pNextWindow->GetStyle() & WB_TABSTOP) ||
112 (pNextWindow->GetType() == WindowType::FIXEDTEXT) ||
113 (pNextWindow->GetType() == WindowType::GROUPBOX) ||
114 (pNextWindow->GetType() == WindowType::RADIOBUTTON) ||
115 (pNextWindow->GetType() == WindowType::CHECKBOX) ||
116 (pNextWindow->GetType() == WindowType::TRISTATEBOX) ||
117 (pNextWindow->GetType() == WindowType::PUSHBUTTON));
120 return false;
123 // Called by native error dialog popup implementations
124 void ImplHideSplash()
126 ImplSVData* pSVData = ImplGetSVData();
127 if( pSVData->mpIntroWindow )
128 pSVData->mpIntroWindow->Hide();
131 vcl::Window * nextLogicalChildOfParent(const vcl::Window *pTopLevel, const vcl::Window *pChild)
133 const vcl::Window *pLastChild = pChild;
135 if (pChild->GetType() == WindowType::SCROLLWINDOW)
136 pChild = static_cast<const VclScrolledWindow*>(pChild)->get_child();
137 else if (isContainerWindow(*pChild))
138 pChild = pChild->GetWindow(GetWindowType::FirstChild);
139 else
140 pChild = pChild->GetWindow(GetWindowType::Next);
142 while (!pChild)
144 vcl::Window *pParent = pLastChild->GetParent();
145 if (!pParent)
146 return nullptr;
147 if (pParent == pTopLevel)
148 return nullptr;
149 pLastChild = pParent;
150 pChild = pParent->GetWindow(GetWindowType::Next);
153 if (isContainerWindow(*pChild))
154 pChild = nextLogicalChildOfParent(pTopLevel, pChild);
156 return const_cast<vcl::Window *>(pChild);
159 vcl::Window * prevLogicalChildOfParent(const vcl::Window *pTopLevel, const vcl::Window *pChild)
161 const vcl::Window *pLastChild = pChild;
163 if (pChild->GetType() == WindowType::SCROLLWINDOW)
164 pChild = static_cast<const VclScrolledWindow*>(pChild)->get_child();
165 else if (isContainerWindow(*pChild))
166 pChild = pChild->GetWindow(GetWindowType::LastChild);
167 else
168 pChild = pChild->GetWindow(GetWindowType::Prev);
170 while (!pChild)
172 vcl::Window *pParent = pLastChild->GetParent();
173 if (!pParent)
174 return nullptr;
175 if (pParent == pTopLevel)
176 return nullptr;
177 pLastChild = pParent;
178 pChild = pParent->GetWindow(GetWindowType::Prev);
181 if (isContainerWindow(*pChild))
182 pChild = prevLogicalChildOfParent(pTopLevel, pChild);
184 return const_cast<vcl::Window *>(pChild);
187 vcl::Window * firstLogicalChildOfParent(const vcl::Window *pTopLevel)
189 const vcl::Window *pChild = pTopLevel->GetWindow(GetWindowType::FirstChild);
190 if (pChild && isContainerWindow(*pChild))
191 pChild = nextLogicalChildOfParent(pTopLevel, pChild);
192 return const_cast<vcl::Window *>(pChild);
195 vcl::Window * lastLogicalChildOfParent(const vcl::Window *pTopLevel)
197 const vcl::Window *pChild = pTopLevel->GetWindow(GetWindowType::LastChild);
198 if (pChild && isContainerWindow(*pChild))
199 pChild = prevLogicalChildOfParent(pTopLevel, pChild);
200 return const_cast<vcl::Window *>(pChild);
203 void Accelerator::GenerateAutoMnemonicsOnHierarchy(const vcl::Window* pWindow)
205 MnemonicGenerator aMnemonicGenerator;
206 vcl::Window* pGetChild;
207 vcl::Window* pChild;
209 // register the assigned mnemonics
210 pGetChild = pWindow->GetWindow( GetWindowType::FirstChild );
211 while ( pGetChild )
213 pChild = pGetChild->ImplGetWindow();
214 aMnemonicGenerator.RegisterMnemonic( pChild->GetText() );
215 pGetChild = nextLogicalChildOfParent(pWindow, pGetChild);
218 // take the Controls of the dialog into account for TabPages
219 if ( pWindow->GetType() == WindowType::TABPAGE )
221 vcl::Window* pParent = pWindow->GetParent();
222 if (pParent && pParent->GetType() == WindowType::TABCONTROL )
223 pParent = pParent->GetParent();
225 if (pParent && (pParent->GetStyle() & (WB_DIALOGCONTROL | WB_NODIALOGCONTROL)) == WB_DIALOGCONTROL )
227 pGetChild = pParent->GetWindow( GetWindowType::FirstChild );
228 while ( pGetChild )
230 pChild = pGetChild->ImplGetWindow();
231 aMnemonicGenerator.RegisterMnemonic( pChild->GetText() );
232 pGetChild = nextLogicalChildOfParent(pWindow, pGetChild);
237 // assign mnemonics to Controls which have none
238 pGetChild = pWindow->GetWindow( GetWindowType::FirstChild );
239 while ( pGetChild )
241 pChild = pGetChild->ImplGetWindow();
242 if ( ImplIsMnemonicCtrl( pChild ) )
244 OUString aText = pChild->GetText();
245 OUString aNewText = aMnemonicGenerator.CreateMnemonic( aText );
246 if ( aText != aNewText )
247 pChild->SetText( aNewText );
250 pGetChild = nextLogicalChildOfParent(pWindow, pGetChild);
254 static VclButtonBox* getActionArea(Dialog const *pDialog)
256 VclButtonBox *pButtonBox = nullptr;
257 if (pDialog->isLayoutEnabled())
259 vcl::Window *pBox = pDialog->GetWindow(GetWindowType::FirstChild);
260 vcl::Window *pChild = pBox->GetWindow(GetWindowType::LastChild);
261 while (pChild)
263 pButtonBox = dynamic_cast<VclButtonBox*>(pChild);
264 if (pButtonBox)
265 break;
266 pChild = pChild->GetWindow(GetWindowType::Prev);
269 return pButtonBox;
272 static vcl::Window* getActionAreaButtonList(Dialog const *pDialog)
274 VclButtonBox* pButtonBox = getActionArea(pDialog);
275 if (pButtonBox)
276 return pButtonBox->GetWindow(GetWindowType::FirstChild);
277 return pDialog->GetWindow(GetWindowType::FirstChild);
280 static PushButton* ImplGetDefaultButton( Dialog const * pDialog )
282 vcl::Window* pChild = getActionAreaButtonList(pDialog);
283 while ( pChild )
285 if ( pChild->ImplIsPushButton() )
287 PushButton* pPushButton = static_cast<PushButton*>(pChild);
288 if ( pPushButton->ImplIsDefButton() )
289 return pPushButton;
292 pChild = pChild->GetWindow( GetWindowType::Next );
295 return nullptr;
298 static PushButton* ImplGetOKButton( Dialog const * pDialog )
300 vcl::Window* pChild = getActionAreaButtonList(pDialog);
301 while ( pChild )
303 if ( pChild->GetType() == WindowType::OKBUTTON )
304 return static_cast<PushButton*>(pChild);
306 pChild = pChild->GetWindow( GetWindowType::Next );
309 return nullptr;
312 static PushButton* ImplGetCancelButton( Dialog const * pDialog )
314 vcl::Window* pChild = getActionAreaButtonList(pDialog);
316 while ( pChild )
318 if ( pChild->GetType() == WindowType::CANCELBUTTON )
319 return static_cast<PushButton*>(pChild);
321 pChild = pChild->GetWindow( GetWindowType::Next );
324 return nullptr;
327 static void ImplMouseAutoPos( Dialog* pDialog )
329 MouseSettingsOptions nMouseOptions = pDialog->GetSettings().GetMouseSettings().GetOptions();
330 if ( nMouseOptions & MouseSettingsOptions::AutoCenterPos )
332 Size aSize = pDialog->GetOutputSizePixel();
333 pDialog->SetPointerPosPixel( Point( aSize.Width()/2, aSize.Height()/2 ) );
335 else if ( nMouseOptions & MouseSettingsOptions::AutoDefBtnPos )
337 vcl::Window* pWindow = ImplGetDefaultButton( pDialog );
338 if ( !pWindow )
339 pWindow = ImplGetOKButton( pDialog );
340 if ( !pWindow )
341 pWindow = ImplGetCancelButton( pDialog );
342 if ( !pWindow )
343 pWindow = pDialog;
344 Size aSize = pWindow->GetOutputSizePixel();
345 pWindow->SetPointerPosPixel( Point( aSize.Width()/2, aSize.Height()/2 ) );
349 struct DialogImpl
351 std::vector<VclPtr<PushButton>> maOwnedButtons;
352 std::map<VclPtr<vcl::Window>, short> maResponses;
353 tools::Long mnResult;
354 bool mbStartedModal;
355 VclAbstractDialog::AsyncContext maEndCtx;
356 Link<const CommandEvent&, bool> m_aPopupMenuHdl;
357 Link<void*, vcl::ILibreOfficeKitNotifier*> m_aInstallLOKNotifierHdl;
359 DialogImpl() : mnResult( -1 ), mbStartedModal( false ) {}
361 #ifndef NDEBUG
362 short get_response(vcl::Window *pWindow) const
364 auto aFind = maResponses.find(pWindow);
365 if (aFind != maResponses.end())
366 return aFind->second;
367 return RET_CANCEL;
369 #endif
371 ~DialogImpl()
373 for (VclPtr<PushButton> & pOwnedButton : maOwnedButtons)
374 pOwnedButton.disposeAndClear();
378 void Dialog::disposeOwnedButtons()
380 for (VclPtr<PushButton> & pOwnedButton : mpDialogImpl->maOwnedButtons)
381 pOwnedButton.disposeAndClear();
384 void Dialog::ImplInitDialogData()
386 mpWindowImpl->mbDialog = true;
387 mbInExecute = false;
388 mbInSyncExecute = false;
389 mbInClose = false;
390 mbModalMode = false;
391 mpContentArea.clear();
392 mpActionArea.clear();
393 mnMousePositioned = 0;
394 mpDialogImpl.reset(new DialogImpl);
397 vcl::Window* Dialog::GetDefaultParent(WinBits nStyle)
399 vcl::Window* pParent = Application::GetDefDialogParent();
400 if (!pParent && !(nStyle & WB_SYSTEMWINDOW))
401 pParent = ImplGetSVData()->maFrameData.mpAppWin;
403 // If Parent is disabled, then we search for a modal dialog
404 // in this frame
405 if (pParent && (!pParent->IsInputEnabled() || pParent->IsInModalMode()))
407 ImplSVData* pSVData = ImplGetSVData();
408 auto& rExecuteDialogs = pSVData->mpWinData->mpExecuteDialogs;
409 auto it = std::find_if(rExecuteDialogs.rbegin(), rExecuteDialogs.rend(),
410 [&pParent](VclPtr<Dialog>& rDialogPtr) {
411 return pParent->ImplGetFirstOverlapWindow()->IsWindowOrChild(rDialogPtr, true) &&
412 rDialogPtr->IsReallyVisible() && rDialogPtr->IsEnabled() &&
413 rDialogPtr->IsInputEnabled() && !rDialogPtr->IsInModalMode(); });
414 if (it != rExecuteDialogs.rend())
415 pParent = it->get();
418 return pParent;
421 VclPtr<vcl::Window> Dialog::AddBorderWindow(vcl::Window* pParent, WinBits nStyle)
423 VclPtrInstance<ImplBorderWindow> pBorderWin( pParent, nStyle, BorderWindowStyle::Frame );
424 ImplInit( pBorderWin, nStyle & ~WB_BORDER, nullptr );
425 pBorderWin->mpWindowImpl->mpClientWindow = this;
426 pBorderWin->GetBorder( mpWindowImpl->mnLeftBorder, mpWindowImpl->mnTopBorder, mpWindowImpl->mnRightBorder, mpWindowImpl->mnBottomBorder );
427 mpWindowImpl->mpBorderWindow = pBorderWin;
428 mpWindowImpl->mpRealParent = pParent;
430 return pBorderWin;
433 void Dialog::ImplInitDialog( vcl::Window* pParent, WinBits nStyle, InitFlag eFlag )
435 SystemWindowFlags nSysWinMode = Application::GetSystemWindowMode();
437 if ( !(nStyle & WB_NODIALOGCONTROL) )
438 nStyle |= WB_DIALOGCONTROL;
439 nStyle |= WB_ROLLABLE;
441 // Now, all Dialogs are per default system windows !!!
442 nStyle |= WB_SYSTEMWINDOW;
444 if (InitFlag::NoParent == eFlag)
446 pParent = nullptr;
448 else if (!pParent) // parent is NULL: get the default Dialog parent
450 pParent = Dialog::GetDefaultParent(nStyle);
453 if ( !pParent || (nStyle & WB_SYSTEMWINDOW) ||
454 (pParent->mpWindowImpl->mpFrameData->mbNeedSysWindow && !(nSysWinMode & SystemWindowFlags::NOAUTOMODE)) ||
455 (nSysWinMode & SystemWindowFlags::DIALOG) )
457 // create window with a small border ?
458 if ((nStyle & WB_ALLOWMENUBAR) || ((nStyle & (WB_BORDER | WB_NOBORDER | WB_MOVEABLE | WB_SIZEABLE | WB_CLOSEABLE)) == WB_BORDER))
460 AddBorderWindow(pParent, nStyle);
462 else
464 mpWindowImpl->mbFrame = true;
465 mpWindowImpl->mbOverlapWin = true;
466 ImplInit( pParent, (nStyle & (WB_MOVEABLE | WB_SIZEABLE | WB_ROLLABLE | WB_STANDALONE)) | WB_CLOSEABLE, nullptr );
467 // Now set all style bits
468 mpWindowImpl->mnStyle = nStyle;
471 else
473 VclPtrInstance<ImplBorderWindow> pBorderWin( pParent, nStyle, BorderWindowStyle::Overlap );
474 ImplInit( pBorderWin, nStyle & ~WB_BORDER, nullptr );
475 pBorderWin->mpWindowImpl->mpClientWindow = this;
476 pBorderWin->GetBorder( mpWindowImpl->mnLeftBorder, mpWindowImpl->mnTopBorder, mpWindowImpl->mnRightBorder, mpWindowImpl->mnBottomBorder );
477 mpWindowImpl->mpBorderWindow = pBorderWin;
478 mpWindowImpl->mpRealParent = pParent;
481 SetActivateMode( ActivateModeFlags::GrabFocus );
483 ImplInitSettings();
486 void Dialog::ApplySettings(vcl::RenderContext& rRenderContext)
488 if (IsControlBackground())
490 // user override
491 SetBackground(GetControlBackground());
493 else if (rRenderContext.IsNativeControlSupported(ControlType::WindowBackground, ControlPart::BackgroundDialog))
495 // NWF background
496 mpWindowImpl->mnNativeBackground = ControlPart::BackgroundDialog;
497 EnableChildTransparentMode();
499 else
501 // fallback to settings color
502 rRenderContext.SetBackground(GetSettings().GetStyleSettings().GetDialogColor());
506 void Dialog::ImplInitSettings()
508 // user override
509 if (IsControlBackground())
510 SetBackground(GetControlBackground());
511 // NWF background
512 else if( IsNativeControlSupported(ControlType::WindowBackground, ControlPart::BackgroundDialog))
514 mpWindowImpl->mnNativeBackground = ControlPart::BackgroundDialog;
515 EnableChildTransparentMode();
517 // fallback to settings color
518 else
519 SetBackground(GetSettings().GetStyleSettings().GetDialogColor());
522 void Dialog::ImplLOKNotifier(vcl::Window* pParent)
524 if (comphelper::LibreOfficeKit::isActive() && pParent)
526 if (VclPtr<vcl::Window> pWin = pParent->GetParentWithLOKNotifier())
528 SetLOKNotifier(pWin->GetLOKNotifier());
533 Dialog::Dialog( WindowType nType )
534 : SystemWindow( nType )
535 , mnInitFlag(InitFlag::Default)
537 ImplInitDialogData();
540 void VclBuilderContainer::disposeBuilder()
542 if (m_pUIBuilder)
543 m_pUIBuilder->disposeBuilder();
546 OUString AllSettings::GetUIRootDir()
548 OUString sShareLayer("$BRAND_BASE_DIR/$BRAND_SHARE_SUBDIR/config/soffice.cfg/");
549 rtl::Bootstrap::expandMacros(sShareLayer);
550 return sShareLayer;
553 //we can't change sizeable after the fact, so need to defer until we know and then
554 //do the init. Find the real parent stashed in mpDialogParent.
555 void Dialog::doDeferredInit(WinBits nBits)
557 VclPtr<vcl::Window> pParent = mpDialogParent;
558 mpDialogParent = nullptr;
559 ImplInitDialog(pParent, nBits | WB_BORDER, mnInitFlag);
560 mbIsDeferredInit = false;
563 Dialog::Dialog(vcl::Window* pParent, const OUString& rID, const OUString& rUIXMLDescription)
564 : SystemWindow(WindowType::DIALOG)
565 , mnInitFlag(InitFlag::Default)
567 ImplLOKNotifier(pParent);
568 ImplInitDialogData();
569 loadUI(pParent, OUStringToOString(rID, RTL_TEXTENCODING_UTF8), rUIXMLDescription);
572 Dialog::Dialog(vcl::Window* pParent, WinBits nStyle, InitFlag eFlag)
573 : SystemWindow(WindowType::DIALOG)
574 , mnInitFlag(eFlag)
576 ImplLOKNotifier(pParent);
577 ImplInitDialogData();
578 ImplInitDialog( pParent, nStyle, eFlag );
581 void Dialog::set_action_area(VclButtonBox* pBox)
583 mpActionArea.set(pBox);
584 if (pBox)
586 const DialogStyle& rDialogStyle =
587 GetSettings().GetStyleSettings().GetDialogStyle();
588 pBox->set_border_width(rDialogStyle.action_area_border);
592 void Dialog::set_content_area(VclBox* pBox)
594 mpContentArea.set(pBox);
597 void Dialog::settingOptimalLayoutSize(Window *pBox)
599 const DialogStyle& rDialogStyle =
600 GetSettings().GetStyleSettings().GetDialogStyle();
601 VclBox * pBox2 = static_cast<VclBox*>(pBox);
602 pBox2->set_border_width(rDialogStyle.content_area_border);
605 Dialog::~Dialog()
607 disposeOnce();
610 void Dialog::dispose()
612 mpDialogImpl.reset();
613 RemoveFromDlgList();
614 mpActionArea.clear();
615 mpContentArea.clear();
617 css::uno::Reference< css::uno::XComponentContext > xContext(
618 comphelper::getProcessComponentContext() );
619 css::uno::Reference<css::frame::XGlobalEventBroadcaster> xEventBroadcaster(css::frame::theGlobalEventBroadcaster::get(xContext), css::uno::UNO_SET_THROW);
620 css::document::DocumentEvent aObject;
621 aObject.EventName = "DialogClosed";
622 xEventBroadcaster->documentEventOccured(aObject);
623 UITestLogger::getInstance().log("Close Dialog");
625 if (comphelper::LibreOfficeKit::isActive())
627 if(const vcl::ILibreOfficeKitNotifier* pNotifier = GetLOKNotifier())
629 pNotifier->notifyWindow(GetLOKWindowId(), "close");
630 ReleaseLOKNotifier();
634 SystemWindow::dispose();
637 IMPL_LINK_NOARG(Dialog, ImplAsyncCloseHdl, void*, void)
639 Close();
642 bool Dialog::EventNotify( NotifyEvent& rNEvt )
644 // first call the base class due to Tab control
645 bool bRet = SystemWindow::EventNotify( rNEvt );
646 if ( !bRet )
648 if ( rNEvt.GetType() == MouseNotifyEvent::KEYINPUT )
650 const KeyEvent* pKEvt = rNEvt.GetKeyEvent();
651 vcl::KeyCode aKeyCode = pKEvt->GetKeyCode();
652 sal_uInt16 nKeyCode = aKeyCode.GetCode();
654 if ( (nKeyCode == KEY_ESCAPE) &&
655 ((GetStyle() & WB_CLOSEABLE) || ImplGetCancelButton( this ) || ImplGetOKButton( this )) )
657 // #i89505# for the benefit of slightly mentally challenged implementations
658 // like e.g. SfxModelessDialog which destroy themselves inside Close()
659 // post this Close asynchronous so we can leave our key handler before
660 // we get destroyed
661 PostUserEvent( LINK( this, Dialog, ImplAsyncCloseHdl ), nullptr, true);
662 return true;
665 else if ( rNEvt.GetType() == MouseNotifyEvent::GETFOCUS )
667 // make sure the dialog is still modal
668 // changing focus between application frames may
669 // have re-enabled input for our parent
670 if( mbInExecute && mbModalMode )
672 ImplSetModalInputMode( false );
673 ImplSetModalInputMode( true );
675 // #93022# def-button might have changed after show
676 if( !mnMousePositioned )
678 mnMousePositioned = 1;
679 ImplMouseAutoPos( this );
686 return bRet;
689 //What we really want here is something that gives the available width and
690 //height of a users screen, taking away the space taken up the OS
691 //taskbar, menus, etc.
692 Size bestmaxFrameSizeForScreenSize(const Size &rScreenSize)
694 #ifndef IOS
695 tools::Long w = rScreenSize.Width();
696 if (w <= 800)
697 w -= 15;
698 else if (w <= 1024)
699 w -= 65;
700 else
701 w -= 115;
703 tools::Long h = rScreenSize.Height();
704 if (h <= 768)
705 h -= 50;
706 else
707 h -= 100;
709 return Size(std::max<tools::Long>(w, 640 - 15),
710 std::max<tools::Long>(h, 480 - 50));
711 #else
712 // Don't bother with ancient magic numbers of unclear relevance on non-desktop apps anyway. It
713 // seems that at least currently in the iOS app, this function is called just once per dialog,
714 // with a rScreenSize parameter of 1x1 (!). This would lead to always returning 625x430 which is
715 // a bit random and needlessly small on an iPad at least. We want something that closely will
716 // just fit on the display in either orientation.
718 // We ignore the rScreenSize as it will be the dummy 1x1 from iosinst.cxx (see "Totally wrong of course").
719 (void) rScreenSize;
721 const int n = std::min<CGFloat>([[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height);
722 return Size(n-10, n-10);
723 #endif
726 void Dialog::SetPopupMenuHdl(const Link<const CommandEvent&, bool>& rLink)
728 mpDialogImpl->m_aPopupMenuHdl = rLink;
731 void Dialog::SetInstallLOKNotifierHdl(const Link<void*, vcl::ILibreOfficeKitNotifier*>& rLink)
733 mpDialogImpl->m_aInstallLOKNotifierHdl = rLink;
736 void Dialog::StateChanged( StateChangedType nType )
738 if (nType == StateChangedType::InitShow)
740 DoInitialLayout();
742 const bool bKitActive = comphelper::LibreOfficeKit::isActive();
743 if (bKitActive)
745 std::vector<vcl::LOKPayloadItem> aItems;
746 aItems.emplace_back("type", "dialog");
747 aItems.emplace_back("size", GetSizePixel().toString());
748 if (!GetText().isEmpty())
749 aItems.emplace_back("title", GetText().toUtf8());
751 if (const vcl::ILibreOfficeKitNotifier* pNotifier = GetLOKNotifier())
753 pNotifier->notifyWindow(GetLOKWindowId(), "created", aItems);
754 pNotifier->notifyWindow(GetLOKWindowId(), "created", aItems);
756 else
758 vcl::ILibreOfficeKitNotifier* pViewShell = mpDialogImpl->m_aInstallLOKNotifierHdl.Call(nullptr);
759 if (pViewShell)
761 SetLOKNotifier(pViewShell);
762 pViewShell->notifyWindow(GetLOKWindowId(), "created", aItems);
767 if ( !HasChildPathFocus() || HasFocus() )
768 GrabFocusToFirstControl();
769 if ( !(GetStyle() & WB_CLOSEABLE) )
771 if ( ImplGetCancelButton( this ) || ImplGetOKButton( this ) )
773 if ( ImplGetBorderWindow() )
774 static_cast<ImplBorderWindow*>(ImplGetBorderWindow())->SetCloseButton();
778 ImplMouseAutoPos( this );
780 else if (nType == StateChangedType::Text)
782 if (const vcl::ILibreOfficeKitNotifier* pNotifier = GetLOKNotifier())
784 std::vector<vcl::LOKPayloadItem> aPayload;
785 aPayload.emplace_back("title", GetText().toUtf8());
786 pNotifier->notifyWindow(GetLOKWindowId(), "title_changed", aPayload);
790 SystemWindow::StateChanged( nType );
792 if (nType == StateChangedType::ControlBackground)
794 ImplInitSettings();
795 Invalidate();
798 if (!mbModalMode && nType == StateChangedType::Visible)
800 if (const vcl::ILibreOfficeKitNotifier* pNotifier = GetLOKNotifier())
802 std::vector<vcl::LOKPayloadItem> aPayload;
803 aPayload.emplace_back("title", GetText().toUtf8());
804 pNotifier->notifyWindow(GetLOKWindowId(), IsVisible()? OUString("show"): OUString("hide"), aPayload);
809 void Dialog::DataChanged( const DataChangedEvent& rDCEvt )
811 SystemWindow::DataChanged( rDCEvt );
813 if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
814 (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
816 ImplInitSettings();
817 Invalidate();
821 bool Dialog::Close()
823 VclPtr<vcl::Window> xWindow = this;
824 CallEventListeners( VclEventId::WindowClose );
825 if ( xWindow->IsDisposed() )
826 return false;
828 if ( mpWindowImpl->mxWindowPeer.is() && IsCreatedWithToolkit() && !IsInExecute() )
829 return false;
831 // If there's a cancel button with a custom handler, then always give it a chance to
832 // handle Dialog::Close
833 PushButton* pCustomCancelButton;
834 PushButton* pCancelButton = dynamic_cast<PushButton*>(get_widget_for_response(RET_CANCEL));
835 if (!mbInClose && pCancelButton && pCancelButton->GetClickHdl().IsSet())
836 pCustomCancelButton = pCancelButton;
837 else
838 pCustomCancelButton = nullptr;
840 mbInClose = true;
842 if (pCustomCancelButton)
844 pCustomCancelButton->Click();
845 if (xWindow->IsDisposed())
846 return true;
847 mbInClose = false;
848 return false;
851 if ( !(GetStyle() & WB_CLOSEABLE) )
853 bool bRet = true;
854 PushButton* pButton = ImplGetCancelButton( this );
855 if ( pButton )
856 pButton->Click();
857 else
859 pButton = ImplGetOKButton( this );
860 if ( pButton )
861 pButton->Click();
862 else
863 bRet = false;
865 if ( xWindow->IsDisposed() )
866 return true;
867 return bRet;
870 if (IsInExecute() || mpDialogImpl->maEndCtx.isSet())
872 EndDialog();
873 mbInClose = false;
874 return true;
876 else
878 mbInClose = false;
879 return SystemWindow::Close();
883 bool Dialog::ImplStartExecute()
885 setDeferredProperties();
887 if (IsInExecute() || mpDialogImpl->maEndCtx.isSet())
889 #ifdef DBG_UTIL
890 SAL_WARN( "vcl", "Dialog::StartExecuteModal() is called in Dialog::StartExecuteModal(): "
891 << ImplGetDialogText(this) );
892 #endif
893 return false;
896 ImplSVData* pSVData = ImplGetSVData();
898 const bool bKitActive = comphelper::LibreOfficeKit::isActive();
900 const bool bModal = GetType() != WindowType::MODELESSDIALOG;
902 if (bModal)
904 if (bKitActive && !GetLOKNotifier())
905 SetLOKNotifier(mpDialogImpl->m_aInstallLOKNotifierHdl.Call(nullptr));
907 switch ( Application::GetDialogCancelMode() )
909 case DialogCancelMode::Off:
910 break;
911 case DialogCancelMode::Silent:
912 if (bModal && GetLOKNotifier())
914 // check if there's already some dialog being ::Execute()d
915 const bool bDialogExecuting = std::any_of(pSVData->mpWinData->mpExecuteDialogs.begin(),
916 pSVData->mpWinData->mpExecuteDialogs.end(),
917 [](const Dialog* pDialog) {
918 return pDialog->IsInSyncExecute();
920 if (!(bDialogExecuting && IsInSyncExecute()))
921 break;
922 else
923 SAL_WARN("lok.dialog", "Dialog \"" << ImplGetDialogText(this) << "\" is being synchronously executed over an existing synchronously executing dialog.");
926 SAL_INFO(
927 "vcl",
928 "Dialog \"" << ImplGetDialogText(this)
929 << "\"cancelled in silent mode");
930 return false;
931 default: // default cannot happen
932 case DialogCancelMode::Fatal:
933 std::abort();
936 #ifdef DBG_UTIL
937 vcl::Window* pParent = GetParent();
938 if ( pParent )
940 pParent = pParent->ImplGetFirstOverlapWindow();
941 SAL_WARN_IF( !pParent->IsReallyVisible(), "vcl",
942 "Dialog::StartExecuteModal() - Parent not visible" );
943 SAL_WARN_IF( !pParent->IsInputEnabled(), "vcl",
944 "Dialog::StartExecuteModal() - Parent input disabled, use another parent to ensure modality!" );
945 SAL_WARN_IF( pParent->IsInModalMode(), "vcl",
946 "Dialog::StartExecuteModal() - Parent already modally disabled, use another parent to ensure modality!" );
948 #endif
950 // link all dialogs which are being executed
951 pSVData->mpWinData->mpExecuteDialogs.push_back(this);
953 // stop capturing, in order to have control over the dialog
954 if (pSVData->mpWinData->mpTrackWin)
955 pSVData->mpWinData->mpTrackWin->EndTracking(TrackingEventFlags::Cancel);
956 if (pSVData->mpWinData->mpCaptureWin)
957 pSVData->mpWinData->mpCaptureWin->ReleaseMouse();
958 EnableInput();
961 mbInExecute = true;
962 // no real modality in LibreOfficeKit
963 if (!bKitActive && bModal)
964 SetModalInputMode(true);
966 // FIXME: no layouting, workaround some clipping issues
967 ImplAdjustNWFSizes();
969 css::uno::Reference< css::uno::XComponentContext > xContext(
970 comphelper::getProcessComponentContext());
971 bool bForceFocusAndToFront(officecfg::Office::Common::View::NewDocumentHandling::ForceFocusAndToFront::get(xContext));
972 ShowFlags showFlags = bForceFocusAndToFront ? ShowFlags::ForegroundTask : ShowFlags::NONE;
973 Show(true, showFlags);
975 if (bModal)
976 pSVData->maAppData.mnModalMode++;
978 css::uno::Reference<css::frame::XGlobalEventBroadcaster> xEventBroadcaster(
979 css::frame::theGlobalEventBroadcaster::get(xContext), css::uno::UNO_SET_THROW);
980 css::document::DocumentEvent aObject;
981 aObject.EventName = "DialogExecute";
982 xEventBroadcaster->documentEventOccured(aObject);
983 if (bModal)
984 UITestLogger::getInstance().log("Open Modal " + get_id());
985 else
986 UITestLogger::getInstance().log("Open Modeless " + get_id());
988 if (comphelper::LibreOfficeKit::isActive())
990 if (const vcl::ILibreOfficeKitNotifier* pNotifier = GetLOKNotifier())
992 // Dialog boxes don't get the Resize call and they
993 // can have invalid size at 'created' message above.
994 // If there is no difference, the client should detect it and ignore us,
995 // otherwise, this should make sure that the window has the correct size.
996 std::vector<vcl::LOKPayloadItem> aItems;
997 aItems.emplace_back("size", GetSizePixel().toString());
998 pNotifier->notifyWindow(GetLOKWindowId(), "size_changed", aItems);
1002 return true;
1005 void Dialog::ImplEndExecuteModal()
1007 ImplSVData* pSVData = ImplGetSVData();
1008 pSVData->maAppData.mnModalMode--;
1011 short Dialog::Execute()
1013 // Once the Android app is based on same idea as the iOS one currently
1014 // being developed, no conditional should be needed here. Until then,
1015 // play it safe.
1016 #if HAVE_FEATURE_DESKTOP || defined IOS
1017 VclPtr<vcl::Window> xWindow = this;
1019 mbInSyncExecute = true;
1020 comphelper::ScopeGuard aGuard([&]() {
1021 mbInSyncExecute = false;
1024 if ( !ImplStartExecute() )
1025 return 0;
1027 // Yield util EndDialog is called or dialog gets destroyed
1028 // (the latter should not happen, but better safe than sorry
1029 while ( !xWindow->IsDisposed() && mbInExecute )
1030 Application::Yield();
1032 ImplEndExecuteModal();
1033 #ifdef DBG_UTIL
1034 assert (!mpDialogParent || !mpDialogParent->IsDisposed());
1035 #endif
1036 if ( !xWindow->IsDisposed() )
1037 xWindow.clear();
1038 else
1040 OSL_FAIL( "Dialog::Execute() - Dialog destroyed in Execute()" );
1043 tools::Long nRet = mpDialogImpl->mnResult;
1044 mpDialogImpl->mnResult = -1;
1046 return static_cast<short>(nRet);
1048 #else
1049 return RET_OK;
1050 #endif
1053 // virtual
1054 bool Dialog::StartExecuteAsync( VclAbstractDialog::AsyncContext &rCtx )
1056 const bool bModal = GetType() != WindowType::MODELESSDIALOG;
1057 if (!ImplStartExecute())
1059 rCtx.mxOwner.disposeAndClear();
1060 rCtx.mxOwnerDialogController.reset();
1061 rCtx.mxOwnerSelf.reset();
1062 return false;
1065 mpDialogImpl->maEndCtx = rCtx;
1066 mpDialogImpl->mbStartedModal = bModal;
1068 return true;
1071 void Dialog::RemoveFromDlgList()
1073 ImplSVData* pSVData = ImplGetSVData();
1074 auto& rExecuteDialogs = pSVData->mpWinData->mpExecuteDialogs;
1076 // remove dialog from the list of dialogs which are being executed
1077 rExecuteDialogs.erase(std::remove_if(rExecuteDialogs.begin(), rExecuteDialogs.end(), [this](VclPtr<Dialog>& dialog){ return dialog.get() == this; }), rExecuteDialogs.end());
1080 void Dialog::EndDialog( tools::Long nResult )
1082 if (!mbInExecute || IsDisposed())
1083 return;
1085 const bool bModal = GetType() != WindowType::MODELESSDIALOG;
1087 Hide();
1089 if (comphelper::LibreOfficeKit::isActive())
1091 if(const vcl::ILibreOfficeKitNotifier* pNotifier = GetLOKNotifier())
1093 pNotifier->notifyWindow(GetLOKWindowId(), "close");
1094 ReleaseLOKNotifier();
1098 if (bModal)
1100 SetModalInputMode(false);
1102 RemoveFromDlgList();
1104 // set focus to previous modal dialog if it is modal for
1105 // the same frame parent (or NULL)
1106 ImplSVData* pSVData = ImplGetSVData();
1107 if (!pSVData->mpWinData->mpExecuteDialogs.empty())
1109 VclPtr<Dialog> pPrevious = pSVData->mpWinData->mpExecuteDialogs.back();
1111 vcl::Window* pFrameParent = ImplGetFrameWindow()->ImplGetParent();
1112 vcl::Window* pPrevFrameParent = pPrevious->ImplGetFrameWindow()? pPrevious->ImplGetFrameWindow()->ImplGetParent(): nullptr;
1113 if( ( !pFrameParent && !pPrevFrameParent ) ||
1114 ( pFrameParent && pPrevFrameParent && pFrameParent->ImplGetFrame() == pPrevFrameParent->ImplGetFrame() )
1117 pPrevious->GrabFocus();
1122 mpDialogImpl->mnResult = nResult;
1124 if ( mpDialogImpl->mbStartedModal )
1125 ImplEndExecuteModal();
1127 if ( mpDialogImpl && mpDialogImpl->maEndCtx.isSet() )
1129 auto fn = std::move(mpDialogImpl->maEndCtx.maEndDialogFn);
1130 // std::move leaves maEndDialogFn in a valid state with unspecified
1131 // value. For the SwSyncBtnDlg case gcc and msvc left maEndDialogFn
1132 // unset, but clang left maEndDialogFn at its original value, keeping
1133 // an extra reference to the DialogController in its lambda giving
1134 // an inconsistent lifecycle for the dialog. Force it to be unset.
1135 mpDialogImpl->maEndCtx.maEndDialogFn = nullptr;
1136 fn(nResult);
1139 if ( mpDialogImpl && mpDialogImpl->mbStartedModal )
1141 mpDialogImpl->mbStartedModal = false;
1142 mpDialogImpl->mnResult = -1;
1144 mbInExecute = false;
1146 if ( mpDialogImpl )
1148 // Destroy ourselves (if we have a context with VclPtr owner)
1149 std::shared_ptr<weld::DialogController> xOwnerDialogController = std::move(mpDialogImpl->maEndCtx.mxOwnerDialogController);
1150 std::shared_ptr<weld::Dialog> xOwnerSelf = std::move(mpDialogImpl->maEndCtx.mxOwnerSelf);
1151 mpDialogImpl->maEndCtx.mxOwner.disposeAndClear();
1152 xOwnerDialogController.reset();
1153 xOwnerSelf.reset();
1157 namespace vcl
1159 void EndAllDialogs( vcl::Window const * pParent )
1161 ImplSVData* pSVData = ImplGetSVData();
1162 auto& rExecuteDialogs = pSVData->mpWinData->mpExecuteDialogs;
1164 for (auto it = rExecuteDialogs.rbegin(); it != rExecuteDialogs.rend(); ++it)
1166 if (!pParent || pParent->IsWindowOrChild(*it, true))
1168 (*it)->EndDialog();
1169 (*it)->PostUserEvent(Link<void*, void>());
1174 void EnableDialogInput(vcl::Window* pWindow)
1176 if (Dialog* pDialog = dynamic_cast<Dialog*>(pWindow))
1178 pDialog->EnableInput();
1182 bool CloseDialog(vcl::Window* pWindow)
1184 if (Dialog* pDialog = dynamic_cast<Dialog*>(pWindow))
1186 pDialog->Close();
1187 return true;
1189 return false;
1193 void Dialog::SetModalInputMode( bool bModal )
1195 if ( bModal == mbModalMode )
1196 return;
1198 ImplGetFrame()->SetModal(bModal);
1200 if (GetParent())
1202 SalFrame* pFrame = GetParent()->ImplGetFrame();
1203 pFrame->NotifyModalHierarchy(bModal);
1206 ImplSetModalInputMode(bModal);
1209 void Dialog::ImplSetModalInputMode( bool bModal )
1211 if ( bModal == mbModalMode )
1212 return;
1214 // previously Execute()'d dialog - the one below the top-most one
1215 VclPtr<Dialog> pPrevious;
1216 ImplSVData* pSVData = ImplGetSVData();
1217 auto& rExecuteDialogs = pSVData->mpWinData->mpExecuteDialogs;
1218 if (rExecuteDialogs.size() > 1)
1219 pPrevious = rExecuteDialogs[rExecuteDialogs.size() - 2];
1221 mbModalMode = bModal;
1222 if ( bModal )
1224 // Disable the prev Modal Dialog, because our dialog must close at first,
1225 // before the other dialog can be closed (because the other dialog
1226 // is on stack since our dialog returns)
1227 if (pPrevious && !pPrevious->IsWindowOrChild(this, true))
1228 pPrevious->EnableInput(false, this);
1230 // determine next overlap dialog parent
1231 vcl::Window* pParent = GetParent();
1232 if ( pParent )
1234 // #103716# dialogs should always be modal to the whole frame window
1235 // #115933# disable the whole frame hierarchy, useful if our parent
1236 // is a modeless dialog
1237 mpDialogParent = pParent->mpWindowImpl->mpFrameWindow;
1238 mpDialogParent->IncModalCount();
1241 else
1243 if ( mpDialogParent )
1245 // #115933# re-enable the whole frame hierarchy again (see above)
1246 // note that code in getfocus assures that we do not accidentally enable
1247 // windows that were disabled before
1248 mpDialogParent->DecModalCount();
1251 // Enable the prev Modal Dialog
1252 if (pPrevious && !pPrevious->IsWindowOrChild(this, true))
1254 pPrevious->EnableInput(true, this);
1256 // ensure continued modality of prev dialog
1257 // do not change modality counter
1259 // #i119994# need find the last modal dialog before reactive it
1260 if (pPrevious->IsModalInputMode() || !pPrevious->IsWindowOrChild(this, true))
1262 pPrevious->ImplSetModalInputMode(false);
1263 pPrevious->ImplSetModalInputMode(true);
1269 void Dialog::GrabFocusToFirstControl()
1271 vcl::Window* pFocusControl;
1273 // find focus control, even if the dialog has focus
1274 if ( HasFocus() )
1275 pFocusControl = nullptr;
1276 else
1278 // prefer a child window which had focus before
1279 pFocusControl = ImplGetFirstOverlapWindow()->mpWindowImpl->mpLastFocusWindow;
1280 // find the control out of the dialog control
1281 if ( pFocusControl )
1282 pFocusControl = ImplFindDlgCtrlWindow( pFocusControl );
1284 // no control had the focus before or the control is not
1285 // part of the tab-control, now give focus to the
1286 // first control in the tab-control
1287 if ( !pFocusControl ||
1288 !(pFocusControl->GetStyle() & WB_TABSTOP) ||
1289 !isVisibleInLayout(pFocusControl) ||
1290 !isEnabledInLayout(pFocusControl) || !pFocusControl->IsInputEnabled() )
1292 pFocusControl = ImplGetDlgWindow( 0, GetDlgWindowType::First );
1294 if ( pFocusControl )
1295 pFocusControl->ImplControlFocus( GetFocusFlags::Init );
1298 void Dialog::GetDrawWindowBorder( sal_Int32& rLeftBorder, sal_Int32& rTopBorder, sal_Int32& rRightBorder, sal_Int32& rBottomBorder ) const
1300 ScopedVclPtrInstance<ImplBorderWindow> aImplWin( static_cast<vcl::Window*>(const_cast<Dialog *>(this)), WB_BORDER|WB_STDWORK, BorderWindowStyle::Overlap );
1301 aImplWin->GetBorder( rLeftBorder, rTopBorder, rRightBorder, rBottomBorder );
1304 void Dialog::Draw( OutputDevice* pDev, const Point& rPos, DrawFlags )
1306 Point aPos = pDev->LogicToPixel( rPos );
1307 Size aSize = GetSizePixel();
1309 Wallpaper aWallpaper = GetBackground();
1310 if ( !aWallpaper.IsBitmap() )
1311 ImplInitSettings();
1313 pDev->Push();
1314 pDev->SetMapMode();
1315 pDev->SetLineColor();
1317 if ( aWallpaper.IsBitmap() )
1318 pDev->DrawBitmapEx( aPos, aSize, aWallpaper.GetBitmap() );
1319 else
1321 pDev->SetFillColor( aWallpaper.GetColor() );
1322 pDev->DrawRect( tools::Rectangle( aPos, aSize ) );
1325 if (!( GetStyle() & WB_NOBORDER ))
1327 ScopedVclPtrInstance< ImplBorderWindow > aImplWin( this, WB_BORDER|WB_STDWORK, BorderWindowStyle::Overlap );
1328 aImplWin->SetText( GetText() );
1329 aImplWin->setPosSizePixel( aPos.X(), aPos.Y(), aSize.Width(), aSize.Height() );
1330 aImplWin->SetDisplayActive( true );
1331 aImplWin->InitView();
1333 aImplWin->Draw( pDev, aPos );
1336 pDev->Pop();
1339 void Dialog::queue_resize(StateChangedType eReason)
1341 if (IsInClose())
1342 return;
1343 SystemWindow::queue_resize(eReason);
1346 void Dialog::Resize()
1348 SystemWindow::Resize();
1350 if (comphelper::LibreOfficeKit::isDialogPainting())
1351 return;
1353 if (const vcl::ILibreOfficeKitNotifier* pNotifier = GetLOKNotifier())
1355 std::vector<vcl::LOKPayloadItem> aItems;
1356 aItems.emplace_back("size", GetSizePixel().toString());
1357 pNotifier->notifyWindow(GetLOKWindowId(), "size_changed", aItems);
1361 bool Dialog::set_property(const OString &rKey, const OUString &rValue)
1363 if (rKey == "border-width")
1364 set_border_width(rValue.toInt32());
1365 else
1366 return SystemWindow::set_property(rKey, rValue);
1367 return true;
1370 FactoryFunction Dialog::GetUITestFactory() const
1372 return DialogUIObject::create;
1375 IMPL_LINK(Dialog, ResponseHdl, Button*, pButton, void)
1377 auto aFind = mpDialogImpl->maResponses.find(pButton);
1378 if (aFind == mpDialogImpl->maResponses.end())
1379 return;
1380 short nResponse = aFind->second;
1381 if (nResponse == RET_HELP)
1383 vcl::Window* pFocusWin = Application::GetFocusWindow();
1384 if (!pFocusWin)
1385 pFocusWin = pButton;
1386 HelpEvent aEvt(pFocusWin->GetPointerPosPixel(), HelpEventMode::CONTEXT);
1387 pFocusWin->RequestHelp(aEvt);
1388 return;
1390 EndDialog(nResponse);
1393 void Dialog::add_button(PushButton* pButton, int response, bool bTransferOwnership)
1395 if (bTransferOwnership)
1396 mpDialogImpl->maOwnedButtons.push_back(pButton);
1397 mpDialogImpl->maResponses[pButton] = response;
1398 switch (pButton->GetType())
1400 case WindowType::PUSHBUTTON:
1402 if (!pButton->GetClickHdl().IsSet())
1403 pButton->SetClickHdl(LINK(this, Dialog, ResponseHdl));
1404 break;
1406 //insist that the response ids match the default actions for those
1407 //widgets, and leave their default handlers in place
1408 case WindowType::OKBUTTON:
1409 assert(mpDialogImpl->get_response(pButton) == RET_OK);
1410 break;
1411 case WindowType::CANCELBUTTON:
1412 assert(mpDialogImpl->get_response(pButton) == RET_CANCEL || mpDialogImpl->get_response(pButton) == RET_CLOSE);
1413 break;
1414 case WindowType::HELPBUTTON:
1415 assert(mpDialogImpl->get_response(pButton) == RET_HELP);
1416 break;
1417 default:
1418 SAL_WARN("vcl.layout", "The type of widget " <<
1419 pButton->GetHelpId() << " is currently not handled");
1420 break;
1424 vcl::Window* Dialog::get_widget_for_response(int response)
1426 //copy explicit responses
1427 std::map<VclPtr<vcl::Window>, short> aResponses(mpDialogImpl->maResponses);
1429 if (mpActionArea)
1431 //add implicit responses
1432 for (vcl::Window* pChild = mpActionArea->GetWindow(GetWindowType::FirstChild); pChild;
1433 pChild = pChild->GetWindow(GetWindowType::Next))
1435 if (aResponses.find(pChild) != aResponses.end())
1436 continue;
1437 switch (pChild->GetType())
1439 case WindowType::OKBUTTON:
1440 aResponses[pChild] = RET_OK;
1441 break;
1442 case WindowType::CANCELBUTTON:
1443 aResponses[pChild] = RET_CANCEL;
1444 break;
1445 case WindowType::HELPBUTTON:
1446 aResponses[pChild] = RET_HELP;
1447 break;
1448 default:
1449 break;
1454 for (const auto& a : aResponses)
1456 if (a.second == response)
1457 return a.first;
1460 return nullptr;
1463 int Dialog::get_default_response() const
1465 //copy explicit responses
1466 std::map<VclPtr<vcl::Window>, short> aResponses(mpDialogImpl->maResponses);
1468 if (mpActionArea)
1470 //add implicit responses
1471 for (vcl::Window* pChild = mpActionArea->GetWindow(GetWindowType::FirstChild); pChild;
1472 pChild = pChild->GetWindow(GetWindowType::Next))
1474 if (aResponses.find(pChild) != aResponses.end())
1475 continue;
1476 switch (pChild->GetType())
1478 case WindowType::OKBUTTON:
1479 aResponses[pChild] = RET_OK;
1480 break;
1481 case WindowType::CANCELBUTTON:
1482 aResponses[pChild] = RET_CANCEL;
1483 break;
1484 case WindowType::HELPBUTTON:
1485 aResponses[pChild] = RET_HELP;
1486 break;
1487 default:
1488 break;
1493 for (const auto& a : aResponses)
1495 if (a.first->GetStyle() & WB_DEFBUTTON)
1497 return a.second;
1500 return RET_CANCEL;
1503 void Dialog::set_default_response(int response)
1505 //copy explicit responses
1506 std::map<VclPtr<vcl::Window>, short> aResponses(mpDialogImpl->maResponses);
1508 if (mpActionArea)
1510 //add implicit responses
1511 for (vcl::Window* pChild = mpActionArea->GetWindow(GetWindowType::FirstChild); pChild;
1512 pChild = pChild->GetWindow(GetWindowType::Next))
1514 if (aResponses.find(pChild) != aResponses.end())
1515 continue;
1516 switch (pChild->GetType())
1518 case WindowType::OKBUTTON:
1519 aResponses[pChild] = RET_OK;
1520 break;
1521 case WindowType::CANCELBUTTON:
1522 aResponses[pChild] = RET_CANCEL;
1523 break;
1524 case WindowType::HELPBUTTON:
1525 aResponses[pChild] = RET_HELP;
1526 break;
1527 default:
1528 break;
1533 for (auto& a : aResponses)
1535 if (a.second == response)
1537 a.first->SetStyle(a.first->GetStyle() | WB_DEFBUTTON);
1538 a.first->GrabFocus();
1540 else
1542 a.first->SetStyle(a.first->GetStyle() & ~WB_DEFBUTTON);
1547 VclBuilderContainer::VclBuilderContainer()
1551 VclBuilderContainer::~VclBuilderContainer()
1555 void Dialog::Activate()
1557 if (GetType() == WindowType::MODELESSDIALOG)
1559 css::uno::Reference< css::uno::XComponentContext > xContext(
1560 comphelper::getProcessComponentContext() );
1561 css::uno::Reference<css::frame::XGlobalEventBroadcaster> xEventBroadcaster(css::frame::theGlobalEventBroadcaster::get(xContext), css::uno::UNO_SET_THROW);
1562 css::document::DocumentEvent aObject;
1563 aObject.EventName = "ModelessDialogVisible";
1564 xEventBroadcaster->documentEventOccured(aObject);
1566 SystemWindow::Activate();
1569 void Dialog::Command(const CommandEvent& rCEvt)
1571 if (mpDialogImpl && mpDialogImpl->m_aPopupMenuHdl.Call(rCEvt))
1572 return;
1573 SystemWindow::Command(rCEvt);
1576 void TopLevelWindowLocker::incBusy(const weld::Widget* pIgnore)
1578 // lock any toplevel windows from being closed until busy is over
1579 std::vector<VclPtr<vcl::Window>> aTopLevels;
1580 vcl::Window *pTopWin = Application::GetFirstTopLevelWindow();
1581 while (pTopWin)
1583 vcl::Window* pCandidate = pTopWin;
1584 if (pCandidate->GetType() == WindowType::BORDERWINDOW)
1585 pCandidate = pCandidate->GetWindow(GetWindowType::FirstChild);
1586 // tdf#125266 ignore HelpTextWindows
1587 if (pCandidate &&
1588 pCandidate->GetType() != WindowType::HELPTEXTWINDOW &&
1589 pCandidate->GetType() != WindowType::FLOATINGWINDOW &&
1590 pCandidate->GetFrameWeld() != pIgnore)
1592 aTopLevels.push_back(pCandidate);
1594 pTopWin = Application::GetNextTopLevelWindow(pTopWin);
1596 for (auto& a : aTopLevels)
1598 a->IncModalCount();
1599 a->ImplGetFrame()->NotifyModalHierarchy(true);
1601 m_aBusyStack.push(aTopLevels);
1604 void TopLevelWindowLocker::decBusy()
1606 // unlock locked toplevel windows from being closed now busy is over
1607 for (auto& a : m_aBusyStack.top())
1609 if (a->IsDisposed())
1610 continue;
1611 a->DecModalCount();
1612 a->ImplGetFrame()->NotifyModalHierarchy(false);
1614 m_aBusyStack.pop();
1617 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */