Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <tools/rc.h>
21 :
22 : #include <svids.hrc>
23 : #include <svdata.hxx>
24 : #include <brdwin.hxx>
25 : #include <window.h>
26 :
27 : #include <vcl/metric.hxx>
28 : #include <vcl/svapp.hxx>
29 : #include <vcl/wrkwin.hxx>
30 : #include <vcl/fixed.hxx>
31 : #include <vcl/vclmedit.hxx>
32 : #include <vcl/msgbox.hxx>
33 : #include <vcl/button.hxx>
34 : #include <vcl/mnemonic.hxx>
35 : #include <vcl/settings.hxx>
36 :
37 0 : static void ImplInitMsgBoxImageList()
38 : {
39 0 : ImplSVData* pSVData = ImplGetSVData();
40 0 : if ( !pSVData->maWinData.mpMsgBoxImgList )
41 : {
42 0 : ResMgr* pResMgr = ImplGetResMgr();
43 0 : pSVData->maWinData.mpMsgBoxImgList = new ImageList(4);
44 0 : if( pResMgr )
45 : {
46 0 : Color aNonAlphaMask( 0xC0, 0xC0, 0xC0 );
47 : pSVData->maWinData.mpMsgBoxImgList->InsertFromHorizontalBitmap
48 0 : ( ResId( SV_RESID_BITMAP_MSGBOX, *pResMgr ), 4, &aNonAlphaMask );
49 : }
50 : }
51 0 : }
52 :
53 0 : void MessBox::ImplInitMessBoxData()
54 : {
55 0 : mpVCLMultiLineEdit = NULL;
56 0 : mpFixedImage = NULL;
57 0 : mbHelpBtn = false;
58 0 : mpCheckBox = NULL;
59 0 : mbCheck = false;
60 0 : }
61 :
62 0 : void MessBox::ImplInitButtons()
63 : {
64 0 : WinBits nStyle = GetStyle();
65 0 : ButtonDialogFlags nOKFlags = ButtonDialogFlags::OK;
66 0 : ButtonDialogFlags nCancelFlags = ButtonDialogFlags::Cancel;
67 0 : ButtonDialogFlags nRetryFlags = ButtonDialogFlags::NONE;
68 0 : ButtonDialogFlags nYesFlags = ButtonDialogFlags::NONE;
69 0 : ButtonDialogFlags nNoFlags = ButtonDialogFlags::NONE;
70 :
71 0 : if ( nStyle & WB_OK_CANCEL )
72 : {
73 0 : if ( nStyle & WB_DEF_CANCEL )
74 0 : nCancelFlags |= ButtonDialogFlags::Default | ButtonDialogFlags::Focus;
75 : else // WB_DEF_OK
76 0 : nOKFlags |= ButtonDialogFlags::Default | ButtonDialogFlags::Focus;
77 :
78 0 : AddButton( StandardButtonType::OK, RET_OK, nOKFlags );
79 0 : AddButton( StandardButtonType::Cancel, RET_CANCEL, nCancelFlags );
80 : }
81 0 : else if ( nStyle & WB_YES_NO )
82 : {
83 0 : if ( nStyle & WB_DEF_YES )
84 0 : nYesFlags |= ButtonDialogFlags::Default | ButtonDialogFlags::Focus;
85 : else // WB_DEF_NO
86 0 : nNoFlags |= ButtonDialogFlags::Default | ButtonDialogFlags::Focus;
87 0 : nNoFlags |= ButtonDialogFlags::Cancel;
88 :
89 0 : AddButton( StandardButtonType::Yes, RET_YES, nYesFlags );
90 0 : AddButton( StandardButtonType::No, RET_NO, nNoFlags );
91 : }
92 0 : else if ( nStyle & WB_YES_NO_CANCEL )
93 : {
94 0 : if ( nStyle & WB_DEF_YES )
95 0 : nYesFlags |= ButtonDialogFlags::Default | ButtonDialogFlags::Focus;
96 0 : else if ( nStyle & WB_DEF_NO )
97 0 : nNoFlags |= ButtonDialogFlags::Default | ButtonDialogFlags::Focus;
98 : else
99 0 : nCancelFlags |= ButtonDialogFlags::Default | ButtonDialogFlags::Focus;
100 :
101 0 : AddButton( StandardButtonType::Yes, RET_YES, nYesFlags );
102 0 : AddButton( StandardButtonType::No, RET_NO, nNoFlags );
103 0 : AddButton( StandardButtonType::Cancel, RET_CANCEL, nCancelFlags );
104 : }
105 0 : else if ( nStyle & WB_RETRY_CANCEL )
106 : {
107 0 : if ( nStyle & WB_DEF_CANCEL )
108 0 : nCancelFlags |= ButtonDialogFlags::Default | ButtonDialogFlags::Focus;
109 : else // WB_DEF_RETRY
110 0 : nRetryFlags |= ButtonDialogFlags::Default | ButtonDialogFlags::Focus;
111 :
112 0 : AddButton( StandardButtonType::Retry, RET_RETRY, nRetryFlags );
113 0 : AddButton( StandardButtonType::Cancel, RET_CANCEL, nCancelFlags );
114 : }
115 0 : else if ( nStyle & WB_ABORT_RETRY_IGNORE )
116 : {
117 0 : ButtonDialogFlags nAbortFlags = ButtonDialogFlags::NONE;
118 0 : ButtonDialogFlags nIgnoreFlags = ButtonDialogFlags::NONE;
119 :
120 0 : if ( nStyle & WB_DEF_CANCEL )
121 0 : nAbortFlags |= ButtonDialogFlags::Default | ButtonDialogFlags::Focus;
122 0 : else if ( nStyle & WB_DEF_RETRY )
123 0 : nRetryFlags |= ButtonDialogFlags::Default | ButtonDialogFlags::Focus;
124 0 : else if ( nStyle & WB_DEF_IGNORE )
125 0 : nIgnoreFlags |= ButtonDialogFlags::Default | ButtonDialogFlags::Focus;
126 :
127 0 : AddButton( StandardButtonType::Abort, RET_CANCEL, nAbortFlags );
128 0 : AddButton( StandardButtonType::Retry, RET_RETRY, nRetryFlags );
129 0 : AddButton( StandardButtonType::Ignore, RET_IGNORE, nIgnoreFlags );
130 : }
131 0 : else if ( nStyle & WB_OK )
132 : {
133 0 : nOKFlags |= ButtonDialogFlags::Default | ButtonDialogFlags::Focus;
134 :
135 0 : AddButton( StandardButtonType::OK, RET_OK, nOKFlags );
136 : }
137 0 : }
138 :
139 0 : MessBox::MessBox( vcl::Window* pParent, WinBits nStyle,
140 : const OUString& rTitle, const OUString& rMessage ) :
141 : ButtonDialog( WINDOW_MESSBOX ),
142 0 : maMessText( rMessage )
143 : {
144 0 : ImplInitMessBoxData();
145 0 : ImplInit( pParent, nStyle | WB_MOVEABLE | WB_HORZ | WB_CENTER );
146 0 : ImplInitButtons();
147 :
148 0 : if ( !rTitle.isEmpty() )
149 0 : SetText( rTitle );
150 0 : }
151 :
152 0 : MessBox::~MessBox()
153 : {
154 0 : disposeOnce();
155 0 : }
156 :
157 0 : void MessBox::dispose()
158 : {
159 0 : mpVCLMultiLineEdit.disposeAndClear();
160 0 : mpFixedImage.disposeAndClear();
161 0 : mpCheckBox.disposeAndClear();
162 0 : ButtonDialog::dispose();
163 0 : }
164 :
165 0 : void MessBox::ImplPosControls()
166 : {
167 0 : if ( !GetHelpId().isEmpty() )
168 : {
169 0 : if ( !mbHelpBtn )
170 : {
171 0 : AddButton( StandardButtonType::Help, RET_HELP, ButtonDialogFlags::Help, 3 );
172 0 : mbHelpBtn = true;
173 : }
174 : }
175 : else
176 : {
177 0 : if ( mbHelpBtn )
178 : {
179 0 : RemoveButton( RET_HELP );
180 0 : mbHelpBtn = false;
181 : }
182 : }
183 :
184 0 : TextRectInfo aTextInfo;
185 0 : Rectangle aRect( 0, 0, 30000, 30000 );
186 0 : Rectangle aFormatRect;
187 0 : Point aTextPos( IMPL_DIALOG_OFFSET, IMPL_DIALOG_OFFSET+IMPL_MSGBOX_OFFSET_EXTRA_Y );
188 0 : Size aImageSize;
189 0 : Size aPageSize;
190 0 : Size aMEditSize;
191 : long nTitleWidth;
192 0 : long nButtonSize = ImplGetButtonSize();
193 0 : long nMaxWidth = GetDesktopRectPixel().GetWidth()-8;
194 : long nMaxLineWidth;
195 : long nWidth;
196 0 : WinBits nWinStyle = WB_LEFT | WB_NOLABEL;
197 0 : DrawTextFlags nTextStyle = DrawTextFlags::MultiLine | DrawTextFlags::Top | DrawTextFlags::Left;
198 :
199 0 : mpVCLMultiLineEdit.disposeAndClear();
200 0 : mpFixedImage.disposeAndClear();
201 0 : if ( mpCheckBox )
202 : {
203 0 : mbCheck = mpCheckBox->IsChecked();
204 0 : mpCheckBox.disposeAndClear();
205 : }
206 :
207 : // Clean up message text with tabs
208 0 : OUString aMessText(maMessText.replaceAll("\t", " "));
209 :
210 : //If window too small, we make dialog box be wider
211 0 : if ( mpWindowImpl->mbFrame )
212 : {
213 0 : nMaxWidth = 630 * GetDPIScaleFactor();
214 : }
215 0 : else if ( nMaxWidth < 120 )
216 0 : nMaxWidth = 120;
217 :
218 0 : nMaxWidth -= mpWindowImpl->mnLeftBorder+mpWindowImpl->mnRightBorder+4;
219 :
220 : // MessagBox should be at least as wide as to see the title
221 : // Extra-Width for Close button, because Close button is set after this call
222 0 : nTitleWidth = CalcTitleWidth();
223 0 : nTitleWidth += mpWindowImpl->mnTopBorder;
224 :
225 0 : nMaxWidth -= (IMPL_DIALOG_OFFSET*2)+(IMPL_MSGBOX_OFFSET_EXTRA_X*2);
226 :
227 : // for an image, get its size, create a suitable control and position it
228 0 : aImageSize = maImage.GetSizePixel();
229 0 : if ( aImageSize.Width() )
230 : {
231 0 : aImageSize.Width() += 4;
232 0 : aImageSize.Height() += 4;
233 0 : aTextPos.X() += aImageSize.Width()+IMPL_SEP_MSGBOX_IMAGE;
234 0 : mpFixedImage = VclPtr<FixedImage>::Create( this );
235 0 : mpFixedImage->SetPosSizePixel( Point( IMPL_DIALOG_OFFSET-2+IMPL_MSGBOX_OFFSET_EXTRA_X,
236 : IMPL_DIALOG_OFFSET-2+IMPL_MSGBOX_OFFSET_EXTRA_Y ),
237 0 : aImageSize );
238 0 : mpFixedImage->SetImage( maImage );
239 0 : mpFixedImage->Show();
240 0 : nMaxWidth -= aImageSize.Width()+IMPL_SEP_MSGBOX_IMAGE;
241 : }
242 : else
243 0 : aTextPos.X() += IMPL_MSGBOX_OFFSET_EXTRA_X;
244 :
245 : // Determine maximum line length without wordbreak
246 0 : aFormatRect = GetTextRect( aRect, aMessText, nTextStyle, &aTextInfo );
247 0 : nMaxLineWidth = aFormatRect.GetWidth();
248 0 : nTextStyle |= DrawTextFlags::WordBreak;
249 :
250 : // Determine the width for text formatting
251 0 : if ( nMaxLineWidth > 450 )
252 0 : nWidth = 450;
253 0 : else if ( nMaxLineWidth > 300 )
254 0 : nWidth = nMaxLineWidth+5;
255 : else
256 0 : nWidth = 300;
257 :
258 0 : nWidth *= GetDPIScaleFactor();
259 :
260 0 : if ( nButtonSize > nWidth )
261 0 : nWidth = nButtonSize-(aTextPos.X()-IMPL_DIALOG_OFFSET);
262 0 : if ( nWidth > nMaxWidth )
263 0 : nWidth = nMaxWidth;
264 :
265 0 : aRect.Right() = nWidth;
266 0 : aFormatRect = GetTextRect( aRect, aMessText, nTextStyle, &aTextInfo );
267 0 : if ( aTextInfo.GetMaxLineWidth() > nWidth )
268 : {
269 0 : nWidth = aTextInfo.GetMaxLineWidth()+8;
270 0 : aRect.Right() = nWidth;
271 0 : aFormatRect = GetTextRect( aRect, aMessText, nTextStyle, &aTextInfo );
272 : }
273 :
274 : // get Style for VCLMultiLineEdit
275 0 : aMEditSize.Width() = aTextInfo.GetMaxLineWidth()+1;
276 0 : aMEditSize.Height() = aFormatRect.GetHeight();
277 0 : aPageSize.Width() = aImageSize.Width();
278 0 : if ( aMEditSize.Height() < aImageSize.Height() )
279 : {
280 0 : nWinStyle |= WB_VCENTER;
281 0 : aPageSize.Height() = aImageSize.Height();
282 0 : aMEditSize.Height() = aImageSize.Height();
283 : }
284 : else
285 : {
286 0 : nWinStyle |= WB_TOP;
287 0 : aPageSize.Height() = aMEditSize.Height();
288 : }
289 0 : if ( aImageSize.Width() )
290 0 : aPageSize.Width() += IMPL_SEP_MSGBOX_IMAGE;
291 0 : aPageSize.Width() += (IMPL_DIALOG_OFFSET*2)+(IMPL_MSGBOX_OFFSET_EXTRA_X*2);
292 0 : aPageSize.Width() += aMEditSize.Width()+1;
293 0 : aPageSize.Height() += (IMPL_DIALOG_OFFSET*2)+(IMPL_MSGBOX_OFFSET_EXTRA_Y*2);
294 :
295 0 : if ( aPageSize.Width() < IMPL_MINSIZE_MSGBOX_WIDTH )
296 0 : aPageSize.Width() = IMPL_MINSIZE_MSGBOX_WIDTH;
297 0 : if ( aPageSize.Width() < nTitleWidth )
298 0 : aPageSize.Width() = nTitleWidth;
299 :
300 0 : if ( !maCheckBoxText.isEmpty() )
301 : {
302 0 : Size aMinCheckboxSize ( aMEditSize );
303 0 : if ( aPageSize.Width() < IMPL_MINSIZE_MSGBOX_WIDTH+80 )
304 : {
305 0 : aPageSize.Width() = IMPL_MINSIZE_MSGBOX_WIDTH+80;
306 0 : aMinCheckboxSize.Width() += 80;
307 : }
308 :
309 : // #104492# auto mnemonics for CJK strings may increase the length, so measure the
310 : // checkbox length including a temporary mnemonic, the correct auto mnemonic will be
311 : // generated later in the dialog (see init_show)
312 :
313 0 : OUString aMnemonicString( maCheckBoxText );
314 0 : if( GetSettings().GetStyleSettings().GetAutoMnemonic() )
315 : {
316 0 : if( aMnemonicString == GetNonMnemonicString( maCheckBoxText ) )
317 : {
318 : // no mnemonic found -> create one
319 0 : MnemonicGenerator aMnemonicGenerator;
320 0 : aMnemonicString = aMnemonicGenerator.CreateMnemonic( aMnemonicString );
321 : }
322 : }
323 :
324 0 : mpCheckBox = VclPtr<CheckBox>::Create( this );
325 0 : mpCheckBox->Check( mbCheck );
326 0 : mpCheckBox->SetText( aMnemonicString );
327 0 : mpCheckBox->SetStyle( mpCheckBox->GetStyle() | WB_WORDBREAK );
328 0 : mpCheckBox->SetHelpId( GetHelpId() ); // DR: Check box and dialog have same HID
329 :
330 : // align checkbox with message text
331 0 : Size aSize = mpCheckBox->CalcMinimumSize( aMinCheckboxSize.Width() );
332 :
333 : // now set the original non-mnemonic string
334 0 : mpCheckBox->SetText( maCheckBoxText );
335 :
336 0 : Point aPos( aTextPos );
337 0 : aPos.Y() += aMEditSize.Height() + (IMPL_DIALOG_OFFSET)+(IMPL_MSGBOX_OFFSET_EXTRA_Y*2);
338 :
339 : // increase messagebox
340 0 : aPageSize.Height() += aSize.Height() + (IMPL_DIALOG_OFFSET*2)+(IMPL_MSGBOX_OFFSET_EXTRA_Y*2);
341 :
342 0 : mpCheckBox->SetPosSizePixel( aPos, aSize );
343 0 : mpCheckBox->Show();
344 : }
345 :
346 0 : mpVCLMultiLineEdit = VclPtr<VclMultiLineEdit>::Create( this, nWinStyle );
347 0 : mpVCLMultiLineEdit->SetText( aMessText );
348 0 : mpVCLMultiLineEdit->SetPosSizePixel( aTextPos, aMEditSize );
349 0 : mpVCLMultiLineEdit->Show();
350 0 : mpVCLMultiLineEdit->SetPaintTransparent(true);
351 0 : mpVCLMultiLineEdit->EnableCursor(false);
352 0 : SetPageSizePixel( aPageSize );
353 0 : }
354 :
355 0 : void MessBox::StateChanged( StateChangedType nType )
356 : {
357 0 : if ( nType == StateChangedType::InitShow )
358 : {
359 0 : ImplPosControls();
360 : }
361 0 : ButtonDialog::StateChanged( nType );
362 0 : }
363 :
364 0 : bool MessBox::GetCheckBoxState() const
365 : {
366 0 : return mpCheckBox ? mpCheckBox->IsChecked() : mbCheck;
367 : }
368 :
369 0 : void MessBox::SetCheckBoxState( bool bCheck )
370 : {
371 0 : if( mpCheckBox ) mpCheckBox->Check( bCheck );
372 0 : mbCheck = bCheck;
373 0 : }
374 :
375 0 : Size MessBox::GetOptimalSize() const
376 : {
377 : // FIXME: base me on the font size ?
378 0 : return Size( 250, 100 );
379 : }
380 :
381 0 : void InfoBox::ImplInitInfoBoxData()
382 : {
383 : // Default Text is the display title from the application
384 0 : if ( GetText().isEmpty() )
385 0 : SetText( Application::GetDisplayName() );
386 :
387 0 : SetImage( InfoBox::GetStandardImage() );
388 0 : }
389 :
390 0 : InfoBox::InfoBox( vcl::Window* pParent, const OUString& rMessage ) :
391 0 : MessBox( pParent, WB_OK | WB_DEF_OK, OUString(), rMessage )
392 : {
393 0 : ImplInitInfoBoxData();
394 0 : }
395 :
396 0 : InfoBox::InfoBox( vcl::Window* pParent, WinBits nStyle, const OUString& rMessage ) :
397 0 : MessBox( pParent, nStyle, OUString(), rMessage )
398 : {
399 0 : ImplInitInfoBoxData();
400 0 : }
401 :
402 0 : Image InfoBox::GetStandardImage()
403 : {
404 0 : ImplInitMsgBoxImageList();
405 0 : return ImplGetSVData()->maWinData.mpMsgBoxImgList->GetImage( 4 );
406 : }
407 :
408 0 : void WarningBox::ImplInitWarningBoxData()
409 : {
410 : // Default Text is the display title from the application
411 0 : if ( GetText().isEmpty() )
412 0 : SetText( Application::GetDisplayName() );
413 :
414 0 : SetImage( WarningBox::GetStandardImage() );
415 0 : }
416 :
417 0 : WarningBox::WarningBox( vcl::Window* pParent, WinBits nStyle,
418 : const OUString& rMessage ) :
419 0 : MessBox( pParent, nStyle, OUString(), rMessage )
420 : {
421 0 : ImplInitWarningBoxData();
422 0 : }
423 :
424 0 : void WarningBox::SetDefaultCheckBoxText()
425 : {
426 0 : ResMgr* pResMgr = ImplGetResMgr();
427 0 : if( pResMgr )
428 0 : maCheckBoxText = ResId(SV_STDTEXT_DONTWARNAGAIN, *pResMgr).toString();
429 0 : }
430 :
431 0 : Image WarningBox::GetStandardImage()
432 : {
433 0 : ImplInitMsgBoxImageList();
434 0 : return ImplGetSVData()->maWinData.mpMsgBoxImgList->GetImage( 3 );
435 : }
436 :
437 0 : void ErrorBox::ImplInitErrorBoxData()
438 : {
439 : // Default Text is the display title from the application
440 0 : if ( GetText().isEmpty() )
441 0 : SetText( Application::GetDisplayName() );
442 :
443 0 : SetImage( ErrorBox::GetStandardImage() );
444 0 : }
445 :
446 0 : ErrorBox::ErrorBox( vcl::Window* pParent, WinBits nStyle,
447 : const OUString& rMessage ) :
448 0 : MessBox( pParent, nStyle, OUString(), rMessage )
449 : {
450 0 : ImplInitErrorBoxData();
451 0 : }
452 :
453 0 : Image ErrorBox::GetStandardImage()
454 : {
455 : try
456 : {
457 0 : ImplInitMsgBoxImageList();
458 : }
459 0 : catch (const ::com::sun::star::uno::Exception &)
460 : {
461 : // During early bootstrap we can have no initialized
462 : // ucb and hence no ability to get this image, so nop.
463 0 : return Image();
464 : }
465 0 : return ImplGetSVData()->maWinData.mpMsgBoxImgList->GetImage( 1 );
466 : }
467 :
468 0 : void QueryBox::ImplInitQueryBoxData()
469 : {
470 : // Default Text is the display title from the application
471 0 : if ( GetText().isEmpty() )
472 0 : SetText( Application::GetDisplayName() );
473 :
474 0 : SetImage( QueryBox::GetStandardImage() );
475 0 : }
476 :
477 0 : QueryBox::QueryBox( vcl::Window* pParent, WinBits nStyle, const OUString& rMessage ) :
478 0 : MessBox( pParent, nStyle, OUString(), rMessage )
479 : {
480 0 : ImplInitQueryBoxData();
481 0 : }
482 :
483 0 : void QueryBox::SetDefaultCheckBoxText()
484 : {
485 0 : ResMgr* pResMgr = ImplGetResMgr();
486 0 : if( pResMgr )
487 0 : maCheckBoxText = ResId(SV_STDTEXT_DONTASKAGAIN, *pResMgr).toString();
488 0 : }
489 :
490 0 : Image QueryBox::GetStandardImage()
491 : {
492 0 : ImplInitMsgBoxImageList();
493 0 : return ImplGetSVData()->maWinData.mpMsgBoxImgList->GetImage( 2 );
494 801 : }
495 :
496 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|