1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_features.h>
22 #include <com/sun/star/beans/XPropertySet.hpp>
23 #include <com/sun/star/util/thePathSettings.hpp>
24 #include <com/sun/star/frame/theGlobalEventBroadcaster.hpp>
25 #include <comphelper/lok.hxx>
26 #include <comphelper/processfactory.hxx>
27 #include <comphelper/scopeguard.hxx>
28 #include <officecfg/Office/Common.hxx>
29 #include <osl/file.hxx>
31 #include <tools/debug.hxx>
38 #include <rtl/strbuf.hxx>
39 #include <sal/log.hxx>
43 #include <vcl/abstdlg.hxx>
44 #include <vcl/builder.hxx>
45 #include <vcl/layout.hxx>
46 #include <vcl/svapp.hxx>
47 #include <vcl/event.hxx>
48 #include <vcl/floatwin.hxx>
49 #include <vcl/wrkwin.hxx>
50 #include <vcl/button.hxx>
51 #include <vcl/mnemonic.hxx>
52 #include <vcl/dialog.hxx>
53 #include <vcl/tabctrl.hxx>
54 #include <vcl/tabpage.hxx>
55 #include <vcl/decoview.hxx>
56 #include <vcl/msgbox.hxx>
57 #include <vcl/unowrap.hxx>
58 #include <vcl/settings.hxx>
59 #include <vcl/uitest/uiobject.hxx>
60 #include <vcl/virdev.hxx>
61 #include <vcl/IDialogRenderable.hxx>
62 #include <salframe.hxx>
67 static OString
ImplGetDialogText( Dialog
* pDialog
)
69 OStringBuffer
aErrorStr(OUStringToOString(
70 pDialog
->GetText(), RTL_TEXTENCODING_UTF8
));
73 if (MessBox
* pMessBox
= dynamic_cast<MessBox
*>(pDialog
))
75 sMessage
= pMessBox
->GetMessText();
77 else if (MessageDialog
* pMessDialog
= dynamic_cast<MessageDialog
*>(pDialog
))
79 sMessage
= pMessDialog
->get_primary_text();
82 if (!sMessage
.isEmpty())
84 aErrorStr
.append(", ");
85 aErrorStr
.append(OUStringToOString(
86 sMessage
, RTL_TEXTENCODING_UTF8
));
88 return aErrorStr
.makeStringAndClear();
91 static bool ImplIsMnemonicCtrl( vcl::Window
* pWindow
)
93 if( ! pWindow
->GetSettings().GetStyleSettings().GetAutoMnemonic() )
96 if ( (pWindow
->GetType() == WINDOW_RADIOBUTTON
) ||
97 (pWindow
->GetType() == WINDOW_CHECKBOX
) ||
98 (pWindow
->GetType() == WINDOW_TRISTATEBOX
) ||
99 (pWindow
->GetType() == WINDOW_PUSHBUTTON
) )
102 if ( pWindow
->GetType() == WINDOW_FIXEDTEXT
)
104 FixedText
*pText
= static_cast<FixedText
*>(pWindow
);
105 if (pText
->get_mnemonic_widget())
107 //This is the legacy pre-layout logic which we retain
108 //until we can be sure we can remove it
109 if (pWindow
->GetStyle() & WB_NOLABEL
)
111 vcl::Window
* pNextWindow
= pWindow
->GetWindow( GetWindowType::Next
);
114 pNextWindow
= pNextWindow
->GetWindow( GetWindowType::Client
);
115 if ( !(pNextWindow
->GetStyle() & WB_TABSTOP
) ||
116 (pNextWindow
->GetType() == WINDOW_FIXEDTEXT
) ||
117 (pNextWindow
->GetType() == WINDOW_GROUPBOX
) ||
118 (pNextWindow
->GetType() == WINDOW_RADIOBUTTON
) ||
119 (pNextWindow
->GetType() == WINDOW_CHECKBOX
) ||
120 (pNextWindow
->GetType() == WINDOW_TRISTATEBOX
) ||
121 (pNextWindow
->GetType() == WINDOW_PUSHBUTTON
) )
130 // Called by native error dialog popup implementations
131 void ImplHideSplash()
133 ImplSVData
* pSVData
= ImplGetSVData();
134 if( pSVData
->mpIntroWindow
)
135 pSVData
->mpIntroWindow
->Hide();
138 //Get next window after pChild of a pTopLevel window as
139 //if any intermediate layout widgets didn't exist
140 vcl::Window
* nextLogicalChildOfParent(vcl::Window
*pTopLevel
, vcl::Window
*pChild
)
142 vcl::Window
*pLastChild
= pChild
;
144 if (isContainerWindow(*pChild
))
145 pChild
= pChild
->GetWindow(GetWindowType::FirstChild
);
147 pChild
= pChild
->GetWindow(GetWindowType::Next
);
151 vcl::Window
*pParent
= pLastChild
->GetParent();
154 if (pParent
== pTopLevel
)
156 pLastChild
= pParent
;
157 pChild
= pParent
->GetWindow(GetWindowType::Next
);
160 if (pChild
&& isContainerWindow(*pChild
))
161 pChild
= nextLogicalChildOfParent(pTopLevel
, pChild
);
166 vcl::Window
* prevLogicalChildOfParent(vcl::Window
*pTopLevel
, vcl::Window
*pChild
)
168 vcl::Window
*pLastChild
= pChild
;
170 if (isContainerWindow(*pChild
))
171 pChild
= pChild
->GetWindow(GetWindowType::LastChild
);
173 pChild
= pChild
->GetWindow(GetWindowType::Prev
);
177 vcl::Window
*pParent
= pLastChild
->GetParent();
180 if (pParent
== pTopLevel
)
182 pLastChild
= pParent
;
183 pChild
= pParent
->GetWindow(GetWindowType::Prev
);
186 if (pChild
&& isContainerWindow(*pChild
))
187 pChild
= prevLogicalChildOfParent(pTopLevel
, pChild
);
192 //Get first window of a pTopLevel window as
193 //if any intermediate layout widgets didn't exist
194 vcl::Window
* firstLogicalChildOfParent(vcl::Window
*pTopLevel
)
196 vcl::Window
*pChild
= pTopLevel
->GetWindow(GetWindowType::FirstChild
);
197 if (pChild
&& isContainerWindow(*pChild
))
198 pChild
= nextLogicalChildOfParent(pTopLevel
, pChild
);
202 void Accelerator::GenerateAutoMnemonicsOnHierarchy(vcl::Window
* pWindow
)
204 MnemonicGenerator aMnemonicGenerator
;
205 vcl::Window
* pGetChild
;
208 // register the assigned mnemonics
209 pGetChild
= pWindow
->GetWindow( GetWindowType::FirstChild
);
212 pChild
= pGetChild
->ImplGetWindow();
213 aMnemonicGenerator
.RegisterMnemonic( pChild
->GetText() );
214 pGetChild
= nextLogicalChildOfParent(pWindow
, pGetChild
);
217 // take the Controls of the dialog into account for TabPages
218 if ( pWindow
->GetType() == WINDOW_TABPAGE
)
220 vcl::Window
* pParent
= pWindow
->GetParent();
221 if ( pParent
->GetType() == WINDOW_TABCONTROL
)
222 pParent
= pParent
->GetParent();
224 if ( (pParent
->GetStyle() & (WB_DIALOGCONTROL
| WB_NODIALOGCONTROL
)) == WB_DIALOGCONTROL
)
226 pGetChild
= pParent
->GetWindow( GetWindowType::FirstChild
);
229 pChild
= pGetChild
->ImplGetWindow();
230 aMnemonicGenerator
.RegisterMnemonic( pChild
->GetText() );
231 pGetChild
= nextLogicalChildOfParent(pWindow
, pGetChild
);
236 // assign mnemonics to Controls which have none
237 pGetChild
= pWindow
->GetWindow( GetWindowType::FirstChild
);
240 pChild
= pGetChild
->ImplGetWindow();
241 if ( ImplIsMnemonicCtrl( pChild
) )
243 OUString aText
= pChild
->GetText();
244 OUString aNewText
= aMnemonicGenerator
.CreateMnemonic( aText
);
245 if ( aText
!= aNewText
)
246 pChild
->SetText( aNewText
);
249 pGetChild
= nextLogicalChildOfParent(pWindow
, pGetChild
);
253 static VclButtonBox
* getActionArea(Dialog
*pDialog
)
255 VclButtonBox
*pButtonBox
= nullptr;
256 if (pDialog
->isLayoutEnabled())
258 vcl::Window
*pBox
= pDialog
->GetWindow(GetWindowType::FirstChild
);
259 vcl::Window
*pChild
= pBox
->GetWindow(GetWindowType::LastChild
);
262 pButtonBox
= dynamic_cast<VclButtonBox
*>(pChild
);
265 pChild
= pChild
->GetWindow(GetWindowType::Prev
);
271 static vcl::Window
* getActionAreaButtonList(Dialog
*pDialog
)
273 VclButtonBox
* pButtonBox
= getActionArea(pDialog
);
275 return pButtonBox
->GetWindow(GetWindowType::FirstChild
);
276 return pDialog
->GetWindow(GetWindowType::FirstChild
);
279 static PushButton
* ImplGetDefaultButton( Dialog
* pDialog
)
281 vcl::Window
* pChild
= getActionAreaButtonList(pDialog
);
284 if ( pChild
->ImplIsPushButton() )
286 PushButton
* pPushButton
= static_cast<PushButton
*>(pChild
);
287 if ( pPushButton
->ImplIsDefButton() )
291 pChild
= pChild
->GetWindow( GetWindowType::Next
);
297 static PushButton
* ImplGetOKButton( Dialog
* pDialog
)
299 vcl::Window
* pChild
= getActionAreaButtonList(pDialog
);
302 if ( pChild
->GetType() == WINDOW_OKBUTTON
)
303 return static_cast<PushButton
*>(pChild
);
305 pChild
= pChild
->GetWindow( GetWindowType::Next
);
311 static PushButton
* ImplGetCancelButton( Dialog
* pDialog
)
313 vcl::Window
* pChild
= getActionAreaButtonList(pDialog
);
317 if ( pChild
->GetType() == WINDOW_CANCELBUTTON
)
318 return static_cast<PushButton
*>(pChild
);
320 pChild
= pChild
->GetWindow( GetWindowType::Next
);
326 static void ImplMouseAutoPos( Dialog
* pDialog
)
328 MouseSettingsOptions nMouseOptions
= pDialog
->GetSettings().GetMouseSettings().GetOptions();
329 if ( nMouseOptions
& MouseSettingsOptions::AutoCenterPos
)
331 Size aSize
= pDialog
->GetOutputSizePixel();
332 pDialog
->SetPointerPosPixel( Point( aSize
.Width()/2, aSize
.Height()/2 ) );
334 else if ( nMouseOptions
& MouseSettingsOptions::AutoDefBtnPos
)
336 vcl::Window
* pWindow
= ImplGetDefaultButton( pDialog
);
338 pWindow
= ImplGetOKButton( pDialog
);
340 pWindow
= ImplGetCancelButton( pDialog
);
343 Size aSize
= pWindow
->GetOutputSizePixel();
344 pWindow
->SetPointerPosPixel( Point( aSize
.Width()/2, aSize
.Height()/2 ) );
352 VclAbstractDialog::AsyncContext maEndCtx
;
354 DialogImpl() : mnResult( -1 ), mbStartedModal( false ) {}
357 void Dialog::ImplInitDialogData()
359 mpWindowImpl
->mbDialog
= true;
360 mpPrevExecuteDlg
= nullptr;
361 mpNextExecuteDlg
= nullptr;
365 mbPaintComplete
= false;
366 mpContentArea
.clear();
367 mpActionArea
.clear();
368 mnMousePositioned
= 0;
369 mpDialogImpl
.reset(new DialogImpl
);
372 void Dialog::ImplInit( vcl::Window
* pParent
, WinBits nStyle
, InitFlag eFlag
)
374 SystemWindowFlags nSysWinMode
= Application::GetSystemWindowMode();
376 if ( !(nStyle
& WB_NODIALOGCONTROL
) )
377 nStyle
|= WB_DIALOGCONTROL
;
378 nStyle
|= WB_ROLLABLE
;
380 // Now, all Dialogs are per default system windows !!!
381 nStyle
|= WB_SYSTEMWINDOW
;
383 if (eFlag
== InitFlag::NoParent
)
385 else if (!pParent
) // parent is NULL: get the default Dialog parent
387 pParent
= Application::GetDefDialogParent();
388 if ( !pParent
&& !(nStyle
& WB_SYSTEMWINDOW
) )
389 pParent
= ImplGetSVData()->maWinData
.mpAppWin
;
391 // If Parent is disabled, then we search for a modal dialog
393 if ( pParent
&& (!pParent
->IsInputEnabled() || pParent
->IsInModalMode()) )
395 ImplSVData
* pSVData
= ImplGetSVData();
396 Dialog
* pExeDlg
= pSVData
->maWinData
.mpLastExecuteDlg
;
399 // only if visible and enabled
400 if ( pParent
->ImplGetFirstOverlapWindow()->IsWindowOrChild( pExeDlg
, true ) &&
401 pExeDlg
->IsReallyVisible() &&
402 pExeDlg
->IsEnabled() && pExeDlg
->IsInputEnabled() && !pExeDlg
->IsInModalMode() )
408 pExeDlg
= pExeDlg
->mpPrevExecuteDlg
;
413 if ( !pParent
|| (nStyle
& WB_SYSTEMWINDOW
) ||
414 (pParent
->mpWindowImpl
->mpFrameData
->mbNeedSysWindow
&& !(nSysWinMode
& SystemWindowFlags::NOAUTOMODE
)) ||
415 (nSysWinMode
& SystemWindowFlags::DIALOG
) )
417 // create window with a small border ?
418 if ( (nStyle
& (WB_BORDER
| WB_NOBORDER
| WB_MOVEABLE
| WB_SIZEABLE
| WB_CLOSEABLE
)) == WB_BORDER
)
420 VclPtrInstance
<ImplBorderWindow
> pBorderWin( pParent
, nStyle
, BorderWindowStyle::Frame
);
421 SystemWindow::ImplInit( pBorderWin
, nStyle
& ~WB_BORDER
, nullptr );
422 pBorderWin
->mpWindowImpl
->mpClientWindow
= this;
423 pBorderWin
->GetBorder( mpWindowImpl
->mnLeftBorder
, mpWindowImpl
->mnTopBorder
, mpWindowImpl
->mnRightBorder
, mpWindowImpl
->mnBottomBorder
);
424 mpWindowImpl
->mpBorderWindow
= pBorderWin
;
425 mpWindowImpl
->mpRealParent
= pParent
;
429 mpWindowImpl
->mbFrame
= true;
430 mpWindowImpl
->mbOverlapWin
= true;
431 SystemWindow::ImplInit( pParent
, (nStyle
& (WB_MOVEABLE
| WB_SIZEABLE
| WB_ROLLABLE
| WB_CLOSEABLE
| WB_STANDALONE
)) | WB_CLOSEABLE
, nullptr );
432 // Now set all style bits
433 mpWindowImpl
->mnStyle
= nStyle
;
438 VclPtrInstance
<ImplBorderWindow
> pBorderWin( pParent
, nStyle
, BorderWindowStyle::Overlap
| BorderWindowStyle::Border
);
439 SystemWindow::ImplInit( pBorderWin
, nStyle
& ~WB_BORDER
, nullptr );
440 pBorderWin
->mpWindowImpl
->mpClientWindow
= this;
441 pBorderWin
->GetBorder( mpWindowImpl
->mnLeftBorder
, mpWindowImpl
->mnTopBorder
, mpWindowImpl
->mnRightBorder
, mpWindowImpl
->mnBottomBorder
);
442 mpWindowImpl
->mpBorderWindow
= pBorderWin
;
443 mpWindowImpl
->mpRealParent
= pParent
;
446 SetActivateMode( ActivateModeFlags::GrabFocus
);
451 void Dialog::ApplySettings(vcl::RenderContext
& rRenderContext
)
453 if (IsControlBackground())
456 SetBackground(GetControlBackground());
458 else if (rRenderContext
.IsNativeControlSupported(ControlType::WindowBackground
, ControlPart::BackgroundDialog
))
461 mpWindowImpl
->mnNativeBackground
= ControlPart::BackgroundDialog
;
462 EnableChildTransparentMode();
466 // fallback to settings color
467 rRenderContext
.SetBackground(GetSettings().GetStyleSettings().GetDialogColor());
471 void Dialog::ImplInitSettings()
474 if (IsControlBackground())
475 SetBackground(GetControlBackground());
477 else if( IsNativeControlSupported(ControlType::WindowBackground
, ControlPart::BackgroundDialog
))
479 mpWindowImpl
->mnNativeBackground
= ControlPart::BackgroundDialog
;
480 EnableChildTransparentMode();
482 // fallback to settings color
484 SetBackground(GetSettings().GetStyleSettings().GetDialogColor());
487 void Dialog::ImplLOKNotifier(vcl::Window
* pParent
)
489 if (comphelper::LibreOfficeKit::isActive() && pParent
)
491 if (VclPtr
<vcl::Window
> pWin
= pParent
->GetParentWithLOKNotifier())
493 SetLOKNotifier(pWin
->GetLOKNotifier());
498 Dialog::Dialog( WindowType nType
)
499 : SystemWindow( nType
)
500 , mnInitFlag(InitFlag::Default
)
502 ImplInitDialogData();
505 void VclBuilderContainer::disposeBuilder()
508 m_pUIBuilder
->disposeBuilder();
511 OUString
VclBuilderContainer::getUIRootDir()
513 /*to-do, check if user config has an override before using shared one, etc*/
514 css::uno::Reference
< css::util::XPathSettings
> xPathSettings
= css::util::thePathSettings::get(
515 ::comphelper::getProcessComponentContext() );
517 OUString sShareLayer
= xPathSettings
->getBasePathShareLayer();
519 // "UIConfig" is a "multi path" ... use first part only here!
520 sal_Int32 nPos
= sShareLayer
.indexOf(';');
522 sShareLayer
= sShareLayer
.copy(0, nPos
);
524 // Note: May be an user uses URLs without a final slash! Check it ...
525 if (!sShareLayer
.endsWith("/"))
528 sShareLayer
+= "soffice.cfg/";
529 /*to-do, can we merge all this foo with existing soffice.cfg finding code, etc*/
533 //we can't change sizeable after the fact, so need to defer until we know and then
534 //do the init. Find the real parent stashed in mpDialogParent.
535 void Dialog::doDeferredInit(WinBits nBits
)
537 VclPtr
<vcl::Window
> pParent
= mpDialogParent
;
538 mpDialogParent
= nullptr;
539 ImplInit(pParent
, nBits
, mnInitFlag
);
540 mbIsDefferedInit
= false;
543 Dialog::Dialog(vcl::Window
* pParent
, const OUString
& rID
, const OUString
& rUIXMLDescription
)
544 : SystemWindow(WINDOW_DIALOG
)
545 , mnInitFlag(InitFlag::Default
)
547 ImplLOKNotifier(pParent
);
548 ImplInitDialogData();
549 loadUI(pParent
, OUStringToOString(rID
, RTL_TEXTENCODING_UTF8
), rUIXMLDescription
);
552 Dialog::Dialog(vcl::Window
* pParent
, const OUString
& rID
, const OUString
& rUIXMLDescription
, WindowType nType
, InitFlag eFlag
)
553 : SystemWindow(nType
)
556 ImplLOKNotifier(pParent
);
557 ImplInitDialogData();
558 loadUI(pParent
, OUStringToOString(rID
, RTL_TEXTENCODING_UTF8
), rUIXMLDescription
);
561 Dialog::Dialog(vcl::Window
* pParent
, WinBits nStyle
, InitFlag eFlag
)
562 : SystemWindow(WINDOW_DIALOG
)
565 ImplLOKNotifier(pParent
);
566 ImplInitDialogData();
567 ImplInit( pParent
, nStyle
, eFlag
);
570 void Dialog::set_action_area(VclButtonBox
* pBox
)
572 mpActionArea
.set(pBox
);
575 void Dialog::set_content_area(VclBox
* pBox
)
577 mpContentArea
.set(pBox
);
580 void Dialog::settingOptimalLayoutSize(Window
*pBox
)
582 const DialogStyle
& rDialogStyle
=
583 GetSettings().GetStyleSettings().GetDialogStyle();
584 VclBox
* pBox2
= static_cast<VclBox
*>(pBox
);
585 pBox2
->set_border_width(rDialogStyle
.content_area_border
);
586 pBox2
->set_spacing(pBox2
->get_spacing() +
587 rDialogStyle
.content_area_spacing
);
589 VclButtonBox
*pActionArea
= getActionArea(this);
592 pActionArea
->set_border_width(rDialogStyle
.action_area_border
);
593 pActionArea
->set_spacing(rDialogStyle
.button_spacing
);
602 void Dialog::dispose()
604 mpDialogImpl
.reset();
606 mpPrevExecuteDlg
.clear();
607 mpNextExecuteDlg
.clear();
608 mpActionArea
.clear();
609 mpContentArea
.clear();
611 css::uno::Reference
< css::uno::XComponentContext
> xContext(
612 comphelper::getProcessComponentContext() );
613 css::uno::Reference
<css::frame::XGlobalEventBroadcaster
> xEventBroadcaster(css::frame::theGlobalEventBroadcaster::get(xContext
), css::uno::UNO_QUERY_THROW
);
614 css::document::DocumentEvent aObject
;
615 aObject
.EventName
= "DialogClosed";
616 xEventBroadcaster
->documentEventOccured(aObject
);
618 if (comphelper::LibreOfficeKit::isActive())
620 if(const vcl::ILibreOfficeKitNotifier
* pNotifier
= GetLOKNotifier())
622 pNotifier
->notifyWindow(GetLOKWindowId(), "close");
623 ReleaseLOKNotifier();
627 SystemWindow::dispose();
630 IMPL_LINK_NOARG(Dialog
, ImplAsyncCloseHdl
, void*, void)
635 bool Dialog::EventNotify( NotifyEvent
& rNEvt
)
637 // first call the base class due to Tab control
638 bool bRet
= SystemWindow::EventNotify( rNEvt
);
641 if ( rNEvt
.GetType() == MouseNotifyEvent::KEYINPUT
)
643 const KeyEvent
* pKEvt
= rNEvt
.GetKeyEvent();
644 vcl::KeyCode aKeyCode
= pKEvt
->GetKeyCode();
645 sal_uInt16 nKeyCode
= aKeyCode
.GetCode();
647 if ( (nKeyCode
== KEY_ESCAPE
) &&
648 ((GetStyle() & WB_CLOSEABLE
) || ImplGetCancelButton( this ) || ImplGetOKButton( this )) )
650 // #i89505# for the benefit of slightly mentally challenged implementations
651 // like e.g. SfxModelessDialog which destroy themselves inside Close()
652 // post this Close asynchronous so we can leave our key handler before
654 PostUserEvent( LINK( this, Dialog
, ImplAsyncCloseHdl
), nullptr, true);
658 else if ( rNEvt
.GetType() == MouseNotifyEvent::GETFOCUS
)
660 // make sure the dialog is still modal
661 // changing focus between application frames may
662 // have re-enabled input for our parent
663 if( mbInExecute
&& mbModalMode
)
665 SetModalInputMode( false );
666 SetModalInputMode( true );
668 // #93022# def-button might have changed after show
669 if( !mnMousePositioned
)
671 mnMousePositioned
= 1;
672 ImplMouseAutoPos( this );
682 //What we really want here is something that gives the available width and
683 //height of a users screen, taking away the space taken up the OS
684 //taskbar, menus, etc.
685 Size
bestmaxFrameSizeForScreenSize(const Size
&rScreenSize
)
687 long w
= rScreenSize
.Width();
695 long h
= rScreenSize
.Height();
701 return Size(std::max
<long>(w
, 640 - 15),
702 std::max
<long>(h
, 480 - 50));
705 void Dialog::StateChanged( StateChangedType nType
)
707 if (nType
== StateChangedType::InitShow
)
711 if ( !HasChildPathFocus() || HasFocus() )
712 GrabFocusToFirstControl();
713 if ( !(GetStyle() & WB_CLOSEABLE
) )
715 if ( ImplGetCancelButton( this ) || ImplGetOKButton( this ) )
717 if ( ImplGetBorderWindow() )
718 static_cast<ImplBorderWindow
*>(ImplGetBorderWindow())->SetCloseButton();
722 ImplMouseAutoPos( this );
724 else if (nType
== StateChangedType::Text
)
726 if (const vcl::ILibreOfficeKitNotifier
* pNotifier
= GetLOKNotifier())
728 std::vector
<vcl::LOKPayloadItem
> aPayload
;
729 aPayload
.emplace_back("title", GetText().toUtf8());
730 pNotifier
->notifyWindow(GetLOKWindowId(), "title_changed", aPayload
);
734 SystemWindow::StateChanged( nType
);
736 if (nType
== StateChangedType::ControlBackground
)
742 if (!mbModalMode
&& nType
== StateChangedType::Visible
)
744 css::uno::Reference
< css::uno::XComponentContext
> xContext(
745 comphelper::getProcessComponentContext() );
746 css::uno::Reference
<css::frame::XGlobalEventBroadcaster
> xEventBroadcaster(css::frame::theGlobalEventBroadcaster::get(xContext
), css::uno::UNO_QUERY_THROW
);
747 css::document::DocumentEvent aObject
;
748 aObject
.EventName
= "ModelessDialogVisible";
749 xEventBroadcaster
->documentEventOccured(aObject
);
753 void Dialog::DataChanged( const DataChangedEvent
& rDCEvt
)
755 SystemWindow::DataChanged( rDCEvt
);
757 if ( (rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
758 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
) )
767 VclPtr
<vcl::Window
> xWindow
= this;
768 CallEventListeners( VCLEVENT_WINDOW_CLOSE
);
769 if ( xWindow
->IsDisposed() )
772 if ( mpWindowImpl
->mxWindowPeer
.is() && IsCreatedWithToolkit() && !IsInExecute() )
777 if ( !(GetStyle() & WB_CLOSEABLE
) )
780 PushButton
* pButton
= ImplGetCancelButton( this );
785 pButton
= ImplGetOKButton( this );
791 if ( xWindow
->IsDisposed() )
805 return SystemWindow::Close();
809 bool Dialog::ImplStartExecuteModal()
811 setDeferredProperties();
813 if ( mbInExecute
|| mpDialogImpl
->maEndCtx
.isSet() )
816 OStringBuffer aErrorStr
;
817 aErrorStr
.append("Dialog::StartExecuteModal() is called in Dialog::StartExecuteModal(): ");
818 aErrorStr
.append(ImplGetDialogText(this));
819 OSL_FAIL(aErrorStr
.getStr());
824 ImplSVData
* pSVData
= ImplGetSVData();
826 switch ( Application::GetDialogCancelMode() )
828 case Application::DialogCancelMode::Off
:
830 case Application::DialogCancelMode::Silent
:
831 if (GetLOKNotifier())
833 // check if there's already some dialog being ::Execute()d
834 Dialog
* pExeDlg
= pSVData
->maWinData
.mpLastExecuteDlg
;
835 while (pExeDlg
&& !pExeDlg
->IsInSyncExecute())
836 pExeDlg
= pExeDlg
->mpPrevExecuteDlg
;
838 const bool bDialogExecuting
= pExeDlg
? pExeDlg
->IsInSyncExecute() : false;
839 if (!(bDialogExecuting
&& IsInSyncExecute()))
842 SAL_WARN("lok.dialog", "Dialog \"" << ImplGetDialogText(this) << "\" is being synchronously executed over an existing synchronously executing dialog.");
847 "Dialog \"" << ImplGetDialogText(this).getStr()
848 << "\"cancelled in silent mode");
850 default: // default cannot happen
851 case Application::DialogCancelMode::Fatal
:
856 vcl::Window
* pParent
= GetParent();
859 pParent
= pParent
->ImplGetFirstOverlapWindow();
860 SAL_WARN_IF( !pParent
->IsReallyVisible(), "vcl",
861 "Dialog::StartExecuteModal() - Parent not visible" );
862 SAL_WARN_IF( !pParent
->IsInputEnabled(), "vcl",
863 "Dialog::StartExecuteModal() - Parent input disabled, use another parent to ensure modality!" );
864 SAL_WARN_IF( pParent
->IsInModalMode(), "vcl",
865 "Dialog::StartExecuteModal() - Parent already modally disabled, use another parent to ensure modality!" );
870 // link all dialogs which are being executed
871 mpPrevExecuteDlg
= pSVData
->maWinData
.mpLastExecuteDlg
;
872 if (mpPrevExecuteDlg
)
873 mpPrevExecuteDlg
->mpNextExecuteDlg
= this;
874 pSVData
->maWinData
.mpLastExecuteDlg
= this;
876 // stop capturing, in order to have control over the dialog
877 if ( pSVData
->maWinData
.mpTrackWin
)
878 pSVData
->maWinData
.mpTrackWin
->EndTracking( TrackingEventFlags::Cancel
);
879 if ( pSVData
->maWinData
.mpCaptureWin
)
880 pSVData
->maWinData
.mpCaptureWin
->ReleaseMouse();
885 NotifyEvent
aNEvt( MouseNotifyEvent::EXECUTEDIALOG
, this );
886 GetParent()->CompatNotify( aNEvt
);
889 // no real modality in LibreOfficeKit
890 if (!comphelper::LibreOfficeKit::isActive())
891 SetModalInputMode(true);
893 // FIXME: no layouting, workaround some clipping issues
894 ImplAdjustNWFSizes();
896 css::uno::Reference
< css::uno::XComponentContext
> xContext(
897 comphelper::getProcessComponentContext());
898 bool bForceFocusAndToFront(officecfg::Office::Common::View::NewDocumentHandling::ForceFocusAndToFront::get(xContext
));
899 ShowFlags showFlags
= bForceFocusAndToFront
? ShowFlags::ForegroundTask
: ShowFlags::NONE
;
900 Show(true, showFlags
);
902 pSVData
->maAppData
.mnModalMode
++;
904 css::uno::Reference
<css::frame::XGlobalEventBroadcaster
> xEventBroadcaster(css::frame::theGlobalEventBroadcaster::get(xContext
), css::uno::UNO_QUERY_THROW
);
905 css::document::DocumentEvent aObject
;
906 aObject
.EventName
= "DialogExecute";
907 xEventBroadcaster
->documentEventOccured(aObject
);
909 if (comphelper::LibreOfficeKit::isActive())
911 if(const vcl::ILibreOfficeKitNotifier
* pNotifier
= GetLOKNotifier())
913 std::vector
<vcl::LOKPayloadItem
> aItems
;
914 aItems
.emplace_back("type", "dialog");
915 aItems
.emplace_back("size", GetSizePixel().toString());
916 if (!GetText().isEmpty())
917 aItems
.emplace_back("title", GetText().toUtf8());
918 pNotifier
->notifyWindow(GetLOKWindowId(), "created", aItems
);
925 void Dialog::ImplEndExecuteModal()
927 ImplSVData
* pSVData
= ImplGetSVData();
928 pSVData
->maAppData
.mnModalMode
--;
931 void Dialog::PrePaint(vcl::RenderContext
& rRenderContext
)
933 SystemWindow::PrePaint(rRenderContext
);
934 mbPaintComplete
= false;
937 void Dialog::PostPaint(vcl::RenderContext
& rRenderContext
)
939 SystemWindow::PostPaint(rRenderContext
);
940 mbPaintComplete
= true;
943 std::vector
<OString
> Dialog::getAllPageUIXMLDescriptions() const
945 // default has no pages
946 return std::vector
<OString
>();
949 bool Dialog::selectPageByUIXMLDescription(const OString
& /*rUIXMLDescription*/)
951 // default cannot select anything (which is okay, return true)
955 void Dialog::ensureRepaint()
959 mbPaintComplete
= false;
961 while (!mbPaintComplete
)
963 Application::Yield();
967 Bitmap
Dialog::createScreenshot()
969 // same prerequisites as in Execute()
970 setDeferredProperties();
971 ImplAdjustNWFSizes();
976 return GetBitmap(Point(), GetOutputSizePixel());
979 short Dialog::Execute()
981 #if HAVE_FEATURE_DESKTOP
982 VclPtr
<vcl::Window
> xWindow
= this;
984 mbInSyncExecute
= true;
985 comphelper::ScopeGuard
aGuard([&]() {
986 mbInSyncExecute
= false;
988 if ( !ImplStartExecuteModal() )
991 // Yield util EndDialog is called or dialog gets destroyed
992 // (the latter should not happen, but better safe than sorry
993 while ( !xWindow
->IsDisposed() && mbInExecute
)
994 Application::Yield();
996 mbInSyncExecute
= false;
997 ImplEndExecuteModal();
999 assert (!mpDialogParent
|| !mpDialogParent
->IsDisposed());
1001 if ( !xWindow
->IsDisposed() )
1006 OSL_FAIL( "Dialog::Execute() - Dialog destroyed in Execute()" );
1010 long nRet
= mpDialogImpl
->mnResult
;
1011 mpDialogImpl
->mnResult
= -1;
1016 // touch_ui_dialog_modal was dummied out both for Android and iOS (well, TiledLibreOffice anyway)
1017 // For Android it returned MLODialogOK always, for iOS Cancel. Let's go with OK.
1018 // MLODialogResult result = touch_ui_dialog_modal(kind, ImplGetDialogText(this).getStr());
1025 void Dialog::StartExecuteModal( const Link
<Dialog
&,void>& rEndDialogHdl
)
1027 VclAbstractDialog::AsyncContext aCtx
;
1028 VclPtr
<Dialog
> ref(this);
1029 aCtx
.maEndDialogFn
= [ref
,rEndDialogHdl
](sal_Int32
){ rEndDialogHdl
.Call(*ref
.get()); };
1030 StartExecuteAsync(aCtx
);
1034 bool Dialog::StartExecuteAsync( VclAbstractDialog::AsyncContext
&rCtx
)
1036 if ( !ImplStartExecuteModal() )
1038 rCtx
.mxOwner
.disposeAndClear();
1042 mpDialogImpl
->maEndCtx
= rCtx
;
1043 mpDialogImpl
->mbStartedModal
= true;
1048 void Dialog::RemoveFromDlgList()
1050 // remove dialog from the list of dialogs which are being executed
1051 ImplSVData
* pSVData
= ImplGetSVData();
1052 if (pSVData
->maWinData
.mpLastExecuteDlg
== this)
1054 if (mpPrevExecuteDlg
)
1055 pSVData
->maWinData
.mpLastExecuteDlg
= mpPrevExecuteDlg
;
1057 pSVData
->maWinData
.mpLastExecuteDlg
= mpNextExecuteDlg
;
1059 if (mpPrevExecuteDlg
)
1060 mpPrevExecuteDlg
->mpNextExecuteDlg
= mpNextExecuteDlg
;
1061 if (mpNextExecuteDlg
)
1062 mpNextExecuteDlg
->mpPrevExecuteDlg
= mpPrevExecuteDlg
;
1063 mpPrevExecuteDlg
.clear();
1064 mpNextExecuteDlg
.clear();
1067 void Dialog::EndDialog( long nResult
)
1071 SetModalInputMode( false );
1073 RemoveFromDlgList();
1075 // set focus to previous modal dialogue if it is modal for
1076 // the same frame parent (or NULL)
1077 if( mpPrevExecuteDlg
)
1079 vcl::Window
* pFrameParent
= ImplGetFrameWindow()->ImplGetParent();
1080 vcl::Window
* pPrevFrameParent
= mpPrevExecuteDlg
->ImplGetFrameWindow()? mpPrevExecuteDlg
->ImplGetFrameWindow()->ImplGetParent(): nullptr;
1081 if( ( !pFrameParent
&& !pPrevFrameParent
) ||
1082 ( pFrameParent
&& pPrevFrameParent
&& pFrameParent
->ImplGetFrame() == pPrevFrameParent
->ImplGetFrame() )
1085 mpPrevExecuteDlg
->GrabFocus();
1088 mpPrevExecuteDlg
= nullptr;
1089 mpNextExecuteDlg
= nullptr;
1094 NotifyEvent
aNEvt( MouseNotifyEvent::ENDEXECUTEDIALOG
, this );
1095 GetParent()->CompatNotify( aNEvt
);
1098 mpDialogImpl
->mnResult
= nResult
;
1100 if ( mpDialogImpl
->mbStartedModal
)
1102 ImplEndExecuteModal();
1103 if (mpDialogImpl
->maEndCtx
.isSet())
1105 mpDialogImpl
->maEndCtx
.maEndDialogFn(nResult
);
1106 mpDialogImpl
->maEndCtx
.maEndDialogFn
= nullptr;
1108 mpDialogImpl
->mbStartedModal
= false;
1109 mpDialogImpl
->mnResult
= -1;
1111 mbInExecute
= false;
1114 // Destroy ourselves (if we have a context with VclPtr owner)
1115 mpDialogImpl
->maEndCtx
.mxOwner
.disposeAndClear();
1118 long Dialog::GetResult() const
1120 return mpDialogImpl
->mnResult
;
1123 void Dialog::EndAllDialogs( vcl::Window
* pParent
)
1125 ImplSVData
* pSVData
= ImplGetSVData();
1126 Dialog
* pTempModDialog
;
1127 Dialog
* pModDialog
= pSVData
->maWinData
.mpLastExecuteDlg
;
1130 pTempModDialog
= pModDialog
->mpPrevExecuteDlg
;
1131 if(!pParent
|| pParent
->IsWindowOrChild(pModDialog
,true))
1133 pModDialog
->EndDialog();
1134 pModDialog
->PostUserEvent( Link
<void*,void>() );
1136 pModDialog
= pTempModDialog
;
1140 void Dialog::SetModalInputMode( bool bModal
)
1142 if ( bModal
== mbModalMode
)
1145 mbModalMode
= bModal
;
1148 // Disable the prev Modal Dialog, because our dialog must close at first,
1149 // before the other dialog can be closed (because the other dialog
1150 // is on stack since our dialog returns)
1151 if ( mpPrevExecuteDlg
&& !mpPrevExecuteDlg
->IsWindowOrChild( this, true ) )
1152 mpPrevExecuteDlg
->EnableInput( false, this );
1154 // determine next overlap dialog parent
1155 vcl::Window
* pParent
= GetParent();
1158 // #103716# dialogs should always be modal to the whole frame window
1159 // #115933# disable the whole frame hierarchy, useful if our parent
1160 // is a modeless dialog
1161 mpDialogParent
= pParent
->mpWindowImpl
->mpFrameWindow
;
1162 mpDialogParent
->ImplIncModalCount();
1167 if ( mpDialogParent
)
1169 // #115933# re-enable the whole frame hierarchy again (see above)
1170 // note that code in getfocus assures that we do not accidentally enable
1171 // windows that were disabled before
1172 mpDialogParent
->ImplDecModalCount();
1175 // Enable the prev Modal Dialog
1176 if ( mpPrevExecuteDlg
&& !mpPrevExecuteDlg
->IsWindowOrChild( this, true ) )
1178 mpPrevExecuteDlg
->EnableInput( true, this );
1179 // ensure continued modality of prev dialog
1180 // do not change modality counter
1182 // #i119994# need find the last modal dialog before reactive it
1183 Dialog
* pPrevModalDlg
= mpPrevExecuteDlg
;
1185 while( pPrevModalDlg
&& !pPrevModalDlg
->IsModalInputMode() )
1186 pPrevModalDlg
= pPrevModalDlg
->mpPrevExecuteDlg
;
1188 if( pPrevModalDlg
&&
1189 ( pPrevModalDlg
== mpPrevExecuteDlg
.get()
1190 || !pPrevModalDlg
->IsWindowOrChild( this, true ) ) )
1192 mpPrevExecuteDlg
->SetModalInputMode( false );
1193 mpPrevExecuteDlg
->SetModalInputMode( true );
1197 ImplGetFrame()->SetModal(bModal
);
1200 void Dialog::SetModalInputMode( bool bModal
, bool bSubModalDialogs
)
1202 if ( bSubModalDialogs
)
1204 vcl::Window
* pOverlap
= ImplGetFirstOverlapWindow();
1205 pOverlap
= pOverlap
->mpWindowImpl
->mpFirstOverlap
;
1208 if ( pOverlap
->IsDialog() )
1209 static_cast<Dialog
*>(pOverlap
)->SetModalInputMode( bModal
, true );
1210 pOverlap
= pOverlap
->mpWindowImpl
->mpNext
;
1214 SetModalInputMode( bModal
);
1217 void Dialog::GrabFocusToFirstControl()
1219 vcl::Window
* pFocusControl
;
1221 // find focus control, even if the dialog has focus
1223 pFocusControl
= nullptr;
1226 // prefer a child window which had focus before
1227 pFocusControl
= ImplGetFirstOverlapWindow()->mpWindowImpl
->mpLastFocusWindow
;
1228 // find the control out of the dialog control
1229 if ( pFocusControl
)
1230 pFocusControl
= ImplFindDlgCtrlWindow( pFocusControl
);
1232 // no control had the focus before or the control is not
1233 // part of the tab-control, now give focus to the
1234 // first control in the tab-control
1235 if ( !pFocusControl
||
1236 !(pFocusControl
->GetStyle() & WB_TABSTOP
) ||
1237 !isVisibleInLayout(pFocusControl
) ||
1238 !isEnabledInLayout(pFocusControl
) || !pFocusControl
->IsInputEnabled() )
1241 pFocusControl
= ImplGetDlgWindow( n
, GetDlgWindowType::First
);
1243 if ( pFocusControl
)
1244 pFocusControl
->ImplControlFocus( GetFocusFlags::Init
);
1247 void Dialog::GetDrawWindowBorder( sal_Int32
& rLeftBorder
, sal_Int32
& rTopBorder
, sal_Int32
& rRightBorder
, sal_Int32
& rBottomBorder
) const
1249 ScopedVclPtrInstance
<ImplBorderWindow
> aImplWin( static_cast<vcl::Window
*>(const_cast<Dialog
*>(this)), WB_BORDER
|WB_STDWORK
, BorderWindowStyle::Overlap
);
1250 aImplWin
->GetBorder( rLeftBorder
, rTopBorder
, rRightBorder
, rBottomBorder
);
1253 void Dialog::Draw( OutputDevice
* pDev
, const Point
& rPos
, const Size
& rSize
, DrawFlags
)
1255 Point aPos
= pDev
->LogicToPixel( rPos
);
1256 Size aSize
= pDev
->LogicToPixel( rSize
);
1258 Wallpaper aWallpaper
= GetBackground();
1259 if ( !aWallpaper
.IsBitmap() )
1264 pDev
->SetLineColor();
1266 if ( aWallpaper
.IsBitmap() )
1267 pDev
->DrawBitmapEx( aPos
, aSize
, aWallpaper
.GetBitmap() );
1270 pDev
->SetFillColor( aWallpaper
.GetColor() );
1271 pDev
->DrawRect( Rectangle( aPos
, aSize
) );
1274 if (!( GetStyle() & WB_NOBORDER
))
1276 ScopedVclPtrInstance
< ImplBorderWindow
> aImplWin( this, WB_BORDER
|WB_STDWORK
, BorderWindowStyle::Overlap
);
1277 aImplWin
->SetText( GetText() );
1278 aImplWin
->setPosSizePixel( aPos
.X(), aPos
.Y(), aSize
.Width(), aSize
.Height() );
1279 aImplWin
->SetDisplayActive( true );
1280 aImplWin
->InitView();
1282 aImplWin
->Draw( Rectangle( aPos
, aSize
), pDev
, aPos
);
1288 void Dialog::queue_resize(StateChangedType eReason
)
1292 SystemWindow::queue_resize(eReason
);
1295 void Dialog::Resize()
1297 SystemWindow::Resize();
1299 if (comphelper::LibreOfficeKit::isDialogPainting())
1302 if (const vcl::ILibreOfficeKitNotifier
* pNotifier
= GetLOKNotifier())
1304 std::vector
<vcl::LOKPayloadItem
> aItems
;
1305 aItems
.emplace_back("size", GetSizePixel().toString());
1306 pNotifier
->notifyWindow(GetLOKWindowId(), "size_changed", aItems
);
1310 bool Dialog::set_property(const OString
&rKey
, const OString
&rValue
)
1312 if (rKey
== "border-width")
1313 set_border_width(rValue
.toInt32());
1315 return SystemWindow::set_property(rKey
, rValue
);
1319 FactoryFunction
Dialog::GetUITestFactory() const
1321 return DialogUIObject::create
;
1324 VclBuilderContainer::VclBuilderContainer()
1325 : m_pUIBuilder(nullptr)
1329 VclBuilderContainer::~VclBuilderContainer()
1333 ModelessDialog::ModelessDialog(vcl::Window
* pParent
, const OUString
& rID
, const OUString
& rUIXMLDescription
, InitFlag eFlag
)
1334 : Dialog(pParent
, rID
, rUIXMLDescription
, WINDOW_MODELESSDIALOG
, eFlag
)
1338 ModalDialog::ModalDialog( vcl::Window
* pParent
, WinBits nStyle
) :
1339 Dialog( WINDOW_MODALDIALOG
)
1341 ImplInit( pParent
, nStyle
);
1344 ModalDialog::ModalDialog( vcl::Window
* pParent
, const OUString
& rID
, const OUString
& rUIXMLDescription
) :
1345 Dialog(pParent
, rID
, rUIXMLDescription
, WINDOW_MODALDIALOG
)
1349 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */