xref: /trunk/main/dbaccess/source/ui/dlg/sqlmessage.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_dbaccess.hxx"
30 
31 #ifndef _DBAUI_SQLMESSAGE_HXX_
32 #include "sqlmessage.hxx"
33 #endif
34 #ifndef _DBU_DLG_HRC_
35 #include "dbu_dlg.hrc"
36 #endif
37 #ifndef _DBAUI_SQLMESSAGE_HRC_
38 #include "sqlmessage.hrc"
39 #endif
40 #ifndef _COM_SUN_STAR_SDBC_SQLEXCEPTION_HPP_
41 #include <com/sun/star/sdbc/SQLException.hpp>
42 #endif
43 #ifndef _COM_SUN_STAR_SDB_SQLCONTEXT_HPP_
44 #include <com/sun/star/sdb/SQLContext.hpp>
45 #endif
46 #ifndef _SV_GROUP_HXX //autogen
47 #include <vcl/fixed.hxx>
48 #endif
49 #ifndef _SVTREEBOX_HXX
50 #include <svtools/svtreebx.hxx>
51 #endif
52 #ifndef _SVEDIT_HXX //autogen
53 #include <svtools/svmedit.hxx>
54 #endif
55 #ifndef _DBHELPER_DBEXCEPTION_HXX_
56 #include <connectivity/dbexception.hxx>
57 #endif
58 #ifndef CONNECTIVITY_SQLERROR_HXX
59 #include <connectivity/sqlerror.hxx>
60 #endif
61 #ifndef _SV_MSGBOX_HXX //autogen
62 #include <vcl/msgbox.hxx>
63 #endif
64 #ifndef _UTL_CONFIGMGR_HXX_
65 #include <unotools/configmgr.hxx>
66 #endif
67 #ifndef _SFX_SFXUNO_HXX
68 #include <sfx2/sfxuno.hxx>
69 #endif
70 #ifndef _DBA_DBACCESS_HELPID_HRC_
71 #include "dbaccess_helpid.hrc"
72 #endif
73 #ifndef DBAUI_TOOLS_HXX
74 #include "UITools.hxx"
75 #endif
76 #ifndef _DBAUI_MODULE_DBU_HXX_
77 #include "moduledbu.hxx"
78 #endif
79 
80 #include <tools/urlobj.hxx>
81 
82 #define BUTTONID_MORE	BUTTONID_RETRY + 1
83 
84 #define DIALOG_WIDTH    220
85 #define OUTER_MARGIN    6
86 #define IMAGE_SIZE      20
87 #define INNER_PADDING   3
88 #define TEXT_POS_X      ( OUTER_MARGIN + IMAGE_SIZE + INNER_PADDING )
89 
90 using namespace dbtools;
91 using namespace com::sun::star::uno;
92 using namespace com::sun::star::sdb;
93 using namespace com::sun::star::sdbc;
94 
95 //.........................................................................
96 namespace dbaui
97 {
98 //.........................................................................
99 
100 namespace
101 {
102     //------------------------------------------------------------------------------
103     class IImageProvider
104     {
105     public:
106         virtual Image   getImage( bool _highContrast ) const = 0;
107 
108         virtual ~IImageProvider() { }
109     };
110 
111     //------------------------------------------------------------------------------
112     class ILabelProvider
113     {
114     public:
115         virtual String  getLabel() const = 0;
116 
117         virtual ~ILabelProvider() { };
118     };
119 
120     //------------------------------------------------------------------------------
121     class ImageProvider : public IImageProvider
122     {
123     private:
124         sal_uInt16  m_defaultImageID;
125         sal_uInt16  m_highContrastImageID;
126 
127         mutable Image   m_defaultImage;
128         mutable Image   m_highContrastImage;
129 
130     public:
131         ImageProvider( sal_uInt16 _defaultImageID, sal_uInt16 _highContrastImageID )
132             :m_defaultImageID( _defaultImageID )
133             ,m_highContrastImageID( _highContrastImageID )
134         {
135         }
136 
137         virtual Image getImage( bool _highContrast ) const
138         {
139             if ( _highContrast )
140             {
141                 if ( !m_highContrastImage )
142                     m_highContrastImage = Image( ModuleRes( m_highContrastImageID ) );
143                 return m_highContrastImage;
144             }
145 
146             if ( !m_defaultImage )
147                 m_defaultImage = Image( ModuleRes( m_defaultImageID ) );
148             return m_defaultImage;
149         }
150     };
151 
152     //------------------------------------------------------------------------------
153     class LabelProvider : public ILabelProvider
154     {
155     private:
156         String  m_label;
157     public:
158         LabelProvider( sal_uInt16 _labelResourceID )
159             :m_label( ModuleRes( _labelResourceID ) )
160         {
161         }
162 
163         virtual String  getLabel() const
164         {
165             return m_label;
166         }
167     };
168 
169     //------------------------------------------------------------------------------
170     class ProviderFactory
171     {
172     private:
173         mutable ::boost::shared_ptr< IImageProvider >   m_pErrorImage;
174         mutable ::boost::shared_ptr< IImageProvider >   m_pWarningsImage;
175         mutable ::boost::shared_ptr< IImageProvider >   m_pInfoImage;
176         mutable ::boost::shared_ptr< ILabelProvider >   m_pErrorLabel;
177         mutable ::boost::shared_ptr< ILabelProvider >   m_pWarningsLabel;
178         mutable ::boost::shared_ptr< ILabelProvider >   m_pInfoLabel;
179 
180     public:
181         ProviderFactory()
182         {
183         }
184 
185         ::boost::shared_ptr< IImageProvider >   getImageProvider( SQLExceptionInfo::TYPE _eType ) const
186         {
187             ::boost::shared_ptr< IImageProvider >* ppProvider( &m_pErrorImage );
188             sal_uInt16 nNormalImageID( BMP_EXCEPTION_ERROR );
189             sal_uInt16 nHCImageID( BMP_EXCEPTION_ERROR_SCH );
190 
191             switch ( _eType )
192             {
193             case SQLExceptionInfo::SQL_WARNING:
194                 ppProvider = &m_pWarningsImage;
195                 nNormalImageID = BMP_EXCEPTION_WARNING;
196                 nHCImageID = BMP_EXCEPTION_WARNING_SCH;
197                 break;
198 
199             case SQLExceptionInfo::SQL_CONTEXT:
200                 ppProvider = &m_pInfoImage;
201                 nNormalImageID = BMP_EXCEPTION_INFO;
202                 nHCImageID = BMP_EXCEPTION_INFO_SCH;
203                 break;
204 
205             default:
206                 break;
207             }
208 
209             if ( !ppProvider->get() )
210                 ppProvider->reset( new ImageProvider( nNormalImageID, nHCImageID ) );
211             return *ppProvider;
212         }
213 
214         ::boost::shared_ptr< ILabelProvider >   getLabelProvider( SQLExceptionInfo::TYPE _eType, bool _bSubLabel ) const
215         {
216             ::boost::shared_ptr< ILabelProvider >* ppProvider( &m_pErrorLabel );
217             sal_uInt16 nLabelID( STR_EXCEPTION_ERROR );
218 
219             switch ( _eType )
220             {
221             case SQLExceptionInfo::SQL_WARNING:
222                 ppProvider = &m_pWarningsLabel;
223                 nLabelID = STR_EXCEPTION_WARNING;
224                 break;
225 
226             case SQLExceptionInfo::SQL_CONTEXT:
227                 ppProvider = &m_pInfoLabel;
228                 nLabelID = _bSubLabel ? STR_EXCEPTION_DETAILS : STR_EXCEPTION_INFO;
229                 break;
230             default:
231                 break;
232             }
233 
234             if ( !ppProvider->get() )
235                 ppProvider->reset( new LabelProvider( nLabelID ) );
236             return *ppProvider;
237         }
238 
239     };
240 
241     //------------------------------------------------------------------------------
242     /// a stripped version of the SQLException, packed for displaying
243     struct ExceptionDisplayInfo
244     {
245         SQLExceptionInfo::TYPE                  eType;
246 
247         ::boost::shared_ptr< IImageProvider >   pImageProvider;
248         ::boost::shared_ptr< ILabelProvider >   pLabelProvider;
249 
250         bool                                    bSubEntry;
251 
252         String                                  sMessage;
253         String                                  sSQLState;
254         String                                  sErrorCode;
255 
256         ExceptionDisplayInfo() : eType( SQLExceptionInfo::UNDEFINED ), bSubEntry( false ) { }
257         ExceptionDisplayInfo( SQLExceptionInfo::TYPE _eType ) : eType( _eType ), bSubEntry( false ) { }
258     };
259 
260     static bool lcl_hasDetails( const ExceptionDisplayInfo& _displayInfo )
261     {
262         return  ( _displayInfo.sErrorCode.Len() )
263                 ||  (   _displayInfo.sSQLState.Len()
264                     &&  !_displayInfo.sSQLState.EqualsAscii( "S1000" )
265                     );
266     }
267 
268     typedef ::std::vector< ExceptionDisplayInfo >   ExceptionDisplayChain;
269 
270     //------------------------------------------------------------------------------
271     /// strips the [OOoBase] vendor identifier from the given error message, if applicable
272     ::rtl::OUString lcl_stripOOoBaseVendor( const ::rtl::OUString& _rErrorMessage )
273     {
274         ::rtl::OUString sErrorMessage( _rErrorMessage );
275 
276         const ::rtl::OUString sVendorIdentifier( ::connectivity::SQLError::getMessagePrefix() );
277         if ( sErrorMessage.indexOf( sVendorIdentifier ) == 0 )
278         {
279             // characters to strip
280             sal_Int32 nStripLen( sVendorIdentifier.getLength() );
281             // usually, there should be a whitespace between the vendor and the real message
282             while   (   ( sErrorMessage.getLength() > nStripLen )
283                     &&  ( sErrorMessage[nStripLen] == ' ' )
284                     )
285                     ++nStripLen;
286             sErrorMessage = sErrorMessage.copy( nStripLen );
287         }
288 
289         return sErrorMessage;
290     }
291 
292     //------------------------------------------------------------------------------
293     void lcl_buildExceptionChain( const SQLExceptionInfo& _rErrorInfo, const ProviderFactory& _rFactory, ExceptionDisplayChain& _out_rChain )
294     {
295         {
296             ExceptionDisplayChain empty;
297             _out_rChain.swap( empty );
298         }
299 
300         SQLExceptionIteratorHelper iter( _rErrorInfo );
301         while ( iter.hasMoreElements() )
302         {
303             // current chain element
304             SQLExceptionInfo aCurrentElement;
305             iter.next( aCurrentElement );
306 
307             const SQLException* pCurrentError = (const SQLException*)aCurrentElement;
308             DBG_ASSERT( pCurrentError, "lcl_buildExceptionChain: iterator failure!" );
309                 // hasMoreElements should not have returned <TRUE/> in this case
310 
311             ExceptionDisplayInfo aDisplayInfo( aCurrentElement.getType() );
312 
313             aDisplayInfo.sMessage = pCurrentError->Message.trim();
314             aDisplayInfo.sSQLState = pCurrentError->SQLState;
315             if ( pCurrentError->ErrorCode )
316                 aDisplayInfo.sErrorCode = String::CreateFromInt32( pCurrentError->ErrorCode );
317 
318             if  (   !aDisplayInfo.sMessage.Len()
319                 &&  !lcl_hasDetails( aDisplayInfo )
320                 )
321             {
322                 OSL_ENSURE( false, "lcl_buildExceptionChain: useles exception: no state, no error code, no message!" );
323                 continue;
324             }
325 
326             aDisplayInfo.pImageProvider = _rFactory.getImageProvider( aCurrentElement.getType() );
327             aDisplayInfo.pLabelProvider = _rFactory.getLabelProvider( aCurrentElement.getType(), false );
328 
329             _out_rChain.push_back( aDisplayInfo );
330 
331             if ( aCurrentElement.getType() == SQLExceptionInfo::SQL_CONTEXT )
332             {
333                 const SQLContext* pContext = (const SQLContext*)aCurrentElement;
334                 if ( pContext->Details.getLength() )
335                 {
336                     ExceptionDisplayInfo aSubInfo( aCurrentElement.getType() );
337 
338                     aSubInfo.sMessage = pContext->Details;
339                     aSubInfo.pImageProvider = _rFactory.getImageProvider( aCurrentElement.getType() );
340                     aSubInfo.pLabelProvider = _rFactory.getLabelProvider( aCurrentElement.getType(), true );
341                     aSubInfo.bSubEntry = true;
342 
343                     _out_rChain.push_back( aSubInfo );
344                 }
345             }
346         }
347     }
348 
349     //------------------------------------------------------------------------------
350     void lcl_insertExceptionEntry( SvTreeListBox& _rList, bool _bHiContrast, size_t _nElementPos, const ExceptionDisplayInfo& _rEntry )
351     {
352         Image aEntryImage( _rEntry.pImageProvider->getImage( _bHiContrast ) );
353         SvLBoxEntry* pListEntry =
354             _rList.InsertEntry( _rEntry.pLabelProvider->getLabel(), aEntryImage, aEntryImage );
355         pListEntry->SetUserData( reinterpret_cast< void* >( _nElementPos ) );
356     }
357 }
358 
359 //==============================================================================
360 class OExceptionChainDialog : public ModalDialog
361 {
362 	FixedLine       m_aFrame;
363 	FixedText		m_aListLabel;
364 	SvTreeListBox	m_aExceptionList;
365 	FixedText		m_aDescLabel;
366 	MultiLineEdit	m_aExceptionText;
367 	OKButton		m_aOK;
368 
369     String          m_sStatusLabel;
370     String          m_sErrorCodeLabel;
371 
372     ExceptionDisplayChain   m_aExceptions;
373 
374 public:
375 	OExceptionChainDialog( Window* pParent, const ExceptionDisplayChain& _rExceptions );
376 	~OExceptionChainDialog();
377 
378 protected:
379 	DECL_LINK(OnExceptionSelected, void*);
380 };
381 
382 DBG_NAME(OExceptionChainDialog)
383 //------------------------------------------------------------------------------
384 OExceptionChainDialog::OExceptionChainDialog( Window* pParent, const ExceptionDisplayChain& _rExceptions )
385 	:ModalDialog(pParent, ModuleRes(DLG_SQLEXCEPTIONCHAIN))
386 	,m_aFrame			(this, ModuleRes(FL_DETAILS))
387 	,m_aListLabel		(this, ModuleRes(FT_ERRORLIST))
388 	,m_aExceptionList	(this, ModuleRes(CTL_ERRORLIST))
389 	,m_aDescLabel		(this, ModuleRes(FT_DESCRIPTION))
390 	,m_aExceptionText	(this, ModuleRes(ME_DESCRIPTION))
391 	,m_aOK				(this, ModuleRes(PB_OK))
392     ,m_aExceptions( _rExceptions )
393 {
394     DBG_CTOR(OExceptionChainDialog,NULL);
395 
396     m_sStatusLabel = String( ModuleRes( STR_EXCEPTION_STATUS ) );
397 	m_sErrorCodeLabel = String( ModuleRes( STR_EXCEPTION_ERRORCODE ) );
398 
399 	FreeResource();
400 
401 	m_aExceptionList.SetSelectionMode(SINGLE_SELECTION);
402 	m_aExceptionList.SetDragDropMode(0);
403 	m_aExceptionList.EnableInplaceEditing(sal_False);
404 	m_aExceptionList.SetStyle(m_aExceptionList.GetStyle() | WB_HASLINES | WB_HASBUTTONS | WB_HASBUTTONSATROOT | WB_HSCROLL);
405 
406 	m_aExceptionList.SetSelectHdl(LINK(this, OExceptionChainDialog, OnExceptionSelected));
407 	m_aExceptionList.SetNodeDefaultImages( );
408 	m_aExceptionText.SetReadOnly(sal_True);
409 
410     bool bHave22018 = false;
411 	bool bHiContrast = isHiContrast( this );
412     size_t elementPos = 0;
413 
414     for (   ExceptionDisplayChain::const_iterator loop = m_aExceptions.begin();
415             loop != m_aExceptions.end();
416             ++loop, ++elementPos
417         )
418     {
419         lcl_insertExceptionEntry( m_aExceptionList, bHiContrast, elementPos, *loop );
420         bHave22018 = loop->sSQLState.EqualsAscii( "22018" );
421     }
422 
423     // if the error has the code 22018, then add an additional explanation
424     // #i24021# / 2004-10-14 / frank.schoenheit@sun.com
425     if ( bHave22018 )
426     {
427         ProviderFactory aProviderFactory;
428 
429         ExceptionDisplayInfo aInfo22018;
430         aInfo22018.sMessage = String( ModuleRes( STR_EXPLAN_STRINGCONVERSION_ERROR ) );
431         aInfo22018.pLabelProvider = aProviderFactory.getLabelProvider( SQLExceptionInfo::SQL_CONTEXT, false );
432         aInfo22018.pImageProvider = aProviderFactory.getImageProvider( SQLExceptionInfo::SQL_CONTEXT );
433         m_aExceptions.push_back( aInfo22018 );
434 
435         lcl_insertExceptionEntry( m_aExceptionList, bHiContrast, m_aExceptions.size() - 1, aInfo22018 );
436     }
437 }
438 
439 //------------------------------------------------------------------------------
440 OExceptionChainDialog::~OExceptionChainDialog()
441 {
442     DBG_DTOR(OExceptionChainDialog,NULL);
443 }
444 
445 //------------------------------------------------------------------------------
446 IMPL_LINK(OExceptionChainDialog, OnExceptionSelected, void*, EMPTYARG)
447 {
448 	SvLBoxEntry* pSelected = m_aExceptionList.FirstSelected();
449 	DBG_ASSERT(!pSelected || !m_aExceptionList.NextSelected(pSelected), "OExceptionChainDialog::OnExceptionSelected : multi selection ?");
450 
451     String sText;
452 
453 	if ( pSelected )
454 	{
455         size_t pos = reinterpret_cast< size_t >( pSelected->GetUserData() );
456         const ExceptionDisplayInfo& aExceptionInfo( m_aExceptions[ pos ] );
457 
458         if ( aExceptionInfo.sSQLState.Len() )
459         {
460             sText += m_sStatusLabel;
461 			sText.AppendAscii(": ");
462 			sText += aExceptionInfo.sSQLState;
463 			sText.AppendAscii("\n");
464         }
465 
466         if ( aExceptionInfo.sErrorCode.Len() )
467 		{
468 			sText += m_sErrorCodeLabel;
469 			sText.AppendAscii(": ");
470 			sText += aExceptionInfo.sErrorCode;
471 			sText.AppendAscii("\n");
472 		}
473 
474         if ( sText.Len() )
475             sText.AppendAscii( "\n" );
476 
477         sText += aExceptionInfo.sMessage;
478 	}
479 
480     m_aExceptionText.SetText(sText);
481 
482     return 0L;
483 }
484 
485 //==============================================================================
486 //= SQLMessageBox_Impl
487 //==============================================================================
488 struct SQLMessageBox_Impl
489 {
490     ExceptionDisplayChain   aDisplayInfo;
491 
492     SQLMessageBox_Impl( const SQLExceptionInfo& _rExceptionInfo )
493     {
494         // transform the exception chain to a form more suitable for displaying it here
495         ProviderFactory aProviderFactory;
496         lcl_buildExceptionChain( _rExceptionInfo, aProviderFactory, aDisplayInfo );
497     }
498 };
499 
500 //------------------------------------------------------------------------------
501 namespace
502 {
503     ::rtl::OUString lcl_getProductName()
504     {
505     	::rtl::OUString sProductName;
506 	    OSL_VERIFY( ::utl::ConfigManager::GetDirectConfigProperty( ::utl::ConfigManager::PRODUCTNAME ) >>= sProductName );
507         return sProductName;
508     }
509 
510     void lcl_positionInAppFont( const Window& _rParent, Window& _rChild, long _nX, long _nY, long _Width, long _Height )
511     {
512         Point aPos = _rParent.LogicToPixel( Point( _nX, _nY ), MAP_APPFONT );
513         Size aSize = _rParent.LogicToPixel( Size( _Width, _Height ), MAP_APPFONT );
514         _rChild.SetPosSizePixel( aPos, aSize );
515     }
516 
517     void lcl_addButton( ButtonDialog& _rDialog, StandardButtonType _eType, bool _bDefault )
518     {
519         sal_uInt16 nButtonID = 0;
520         switch ( _eType )
521         {
522         case BUTTON_YES:    nButtonID = BUTTONID_YES; break;
523         case BUTTON_NO:     nButtonID = BUTTONID_NO; break;
524         case BUTTON_OK:     nButtonID = BUTTONID_OK; break;
525         case BUTTON_CANCEL: nButtonID = BUTTONID_CANCEL; break;
526         case BUTTON_RETRY:  nButtonID = BUTTONID_RETRY; break;
527         case BUTTON_HELP:   nButtonID = BUTTONID_HELP; break;
528         default:
529             OSL_ENSURE( false, "lcl_addButton: invalid button id!" );
530             break;
531         }
532         _rDialog.AddButton( _eType, nButtonID, _bDefault ? BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_FOCUSBUTTON : 0 );
533     }
534 }
535 
536 //------------------------------------------------------------------------------
537 void OSQLMessageBox::impl_positionControls()
538 {
539     OSL_PRECOND( !m_pImpl->aDisplayInfo.empty(), "OSQLMessageBox::impl_positionControls: nothing to display at all?" );
540 
541 
542     if ( m_pImpl->aDisplayInfo.empty() )
543         return;
544     const ExceptionDisplayInfo* pSecondInfo = NULL;
545 
546     const ExceptionDisplayInfo& rFirstInfo = *m_pImpl->aDisplayInfo.begin();
547     if ( m_pImpl->aDisplayInfo.size() > 1 )
548         pSecondInfo = &m_pImpl->aDisplayInfo[1];
549     String sPrimary, sSecondary;
550     sPrimary = rFirstInfo.sMessage;
551     // one or two texts to display?
552     if ( pSecondInfo )
553     {
554         // we show two elements in the main dialog if and only if one of
555         // - the first element in the chain is an SQLContext, and the second
556         //   element denotes its sub entry
557         // - the first and the second element are both independent (i.e. the second
558         //   is no sub entry), and none of them is a context.
559         bool bFirstElementIsContext = ( rFirstInfo.eType == SQLExceptionInfo::SQL_CONTEXT );
560         bool bSecondElementIsContext = ( pSecondInfo->eType == SQLExceptionInfo::SQL_CONTEXT );
561 
562         if ( bFirstElementIsContext && pSecondInfo->bSubEntry )
563             sSecondary = pSecondInfo->sMessage;
564         if ( !bFirstElementIsContext && !bSecondElementIsContext )
565             sSecondary = pSecondInfo->sMessage;
566     }
567 
568     // image
569     lcl_positionInAppFont( *this, m_aInfoImage, OUTER_MARGIN, OUTER_MARGIN, IMAGE_SIZE, IMAGE_SIZE );
570 	m_aInfoImage.Show();
571 
572     // primary text
573     lcl_positionInAppFont( *this, m_aTitle, TEXT_POS_X, OUTER_MARGIN, DIALOG_WIDTH - TEXT_POS_X - 2 * OUTER_MARGIN, 16 );
574     sPrimary = lcl_stripOOoBaseVendor( sPrimary );
575     m_aTitle.SetText( sPrimary );
576 	m_aTitle.Show();
577 
578     Rectangle aPrimaryRect( m_aTitle.GetPosPixel(), m_aTitle.GetSizePixel() );
579 
580     // secondary text (if applicable)
581 	m_aMessage.SetStyle( m_aMessage.GetStyle() | WB_NOLABEL );
582     sSecondary = lcl_stripOOoBaseVendor( sSecondary );
583     m_aMessage.SetText( sSecondary );
584 
585     lcl_positionInAppFont( *this, m_aMessage, TEXT_POS_X, OUTER_MARGIN + 16 + 3, DIALOG_WIDTH - TEXT_POS_X - 2 * OUTER_MARGIN, 8 );
586     Rectangle aSecondaryRect( m_aMessage.GetPosPixel(), m_aMessage.GetSizePixel() );
587 
588     bool bHaveSecondaryText = sSecondary.Len() != 0;
589 
590     // determine which space the secondary text would occupy
591     if ( bHaveSecondaryText )
592 	    aSecondaryRect = GetTextRect( aSecondaryRect, sSecondary, TEXT_DRAW_WORDBREAK | TEXT_DRAW_MULTILINE | TEXT_DRAW_LEFT );
593     else
594         aSecondaryRect.Bottom() = aSecondaryRect.Top() - 1;
595 
596     // adjust secondary control height accordingly
597     m_aMessage.SetSizePixel( aSecondaryRect.GetSize() );
598 	m_aMessage.Show( aSecondaryRect.GetHeight() > 0 );
599 
600     // if there's no secondary text ...
601     if ( !bHaveSecondaryText )
602     {   // then give the primary text as much horizontal space as it needs
603         Rectangle aSuggestedRect( GetTextRect( aPrimaryRect, sPrimary, TEXT_DRAW_WORDBREAK | TEXT_DRAW_MULTILINE | TEXT_DRAW_CENTER ) );
604         aPrimaryRect.Right() = aPrimaryRect.Left() + aSuggestedRect.GetWidth();
605         aPrimaryRect.Bottom() = aPrimaryRect.Top() + aSuggestedRect.GetHeight();
606         // and center it horizontally
607         m_aTitle.SetStyle( ( m_aTitle.GetStyle() & ~WB_LEFT ) | WB_CENTER );
608 
609         Rectangle aInfoRect( m_aInfoImage.GetPosPixel(), m_aInfoImage.GetSizePixel() );
610         // also, if it's not as high as the image ...
611         if ( aPrimaryRect.GetHeight() < m_aInfoImage.GetSizePixel().Height() )
612         {   // ... make it fit the image height
613             aPrimaryRect.Bottom() += aInfoRect.GetHeight() - aPrimaryRect.GetHeight();
614             // and center it vertically
615             m_aTitle.SetStyle( m_aTitle.GetStyle() | WB_VCENTER );
616         }
617         else
618         {   // ... otherwise, center the image vertically, relative to the primary text
619             aInfoRect.Move( 0, ( aPrimaryRect.GetHeight() - aInfoRect.GetHeight() ) / 2 );
620             m_aInfoImage.SetPosSizePixel( aInfoRect.TopLeft(), aInfoRect.GetSize() );
621         }
622 
623         m_aTitle.SetPosSizePixel( aPrimaryRect.TopLeft(), aPrimaryRect.GetSize() );
624     }
625 
626     // adjust dialog size accordingly
627     const Rectangle& rBottomTextRect( bHaveSecondaryText ? aSecondaryRect : aPrimaryRect );
628     Size aBorderSize = LogicToPixel( Size( OUTER_MARGIN, OUTER_MARGIN ), MAP_APPFONT );
629     Size aDialogSize( LogicToPixel( Size( DIALOG_WIDTH, 30 ), MAP_APPFONT ) );
630     aDialogSize.Height() = rBottomTextRect.Bottom() + aBorderSize.Height();
631     aDialogSize.Width() = aPrimaryRect.Right() + aBorderSize.Width();
632 
633 	SetSizePixel( aDialogSize );
634 	SetPageSizePixel( aDialogSize );
635 }
636 
637 //------------------------------------------------------------------------------
638 void OSQLMessageBox::impl_initImage( MessageType _eImage )
639 {
640 	switch (_eImage)
641 	{
642         default:
643             DBG_ERROR( "OSQLMessageBox::impl_initImage: unsupported image type!" );
644 
645 		case Info:
646 			m_aInfoImage.SetImage(InfoBox::GetStandardImage());
647 			break;
648 		case Warning:
649 			m_aInfoImage.SetImage(WarningBox::GetStandardImage());
650 			break;
651 		case Error:
652 			m_aInfoImage.SetImage(ErrorBox::GetStandardImage());
653 			break;
654 		case Query:
655 			m_aInfoImage.SetImage(QueryBox::GetStandardImage());
656 			break;
657 	}
658 }
659 
660 //------------------------------------------------------------------------------
661 void OSQLMessageBox::impl_createStandardButtons( WinBits _nStyle )
662 {
663 	if ( _nStyle & WB_YES_NO_CANCEL )
664 	{
665         lcl_addButton( *this, BUTTON_YES,    ( _nStyle & WB_DEF_YES ) != 0 );
666         lcl_addButton( *this, BUTTON_NO,     ( _nStyle & WB_DEF_NO ) != 0 );
667         lcl_addButton( *this, BUTTON_CANCEL, ( _nStyle & WB_DEF_CANCEL ) != 0 );
668 	}
669 	else if ( _nStyle & WB_OK_CANCEL )
670 	{
671         lcl_addButton( *this, BUTTON_OK,     ( _nStyle & WB_DEF_OK ) != 0 );
672         lcl_addButton( *this, BUTTON_CANCEL, ( _nStyle & WB_DEF_CANCEL ) != 0 );
673 	}
674 	else if ( _nStyle & WB_YES_NO )
675 	{
676         lcl_addButton( *this, BUTTON_YES,    ( _nStyle & WB_DEF_YES ) != 0 );
677         lcl_addButton( *this, BUTTON_NO,     ( _nStyle & WB_DEF_NO ) != 0 );
678 	}
679 	else if ( _nStyle & WB_RETRY_CANCEL )
680 	{
681         lcl_addButton( *this, BUTTON_RETRY,  ( _nStyle & WB_DEF_RETRY ) != 0 );
682         lcl_addButton( *this, BUTTON_CANCEL, ( _nStyle & WB_DEF_CANCEL ) != 0 );
683 	}
684 	else
685 	{
686         OSL_ENSURE( WB_OK & _nStyle, "OSQLMessageBox::impl_createStandardButtons: unsupported dialog style requested!" );
687 		AddButton( BUTTON_OK, BUTTONID_OK, BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_FOCUSBUTTON );
688 	}
689 
690     if ( m_sHelpURL.getLength() )
691     {
692         lcl_addButton( *this, BUTTON_HELP, false );
693 
694         rtl::OUString aTmp;
695         INetURLObject aHID( m_sHelpURL );
696         if ( aHID.GetProtocol() == INET_PROT_HID )
697 	  	    aTmp = aHID.GetURLPath();
698         else
699             aTmp = m_sHelpURL;
700 
701         SetHelpId( rtl::OUStringToOString( aTmp, RTL_TEXTENCODING_UTF8 ) );
702     }
703 }
704 
705 //------------------------------------------------------------------------------
706 void OSQLMessageBox::impl_addDetailsButton()
707 {
708     size_t nFirstPageVisible = m_aMessage.IsVisible() ? 2 : 1;
709 
710     bool bMoreDetailsAvailable = m_pImpl->aDisplayInfo.size() > nFirstPageVisible;
711     if ( !bMoreDetailsAvailable )
712     {
713         // even if the text fits into what we can display, we might need to details button
714         // if there is more non-trivial information in the errors than the mere messages
715         for (   ExceptionDisplayChain::const_iterator error = m_pImpl->aDisplayInfo.begin();
716                 error != m_pImpl->aDisplayInfo.end();
717                 ++error
718             )
719         {
720             if ( lcl_hasDetails( *error ) )
721             {
722                 bMoreDetailsAvailable = true;
723                 break;
724             }
725         }
726     }
727 
728     if ( bMoreDetailsAvailable )
729 	{
730         AddButton( BUTTON_MORE, BUTTONID_MORE, 0 );
731         PushButton* pButton = GetPushButton( BUTTONID_MORE );
732         OSL_ENSURE( pButton, "OSQLMessageBox::impl_addDetailsButton: just added this button, why isn't it there?" );
733 		pButton->SetClickHdl( LINK( this, OSQLMessageBox, ButtonClickHdl ) );
734 		pButton->SetUniqueId( UID_SQLERROR_BUTTONMORE );
735 	}
736 }
737 
738 //------------------------------------------------------------------------------
739 void OSQLMessageBox::Construct( WinBits _nStyle, MessageType _eImage )
740 {
741 	// Changed as per BugID 79541 Branding/Configuration
742     String sDialogTitle( lcl_getProductName() );
743     SetText( sDialogTitle.AppendAscii( " Base" ) );
744 
745     // position and size the controls and the dialog, depending on whether we have one or two texts to display
746     impl_positionControls();
747 
748     // init the image
749     MessageType eType( _eImage );
750     if ( eType == AUTO )
751     {
752         switch ( m_pImpl->aDisplayInfo[0].eType )
753         {
754         case SQLExceptionInfo::SQL_EXCEPTION: eType = Error;    break;
755         case SQLExceptionInfo::SQL_WARNING:   eType = Warning;  break;
756         case SQLExceptionInfo::SQL_CONTEXT:   eType = Info;     break;
757         default: OSL_ENSURE( false, "OSQLMessageBox::Construct: invalid type!" );
758         }
759     }
760     impl_initImage( eType );
761 
762 	// create buttons
763     impl_createStandardButtons( _nStyle );
764     impl_addDetailsButton();
765 }
766 
767 //------------------------------------------------------------------------------
768 OSQLMessageBox::OSQLMessageBox(Window* _pParent, const SQLExceptionInfo& _rException, WinBits _nStyle, const ::rtl::OUString& _rHelpURL )
769     :ButtonDialog( _pParent, WB_HORZ | WB_STDDIALOG )
770     ,m_aInfoImage( this )
771     ,m_aTitle( this, WB_WORDBREAK | WB_LEFT )
772     ,m_aMessage( this, WB_WORDBREAK | WB_LEFT )
773     ,m_sHelpURL( _rHelpURL )
774     ,m_pImpl( new SQLMessageBox_Impl( _rException ) )
775 {
776 	Construct( _nStyle, AUTO );
777 }
778 
779 //------------------------------------------------------------------------------
780 OSQLMessageBox::OSQLMessageBox( Window* _pParent, const UniString& _rTitle, const UniString& _rMessage, WinBits _nStyle, MessageType _eType, const ::dbtools::SQLExceptionInfo* _pAdditionalErrorInfo )
781     :ButtonDialog( _pParent, WB_HORZ | WB_STDDIALOG )
782     ,m_aInfoImage( this )
783     ,m_aTitle( this, WB_WORDBREAK | WB_LEFT )
784     ,m_aMessage( this, WB_WORDBREAK | WB_LEFT )
785 {
786     SQLContext aError;
787     aError.Message = _rTitle;
788     aError.Details = _rMessage;
789     if ( _pAdditionalErrorInfo )
790         aError.NextException = _pAdditionalErrorInfo->get();
791 
792     m_pImpl.reset( new SQLMessageBox_Impl( SQLExceptionInfo( aError ) ) );
793 
794     Construct( _nStyle, _eType );
795 }
796 
797 //--------------------------------------------------------------------------
798 OSQLMessageBox::~OSQLMessageBox()
799 {
800 }
801 
802 //--------------------------------------------------------------------------
803 IMPL_LINK( OSQLMessageBox, ButtonClickHdl, Button *, /*pButton*/ )
804 {
805 	OExceptionChainDialog aDlg( this, m_pImpl->aDisplayInfo );
806 	aDlg.Execute();
807 	return 0;
808 }
809 
810 //==================================================================
811 // OSQLWarningBox
812 //==================================================================
813 OSQLWarningBox::OSQLWarningBox( Window* _pParent, const UniString& _rMessage, WinBits _nStyle,
814     const ::dbtools::SQLExceptionInfo* _pAdditionalErrorInfo )
815     :OSQLMessageBox( _pParent, String( ModuleRes( STR_STAT_WARNING ) ), _rMessage, _nStyle, OSQLMessageBox::Warning, _pAdditionalErrorInfo )
816 {
817 }
818 
819 //.........................................................................
820 }	// namespace dbaui
821 //.........................................................................
822 
823