bump product version to 4.1.6.2
[LibreOffice.git] / vcl / source / window / dialog.cxx
blob2a341c5af1bcccd7c147d61419a250c5c6ea1535
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 <com/sun/star/beans/XPropertySet.hpp>
21 #include <com/sun/star/util/PathSettings.hpp>
22 #include <comphelper/processfactory.hxx>
23 #include <osl/file.hxx>
25 #include <tools/debug.hxx>
27 #include <tools/rc.h>
28 #include <svdata.hxx>
29 #include <window.h>
30 #include <brdwin.hxx>
32 #include <rtl/strbuf.hxx>
33 #include <sal/log.hxx>
35 #include <vcl/builder.hxx>
36 #include <vcl/layout.hxx>
37 #include <vcl/svapp.hxx>
38 #include <vcl/event.hxx>
39 #include <vcl/wrkwin.hxx>
40 #include <vcl/button.hxx>
41 #include <vcl/mnemonic.hxx>
42 #include <vcl/dialog.hxx>
43 #include <vcl/decoview.hxx>
44 #include <vcl/msgbox.hxx>
45 #include <vcl/unowrap.hxx>
46 #include <iostream>
48 #ifdef ANDROID
49 #include <osl/detail/android-bootstrap.h>
50 #endif
52 // =======================================================================
54 static OString ImplGetDialogText( Dialog* pDialog )
56 OStringBuffer aErrorStr(OUStringToOString(
57 pDialog->GetText(), RTL_TEXTENCODING_UTF8));
58 if ( (pDialog->GetType() == WINDOW_MESSBOX) ||
59 (pDialog->GetType() == WINDOW_INFOBOX) ||
60 (pDialog->GetType() == WINDOW_WARNINGBOX) ||
61 (pDialog->GetType() == WINDOW_ERRORBOX) ||
62 (pDialog->GetType() == WINDOW_QUERYBOX) )
64 aErrorStr.append(", ");
65 aErrorStr.append(OUStringToOString(
66 ((MessBox*)pDialog)->GetMessText(), RTL_TEXTENCODING_UTF8));
68 return aErrorStr.makeStringAndClear();
71 // =======================================================================
73 static sal_Bool ImplIsMnemonicCtrl( Window* pWindow )
75 if( ! pWindow->GetSettings().GetStyleSettings().GetAutoMnemonic() )
76 return sal_False;
78 if ( (pWindow->GetType() == WINDOW_RADIOBUTTON) ||
79 (pWindow->GetType() == WINDOW_CHECKBOX) ||
80 (pWindow->GetType() == WINDOW_TRISTATEBOX) ||
81 (pWindow->GetType() == WINDOW_PUSHBUTTON) )
82 return sal_True;
84 if ( pWindow->GetType() == WINDOW_FIXEDTEXT )
86 if ( pWindow->GetStyle() & (WB_INFO | WB_NOLABEL) )
87 return sal_False;
88 Window* pNextWindow = pWindow->GetWindow( WINDOW_NEXT );
89 if ( !pNextWindow )
90 return sal_False;
91 pNextWindow = pNextWindow->GetWindow( WINDOW_CLIENT );
92 if ( !(pNextWindow->GetStyle() & WB_TABSTOP) ||
93 (pNextWindow->GetType() == WINDOW_FIXEDTEXT) ||
94 (pNextWindow->GetType() == WINDOW_GROUPBOX) ||
95 (pNextWindow->GetType() == WINDOW_RADIOBUTTON) ||
96 (pNextWindow->GetType() == WINDOW_CHECKBOX) ||
97 (pNextWindow->GetType() == WINDOW_TRISTATEBOX) ||
98 (pNextWindow->GetType() == WINDOW_PUSHBUTTON) )
99 return sal_False;
101 return sal_True;
104 return sal_False;
107 // -----------------------------------------------------------------------
109 // Called by native error dialog popup implementations
110 void ImplHideSplash()
112 ImplSVData* pSVData = ImplGetSVData();
113 if( pSVData->mpIntroWindow )
114 pSVData->mpIntroWindow->Hide();
117 //Get next window after pChild of a pTopLevel window as
118 //if any intermediate layout widgets didn't exist
119 Window * nextLogicalChildOfParent(Window *pTopLevel, Window *pChild)
121 Window *pLastChild = pChild;
123 if (isContainerWindow(*pChild))
124 pChild = pChild->GetWindow(WINDOW_FIRSTCHILD);
125 else
126 pChild = pChild->GetWindow(WINDOW_NEXT);
128 while (!pChild)
130 Window *pParent = pLastChild->GetParent();
131 if (!pParent)
132 return NULL;
133 if (pParent == pTopLevel)
134 return NULL;
135 pLastChild = pParent;
136 pChild = pParent->GetWindow(WINDOW_NEXT);
139 if (pChild && isContainerWindow(*pChild))
140 pChild = nextLogicalChildOfParent(pTopLevel, pChild);
142 return pChild;
145 Window * prevLogicalChildOfParent(Window *pTopLevel, Window *pChild)
147 Window *pLastChild = pChild;
149 if (isContainerWindow(*pChild))
150 pChild = pChild->GetWindow(WINDOW_LASTCHILD);
151 else
152 pChild = pChild->GetWindow(WINDOW_PREV);
154 while (!pChild)
156 Window *pParent = pLastChild->GetParent();
157 if (!pParent)
158 return NULL;
159 if (pParent == pTopLevel)
160 return NULL;
161 pLastChild = pParent;
162 pChild = pParent->GetWindow(WINDOW_PREV);
165 if (pChild && isContainerWindow(*pChild))
166 pChild = prevLogicalChildOfParent(pTopLevel, pChild);
168 return pChild;
171 //Get first window of a pTopLevel window as
172 //if any intermediate layout widgets didn't exist
173 Window * firstLogicalChildOfParent(Window *pTopLevel)
175 Window *pChild = pTopLevel->GetWindow(WINDOW_FIRSTCHILD);
176 if (pChild && isContainerWindow(*pChild))
177 pChild = nextLogicalChildOfParent(pTopLevel, pChild);
178 return pChild;
181 // -----------------------------------------------------------------------
183 void ImplWindowAutoMnemonic( Window* pWindow )
185 MnemonicGenerator aMnemonicGenerator;
186 Window* pGetChild;
187 Window* pChild;
189 // Die schon vergebenen Mnemonics registieren
190 pGetChild = pWindow->GetWindow( WINDOW_FIRSTCHILD );
191 while ( pGetChild )
193 pChild = pGetChild->ImplGetWindow();
194 aMnemonicGenerator.RegisterMnemonic( pChild->GetText() );
195 pGetChild = nextLogicalChildOfParent(pWindow, pGetChild);
198 // Bei TabPages auch noch die Controls vom Dialog beruecksichtigen
199 if ( pWindow->GetType() == WINDOW_TABPAGE )
201 Window* pParent = pWindow->GetParent();
202 if ( pParent->GetType() == WINDOW_TABCONTROL )
203 pParent = pParent->GetParent();
205 if ( (pParent->GetStyle() & (WB_DIALOGCONTROL | WB_NODIALOGCONTROL)) == WB_DIALOGCONTROL )
207 pGetChild = pParent->GetWindow( WINDOW_FIRSTCHILD );
208 while ( pGetChild )
210 pChild = pGetChild->ImplGetWindow();
211 aMnemonicGenerator.RegisterMnemonic( pChild->GetText() );
212 pGetChild = nextLogicalChildOfParent(pWindow, pGetChild);
217 // Die Mnemonics an die Controls vergeben, die noch keinen haben
218 pGetChild = pWindow->GetWindow( WINDOW_FIRSTCHILD );
219 while ( pGetChild )
221 pChild = pGetChild->ImplGetWindow();
222 if ( ImplIsMnemonicCtrl( pChild ) )
224 XubString aText = pChild->GetText();
225 if ( aMnemonicGenerator.CreateMnemonic( aText ) )
226 pChild->SetText( aText );
229 pGetChild = nextLogicalChildOfParent(pWindow, pGetChild);
233 static VclButtonBox* getActionArea(Dialog *pDialog)
235 VclButtonBox *pButtonBox = NULL;
236 if (pDialog->isLayoutEnabled())
238 Window *pBox = pDialog->GetWindow(WINDOW_FIRSTCHILD);
239 Window *pChild = pBox->GetWindow(WINDOW_LASTCHILD);
240 while (pChild)
242 pButtonBox = dynamic_cast<VclButtonBox*>(pChild);
243 if (pButtonBox)
244 break;
245 pChild = pChild->GetWindow(WINDOW_PREV);
248 return pButtonBox;
251 static Window* getActionAreaButtonList(Dialog *pDialog)
253 VclButtonBox* pButtonBox = getActionArea(pDialog);
254 if (pButtonBox)
255 return pButtonBox->GetWindow(WINDOW_FIRSTCHILD);
256 return pDialog->GetWindow(WINDOW_FIRSTCHILD);
259 // =======================================================================
261 static PushButton* ImplGetDefaultButton( Dialog* pDialog )
263 Window* pChild = getActionAreaButtonList(pDialog);
264 while ( pChild )
266 if ( pChild->ImplIsPushButton() )
268 PushButton* pPushButton = (PushButton*)pChild;
269 if ( pPushButton->ImplIsDefButton() )
270 return pPushButton;
273 pChild = pChild->GetWindow( WINDOW_NEXT );
276 return NULL;
279 // -----------------------------------------------------------------------
281 static PushButton* ImplGetOKButton( Dialog* pDialog )
283 Window* pChild = getActionAreaButtonList(pDialog);
284 while ( pChild )
286 if ( pChild->GetType() == WINDOW_OKBUTTON )
287 return (PushButton*)pChild;
289 pChild = pChild->GetWindow( WINDOW_NEXT );
292 return NULL;
295 // -----------------------------------------------------------------------
297 static PushButton* ImplGetCancelButton( Dialog* pDialog )
299 Window* pChild = getActionAreaButtonList(pDialog);
301 while ( pChild )
303 if ( pChild->GetType() == WINDOW_CANCELBUTTON )
304 return (PushButton*)pChild;
306 pChild = pChild->GetWindow( WINDOW_NEXT );
309 return NULL;
312 // -----------------------------------------------------------------------
314 static void ImplMouseAutoPos( Dialog* pDialog )
316 sal_uLong nMouseOptions = pDialog->GetSettings().GetMouseSettings().GetOptions();
317 if ( nMouseOptions & MOUSE_OPTION_AUTOCENTERPOS )
319 Size aSize = pDialog->GetOutputSizePixel();
320 pDialog->SetPointerPosPixel( Point( aSize.Width()/2, aSize.Height()/2 ) );
322 else if ( nMouseOptions & MOUSE_OPTION_AUTODEFBTNPOS )
324 Window* pWindow = ImplGetDefaultButton( pDialog );
325 if ( !pWindow )
326 pWindow = ImplGetOKButton( pDialog );
327 if ( !pWindow )
328 pWindow = ImplGetCancelButton( pDialog );
329 if ( !pWindow )
330 pWindow = pDialog;
331 Size aSize = pWindow->GetOutputSizePixel();
332 pWindow->SetPointerPosPixel( Point( aSize.Width()/2, aSize.Height()/2 ) );
336 // =======================================================================
338 struct DialogImpl
340 long mnResult;
341 bool mbStartedModal;
342 Link maEndDialogHdl;
344 DialogImpl() : mnResult( -1 ), mbStartedModal( false ) {}
347 // =======================================================================
349 void Dialog::ImplInitDialogData()
351 mpWindowImpl->mbDialog = sal_True;
352 mpDialogParent = NULL;
353 mpPrevExecuteDlg = NULL;
354 mbInExecute = sal_False;
355 mbOldSaveBack = sal_False;
356 mbInClose = sal_False;
357 mbModalMode = sal_False;
358 mpContentArea = NULL;
359 mpActionArea = NULL;
360 mbIsCalculatingInitialLayoutSize = false;
361 mnMousePositioned = 0;
362 mpDialogImpl = new DialogImpl;
364 //To-Do, reuse maResizeTimer
365 maLayoutTimer.SetTimeout(50);
366 maLayoutTimer.SetTimeoutHdl( LINK( this, Dialog, ImplHandleLayoutTimerHdl ) );
369 // -----------------------------------------------------------------------
371 void Dialog::ImplInit( Window* pParent, WinBits nStyle )
373 sal_uInt16 nSysWinMode = Application::GetSystemWindowMode();
375 if ( !(nStyle & WB_NODIALOGCONTROL) )
376 nStyle |= WB_DIALOGCONTROL;
377 nStyle |= WB_ROLLABLE;
379 // Now, all Dialogs are per default system windows !!!
380 nStyle |= WB_SYSTEMWINDOW;
383 // parent is NULL: get the default Dialog parent
384 if ( !pParent )
386 pParent = Application::GetDefDialogParent();
387 if ( !pParent && !(nStyle & WB_SYSTEMWINDOW) )
388 pParent = ImplGetSVData()->maWinData.mpAppWin;
390 // If Parent is disabled, then we search for a modal dialog
391 // in this frame
392 if ( pParent && (!pParent->IsInputEnabled() || pParent->IsInModalMode()) )
394 ImplSVData* pSVData = ImplGetSVData();
395 Dialog* pExeDlg = pSVData->maWinData.mpLastExecuteDlg;
396 while ( pExeDlg )
398 // Nur wenn er sichtbar und enabled ist
399 if ( pParent->ImplGetFirstOverlapWindow()->IsWindowOrChild( pExeDlg, sal_True ) &&
400 pExeDlg->IsReallyVisible() &&
401 pExeDlg->IsEnabled() && pExeDlg->IsInputEnabled() && !pExeDlg->IsInModalMode() )
403 pParent = pExeDlg;
404 break;
407 pExeDlg = pExeDlg->mpPrevExecuteDlg;
411 // DIALOG_NO_PARENT: explicitly don't have a parent for this Dialog
412 else if( pParent == DIALOG_NO_PARENT )
413 pParent = NULL;
416 if ( !pParent || (nStyle & WB_SYSTEMWINDOW) ||
417 (pParent->mpWindowImpl->mpFrameData->mbNeedSysWindow && !(nSysWinMode & SYSTEMWINDOW_MODE_NOAUTOMODE)) ||
418 (nSysWinMode & SYSTEMWINDOW_MODE_DIALOG) )
420 // create window with a small border ?
421 if ( (nStyle & (WB_BORDER | WB_NOBORDER | WB_MOVEABLE | WB_SIZEABLE | WB_CLOSEABLE)) == WB_BORDER )
423 ImplBorderWindow* pBorderWin = new ImplBorderWindow( pParent, nStyle, BORDERWINDOW_STYLE_FRAME );
424 SystemWindow::ImplInit( pBorderWin, nStyle & ~WB_BORDER, NULL );
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 else
432 mpWindowImpl->mbFrame = sal_True;
433 mpWindowImpl->mbOverlapWin = sal_True;
434 SystemWindow::ImplInit( pParent, (nStyle & (WB_MOVEABLE | WB_SIZEABLE | WB_ROLLABLE | WB_CLOSEABLE | WB_STANDALONE)) | WB_CLOSEABLE, NULL );
435 // Now set all style bits
436 mpWindowImpl->mnStyle = nStyle;
439 else
441 ImplBorderWindow* pBorderWin = new ImplBorderWindow( pParent, nStyle, BORDERWINDOW_STYLE_OVERLAP | BORDERWINDOW_STYLE_BORDER );
442 SystemWindow::ImplInit( pBorderWin, nStyle & ~WB_BORDER, NULL );
443 pBorderWin->mpWindowImpl->mpClientWindow = this;
444 pBorderWin->GetBorder( mpWindowImpl->mnLeftBorder, mpWindowImpl->mnTopBorder, mpWindowImpl->mnRightBorder, mpWindowImpl->mnBottomBorder );
445 mpWindowImpl->mpBorderWindow = pBorderWin;
446 mpWindowImpl->mpRealParent = pParent;
449 SetActivateMode( ACTIVATE_MODE_GRABFOCUS );
451 ImplInitSettings();
454 // -----------------------------------------------------------------------
456 void Dialog::ImplInitSettings()
458 // user override
459 if ( IsControlBackground() )
460 SetBackground( GetControlBackground() );
461 // NWF background
462 else if( IsNativeControlSupported( CTRL_WINDOW_BACKGROUND, PART_BACKGROUND_DIALOG ) )
464 mpWindowImpl->mnNativeBackground = PART_BACKGROUND_DIALOG;
465 EnableChildTransparentMode( sal_True );
467 // fallback to settings color
468 else
469 SetBackground( GetSettings().GetStyleSettings().GetDialogColor() );
472 // -----------------------------------------------------------------------
474 Dialog::Dialog( WindowType nType )
475 : SystemWindow( nType )
476 , mbIsDefferedInit(false)
478 ImplInitDialogData();
481 #define RELPATH_SHARE_LAYER OUString("soffice.cfg")
483 OUString VclBuilderContainer::getUIRootDir()
485 /*to-do, check if user config has an override before using shared one, etc*/
486 css::uno::Reference< css::util::XPathSettings > xPathSettings = css::util::PathSettings::create(
487 ::comphelper::getProcessComponentContext() );
489 OUString sShareLayer = xPathSettings->getBasePathShareLayer();
491 // "UIConfig" is a "multi path" ... use first part only here!
492 sal_Int32 nPos = sShareLayer.indexOf(';');
493 if (nPos > 0)
494 sShareLayer = sShareLayer.copy(0, nPos);
496 // Note: May be an user uses URLs without a final slash! Check it ...
497 nPos = sShareLayer.lastIndexOf('/');
498 if (nPos != sShareLayer.getLength()-1)
499 sShareLayer += "/";
501 sShareLayer += RELPATH_SHARE_LAYER; // folder
502 sShareLayer += "/";
503 /*to-do, can we merge all this foo with existing soffice.cfg finding code, etc*/
504 return sShareLayer;
507 //we can't change sizeable after the fact, so need to defer until we know and then
508 //do the init. Find the real parent stashed in mpDialogParent.
509 void Dialog::doDeferredInit(bool bResizable)
511 WinBits nBits = WB_3DLOOK|WB_CLOSEABLE|WB_MOVEABLE;
512 if (bResizable)
513 nBits |= WB_SIZEABLE;
514 Window *pParent = mpDialogParent;
515 mpDialogParent = NULL;
516 ImplInit(pParent, nBits);
517 mbIsDefferedInit = false;
520 Dialog::Dialog(Window* pParent, const OString& rID, const OUString& rUIXMLDescription)
521 : SystemWindow( WINDOW_DIALOG )
522 , mbIsDefferedInit(true)
524 ImplInitDialogData();
525 mpDialogParent = pParent; //will be unset in doDeferredInit
526 m_pUIBuilder = new VclBuilder(this, getUIRootDir(), rUIXMLDescription, rID);
529 Dialog::Dialog(Window* pParent, const OString& rID, const OUString& rUIXMLDescription, WindowType nType)
530 : SystemWindow( nType )
531 , mbIsDefferedInit(true)
533 ImplInitDialogData();
534 mpDialogParent = pParent; //will be unset in doDeferredInit
535 m_pUIBuilder = new VclBuilder(this, getUIRootDir(), rUIXMLDescription, rID);
539 // -----------------------------------------------------------------------
541 Dialog::Dialog( Window* pParent, WinBits nStyle )
542 : SystemWindow( WINDOW_DIALOG )
543 , mbIsDefferedInit(false)
545 ImplInitDialogData();
546 ImplInit( pParent, nStyle );
549 WinBits Dialog::init(Window *pParent, const ResId& rResId)
551 WinBits nStyle = ImplInitRes( rResId );
553 ImplInit( pParent, nStyle );
554 ImplLoadRes( rResId );
556 return nStyle;
559 VclButtonBox* Dialog::get_action_area()
561 return mpActionArea;
564 void Dialog::set_action_area(VclButtonBox* pActionArea)
566 mpActionArea = pActionArea;
569 VclBox* Dialog::get_content_area()
571 return mpContentArea;
574 void Dialog::set_content_area(VclBox* pContentArea)
576 mpContentArea = pContentArea;
579 // -----------------------------------------------------------------------
581 Dialog::~Dialog()
583 maLayoutTimer.Stop();
584 delete mpDialogImpl;
585 mpDialogImpl = NULL;
588 // -----------------------------------------------------------------------
590 IMPL_LINK_NOARG(Dialog, ImplAsyncCloseHdl)
592 Close();
593 return 0;
596 // -----------------------------------------------------------------------
598 long Dialog::Notify( NotifyEvent& rNEvt )
600 // Zuerst Basisklasse rufen wegen TabSteuerung
601 long nRet = SystemWindow::Notify( rNEvt );
602 if ( !nRet )
604 if ( rNEvt.GetType() == EVENT_KEYINPUT )
606 const KeyEvent* pKEvt = rNEvt.GetKeyEvent();
607 KeyCode aKeyCode = pKEvt->GetKeyCode();
608 sal_uInt16 nKeyCode = aKeyCode.GetCode();
610 if ( (nKeyCode == KEY_ESCAPE) &&
611 ((GetStyle() & WB_CLOSEABLE) || ImplGetCancelButton( this ) || ImplGetOKButton( this )) )
613 // #i89505# for the benefit of slightly mentally challenged implementations
614 // like e.g. SfxModelessDialog which destroy themselves inside Close()
615 // post this Close asynchronous so we can leave our key handler before
616 // we get destroyed
617 PostUserEvent( LINK( this, Dialog, ImplAsyncCloseHdl ), this );
618 return sal_True;
621 else if ( rNEvt.GetType() == EVENT_GETFOCUS )
623 // make sure the dialog is still modal
624 // changing focus between application frames may
625 // have re-enabled input for our parent
626 if( mbInExecute && mbModalMode )
628 // do not change modal counter (pSVData->maAppData.mnModalDialog)
629 SetModalInputMode( sal_False );
630 SetModalInputMode( sal_True );
632 // #93022# def-button might have changed after show
633 if( !mnMousePositioned )
635 mnMousePositioned = 1;
636 ImplMouseAutoPos( this );
643 return nRet;
646 //What we really want here is something that gives the available width and
647 //height of a users screen, taking away the space taken up the OS
648 //taskbar, menus, etc.
649 Size bestmaxFrameSizeForScreenSize(const Size &rScreenSize)
651 long w = rScreenSize.Width();
652 if (w <= 800)
653 w -= 15;
654 else if (w <= 1024)
655 w -= 65;
656 else
657 w -= 115;
659 long h = rScreenSize.Height();
660 if (h <= 768)
661 h -= 50;
662 else
663 h -= 100;
665 return Size(w, h);
668 void Dialog::setOptimalLayoutSize()
670 maLayoutTimer.Stop();
672 //resize dialog to fit requisition on initial show
673 VclBox *pBox = static_cast<VclBox*>(GetWindow(WINDOW_FIRSTCHILD));
675 const DialogStyle& rDialogStyle =
676 GetSettings().GetStyleSettings().GetDialogStyle();
677 pBox->set_border_width(rDialogStyle.content_area_border);
678 pBox->set_spacing(pBox->get_spacing() +
679 rDialogStyle.content_area_spacing);
681 VclButtonBox *pActionArea = getActionArea(this);
682 if (pActionArea)
684 pActionArea->set_border_width(rDialogStyle.action_area_border);
685 pActionArea->set_spacing(rDialogStyle.button_spacing);
688 Size aSize = get_preferred_size();
690 Size aMax(bestmaxFrameSizeForScreenSize(GetDesktopRectPixel().GetSize()));
692 aSize.Width() = std::min(aMax.Width(), aSize.Width());
693 aSize.Height() = std::min(aMax.Height(), aSize.Height());
695 SetMinOutputSizePixel(aSize);
696 SetSizePixel(aSize);
697 setPosSizeOnContainee(aSize, *pBox);
700 // -----------------------------------------------------------------------
702 void Dialog::StateChanged( StateChangedType nType )
704 SystemWindow::StateChanged( nType );
706 if ( nType == STATE_CHANGE_INITSHOW )
708 if ( GetSettings().GetStyleSettings().GetAutoMnemonic() )
709 ImplWindowAutoMnemonic( this );
711 if (isLayoutEnabled())
713 mbIsCalculatingInitialLayoutSize = true;
714 setDeferredProperties();
715 setOptimalLayoutSize();
716 mbIsCalculatingInitialLayoutSize = false;
719 if ( !HasChildPathFocus() || HasFocus() )
720 GrabFocusToFirstControl();
721 if ( !(GetStyle() & WB_CLOSEABLE) )
723 if ( ImplGetCancelButton( this ) || ImplGetOKButton( this ) )
725 if ( ImplGetBorderWindow() )
726 ((ImplBorderWindow*)ImplGetBorderWindow())->SetCloser();
730 ImplMouseAutoPos( this );
732 else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
734 ImplInitSettings();
735 Invalidate();
739 // -----------------------------------------------------------------------
741 void Dialog::DataChanged( const DataChangedEvent& rDCEvt )
743 SystemWindow::DataChanged( rDCEvt );
745 if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
746 (rDCEvt.GetFlags() & SETTINGS_STYLE) )
748 ImplInitSettings();
749 Invalidate();
753 // -----------------------------------------------------------------------
755 sal_Bool Dialog::Close()
757 ImplDelData aDelData;
758 ImplAddDel( &aDelData );
759 ImplCallEventListeners( VCLEVENT_WINDOW_CLOSE );
760 if ( aDelData.IsDead() )
761 return sal_False;
762 ImplRemoveDel( &aDelData );
764 if ( mpWindowImpl->mxWindowPeer.is() && IsCreatedWithToolkit() && !IsInExecute() )
765 return sal_False;
767 mbInClose = sal_True;
769 if ( !(GetStyle() & WB_CLOSEABLE) )
771 sal_Bool bRet = sal_True;
772 ImplAddDel( &aDelData );
773 PushButton* pButton = ImplGetCancelButton( this );
774 if ( pButton )
775 pButton->Click();
776 else
778 pButton = ImplGetOKButton( this );
779 if ( pButton )
780 pButton->Click();
781 else
782 bRet = sal_False;
784 if ( aDelData.IsDead() )
785 return sal_True;
786 ImplRemoveDel( &aDelData );
787 return bRet;
790 if ( IsInExecute() )
792 EndDialog( sal_False );
793 mbInClose = sal_False;
794 return sal_True;
796 else
798 mbInClose = sal_False;
799 return SystemWindow::Close();
803 // -----------------------------------------------------------------------
805 sal_Bool Dialog::ImplStartExecuteModal()
807 #ifdef ANDROID
808 // Not sure if the idea is that this will be called on Android or
809 // not? But OK, let's try to have the below code reached on
810 // Android...
811 #endif
813 if ( mbInExecute )
815 #ifdef DBG_UTIL
816 OStringBuffer aErrorStr;
817 aErrorStr.append("Dialog::StartExecuteModal() is called in Dialog::StartExecuteModal(): ");
818 aErrorStr.append(ImplGetDialogText(this));
819 OSL_FAIL(aErrorStr.getStr());
820 #endif
821 return sal_False;
824 switch ( Application::GetDialogCancelMode() )
826 case Application::DIALOG_CANCEL_OFF:
827 break;
828 case Application::DIALOG_CANCEL_SILENT:
829 SAL_INFO(
830 "vcl",
831 "Dialog \"" << ImplGetDialogText(this).getStr()
832 << "\"cancelled in silent mode");
833 return sal_False;
834 default:
835 assert(false); // this cannot happen
836 // fall through
837 case Application::DIALOG_CANCEL_FATAL:
838 throw Application::DialogCancelledException(
839 ImplGetDialogText(this).getStr());
842 #ifdef DBG_UTIL
843 Window* pParent = GetParent();
844 if ( pParent )
846 pParent = pParent->ImplGetFirstOverlapWindow();
847 DBG_ASSERT( pParent->IsReallyVisible(),
848 "Dialog::StartExecuteModal() - Parent not visible" );
849 DBG_ASSERT( pParent->IsInputEnabled(),
850 "Dialog::StartExecuteModal() - Parent input disabled, use another parent to ensure modality!" );
851 DBG_ASSERT( ! pParent->IsInModalMode(),
852 "Dialog::StartExecuteModal() - Parent already modally disabled, use another parent to ensure modality!" );
855 #endif
857 ImplSVData* pSVData = ImplGetSVData();
859 // Dialoge, die sich in Execute befinden, miteinander verketten
860 mpPrevExecuteDlg = pSVData->maWinData.mpLastExecuteDlg;
861 pSVData->maWinData.mpLastExecuteDlg = this;
863 // Capture beenden, damit der Dialog bedient werden kann
864 if ( pSVData->maWinData.mpTrackWin )
865 pSVData->maWinData.mpTrackWin->EndTracking( ENDTRACK_CANCEL );
866 if ( pSVData->maWinData.mpCaptureWin )
867 pSVData->maWinData.mpCaptureWin->ReleaseMouse();
868 EnableInput( sal_True, sal_True );
870 if ( GetParent() )
872 NotifyEvent aNEvt( EVENT_EXECUTEDIALOG, this );
873 GetParent()->Notify( aNEvt );
875 mbInExecute = sal_True;
876 SetModalInputMode( sal_True );
877 mbOldSaveBack = IsSaveBackgroundEnabled();
878 EnableSaveBackground();
880 // FIXME: no layouting, workaround some clipping issues
881 ImplAdjustNWFSizes();
883 Show();
885 pSVData->maAppData.mnModalMode++;
886 return sal_True;
889 // -----------------------------------------------------------------------
891 void Dialog::ImplEndExecuteModal()
893 ImplSVData* pSVData = ImplGetSVData();
894 pSVData->maAppData.mnModalMode--;
897 // -----------------------------------------------------------------------
899 short Dialog::Execute()
901 setDeferredProperties();
903 if ( !ImplStartExecuteModal() )
904 return 0;
906 ImplDelData aDelData;
907 ImplAddDel( &aDelData );
909 #ifdef DBG_UTIL
910 ImplDelData aParentDelData;
911 Window* pDialogParent = mpDialogParent;
912 if( pDialogParent )
913 pDialogParent->ImplAddDel( &aParentDelData );
914 #endif
916 // Yield util EndDialog is called or dialog gets destroyed
917 // (the latter should not happen, but better safe than sorry
918 while ( !aDelData.IsDead() && mbInExecute )
919 Application::Yield();
921 ImplEndExecuteModal();
923 #ifdef DBG_UTIL
924 if( pDialogParent )
926 if( ! aParentDelData.IsDead() )
927 pDialogParent->ImplRemoveDel( &aParentDelData );
928 else
929 OSL_FAIL( "Dialog::Execute() - Parent of dialog destroyed in Execute()" );
931 #endif
932 if ( !aDelData.IsDead() )
933 ImplRemoveDel( &aDelData );
934 #ifdef DBG_UTIL
935 else
937 OSL_FAIL( "Dialog::Execute() - Dialog destroyed in Execute()" );
939 #endif
941 long nRet = mpDialogImpl->mnResult;
942 mpDialogImpl->mnResult = -1;
943 return (short)nRet;
946 // -----------------------------------------------------------------------
948 // virtual
949 void Dialog::StartExecuteModal( const Link& rEndDialogHdl )
951 if ( !ImplStartExecuteModal() )
952 return;
954 mpDialogImpl->maEndDialogHdl = rEndDialogHdl;
955 mpDialogImpl->mbStartedModal = true;
958 // -----------------------------------------------------------------------
960 void Dialog::EndDialog( long nResult )
962 if ( mbInExecute )
964 SetModalInputMode( sal_False );
966 // Dialog aus der Kette der Dialoge die in Execute stehen entfernen
967 ImplSVData* pSVData = ImplGetSVData();
968 Dialog* pExeDlg = pSVData->maWinData.mpLastExecuteDlg;
969 while ( pExeDlg )
971 if ( pExeDlg == this )
973 pSVData->maWinData.mpLastExecuteDlg = mpPrevExecuteDlg;
974 break;
976 pExeDlg = pExeDlg->mpPrevExecuteDlg;
978 // set focus to previous modal dialogue if it is modal for
979 // the same frame parent (or NULL)
980 if( mpPrevExecuteDlg )
982 Window* pFrameParent = ImplGetFrameWindow()->ImplGetParent();
983 Window* pPrevFrameParent = mpPrevExecuteDlg->ImplGetFrameWindow()->ImplGetParent();
984 if( ( !pFrameParent && !pPrevFrameParent ) ||
985 ( pFrameParent && pPrevFrameParent && pFrameParent->ImplGetFrame() == pPrevFrameParent->ImplGetFrame() )
988 mpPrevExecuteDlg->GrabFocus();
991 mpPrevExecuteDlg = NULL;
993 Hide();
994 EnableSaveBackground( mbOldSaveBack );
995 if ( GetParent() )
997 NotifyEvent aNEvt( EVENT_ENDEXECUTEDIALOG, this );
998 GetParent()->Notify( aNEvt );
1001 mpDialogImpl->mnResult = nResult;
1003 if ( mpDialogImpl->mbStartedModal )
1005 ImplEndExecuteModal();
1006 mpDialogImpl->maEndDialogHdl.Call( this );
1008 mpDialogImpl->maEndDialogHdl = Link();
1009 mpDialogImpl->mbStartedModal = false;
1010 mpDialogImpl->mnResult = -1;
1012 mbInExecute = sal_False;
1016 // -----------------------------------------------------------------------
1018 long Dialog::GetResult() const
1020 return mpDialogImpl->mnResult;
1023 // -----------------------------------------------------------------------
1025 void Dialog::EndAllDialogs( Window* pParent )
1027 ImplSVData* pSVData = ImplGetSVData();
1028 Dialog* pTempModDialog;
1029 Dialog* pModDialog = pSVData->maWinData.mpLastExecuteDlg;
1030 while ( pModDialog )
1032 pTempModDialog = pModDialog->mpPrevExecuteDlg;
1033 if( !pParent || ( pParent && pParent->IsWindowOrChild( pModDialog, sal_True ) ) )
1035 pModDialog->EndDialog( sal_False );
1036 pModDialog->PostUserEvent( Link() );
1038 pModDialog = pTempModDialog;
1042 // -----------------------------------------------------------------------
1044 void Dialog::SetModalInputMode( sal_Bool bModal )
1046 if ( bModal == mbModalMode )
1047 return;
1049 ImplSVData* pSVData = ImplGetSVData();
1050 mbModalMode = bModal;
1051 if ( bModal )
1053 pSVData->maAppData.mnModalDialog++;
1055 // Diable the prev Modal Dialog, because our dialog must close at first,
1056 // before the other dialog can be closed (because the other dialog
1057 // is on stack since our dialog returns)
1058 if ( mpPrevExecuteDlg && !mpPrevExecuteDlg->IsWindowOrChild( this, sal_True ) )
1059 mpPrevExecuteDlg->EnableInput( sal_False, sal_True, sal_True, this );
1061 // determine next overlap dialog parent
1062 Window* pParent = GetParent();
1063 if ( pParent )
1065 // #103716# dialogs should always be modal to the whole frame window
1066 // #115933# disable the whole frame hierarchie, useful if our parent
1067 // is a modeless dialog
1068 mpDialogParent = pParent->mpWindowImpl->mpFrameWindow;
1069 mpDialogParent->ImplIncModalCount();
1073 else
1075 pSVData->maAppData.mnModalDialog--;
1077 if ( mpDialogParent )
1079 // #115933# re-enable the whole frame hierarchie again (see above)
1080 // note that code in getfocus assures that we do not accidentally enable
1081 // windows that were disabled before
1082 mpDialogParent->ImplDecModalCount();
1085 // Enable the prev Modal Dialog
1086 if ( mpPrevExecuteDlg && !mpPrevExecuteDlg->IsWindowOrChild( this, sal_True ) )
1088 mpPrevExecuteDlg->EnableInput( sal_True, sal_True, sal_True, this );
1089 // ensure continued modality of prev dialog
1090 // do not change modality counter
1091 mpPrevExecuteDlg->SetModalInputMode( sal_False );
1092 mpPrevExecuteDlg->SetModalInputMode( sal_True );
1097 // -----------------------------------------------------------------------
1099 void Dialog::SetModalInputMode( sal_Bool bModal, sal_Bool bSubModalDialogs )
1101 if ( bSubModalDialogs )
1103 Window* pOverlap = ImplGetFirstOverlapWindow();
1104 pOverlap = pOverlap->mpWindowImpl->mpFirstOverlap;
1105 while ( pOverlap )
1107 if ( pOverlap->IsDialog() )
1108 ((Dialog*)pOverlap)->SetModalInputMode( bModal, sal_True );
1109 pOverlap = pOverlap->mpWindowImpl->mpNext;
1113 SetModalInputMode( bModal );
1116 // -----------------------------------------------------------------------
1118 void Dialog::GrabFocusToFirstControl()
1120 Window* pFocusControl;
1122 // Wenn Dialog den Focus hat, versuchen wr trotzdem
1123 // ein Focus-Control zu finden
1124 if ( HasFocus() )
1125 pFocusControl = NULL;
1126 else
1128 // Wenn schon ein Child-Fenster mal den Focus hatte,
1129 // dann dieses bevorzugen
1130 pFocusControl = ImplGetFirstOverlapWindow()->mpWindowImpl->mpLastFocusWindow;
1131 // Control aus der Dialog-Steuerung suchen
1132 if ( pFocusControl )
1133 pFocusControl = ImplFindDlgCtrlWindow( pFocusControl );
1135 // Kein Control hatte vorher den Focus, oder das Control
1136 // befindet sich nicht in der Tab-Steuerung, dann das erste
1137 // Control in der TabSteuerung den Focus geben
1138 if ( !pFocusControl ||
1139 !(pFocusControl->GetStyle() & WB_TABSTOP) ||
1140 !isVisibleInLayout(pFocusControl) ||
1141 !isEnabledInLayout(pFocusControl) || !pFocusControl->IsInputEnabled() )
1143 sal_uInt16 n = 0;
1144 pFocusControl = ImplGetDlgWindow( n, DLGWINDOW_FIRST );
1146 if ( pFocusControl )
1147 pFocusControl->ImplControlFocus( GETFOCUS_INIT );
1150 void Dialog::GetDrawWindowBorder( sal_Int32& rLeftBorder, sal_Int32& rTopBorder, sal_Int32& rRightBorder, sal_Int32& rBottomBorder ) const
1152 ImplBorderWindow aImplWin( (Window*)this, WB_BORDER|WB_STDWORK, BORDERWINDOW_STYLE_OVERLAP );
1153 // aImplWin.SetText( GetText() );
1154 // aImplWin.SetPosSizePixel( aPos.X(), aPos.Y(), aSize.Width(), aSize.Height() );
1155 // aImplWin.SetDisplayActive( sal_True );
1156 // aImplWin.InitView();
1157 aImplWin.GetBorder( rLeftBorder, rTopBorder, rRightBorder, rBottomBorder );
1161 void Dialog::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, sal_uLong )
1163 Point aPos = pDev->LogicToPixel( rPos );
1164 Size aSize = pDev->LogicToPixel( rSize );
1166 Wallpaper aWallpaper = GetBackground();
1167 if ( !aWallpaper.IsBitmap() )
1168 ImplInitSettings();
1170 pDev->Push();
1171 pDev->SetMapMode();
1172 pDev->SetLineColor();
1174 if ( aWallpaper.IsBitmap() )
1175 pDev->DrawBitmapEx( aPos, aSize, aWallpaper.GetBitmap() );
1176 else
1178 pDev->SetFillColor( aWallpaper.GetColor() );
1179 pDev->DrawRect( Rectangle( aPos, aSize ) );
1182 if (!( GetStyle() & WB_NOBORDER ))
1184 ImplBorderWindow aImplWin( this, WB_BORDER|WB_STDWORK, BORDERWINDOW_STYLE_OVERLAP );
1185 aImplWin.SetText( GetText() );
1186 aImplWin.setPosSizePixel( aPos.X(), aPos.Y(), aSize.Width(), aSize.Height() );
1187 aImplWin.SetDisplayActive( sal_True );
1188 aImplWin.InitView();
1190 aImplWin.Draw( Rectangle( aPos, aSize ), pDev, aPos );
1193 pDev->Pop();
1196 bool Dialog::isLayoutEnabled() const
1198 //pre dtor called, and single child is a container => we're layout enabled
1199 return mpDialogImpl ? ::isLayoutEnabled(this) : false;
1202 Size Dialog::GetOptimalSize() const
1204 if (!isLayoutEnabled())
1205 return SystemWindow::GetOptimalSize();
1207 Size aSize = VclContainer::getLayoutRequisition(*GetWindow(WINDOW_FIRSTCHILD));
1209 sal_Int32 nBorderWidth = get_border_width();
1211 aSize.Height() += mpWindowImpl->mnLeftBorder + mpWindowImpl->mnRightBorder
1212 + 2*nBorderWidth;
1213 aSize.Width() += mpWindowImpl->mnTopBorder + mpWindowImpl->mnBottomBorder
1214 + 2*nBorderWidth;
1216 return Window::CalcWindowSize(aSize);
1219 void Dialog::setPosSizeOnContainee(Size aSize, VclContainer &rBox)
1221 sal_Int32 nBorderWidth = get_border_width();
1223 aSize.Width() -= mpWindowImpl->mnLeftBorder + mpWindowImpl->mnRightBorder
1224 + 2 * nBorderWidth;
1225 aSize.Height() -= mpWindowImpl->mnTopBorder + mpWindowImpl->mnBottomBorder
1226 + 2 * nBorderWidth;
1228 Point aPos(mpWindowImpl->mnLeftBorder + nBorderWidth,
1229 mpWindowImpl->mnTopBorder + nBorderWidth);
1231 VclContainer::setLayoutAllocation(rBox, aPos, aSize);
1234 IMPL_LINK( Dialog, ImplHandleLayoutTimerHdl, void*, EMPTYARG )
1236 if (!isLayoutEnabled())
1238 SAL_WARN("vcl.layout", "Dialog has become non-layout because extra children have been added directly to it.");
1239 return 0;
1242 VclBox *pBox = static_cast<VclBox*>(GetWindow(WINDOW_FIRSTCHILD));
1243 assert(pBox);
1244 setPosSizeOnContainee(GetSizePixel(), *pBox);
1245 return 0;
1248 void Dialog::queue_layout()
1250 if (hasPendingLayout() || isCalculatingInitialLayoutSize())
1251 return;
1252 if (IsInClose())
1253 return;
1254 if (!isLayoutEnabled())
1255 return;
1256 maLayoutTimer.Start();
1259 void Dialog::Resize()
1261 queue_layout();
1264 bool Dialog::set_property(const OString &rKey, const OString &rValue)
1266 if (rKey == "border-width")
1267 set_border_width(rValue.toInt32());
1268 else
1269 return SystemWindow::set_property(rKey, rValue);
1270 return true;
1273 void Dialog::SetText(const OUString& rStr)
1275 setDeferredProperties();
1276 SystemWindow::SetText(rStr);
1279 OUString Dialog::GetText() const
1281 const_cast<Dialog*>(this)->setDeferredProperties();
1282 return SystemWindow::GetText();
1285 VclBuilderContainer::VclBuilderContainer()
1286 : m_pUIBuilder(NULL)
1290 VclBuilderContainer::~VclBuilderContainer()
1292 delete m_pUIBuilder;
1295 // -----------------------------------------------------------------------
1297 ModelessDialog::ModelessDialog( Window* pParent, const ResId& rResId ) :
1298 Dialog( WINDOW_MODELESSDIALOG )
1300 rResId.SetRT( RSC_MODELESSDIALOG );
1302 WinBits nStyle = init( pParent, rResId );
1304 if ( !(nStyle & WB_HIDE) )
1305 Show();
1308 ModelessDialog::ModelessDialog( Window* pParent, const OString& rID, const OUString& rUIXMLDescription ) :
1309 Dialog(pParent, rID, rUIXMLDescription, WINDOW_MODELESSDIALOG)
1313 // =======================================================================
1315 ModalDialog::ModalDialog( Window* pParent, WinBits nStyle ) :
1316 Dialog( WINDOW_MODALDIALOG )
1318 ImplInit( pParent, nStyle );
1321 // -----------------------------------------------------------------------
1323 ModalDialog::ModalDialog( Window* pParent, const ResId& rResId ) :
1324 Dialog( WINDOW_MODALDIALOG )
1326 rResId.SetRT( RSC_MODALDIALOG );
1327 init( pParent, rResId );
1330 ModalDialog::ModalDialog( Window* pParent, const OString& rID, const OUString& rUIXMLDescription ) :
1331 Dialog(pParent, rID, rUIXMLDescription, WINDOW_MODALDIALOG)
1335 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */