Bugfix : Zooming works correct, no more errors on screen.
[xara-cairo.git] / wxOil / errorbox.cpp
blobbc7125c85dbb395bf82ca33971c970f9dca0e3eb
1 // $Id: errorbox.cpp 1282 2006-06-09 09:46:49Z alex $
2 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
3 ================================XARAHEADERSTART===========================
5 Xara LX, a vector drawing and manipulation program.
6 Copyright (C) 1993-2006 Xara Group Ltd.
7 Copyright on certain contributions may be held in joint with their
8 respective authors. See AUTHORS file for details.
10 LICENSE TO USE AND MODIFY SOFTWARE
11 ----------------------------------
13 This file is part of Xara LX.
15 Xara LX is free software; you can redistribute it and/or modify it
16 under the terms of the GNU General Public License version 2 as published
17 by the Free Software Foundation.
19 Xara LX and its component source files are distributed in the hope
20 that it will be useful, but WITHOUT ANY WARRANTY; without even the
21 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
22 See the GNU General Public License for more details.
24 You should have received a copy of the GNU General Public License along
25 with Xara LX (see the file GPL in the root directory of the
26 distribution); if not, write to the Free Software Foundation, Inc., 51
27 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 ADDITIONAL RIGHTS
31 -----------------
33 Conditional upon your continuing compliance with the GNU General Public
34 License described above, Xara Group Ltd grants to you certain additional
35 rights.
37 The additional rights are to use, modify, and distribute the software
38 together with the wxWidgets library, the wxXtra library, and the "CDraw"
39 library and any other such library that any version of Xara LX relased
40 by Xara Group Ltd requires in order to compile and execute, including
41 the static linking of that library to XaraLX. In the case of the
42 "CDraw" library, you may satisfy obligation under the GNU General Public
43 License to provide source code by providing a binary copy of the library
44 concerned and a copy of the license accompanying it.
46 Nothing in this section restricts any of the rights you have under
47 the GNU General Public License.
50 SCOPE OF LICENSE
51 ----------------
53 This license applies to this program (XaraLX) and its constituent source
54 files only, and does not necessarily apply to other Xara products which may
55 in part share the same code base, and are subject to their own licensing
56 terms.
58 This license does not apply to files in the wxXtra directory, which
59 are built into a separate library, and are subject to the wxWindows
60 license contained within that directory in the file "WXXTRA-LICENSE".
62 This license does not apply to the binary libraries (if any) within
63 the "libs" directory, which are subject to a separate license contained
64 within that directory in the file "LIBS-LICENSE".
67 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
68 ----------------------------------------------
70 Subject to the terms of the GNU Public License (see above), you are
71 free to do whatever you like with your modifications. However, you may
72 (at your option) wish contribute them to Xara's source tree. You can
73 find details of how to do this at:
74 http://www.xaraxtreme.org/developers/
76 Prior to contributing your modifications, you will need to complete our
77 contributor agreement. This can be found at:
78 http://www.xaraxtreme.org/developers/contribute/
80 Please note that Xara will not accept modifications which modify any of
81 the text between the start and end of this header (marked
82 XARAHEADERSTART and XARAHEADEREND).
85 MARKS
86 -----
88 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
89 designs are registered or unregistered trademarks, design-marks, and/or
90 service marks of Xara Group Ltd. All rights in these marks are reserved.
93 Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
94 http://www.xara.com/
96 =================================XARAHEADEREND============================
99 // implementation of CInformErrorDialog, used for error reporting
100 // (taken from errors.cpp 1.27)
103 #include "camtypes.h"
105 #include "errorbox.h"
106 //#include "errors.h" - in camtypes.h [AUTOMATICALLY REMOVED]
107 //#include "andy.h"
108 //#include "tim.h"
109 //#include "resource.h"
110 #include "splash.h"
111 #include "mainfrm.h"
112 //#include "richard2.h"
113 #include "prdlgctl.h"
115 #include "helpuser.h"
118 CInformErrorDialog::CInformErrorDialog(CWnd* pParent /*=NULL*/)
119 : CDialog(CInformErrorDialog::IDD, pParent ? pParent : GetSafeParent() )
121 //{{AFX_DATA_INIT(CInformErrorDialog)
122 // NOTE: the ClassWizard will add member initialization here
123 //}}AFX_DATA_INIT
125 // remember the HWND to use in case of emergency
126 ParentHwnd = GetSafeParent()->GetSafeHwnd();
128 // Make sure all the string variables are NULL.
129 m_StaticTextStr = 0;
130 m_TitleStr = 0; // by default NOT a custom title
131 m_ErrorBoxType = ERRORTYPE_ERROR; // This is an error box by default
132 m_OwnerModule = 0L;
133 m_OK = 1;
134 m_Cancel = 2;
135 m_Help = 0; // by default there is no help button
137 // Set reasonable defaults for the button captions.
138 m_ButtonStr[0] = _R(IDS_OK);
139 for (INT32 i = 1; i < ERRORDLG_MAXBUTTONS; i++) m_ButtonStr[i] = 0;
144 void CInformErrorDialog::DoDataExchange(CDataExchange* pDX)
146 // IF YOU CHANGE THE VALUE OF ERRORDLG_MAXBUTTONS YOU MUST CHANGE THIS AS WELL!
147 CDialog::DoDataExchange(pDX);
148 //{{AFX_DATA_MAP(CInformErrorDialog)
149 DDX_Control(pDX, _R(ID_ERRORBOX_BUTTON5), m_Button[4]);
150 DDX_Control(pDX, _R(ID_ERRORBOX_BUTTON4), m_Button[3]);
151 DDX_Control(pDX, _R(ID_ERRORBOX_BUTTON3), m_Button[2]);
152 DDX_Control(pDX, _R(ID_ERRORBOX_BUTTON2), m_Button[1]);
153 DDX_Control(pDX, _R(ID_ERRORBOX_BUTTON1), m_Button[0]);
154 //}}AFX_DATA_MAP
158 // IF YOU CHANGE THE VALUE OF ERRORDLG_MAXBUTTONS YOU MUST CHANGE THIS AS WELL!
159 BEGIN_MESSAGE_MAP(CInformErrorDialog, CDialog)
160 //{{AFX_MSG_MAP(CInformErrorDialog)
161 ON_WM_PAINT()
162 ON_BN_CLICKED(_R(ID_ERRORBOX_BUTTON1), OnClickedButton1)
163 ON_BN_CLICKED(_R(ID_ERRORBOX_BUTTON2), OnClickedButton2)
164 ON_BN_CLICKED(_R(ID_ERRORBOX_BUTTON3), OnClickedButton3)
165 ON_BN_CLICKED(_R(ID_ERRORBOX_BUTTON4), OnClickedButton4)
166 ON_BN_CLICKED(_R(ID_ERRORBOX_BUTTON5), OnClickedButton5)
167 ON_COMMAND(IDCANCEL, OnCancelCmd)
168 //}}AFX_MSG_MAP
169 END_MESSAGE_MAP()
172 // Static variables used to hold info about the error box template.
173 SIZE CInformErrorDialog::DefButtonSize;
174 INT32 CInformErrorDialog::ButtonSpacing;
175 SIZE CInformErrorDialog::DialogSize;
176 INT32 CInformErrorDialog::EdgeSpacing;
177 INT32 CInformErrorDialog::DefTopOfButton;
178 POINT CInformErrorDialog::DefIconPos;
179 SIZE CInformErrorDialog::DefMsgSize;
180 BOOL CInformErrorDialog::ValidInfo = FALSE;
181 String_64 CInformErrorDialog::ButtonText[ERRORDLG_MAXBUTTONS];
184 // The ID's of the error box buttons.
185 // IF YOU CHANGE THE VALUE OF ERRORDLG_MAXBUTTONS YOU MUST CHANGE THIS AS WELL!
186 UINT32 CInformErrorDialog::ButtonID[ERRORDLG_MAXBUTTONS] =
188 _R(ID_ERRORBOX_BUTTON1),
189 _R(ID_ERRORBOX_BUTTON2),
190 _R(ID_ERRORBOX_BUTTON3),
191 _R(ID_ERRORBOX_BUTTON4),
192 _R(ID_ERRORBOX_BUTTON5)
197 /********************************************************************************************
199 > void CInformErrorDialog::GetDialogInfo()
201 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
202 Created: 19/05/94
203 Purpose: Finds out various properties of the error box dialog. This is done once
204 only - the first time an error box is displayed.
205 These properties are used when moving/resizing buttons, the icon, and
206 the static control used to display the message.
207 SeeAlso: CInformErrorDialog::SetupButtons; CInformErrorDialog::SetupMessage
209 ********************************************************************************************/
211 void CInformErrorDialog::GetDialogInfo()
213 // Skip this if we've already done it.
214 if (ValidInfo)
215 return;
217 // Find out how bug the dialog is by default.
218 CRect DlgRect;
219 GetClientRect(&DlgRect);
220 DialogSize.cx = DlgRect.Width();
221 DialogSize.cy = DlgRect.Height();
223 // Find out the button spacing/sizes etc.
224 CWnd *pCtrl1 = GetDlgItem(ButtonID[0]);
225 CWnd *pCtrl2 = GetDlgItem(ButtonID[1]);
226 ENSURE((pCtrl1 != NULL) && (pCtrl2 != NULL),
227 "Can't find control in CInformErrorDialog::OnInitDialog()");
229 // Safety check.
230 if ((pCtrl1 == NULL) || (pCtrl2 == NULL))
231 return;
233 // Get width of buttons, and the spacing between the buttons and the edge of the dialog.
234 WINDOWPLACEMENT Placement;
235 Placement.length = sizeof(WINDOWPLACEMENT);
236 pCtrl1->GetWindowPlacement(&Placement);
238 DefTopOfButton = Placement.rcNormalPosition.top;
239 DefButtonSize.cx = Placement.rcNormalPosition.right - Placement.rcNormalPosition.left;
240 DefButtonSize.cy = Placement.rcNormalPosition.bottom - Placement.rcNormalPosition.top;
241 EdgeSpacing = Placement.rcNormalPosition.left;
243 // Get space between adjacent buttons.
244 Placement.length = sizeof(WINDOWPLACEMENT);
245 pCtrl2->GetWindowPlacement(&Placement);
247 ButtonSpacing = Placement.rcNormalPosition.left - (EdgeSpacing + DefButtonSize.cx);
249 // Find the position of the icon.
250 CWnd *pIconCtrl = GetDlgItem(_R(IDC_ERRORBOX_ICON));
251 ENSURE(pIconCtrl != NULL, "Can't find Icon control in CInformErrorDialog::GetDialogInfo()");
253 // Safety check.
254 if (pIconCtrl == NULL)
255 return;
257 Placement.length = sizeof(WINDOWPLACEMENT);
258 pIconCtrl->GetWindowPlacement(&Placement);
260 DefIconPos.x = Placement.rcNormalPosition.left;
261 DefIconPos.y = Placement.rcNormalPosition.top;
263 // Find the position of the message text area.
264 CWnd *pMsgCtrl = GetDlgItem(_R(IDC_ERRORBOX_TEXT));
265 ENSURE(pMsgCtrl != NULL, "Can't find Text control in CInformErrorDialog::GetDialogInfo()");
267 // Safety check.
268 if (pMsgCtrl == NULL)
269 return;
271 Placement.length = sizeof(WINDOWPLACEMENT);
272 pMsgCtrl->GetWindowPlacement(&Placement);
274 DefMsgSize.cx = Placement.rcNormalPosition.right - Placement.rcNormalPosition.left;
275 DefMsgSize.cy = Placement.rcNormalPosition.bottom - Placement.rcNormalPosition.top;
277 // The static variables now contain valid information.
278 ValidInfo = TRUE;
283 /********************************************************************************************
285 > BOOL CInformErrorDialog::SetupButtons(HDC hDC, INT32 NumButtons)
287 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
288 Created: 19/05/94
289 Inputs: hDC - device context for the dialog (used to access the font).
290 NumButtons - how many buttons the caller has asked for.
291 Returns: TRUE if the buttons were set up ok;
292 FALSE if not, and hence caller should fall back on MessageBox().
293 Purpose: Initialises the buttons in the dialog ready to be displayed.
294 This includes setting the text, resizing the buttons if the text is too
295 big to fit, moveing the buttons so they are always centred no matter how
296 big they are or how many there are.
297 If the buttons get very wide, then the dialog is made wider to accomadate
298 them.
299 SeeAlso: CInformErrorDialog::GetDialogInfo; CInformErrorDialog::SetupMessage
301 ********************************************************************************************/
303 BOOL CInformErrorDialog::SetupButtons(HDC hDC, INT32 NumButtons)
305 // Set the default button in the dialog.
306 CWnd *pDefCtrl = GetDlgItem(ButtonID[m_OK - 1]);
307 ENSURE(pDefCtrl != NULL, "Can't get handle to default control in CInformErrorDialog");
309 // If we can't get at this button then ooer...bit of a fatal error
310 if (pDefCtrl == NULL)
312 ENSURE(FALSE, "Can't get default button in error box!");
313 return FALSE;
316 // Set the keyboard focus to the default button, and give it a 'default' border.
317 pDefCtrl->SetFocus();
318 SendMessage(DM_SETDEFID, ButtonID[m_OK - 1], 0);
320 // Read in the button texts, and find which is the widest string.
321 INT32 ButtonWidth = DefButtonSize.cx;
322 INT32 i;
323 for (i = 0; i < NumButtons; i++)
325 // Try to load text for this button
326 if (!ButtonText[i].Load(m_ButtonStr[i], m_OwnerModule))
328 ENSURE(FALSE, "Unable to load button text for error box!");
329 return FALSE;
332 // Try to read the size of this button text.
333 SIZE TextSize;
334 if (!GetTextExtentPoint(hDC, (TCHAR *) ButtonText[i], ButtonText[i].Length(),
335 &TextSize))
337 // Error reading text size
338 ENSURE(FALSE, "Unable to read button text size for error box!");
339 return FALSE;
342 if (TextSize.cx > ButtonWidth)
343 ButtonWidth = TextSize.cx + 8;
346 // Allow for space on either side in the button
347 ButtonWidth += 8;
349 // Find out how big the buttons can be at the most.
350 INT32 MaxWidth = DialogSize.cx -
351 (2 * EdgeSpacing) -
352 ((NumButtons - 1) * ButtonSpacing);
354 // NumButtons cannot be 0 if we get to here...but just in case :-)
355 if (NumButtons == 0)
357 ENSURE(FALSE, "NumButtons is zero in error box!");
358 return FALSE;
361 // Safe to do a divide now!
362 MaxWidth /= NumButtons;
364 // The width of the dialog may change.
365 INT32 NewWidth = DialogSize.cx;
367 // Find out if we need to make the dialog bigger to accomodate the buttons.
368 if (ButtonWidth > MaxWidth)
370 // Yes - find out if the buttons actually fit on screen - if not, make them
371 // smaller and truncate the button text (this shouldn't happen too often!)
373 // Get required dialog width
374 NewWidth = (EdgeSpacing * 2) +
375 (NumButtons * ButtonWidth) +
376 ((NumButtons - 1) * ButtonSpacing);
378 // Does this actually fit on screen?
379 INT32 ScreenWidth = GetSystemMetrics(SM_CXSCREEN);
381 if (ScreenWidth < NewWidth)
383 // They don't fit - downsize the buttons to fit.
384 ButtonWidth = ScreenWidth -
385 (2 * EdgeSpacing) -
386 ((NumButtons - 1) * ButtonSpacing);
387 ButtonWidth /= NumButtons;
389 NewWidth = ScreenWidth;
392 // Ok - buttons are now correct size - resize the dialog.
393 SIZE BorderSize;
394 BorderSize.cx = 2 * ::GetSystemMetrics(SM_CXDLGFRAME);
395 BorderSize.cy = ::GetSystemMetrics(SM_CYDLGFRAME) +
396 ::GetSystemMetrics(SM_CYCAPTION);
398 if (!SetWindowPos(NULL, 0, 0,
399 NewWidth + BorderSize.cx, DialogSize.cy + BorderSize.cy,
400 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE | SWP_NOREDRAW))
402 ENSURE(FALSE, "Unable to resize the error box!");
403 return FALSE;
406 // Resize the error message control so it doesn't look silly.
407 INT32 Diff = NewWidth - DialogSize.cx;
409 CWnd *pMsgCtrl = GetDlgItem(_R(IDC_ERRORBOX_TEXT));
410 ENSURE(pMsgCtrl != NULL, "Can't get handle to text control in CInformErrorDialog");
412 if (pMsgCtrl != NULL)
414 // Ok - resize it.
415 if (!pMsgCtrl->SetWindowPos(NULL, 0, 0,
416 DefMsgSize.cx + Diff, DefMsgSize.cy,
417 SWP_NOACTIVATE | SWP_NOZORDER |
418 SWP_NOMOVE | SWP_NOREDRAW))
420 ENSURE(FALSE, "Unable to adjust error message control in error box!");
421 return FALSE;
426 // Position buttons accordingly...
428 // How much space is left on either side of the row of buttons?
429 INT32 SpareSpace = NewWidth -
430 (NumButtons * ButtonWidth) -
431 ((NumButtons - 1) * ButtonSpacing);
433 // Work out where the first button should be.
434 INT32 FarLeft = SpareSpace / 2;
436 INT32 ButtonStep = ButtonSpacing + ButtonWidth;
438 // For each button:
439 // * Set the button text.
440 // * Move the button to the correct position.
441 // * Show the button.
442 for (i = 0; i < NumButtons; i++)
444 SetDlgItemText(ButtonID[i], ButtonText[i]);
446 if (!m_Button[i].SetWindowPos(NULL,
447 FarLeft + (i * ButtonStep), DefTopOfButton,
448 ButtonWidth, DefButtonSize.cy,
449 SWP_NOACTIVATE | SWP_NOZORDER |
450 SWP_NOREDRAW | SWP_SHOWWINDOW))
452 ENSURE(FALSE, "Unable to move button in the error box!");
453 return FALSE;
457 // Tell the caller that we managed to do all this successfully!
458 return TRUE;
464 /********************************************************************************************
466 > BOOL CInformErrorDialog::SetupMessage(HDC hDC)
468 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
469 Created: 19/05/94
470 Inputs: hDC - the device context of the dialog (used to access the dialog's font).
471 Purpose: Puts the error message into the dialog, and checks to see if this message
472 will fit. If it doesn't, the dialog is expanded vertically so that it does
473 fit, and the buttons are moved down, and the icon is moved down so it's
474 halfway down the message text so it looks all neat and luvverly.
475 SeeAlso: CInformErrorDialog::GetDialogInfo; CInformErrorDialog::SetupButtons
477 ********************************************************************************************/
479 BOOL CInformErrorDialog::SetupMessage(HDC hDC)
481 // Set the error message in the text control, and find out the size of the message.
482 SIZE TextSize;
483 RECT TextRect;
484 INT32 Offset = 0;
486 CWnd *pMsgCtrl = GetDlgItem(_R(IDC_ERRORBOX_TEXT));
487 ENSURE(pMsgCtrl != NULL, "Can't get handle to text control in CInformErrorDialog");
490 if (pMsgCtrl == NULL)
492 // Failed to get at the message control - flag an error
493 ENSURE(FALSE, "Unable to access error message control");
494 return FALSE;
497 // Get rectangle of message control.
498 RECT MsgCtrlRect;
499 pMsgCtrl->GetWindowRect(&MsgCtrlRect);
500 ScreenToClient(&MsgCtrlRect);
502 // Use the current control's rectangle as the basis for the formatting rectangle
503 // of the text (Bottom will extend in preference to Right)
504 TextRect = MsgCtrlRect;
506 if (m_StaticTextStr != 0)
508 String_256 MsgStr(m_StaticTextStr, m_OwnerModule);
509 SetDlgItemText(_R(IDC_ERRORBOX_TEXT), MsgStr);
510 DrawText(hDC, (TCHAR *) MsgStr, -1, &TextRect, DT_CALCRECT | DT_TOP | DT_LEFT | DT_WORDBREAK);
512 else
514 TCHAR *pMsg = Error::GetErrorString();
515 SetDlgItemText(_R(IDC_ERRORBOX_TEXT), pMsg);
516 DrawText(hDC, pMsg, -1, &TextRect, DT_CALCRECT | DT_TOP | DT_LEFT | DT_WORDBREAK);
519 TextSize.cx = TextRect.right - TextRect.left;
520 TextSize.cy = TextRect.bottom - TextRect.top;
522 if ((TextSize.cx == 0) || (TextSize.cy == 0))
524 // Failed to get the size of the text - flag an error
525 ENSURE(FALSE, "Unable to read size of error message");
526 return FALSE;
529 // Get dimensions of message control.
530 SIZE MsgCtrlSize;
531 MsgCtrlSize.cx = MsgCtrlRect.right - MsgCtrlRect.left;
532 MsgCtrlSize.cy = MsgCtrlRect.bottom - MsgCtrlRect.top;
534 if ((MsgCtrlSize.cx == 0) || (MsgCtrlSize.cy == 0))
536 // Message control has a bad size - flag an error
537 ENSURE(FALSE, "Bad message control size in error dialog box!");
538 return FALSE;
541 // If formatted text is bigger than current control rect
542 // we need to resize it...
543 if (MsgCtrlSize.cx < TextSize.cx || MsgCtrlSize.cy < TextSize.cy)
545 if (MsgCtrlSize.cx < TextSize.cx)
546 MsgCtrlSize.cx = TextSize.cx + 8;
548 if (MsgCtrlSize.cy < TextSize.cy)
550 Offset = TextSize.cy - MsgCtrlSize.cy + 8;
551 MsgCtrlSize.cy = TextSize.cy + 8;
554 // Resize message.
555 if (!pMsgCtrl->SetWindowPos(NULL, 0, 0, MsgCtrlSize.cx, MsgCtrlSize.cy,
556 SWP_NOACTIVATE | SWP_NOZORDER |
557 SWP_NOMOVE | SWP_NOREDRAW))
559 ENSURE(FALSE, "Unable to resize the message control in error box!");
560 return FALSE;
563 // Move icon (just change IconPos - we ignore the real icon from now on)
564 IconPos.y += (Offset / 2);
566 // Move buttons
567 for (INT32 i = 0; i < ERRORDLG_MAXBUTTONS; i++)
569 RECT ButtonRect;
570 m_Button[i].GetWindowRect(&ButtonRect);
571 ScreenToClient(&ButtonRect);
572 if (!m_Button[i].SetWindowPos(NULL, ButtonRect.left, ButtonRect.top + Offset,
573 0, 0,
574 SWP_NOACTIVATE | SWP_NOZORDER |
575 SWP_NOSIZE | SWP_NOREDRAW))
577 ENSURE(FALSE, "Unable to resize the button control in error box!");
578 return FALSE;
582 // Resize dialog.
583 RECT DialogRect;
584 GetWindowRect(&DialogRect);
585 INT32 DialogWidth = DialogRect.right - DialogRect.left;
586 INT32 DialogHeight = DialogRect.bottom - DialogRect.top;
588 if (!SetWindowPos(NULL, 0, 0, DialogWidth, DialogHeight + Offset,
589 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE | SWP_NOREDRAW))
591 ENSURE(FALSE, "Unable to resize the error box dialog!");
592 return FALSE;
596 // All ok!
597 return TRUE;
601 ///////////////////////////////////////
602 // CInformErrorDialog message handlers
605 /********************************************************************************************
607 > BOOL CInformErrorDialog::OnInitDialog()
609 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
610 Created: 20/7/93
611 Returns: TRUE if all went OK, FALSE if the focus was set to a control
612 Purpose: This function sets up the dialog accoding to the data supplied by the
613 program. First the various fields in the dialog are filled in and the
614 relevant buttons activated, and then the dialog is centred.
616 ********************************************************************************************/
618 BOOL CInformErrorDialog::OnInitDialog()
620 CDialog::OnInitDialog();
622 String_64 BoxTitle;
623 BoxTitle = _R(IDS_ERROR_BOX_SERIOUS_ERROR); // "Serious error"
625 String_256 VerySeriousError;
626 VerySeriousError = _R(IDS_ERROR_BOX_VERY_SERIOUS_ERROR); // "A very serious error has occured - please consult your technical support."
628 // Andy Hills, 22-11-00
629 // Store the help context.
630 // We need to do this here, because the global help context variable
631 // nNextMessageHelpContext may change before the user clicks the 'Help'
632 // button. This fixes bug 6359.
633 m_nHelpContext = Error::GetErrorNumber();
634 if (! m_nHelpContext) m_nHelpContext = GetNextMsgHelpContext();
636 // Find out how many buttons there are.
637 for (INT32 NumButtons = ERRORDLG_MAXBUTTONS; NumButtons > 0; NumButtons--)
639 if (m_ButtonStr[NumButtons - 1] != 0) break;
642 // Adjust the OK and Cancel fields if necessary
643 if (m_OK > (UINT32) NumButtons)
645 if (IsUserName("Tim"))
647 TRACE( _T("OK out of range, OK=%u, NumButtons=%d\n"), m_OK, NumButtons);
649 // Default to first button
650 m_OK = 1;
653 if (m_Cancel > (UINT32) NumButtons)
655 if (IsUserName("Tim"))
657 TRACE( _T("Cancel out of range, Cancel=%u, NumButtons=%d\n"), m_Cancel, NumButtons);
660 // Default to be the same as OK (this means a box with a single OK box will
661 // respond to Enter and Esc without the user having to specify a Cancel ID).
662 m_Cancel = m_OK;
665 if (m_Help > (UINT32) NumButtons)
667 TRACEUSER( "JustinF", _T("Help button (%d) out of range (%d)\n"),
668 (INT32) m_Help, (INT32) NumButtons);
670 // The only really safe thing we can do is drop the help button.
671 m_Help = 0;
674 // Make sure we have correct dialog information
675 GetDialogInfo();
676 if (!ValidInfo)
678 // Serious error - fall back to to MessageBox().
679 goto SevereError;
682 // Get icon position
683 IconPos = DefIconPos;
686 // Get a DC for this dialog, so we can find out the size of text strings.
687 // We'll also need to select in our font or else it'll base the width upon the
688 // System font rather than the font we're using (MS Sans Serif at last check)
689 CDC *pDC;
690 CFont *OldFont;
692 pDC = GetDC();
693 ENSURE(pDC != NULL, "Can't get DC for error box dialog");
695 // Check the DC
696 if (pDC == NULL)
697 goto SevereError;
699 OldFont = pDC->SelectObject(GetFont());
701 // Set buttons text and move/resize buttons according to the number of them,
702 // and their contents.
703 BOOL Success;
704 Success = SetupButtons(pDC->m_hDC, NumButtons);
706 // Size the error message control, and put the message in it.
707 Success = Success && SetupMessage(pDC->m_hDC);
709 if (OldFont != NULL)
710 pDC->SelectObject(OldFont);
712 // We've finished with this DC now.
713 ReleaseDC(pDC);
716 // Check for failure in button/message setup.
717 if (!Success)
718 goto SevereError;
720 // Play the appropriate sound and set the appropriate title bar text ID.
721 UINT32 TitleID;
722 TitleID = m_TitleStr;
723 switch (m_ErrorBoxType)
725 case ERRORTYPE_NORMAL:
726 // No sound for this one - it's just a message; nothing to shout about.
727 if (TitleID == 0) TitleID = _R(IDS_ERRORBOX_NORMAL);
728 break;
730 case ERRORTYPE_QUESTION:
731 MessageBeep(MB_ICONQUESTION);
732 if (TitleID == 0) TitleID = _R(IDS_ERRORBOX_NORMAL);
733 break;
735 case ERRORTYPE_ERROR:
736 MessageBeep(MB_ICONEXCLAMATION);
737 if (TitleID == 0) TitleID = _R(IDS_ERRORBOX_ERROR);
738 break;
740 case ERRORTYPE_WARNING:
741 MessageBeep(MB_ICONASTERISK);
742 if (TitleID == 0) TitleID = _R(IDS_ERRORBOX_WARNING);
743 break;
745 case ERRORTYPE_SERIOUS:
746 MessageBeep(MB_ICONHAND);
747 if (TitleID == 0) TitleID = _R(IDS_ERRORBOX_SERIOUS);
748 break;
750 case ERRORTYPE_ENSURE:
751 MessageBeep(MB_ICONHAND);
752 if (TitleID == 0) TitleID = _R(IDS_ERRORBOX_ENSURE);
753 break;
755 default:
756 ENSURE(FALSE, "Bad errortype in CInformErrorDialog::OnInitDialog()");
757 goto SevereError;
758 break;
761 // Set the title bar text if necessary.
762 if (TitleID != 0)
764 String_64 Title(TitleID);
765 SetWindowText((TCHAR*) Title);
768 // Centre the dialog on the screen (Code stolen from splash.cpp)
769 // Get the size of the screen
770 INT32 ScreenWidth, ScreenHeight;
771 ScreenWidth = GetSystemMetrics(SM_CXSCREEN);
772 ScreenHeight = GetSystemMetrics(SM_CYSCREEN);
774 // Get the size of the dialog box
775 RECT DialogRect;
776 GetWindowRect(&DialogRect);
777 INT32 DialogWidth, DialogHeight;
778 DialogWidth = DialogRect.right - DialogRect.left;
779 DialogHeight = DialogRect.bottom - DialogRect.top;
781 // Chicago M7 gives us crap values at this point if we are minimized so try and make them sane
782 if (DialogWidth<=0)
783 DialogWidth = ScreenWidth / 2;
784 else if (DialogWidth > ScreenWidth)
785 DialogWidth = ScreenWidth;
787 if (DialogHeight<=0)
788 DialogHeight = ScreenHeight / 2;
789 else if (DialogHeight > ScreenHeight)
790 DialogHeight = ScreenHeight;
792 // Centre the dialog box and give it the 'top' style.
793 INT32 Left, Top;
794 Left = (ScreenWidth - DialogWidth) / 2;
795 Top = (ScreenHeight - DialogHeight) / 2;
796 SetWindowPos(&wndTop, Left, Top, DialogWidth, DialogHeight, SWP_SHOWWINDOW);
798 // If we got this far, then we changed the keyboard focus, so return FALSE.
799 return FALSE;
801 SevereError:
802 // Ooer - deeply catastrophic error...report to user and exit.
803 String_256 Message;
805 // First - check that this isn't just because of an empty error message.
806 if (m_StaticTextStr == 0)
808 // Get the error message
809 TCHAR *pMsg = Error::GetErrorString();
811 if ((pMsg == NULL) || (pMsg[0] == 0))
814 // There is no error message!
817 // In debug builds, give developer a chance to go into debugger to see who is not
818 // setting an error message.
819 #ifdef _DEBUG
820 if (::MessageBox(ParentHwnd,
821 "Somebody reported an error without an error message being set.\r"
822 "Click OK to continue, or Cancel to go into debugger",
823 "DEBUG Warning from Camelot",
824 MB_OKCANCEL| MB_SYSTEMMODAL | MB_ICONHAND) == IDCANCEL)
826 // User wants to go into debugger
827 DebugBreak();
829 #endif
831 // Tell the user a spurious error has occured,
832 if (!Message.Load(_R(IDS_ERRORBOX_SPURIOUS)))
833 // Can't load error message - panic.
834 goto VerySevereError;
836 // Try to get the string that says "Warning from Camelot"
837 String_64 Title;
838 if (!Title.Load(_R(IDS_ERRORBOX_WARNING)))
839 goto VerySevereError;
841 if (::MessageBox(ParentHwnd, (TCHAR *) Message, (TCHAR *) Title,
842 MB_OK | MB_SYSTEMMODAL | MB_ICONHAND) == 0)
843 // Could not create the message box - try our fallback one (probably won't
844 // work but what the hell).
845 goto VerySevereError;
847 // Simulate user hitting default button.
848 EndDialog((INT32) m_OK);
850 return TRUE; // We haven't set the keyboard focus.
855 // Inform the user that we've got a bit of a bad karma situation, and that the error
856 // box might be not be completely accurate.
857 if (!Message.Load(_R(IDS_ERRORBOX_SEVERE)))
858 goto VerySevereError;
860 if (::MessageBox(ParentHwnd, (TCHAR *) Message, (TCHAR *)BoxTitle, /*"Serious Error", */
861 MB_OK | MB_SYSTEMMODAL | MB_ICONHAND) == 0)
862 // Could not create the message box - try our fallback one (probably won't
863 // work but what the hell).
864 goto VerySevereError;
866 // Ok - try to report the error as best we can...
868 // Work out what buttons to put on the dialog...
870 // We use SYSTEMMODAL with ICONHAND because the SDK docs recommend this for low
871 // memory/severe error situations.
872 UINT32 MBFlags;
873 MBFlags = MB_SYSTEMMODAL | MB_ICONHAND;
875 // Do we need a cancel icon?
876 if (m_Cancel != m_OK)
877 MBFlags |= MB_OKCANCEL;
878 else
879 MBFlags |= MB_OK;
881 if (m_StaticTextStr != 0)
883 if (Message.Load(m_StaticTextStr, m_OwnerModule))
885 // Error message loaded ok - display it
886 INT32 Result = ::MessageBox(ParentHwnd, (TCHAR *) Message, (TCHAR *)BoxTitle, MBFlags);
888 if (Result == 0)
889 // Could not create the message box - try our fallback one (probably won't
890 // work but what the hell).
891 goto VerySevereError;
893 if (Result == IDCANCEL)
895 // Simulate user hitting cancel button.
896 EndDialog((INT32) m_Cancel);
898 else
900 // Simulate user hitting default button.
901 EndDialog((INT32) m_OK);
904 return TRUE; // We haven't set the keyboard focus.
906 else
908 // Can't load error message - bail out
909 goto VerySevereError;
912 else
914 // Get the error message
915 TCHAR *pMsg = Error::GetErrorString();
917 if (pMsg == NULL)
918 // No error message!
919 goto VerySevereError;
921 // Found error message ok - display it
922 INT32 Result = ::MessageBox(ParentHwnd, pMsg, (TCHAR *)BoxTitle, MBFlags);
924 if (Result == 0)
925 // Could not create the message box - try our fallback one (probably won't
926 // work but what the hell).
927 goto VerySevereError;
929 if (Result == IDCANCEL)
931 // Simulate user hitting cancel button.
932 EndDialog((INT32) m_Cancel);
934 else
936 // Simulate user hitting default button.
937 EndDialog((INT32) m_OK);
940 return TRUE; // We haven't set the keyboard focus.
943 VerySevereError:
944 // Very bad - we can't even report the error - just let the user that something deeply
945 // sad has happened, and pretend that the OK button was pressed.
946 ::MessageBox(ParentHwnd, (TCHAR *)VerySeriousError, (TCHAR *)BoxTitle, MB_OK | MB_SYSTEMMODAL | MB_ICONHAND);
948 // Simulate user hitting default button.
949 EndDialog((INT32) m_OK);
951 return TRUE; // We haven't set the keyboard focus.
956 /********************************************************************************************
958 > void CInformErrorDialog::OnPaint()
960 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
961 Created: 19/05/94
962 Purpose: Special painting of the dialog. This involves drawing the correct icon
963 onto the dialog, according to the type/degree of error.
964 The icon position is based on the position of the hidden icon control in
965 the dialog, but may be moved down if the message area needs to grow to
966 accomodate a long message.
967 SeeAlso: CInformErrorDialog::SetupMessage
969 ********************************************************************************************/
971 void CInformErrorDialog::OnPaint()
973 CPaintDC dc(this); // device context for painting
975 HICON hIcon;
976 CWinApp *pApp = AfxGetApp();
978 ENSURE(pApp != NULL, "Could not get application object in CInformErrorDialog::OnPaint()");
979 if (pApp == NULL)
980 return;
982 switch (m_ErrorBoxType)
984 case ERRORTYPE_NORMAL:
985 hIcon = pApp->LoadIcon(_R(IDR_MAINFRAME));
986 break;
988 case ERRORTYPE_QUESTION:
989 // The line below is commented out (by Phil, 12/8/96) because the latest UI guidelines
990 // advise against using this icon.
991 // See "The Windows Interface Guidelines for Software Design" P.211.
992 // hIcon = pApp->LoadStandardIcon(_R(IDI_QUESTION));
993 hIcon = pApp->LoadStandardIcon(_R(IDI_EXCLAMATION));
994 break;
996 case ERRORTYPE_ERROR:
997 hIcon = pApp->LoadStandardIcon(_R(IDI_EXCLAMATION));
998 break;
1000 case ERRORTYPE_WARNING:
1001 hIcon = pApp->LoadStandardIcon(_R(IDI_ASTERISK));
1002 break;
1004 case ERRORTYPE_SERIOUS:
1005 case ERRORTYPE_ENSURE:
1006 hIcon = pApp->LoadStandardIcon(_R(IDI_HAND));
1007 break;
1009 default:
1010 ENSURE(FALSE, "Bad errortype in CInformErrorDialog::OnPaint()");
1011 return;
1015 ENSURE(hIcon != NULL, "Could not load icon in CInformErrorDialog::OnPaint()");
1016 if (hIcon != NULL)
1018 // Got an icon - let's draw it on the dialog.
1019 dc.DrawIcon(IconPos.x, IconPos.y, hIcon);
1022 // Do not call CWnd::OnPaint() for painting messages
1027 /********************************************************************************************
1028 > void CInformErrorDialog::OnClickedButton1()
1029 void CInformErrorDialog::OnClickedButton2()
1030 void CInformErrorDialog::OnClickedButton3()
1031 void CInformErrorDialog::OnClickedButton4()
1032 void CInformErrorDialog::OnClickedButton5()
1034 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
1035 Created: 20/7/93
1036 Purpose: Responds to the five buttons at the bottom of the dialog. Calls the
1037 HandleButton function in each case, passing the ID of the button.
1038 SeeAlso: CInformErrorDialog::HandleButton
1039 ********************************************************************************************/
1041 void CInformErrorDialog::OnClickedButton1()
1043 HandleButton(1);
1047 void CInformErrorDialog::OnClickedButton2()
1049 HandleButton(2);
1053 void CInformErrorDialog::OnClickedButton3()
1055 HandleButton(3);
1059 void CInformErrorDialog::OnClickedButton4()
1061 HandleButton(4);
1065 void CInformErrorDialog::OnClickedButton5()
1067 HandleButton(5);
1072 /********************************************************************************************
1073 > virtual void CInformErrorDialog::HandleButton(UINT32 idButton)
1075 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
1076 Created: 11/5/95
1077 Inputs: idButton which button was clicked, ie. 1-5
1078 Purpose: Handles a button being clicked in a Inform... dialog box. If the button
1079 is the "help" button it runs help for the dialog, otherwise it ends the
1080 dialog and returns which button was clicked.
1081 SeeAlso: CInformErrorDialog::OnClickedButton1
1082 ********************************************************************************************/
1084 void CInformErrorDialog::HandleButton(UINT32 idButton)
1086 // Check if the clicked button is a "Help" button.
1087 if (idButton == m_Help)
1089 #if !defined(EXCLUDE_FROM_RALPH) && !defined(EXCLUDE_FROM_XARALX)
1090 // It is, so run the help topic associated with the message ID.
1091 HelpUser(m_nHelpContext);
1092 #endif
1094 else
1096 // It isn't, so end the dialog, returning which button was clicked.
1097 EndDialog((INT32) idButton);
1103 /********************************************************************************************
1104 > void CInformErrorDialog::OnCancelCmd()
1106 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
1107 Created: 19/05/94
1108 Purpose: Responds to an Esc keypress from the user - it simulates pressing the
1109 button defined to be the 'cancel' button in the dialog (although the
1110 button may not actually be labelled 'cancel' - it may say 'No' or
1111 whatever).
1112 ********************************************************************************************/
1114 void CInformErrorDialog::OnCancelCmd()
1116 // User has hit Esc - return with the ID of the 'Cancel' button.
1117 EndDialog((INT32) m_Cancel);
1122 /********************************************************************************************
1124 > CWnd* CInformErrorDialog::GetSafeParent()
1126 Author: Andy_Pennell (Xara Group Ltd) <camelotdev@xara.com>
1127 Created: 2/11/94
1128 Returns: Pointer to a CWnd for use as a parent window in error dialogs, or NULL
1129 if we don't have one.
1130 Purpose: Used by the error reporter and ensure handler to get a suitable parent
1131 window.
1133 ********************************************************************************************/
1135 CWnd* CInformErrorDialog::GetSafeParent()
1137 CWnd *Parent = NULL;
1139 #if !defined(EXCLUDE_FROM_RALPH) && !defined(EXCLUDE_FROM_XARALX)
1140 // if the splash box is up, use that as the parent
1141 Parent = CSplashDialog::GetpWnd();
1143 if (Parent)
1144 return Parent;
1145 #endif
1147 // WEBSTER-ranbirr-12/11/96
1148 #ifndef WEBSTER
1149 #ifndef STANDALONE
1150 // If there is a print-related dlg up, use it as the parent
1151 Parent = CCPrintDialog::GetPrintCWnd();
1152 if (Parent)
1153 return Parent;
1154 #endif
1155 #endif //webster
1157 // see if mainframe is up - use it if visible
1158 Parent = GetMainFrame();
1159 if (Parent && Parent->IsWindowVisible())
1160 return Parent;
1161 return NULL;