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 "sqlmessage.hxx"
21 : #include "dbu_dlg.hrc"
22 : #include <com/sun/star/sdbc/SQLException.hpp>
23 : #include <com/sun/star/sdb/SQLContext.hpp>
24 : #include <vcl/fixed.hxx>
25 : #include <osl/diagnose.h>
26 : #include <svtools/treelistbox.hxx>
27 : #include "svtools/treelistentry.hxx"
28 : #include <svtools/svmedit.hxx>
29 : #include <connectivity/dbexception.hxx>
30 : #include <connectivity/sqlerror.hxx>
31 : #include <vcl/msgbox.hxx>
32 : #include <unotools/configmgr.hxx>
33 : #include <sfx2/sfxuno.hxx>
34 : #include "dbaccess_helpid.hrc"
35 : #include "UITools.hxx"
36 : #include "moduledbu.hxx"
37 :
38 : #include <tools/urlobj.hxx>
39 :
40 : #define RET_MORE RET_RETRY + 1
41 :
42 : #define DIALOG_WIDTH 220
43 : #define OUTER_MARGIN 6
44 : #define IMAGE_SIZE 20
45 : #define INNER_PADDING 3
46 : #define TEXT_POS_X ( OUTER_MARGIN + IMAGE_SIZE + INNER_PADDING )
47 :
48 : using namespace dbtools;
49 : using namespace com::sun::star::uno;
50 : using namespace com::sun::star::sdb;
51 : using namespace com::sun::star::sdbc;
52 :
53 : namespace dbaui
54 : {
55 :
56 : namespace
57 : {
58 0 : class IImageProvider
59 : {
60 : public:
61 : virtual Image getImage() const = 0;
62 :
63 0 : virtual ~IImageProvider() { }
64 : };
65 :
66 0 : class ILabelProvider
67 : {
68 : public:
69 : virtual OUString getLabel() const = 0;
70 :
71 0 : virtual ~ILabelProvider() { };
72 : };
73 :
74 0 : class ImageProvider : public IImageProvider
75 : {
76 : private:
77 : sal_uInt16 m_defaultImageID;
78 :
79 : mutable Image m_defaultImage;
80 :
81 : public:
82 0 : ImageProvider( sal_uInt16 _defaultImageID )
83 0 : :m_defaultImageID( _defaultImageID )
84 : {
85 0 : }
86 :
87 0 : virtual Image getImage() const SAL_OVERRIDE
88 : {
89 0 : if ( !m_defaultImage )
90 0 : m_defaultImage = Image( ModuleRes( m_defaultImageID ) );
91 0 : return m_defaultImage;
92 : }
93 : };
94 :
95 0 : class LabelProvider : public ILabelProvider
96 : {
97 : private:
98 : OUString m_label;
99 : public:
100 0 : LabelProvider( sal_uInt16 _labelResourceID )
101 0 : :m_label( ModuleRes( _labelResourceID ) )
102 : {
103 0 : }
104 :
105 0 : virtual OUString getLabel() const SAL_OVERRIDE
106 : {
107 0 : return m_label;
108 : }
109 : };
110 :
111 0 : class ProviderFactory
112 : {
113 : private:
114 : mutable ::boost::shared_ptr< IImageProvider > m_pErrorImage;
115 : mutable ::boost::shared_ptr< IImageProvider > m_pWarningsImage;
116 : mutable ::boost::shared_ptr< IImageProvider > m_pInfoImage;
117 : mutable ::boost::shared_ptr< ILabelProvider > m_pErrorLabel;
118 : mutable ::boost::shared_ptr< ILabelProvider > m_pWarningsLabel;
119 : mutable ::boost::shared_ptr< ILabelProvider > m_pInfoLabel;
120 :
121 : public:
122 0 : ProviderFactory()
123 0 : {
124 0 : }
125 :
126 0 : ::boost::shared_ptr< IImageProvider > getImageProvider( SQLExceptionInfo::TYPE _eType ) const
127 : {
128 0 : ::boost::shared_ptr< IImageProvider >* ppProvider( &m_pErrorImage );
129 0 : sal_uInt16 nNormalImageID( BMP_EXCEPTION_ERROR );
130 :
131 0 : switch ( _eType )
132 : {
133 : case SQLExceptionInfo::SQL_WARNING:
134 0 : ppProvider = &m_pWarningsImage;
135 0 : nNormalImageID = BMP_EXCEPTION_WARNING;
136 0 : break;
137 :
138 : case SQLExceptionInfo::SQL_CONTEXT:
139 0 : ppProvider = &m_pInfoImage;
140 0 : nNormalImageID = BMP_EXCEPTION_INFO;
141 0 : break;
142 :
143 : default:
144 0 : break;
145 : }
146 :
147 0 : if ( !ppProvider->get() )
148 0 : ppProvider->reset( new ImageProvider( nNormalImageID ) );
149 0 : return *ppProvider;
150 : }
151 :
152 0 : ::boost::shared_ptr< ILabelProvider > getLabelProvider( SQLExceptionInfo::TYPE _eType, bool _bSubLabel ) const
153 : {
154 0 : ::boost::shared_ptr< ILabelProvider >* ppProvider( &m_pErrorLabel );
155 0 : sal_uInt16 nLabelID( STR_EXCEPTION_ERROR );
156 :
157 0 : switch ( _eType )
158 : {
159 : case SQLExceptionInfo::SQL_WARNING:
160 0 : ppProvider = &m_pWarningsLabel;
161 0 : nLabelID = STR_EXCEPTION_WARNING;
162 0 : break;
163 :
164 : case SQLExceptionInfo::SQL_CONTEXT:
165 0 : ppProvider = &m_pInfoLabel;
166 0 : nLabelID = _bSubLabel ? STR_EXCEPTION_DETAILS : STR_EXCEPTION_INFO;
167 0 : break;
168 : default:
169 0 : break;
170 : }
171 :
172 0 : if ( !ppProvider->get() )
173 0 : ppProvider->reset( new LabelProvider( nLabelID ) );
174 0 : return *ppProvider;
175 : }
176 :
177 : };
178 :
179 : /// a stripped version of the SQLException, packed for displaying
180 0 : struct ExceptionDisplayInfo
181 : {
182 : SQLExceptionInfo::TYPE eType;
183 :
184 : ::boost::shared_ptr< IImageProvider > pImageProvider;
185 : ::boost::shared_ptr< ILabelProvider > pLabelProvider;
186 :
187 : bool bSubEntry;
188 :
189 : OUString sMessage;
190 : OUString sSQLState;
191 : OUString sErrorCode;
192 :
193 0 : ExceptionDisplayInfo() : eType( SQLExceptionInfo::UNDEFINED ), bSubEntry( false ) { }
194 0 : ExceptionDisplayInfo( SQLExceptionInfo::TYPE _eType ) : eType( _eType ), bSubEntry( false ) { }
195 : };
196 :
197 0 : static bool lcl_hasDetails( const ExceptionDisplayInfo& _displayInfo )
198 : {
199 0 : return ( !_displayInfo.sErrorCode.isEmpty() )
200 0 : || ( !_displayInfo.sSQLState.isEmpty()
201 0 : && !_displayInfo.sSQLState.equalsAscii( "S1000" )
202 0 : );
203 : }
204 :
205 : typedef ::std::vector< ExceptionDisplayInfo > ExceptionDisplayChain;
206 :
207 : /// strips the [OOoBase] vendor identifier from the given error message, if applicable
208 0 : OUString lcl_stripOOoBaseVendor( const OUString& _rErrorMessage )
209 : {
210 0 : OUString sErrorMessage( _rErrorMessage );
211 :
212 0 : const OUString sVendorIdentifier( ::connectivity::SQLError::getMessagePrefix() );
213 0 : if ( sErrorMessage.startsWith( sVendorIdentifier ) )
214 : {
215 : // characters to strip
216 0 : sal_Int32 nStripLen( sVendorIdentifier.getLength() );
217 : // usually, there should be a whitespace between the vendor and the real message
218 0 : while ( ( sErrorMessage.getLength() > nStripLen )
219 0 : && ( sErrorMessage[nStripLen] == ' ' )
220 : )
221 0 : ++nStripLen;
222 0 : sErrorMessage = sErrorMessage.copy( nStripLen );
223 : }
224 :
225 0 : return sErrorMessage;
226 : }
227 :
228 0 : void lcl_buildExceptionChain( const SQLExceptionInfo& _rErrorInfo, const ProviderFactory& _rFactory, ExceptionDisplayChain& _out_rChain )
229 : {
230 : {
231 0 : ExceptionDisplayChain empty;
232 0 : _out_rChain.swap( empty );
233 : }
234 :
235 0 : SQLExceptionIteratorHelper iter( _rErrorInfo );
236 0 : while ( iter.hasMoreElements() )
237 : {
238 : // current chain element
239 0 : SQLExceptionInfo aCurrentElement;
240 0 : iter.next( aCurrentElement );
241 :
242 0 : const SQLException* pCurrentError = (const SQLException*)aCurrentElement;
243 : OSL_ENSURE( pCurrentError, "lcl_buildExceptionChain: iterator failure!" );
244 : // hasMoreElements should not have returned <TRUE/> in this case
245 :
246 0 : ExceptionDisplayInfo aDisplayInfo( aCurrentElement.getType() );
247 :
248 0 : aDisplayInfo.sMessage = pCurrentError->Message.trim();
249 0 : aDisplayInfo.sSQLState = pCurrentError->SQLState;
250 0 : if ( pCurrentError->ErrorCode )
251 0 : aDisplayInfo.sErrorCode = OUString::number( pCurrentError->ErrorCode );
252 :
253 0 : if ( aDisplayInfo.sMessage.isEmpty()
254 0 : && !lcl_hasDetails( aDisplayInfo )
255 : )
256 : {
257 : OSL_FAIL( "lcl_buildExceptionChain: useles exception: no state, no error code, no message!" );
258 0 : continue;
259 : }
260 :
261 0 : aDisplayInfo.pImageProvider = _rFactory.getImageProvider( aCurrentElement.getType() );
262 0 : aDisplayInfo.pLabelProvider = _rFactory.getLabelProvider( aCurrentElement.getType(), false );
263 :
264 0 : _out_rChain.push_back( aDisplayInfo );
265 :
266 0 : if ( aCurrentElement.getType() == SQLExceptionInfo::SQL_CONTEXT )
267 : {
268 0 : const SQLContext* pContext = (const SQLContext*)aCurrentElement;
269 0 : if ( !pContext->Details.isEmpty() )
270 : {
271 0 : ExceptionDisplayInfo aSubInfo( aCurrentElement.getType() );
272 :
273 0 : aSubInfo.sMessage = pContext->Details;
274 0 : aSubInfo.pImageProvider = _rFactory.getImageProvider( aCurrentElement.getType() );
275 0 : aSubInfo.pLabelProvider = _rFactory.getLabelProvider( aCurrentElement.getType(), true );
276 0 : aSubInfo.bSubEntry = true;
277 :
278 0 : _out_rChain.push_back( aSubInfo );
279 : }
280 : }
281 0 : }
282 0 : }
283 :
284 0 : void lcl_insertExceptionEntry( SvTreeListBox& _rList, size_t _nElementPos, const ExceptionDisplayInfo& _rEntry )
285 : {
286 0 : Image aEntryImage( _rEntry.pImageProvider->getImage() );
287 : SvTreeListEntry* pListEntry =
288 0 : _rList.InsertEntry( _rEntry.pLabelProvider->getLabel(), aEntryImage, aEntryImage );
289 0 : pListEntry->SetUserData( reinterpret_cast< void* >( _nElementPos ) );
290 0 : }
291 : }
292 :
293 0 : class OExceptionChainDialog : public ModalDialog
294 : {
295 : SvTreeListBox* m_pExceptionList;
296 : VclMultiLineEdit* m_pExceptionText;
297 :
298 : OUString m_sStatusLabel;
299 : OUString m_sErrorCodeLabel;
300 :
301 : ExceptionDisplayChain m_aExceptions;
302 :
303 : public:
304 : OExceptionChainDialog( Window* pParent, const ExceptionDisplayChain& _rExceptions );
305 :
306 : protected:
307 : DECL_LINK(OnExceptionSelected, void*);
308 : };
309 :
310 0 : OExceptionChainDialog::OExceptionChainDialog(Window* pParent, const ExceptionDisplayChain& _rExceptions)
311 : : ModalDialog(pParent, "SQLExceptionDialog", "dbaccess/ui/sqlexception.ui")
312 0 : , m_aExceptions(_rExceptions)
313 : {
314 0 : get(m_pExceptionList, "list");
315 0 : Size aListSize(LogicToPixel(Size(85, 93), MAP_APPFONT));
316 0 : m_pExceptionList->set_width_request(aListSize.Width());
317 0 : m_pExceptionList->set_height_request(aListSize.Height());
318 0 : get(m_pExceptionText, "description");
319 0 : Size aTextSize(LogicToPixel(Size(125 , 93), MAP_APPFONT));
320 0 : m_pExceptionText->set_width_request(aTextSize.Width());
321 0 : m_pExceptionText->set_height_request(aTextSize.Height());
322 :
323 0 : m_sStatusLabel = ModuleRes( STR_EXCEPTION_STATUS );
324 0 : m_sErrorCodeLabel = ModuleRes( STR_EXCEPTION_ERRORCODE );
325 :
326 0 : m_pExceptionList->SetSelectionMode(SINGLE_SELECTION);
327 0 : m_pExceptionList->SetDragDropMode(0);
328 0 : m_pExceptionList->EnableInplaceEditing(false);
329 0 : m_pExceptionList->SetStyle(m_pExceptionList->GetStyle() | WB_HASLINES | WB_HASBUTTONS | WB_HASBUTTONSATROOT | WB_HSCROLL);
330 :
331 0 : m_pExceptionList->SetSelectHdl(LINK(this, OExceptionChainDialog, OnExceptionSelected));
332 0 : m_pExceptionList->SetNodeDefaultImages( );
333 :
334 0 : bool bHave22018 = false;
335 0 : size_t elementPos = 0;
336 :
337 0 : for ( ExceptionDisplayChain::const_iterator loop = m_aExceptions.begin();
338 0 : loop != m_aExceptions.end();
339 : ++loop, ++elementPos
340 : )
341 : {
342 0 : lcl_insertExceptionEntry( *m_pExceptionList, elementPos, *loop );
343 0 : bHave22018 = loop->sSQLState.equalsAscii( "22018" );
344 : }
345 :
346 : // if the error has the code 22018, then add an additional explanation
347 : // #i24021#
348 0 : if ( bHave22018 )
349 : {
350 0 : ProviderFactory aProviderFactory;
351 :
352 0 : ExceptionDisplayInfo aInfo22018;
353 0 : aInfo22018.sMessage = ModuleRes( STR_EXPLAN_STRINGCONVERSION_ERROR );
354 0 : aInfo22018.pLabelProvider = aProviderFactory.getLabelProvider( SQLExceptionInfo::SQL_CONTEXT, false );
355 0 : aInfo22018.pImageProvider = aProviderFactory.getImageProvider( SQLExceptionInfo::SQL_CONTEXT );
356 0 : m_aExceptions.push_back( aInfo22018 );
357 :
358 0 : lcl_insertExceptionEntry( *m_pExceptionList, m_aExceptions.size() - 1, aInfo22018 );
359 : }
360 0 : }
361 :
362 0 : IMPL_LINK_NOARG(OExceptionChainDialog, OnExceptionSelected)
363 : {
364 0 : SvTreeListEntry* pSelected = m_pExceptionList->FirstSelected();
365 : OSL_ENSURE(!pSelected || !m_pExceptionList->NextSelected(pSelected), "OExceptionChainDialog::OnExceptionSelected : multi selection ?");
366 :
367 0 : OUString sText;
368 :
369 0 : if ( pSelected )
370 : {
371 0 : size_t pos = reinterpret_cast< size_t >( pSelected->GetUserData() );
372 0 : const ExceptionDisplayInfo& aExceptionInfo( m_aExceptions[ pos ] );
373 :
374 0 : if ( !aExceptionInfo.sSQLState.isEmpty() )
375 : {
376 0 : sText += m_sStatusLabel;
377 0 : sText += ": ";
378 0 : sText += aExceptionInfo.sSQLState;
379 0 : sText += "\n";
380 : }
381 :
382 0 : if ( !aExceptionInfo.sErrorCode.isEmpty() )
383 : {
384 0 : sText += m_sErrorCodeLabel;
385 0 : sText += ": ";
386 0 : sText += aExceptionInfo.sErrorCode;
387 0 : sText += "\n";
388 : }
389 :
390 0 : if ( !sText.isEmpty() )
391 0 : sText += "\n";
392 :
393 0 : sText += aExceptionInfo.sMessage;
394 : }
395 :
396 0 : m_pExceptionText->SetText(sText);
397 :
398 0 : return 0L;
399 : }
400 :
401 : // SQLMessageBox_Impl
402 0 : struct SQLMessageBox_Impl
403 : {
404 : ExceptionDisplayChain aDisplayInfo;
405 :
406 0 : SQLMessageBox_Impl( const SQLExceptionInfo& _rExceptionInfo )
407 0 : {
408 : // transform the exception chain to a form more suitable for displaying it here
409 0 : ProviderFactory aProviderFactory;
410 0 : lcl_buildExceptionChain( _rExceptionInfo, aProviderFactory, aDisplayInfo );
411 0 : }
412 : };
413 :
414 : namespace
415 : {
416 0 : void lcl_positionInAppFont( const Window& _rParent, Window& _rChild, long _nX, long _nY, long _Width, long _Height )
417 : {
418 0 : Point aPos = _rParent.LogicToPixel( Point( _nX, _nY ), MAP_APPFONT );
419 0 : Size aSize = _rParent.LogicToPixel( Size( _Width, _Height ), MAP_APPFONT );
420 0 : _rChild.SetPosSizePixel( aPos, aSize );
421 0 : }
422 :
423 0 : void lcl_addButton( ButtonDialog& _rDialog, StandardButtonType _eType, bool _bDefault )
424 : {
425 0 : sal_uInt16 nButtonID = 0;
426 0 : switch ( _eType )
427 : {
428 0 : case BUTTON_YES: nButtonID = RET_YES; break;
429 0 : case BUTTON_NO: nButtonID = RET_NO; break;
430 0 : case BUTTON_OK: nButtonID = RET_OK; break;
431 0 : case BUTTON_CANCEL: nButtonID = RET_CANCEL; break;
432 0 : case BUTTON_RETRY: nButtonID = RET_RETRY; break;
433 0 : case BUTTON_HELP: nButtonID = RET_HELP; break;
434 : default:
435 : OSL_FAIL( "lcl_addButton: invalid button id!" );
436 0 : break;
437 : }
438 0 : _rDialog.AddButton( _eType, nButtonID, _bDefault ? BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_FOCUSBUTTON : 0 );
439 0 : }
440 : }
441 :
442 0 : void OSQLMessageBox::impl_positionControls()
443 : {
444 : OSL_PRECOND( !m_pImpl->aDisplayInfo.empty(), "OSQLMessageBox::impl_positionControls: nothing to display at all?" );
445 :
446 0 : if ( m_pImpl->aDisplayInfo.empty() )
447 0 : return;
448 0 : const ExceptionDisplayInfo* pSecondInfo = NULL;
449 :
450 0 : const ExceptionDisplayInfo& rFirstInfo = *m_pImpl->aDisplayInfo.begin();
451 0 : if ( m_pImpl->aDisplayInfo.size() > 1 )
452 0 : pSecondInfo = &m_pImpl->aDisplayInfo[1];
453 0 : OUString sPrimary, sSecondary;
454 0 : sPrimary = rFirstInfo.sMessage;
455 : // one or two texts to display?
456 0 : if ( pSecondInfo )
457 : {
458 : // we show two elements in the main dialog if and only if one of
459 : // - the first element in the chain is an SQLContext, and the second
460 : // element denotes its sub entry
461 : // - the first and the second element are both independent (i.e. the second
462 : // is no sub entry), and none of them is a context.
463 0 : bool bFirstElementIsContext = ( rFirstInfo.eType == SQLExceptionInfo::SQL_CONTEXT );
464 0 : bool bSecondElementIsContext = ( pSecondInfo->eType == SQLExceptionInfo::SQL_CONTEXT );
465 :
466 0 : if ( bFirstElementIsContext && pSecondInfo->bSubEntry )
467 0 : sSecondary = pSecondInfo->sMessage;
468 0 : if ( !bFirstElementIsContext && !bSecondElementIsContext )
469 0 : sSecondary = pSecondInfo->sMessage;
470 : }
471 :
472 : // image
473 0 : lcl_positionInAppFont( *this, m_aInfoImage, OUTER_MARGIN, OUTER_MARGIN, IMAGE_SIZE, IMAGE_SIZE );
474 0 : m_aInfoImage.Show();
475 :
476 : // primary text
477 0 : lcl_positionInAppFont( *this, m_aTitle, TEXT_POS_X, OUTER_MARGIN, DIALOG_WIDTH - TEXT_POS_X - 2 * OUTER_MARGIN, 16 );
478 0 : sPrimary = lcl_stripOOoBaseVendor( sPrimary );
479 0 : m_aTitle.SetText( sPrimary );
480 0 : m_aTitle.Show();
481 :
482 0 : Rectangle aPrimaryRect( m_aTitle.GetPosPixel(), m_aTitle.GetSizePixel() );
483 :
484 : // secondary text (if applicable)
485 0 : m_aMessage.SetStyle( m_aMessage.GetStyle() | WB_NOLABEL );
486 0 : sSecondary = lcl_stripOOoBaseVendor( sSecondary );
487 0 : m_aMessage.SetText( sSecondary );
488 :
489 0 : lcl_positionInAppFont( *this, m_aMessage, TEXT_POS_X, OUTER_MARGIN + 16 + 3, DIALOG_WIDTH - TEXT_POS_X - 2 * OUTER_MARGIN, 8 );
490 0 : Rectangle aSecondaryRect( m_aMessage.GetPosPixel(), m_aMessage.GetSizePixel() );
491 :
492 0 : bool bHaveSecondaryText = !sSecondary.isEmpty();
493 :
494 : // determine which space the secondary text would occupy
495 0 : if ( bHaveSecondaryText )
496 0 : aSecondaryRect = GetTextRect( aSecondaryRect, sSecondary, TEXT_DRAW_WORDBREAK | TEXT_DRAW_MULTILINE | TEXT_DRAW_LEFT );
497 : else
498 0 : aSecondaryRect.Bottom() = aSecondaryRect.Top() - 1;
499 :
500 : // adjust secondary control height accordingly
501 0 : m_aMessage.SetSizePixel( aSecondaryRect.GetSize() );
502 0 : m_aMessage.Show( aSecondaryRect.GetHeight() > 0 );
503 :
504 : // if there's no secondary text ...
505 0 : if ( !bHaveSecondaryText )
506 : { // then give the primary text as much horizontal space as it needs
507 0 : Rectangle aSuggestedRect( GetTextRect( aPrimaryRect, sPrimary, TEXT_DRAW_WORDBREAK | TEXT_DRAW_MULTILINE | TEXT_DRAW_CENTER ) );
508 0 : aPrimaryRect.Right() = aPrimaryRect.Left() + aSuggestedRect.GetWidth();
509 0 : aPrimaryRect.Bottom() = aPrimaryRect.Top() + aSuggestedRect.GetHeight();
510 : // and center it horizontally
511 0 : m_aTitle.SetStyle( ( m_aTitle.GetStyle() & ~WB_LEFT ) | WB_CENTER );
512 :
513 0 : Rectangle aInfoRect( m_aInfoImage.GetPosPixel(), m_aInfoImage.GetSizePixel() );
514 : // also, if it's not as high as the image ...
515 0 : if ( aPrimaryRect.GetHeight() < m_aInfoImage.GetSizePixel().Height() )
516 : { // ... make it fit the image height
517 0 : aPrimaryRect.Bottom() += aInfoRect.GetHeight() - aPrimaryRect.GetHeight();
518 : // and center it vertically
519 0 : m_aTitle.SetStyle( m_aTitle.GetStyle() | WB_VCENTER );
520 : }
521 : else
522 : { // ... otherwise, center the image vertically, relative to the primary text
523 0 : aInfoRect.Move( 0, ( aPrimaryRect.GetHeight() - aInfoRect.GetHeight() ) / 2 );
524 0 : m_aInfoImage.SetPosSizePixel( aInfoRect.TopLeft(), aInfoRect.GetSize() );
525 : }
526 :
527 0 : m_aTitle.SetPosSizePixel( aPrimaryRect.TopLeft(), aPrimaryRect.GetSize() );
528 : }
529 :
530 : // adjust dialog size accordingly
531 0 : const Rectangle& rBottomTextRect( bHaveSecondaryText ? aSecondaryRect : aPrimaryRect );
532 0 : Size aBorderSize = LogicToPixel( Size( OUTER_MARGIN, OUTER_MARGIN ), MAP_APPFONT );
533 0 : Size aDialogSize( LogicToPixel( Size( DIALOG_WIDTH, 30 ), MAP_APPFONT ) );
534 0 : aDialogSize.Height() = rBottomTextRect.Bottom() + aBorderSize.Height();
535 0 : aDialogSize.Width() = aPrimaryRect.Right() + aBorderSize.Width();
536 :
537 0 : SetSizePixel( aDialogSize );
538 0 : SetPageSizePixel( aDialogSize );
539 : }
540 :
541 0 : void OSQLMessageBox::impl_initImage( MessageType _eImage )
542 : {
543 0 : switch (_eImage)
544 : {
545 : default:
546 : OSL_FAIL( "OSQLMessageBox::impl_initImage: unsupported image type!" );
547 : /* Fall through */
548 : case Info:
549 0 : m_aInfoImage.SetImage(InfoBox::GetStandardImage());
550 0 : break;
551 : case Warning:
552 0 : m_aInfoImage.SetImage(WarningBox::GetStandardImage());
553 0 : break;
554 : case Error:
555 0 : m_aInfoImage.SetImage(ErrorBox::GetStandardImage());
556 0 : break;
557 : case Query:
558 0 : m_aInfoImage.SetImage(QueryBox::GetStandardImage());
559 0 : break;
560 : }
561 0 : }
562 :
563 0 : void OSQLMessageBox::impl_createStandardButtons( WinBits _nStyle )
564 : {
565 0 : if ( _nStyle & WB_YES_NO_CANCEL )
566 : {
567 0 : lcl_addButton( *this, BUTTON_YES, ( _nStyle & WB_DEF_YES ) != 0 );
568 0 : lcl_addButton( *this, BUTTON_NO, ( _nStyle & WB_DEF_NO ) != 0 );
569 0 : lcl_addButton( *this, BUTTON_CANCEL, ( _nStyle & WB_DEF_CANCEL ) != 0 );
570 : }
571 0 : else if ( _nStyle & WB_OK_CANCEL )
572 : {
573 0 : lcl_addButton( *this, BUTTON_OK, ( _nStyle & WB_DEF_OK ) != 0 );
574 0 : lcl_addButton( *this, BUTTON_CANCEL, ( _nStyle & WB_DEF_CANCEL ) != 0 );
575 : }
576 0 : else if ( _nStyle & WB_YES_NO )
577 : {
578 0 : lcl_addButton( *this, BUTTON_YES, ( _nStyle & WB_DEF_YES ) != 0 );
579 0 : lcl_addButton( *this, BUTTON_NO, ( _nStyle & WB_DEF_NO ) != 0 );
580 : }
581 0 : else if ( _nStyle & WB_RETRY_CANCEL )
582 : {
583 0 : lcl_addButton( *this, BUTTON_RETRY, ( _nStyle & WB_DEF_RETRY ) != 0 );
584 0 : lcl_addButton( *this, BUTTON_CANCEL, ( _nStyle & WB_DEF_CANCEL ) != 0 );
585 : }
586 : else
587 : {
588 : OSL_ENSURE( WB_OK & _nStyle, "OSQLMessageBox::impl_createStandardButtons: unsupported dialog style requested!" );
589 0 : AddButton( BUTTON_OK, RET_OK, BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_FOCUSBUTTON );
590 : }
591 :
592 0 : if ( !m_sHelpURL.isEmpty() )
593 : {
594 0 : lcl_addButton( *this, BUTTON_HELP, false );
595 :
596 0 : OUString aTmp;
597 0 : INetURLObject aHID( m_sHelpURL );
598 0 : if ( aHID.GetProtocol() == INET_PROT_HID )
599 0 : aTmp = aHID.GetURLPath();
600 : else
601 0 : aTmp = m_sHelpURL;
602 :
603 0 : SetHelpId( OUStringToOString( aTmp, RTL_TEXTENCODING_UTF8 ) );
604 : }
605 0 : }
606 :
607 0 : void OSQLMessageBox::impl_addDetailsButton()
608 : {
609 0 : size_t nFirstPageVisible = m_aMessage.IsVisible() ? 2 : 1;
610 :
611 0 : bool bMoreDetailsAvailable = m_pImpl->aDisplayInfo.size() > nFirstPageVisible;
612 0 : if ( !bMoreDetailsAvailable )
613 : {
614 : // even if the text fits into what we can display, we might need to details button
615 : // if there is more non-trivial information in the errors than the mere messages
616 0 : for ( ExceptionDisplayChain::const_iterator error = m_pImpl->aDisplayInfo.begin();
617 0 : error != m_pImpl->aDisplayInfo.end();
618 : ++error
619 : )
620 : {
621 0 : if ( lcl_hasDetails( *error ) )
622 : {
623 0 : bMoreDetailsAvailable = true;
624 0 : break;
625 : }
626 : }
627 : }
628 :
629 0 : if ( bMoreDetailsAvailable )
630 : {
631 0 : AddButton( BUTTON_MORE, RET_MORE, 0 );
632 0 : PushButton* pButton = GetPushButton( RET_MORE );
633 : OSL_ENSURE( pButton, "OSQLMessageBox::impl_addDetailsButton: just added this button, why isn't it there?" );
634 0 : pButton->SetClickHdl( LINK( this, OSQLMessageBox, ButtonClickHdl ) );
635 0 : pButton->SetUniqueId( UID_SQLERROR_BUTTONMORE );
636 : }
637 0 : }
638 :
639 0 : void OSQLMessageBox::Construct( WinBits _nStyle, MessageType _eImage )
640 : {
641 : SetText(
642 0 : utl::ConfigManager::getProductName() +
643 0 : OUString( " Base" ) );
644 :
645 : // position and size the controls and the dialog, depending on whether we have one or two texts to display
646 0 : impl_positionControls();
647 :
648 : // init the image
649 0 : MessageType eType( _eImage );
650 0 : if ( eType == AUTO )
651 : {
652 0 : switch ( m_pImpl->aDisplayInfo[0].eType )
653 : {
654 0 : case SQLExceptionInfo::SQL_EXCEPTION: eType = Error; break;
655 0 : case SQLExceptionInfo::SQL_WARNING: eType = Warning; break;
656 0 : case SQLExceptionInfo::SQL_CONTEXT: eType = Info; break;
657 : default: OSL_FAIL( "OSQLMessageBox::Construct: invalid type!" );
658 : }
659 : }
660 0 : impl_initImage( eType );
661 :
662 : // create buttons
663 0 : impl_createStandardButtons( _nStyle );
664 0 : impl_addDetailsButton();
665 0 : }
666 :
667 0 : OSQLMessageBox::OSQLMessageBox(Window* _pParent, const SQLExceptionInfo& _rException, WinBits _nStyle, const OUString& _rHelpURL )
668 : :ButtonDialog( _pParent, WB_HORZ | WB_STDDIALOG )
669 : ,m_aInfoImage( this )
670 : ,m_aTitle( this, WB_WORDBREAK | WB_LEFT )
671 : ,m_aMessage( this, WB_WORDBREAK | WB_LEFT )
672 : ,m_sHelpURL( _rHelpURL )
673 0 : ,m_pImpl( new SQLMessageBox_Impl( _rException ) )
674 : {
675 0 : Construct( _nStyle, AUTO );
676 0 : }
677 :
678 0 : OSQLMessageBox::OSQLMessageBox( Window* _pParent, const OUString& _rTitle, const OUString& _rMessage, WinBits _nStyle, MessageType _eType, const ::dbtools::SQLExceptionInfo* _pAdditionalErrorInfo )
679 : :ButtonDialog( _pParent, WB_HORZ | WB_STDDIALOG )
680 : ,m_aInfoImage( this )
681 : ,m_aTitle( this, WB_WORDBREAK | WB_LEFT )
682 0 : ,m_aMessage( this, WB_WORDBREAK | WB_LEFT )
683 : {
684 0 : SQLContext aError;
685 0 : aError.Message = _rTitle;
686 0 : aError.Details = _rMessage;
687 0 : if ( _pAdditionalErrorInfo )
688 0 : aError.NextException = _pAdditionalErrorInfo->get();
689 :
690 0 : m_pImpl.reset( new SQLMessageBox_Impl( SQLExceptionInfo( aError ) ) );
691 :
692 0 : Construct( _nStyle, _eType );
693 0 : }
694 :
695 0 : OSQLMessageBox::~OSQLMessageBox()
696 : {
697 0 : }
698 :
699 0 : IMPL_LINK( OSQLMessageBox, ButtonClickHdl, Button *, /*pButton*/ )
700 : {
701 0 : OExceptionChainDialog aDlg( this, m_pImpl->aDisplayInfo );
702 0 : aDlg.Execute();
703 0 : return 0;
704 : }
705 :
706 : // OSQLWarningBox
707 0 : OSQLWarningBox::OSQLWarningBox( Window* _pParent, const OUString& _rMessage, WinBits _nStyle,
708 : const ::dbtools::SQLExceptionInfo* _pAdditionalErrorInfo )
709 0 : :OSQLMessageBox( _pParent, ModuleRes( STR_EXCEPTION_WARNING ), _rMessage, _nStyle, OSQLMessageBox::Warning, _pAdditionalErrorInfo )
710 : {
711 0 : }
712 :
713 : // OSQLErrorBox
714 0 : OSQLErrorBox::OSQLErrorBox( Window* _pParent, const OUString& _rMessage, WinBits _nStyle,
715 : const ::dbtools::SQLExceptionInfo* _pAdditionalErrorInfo )
716 0 : :OSQLMessageBox( _pParent, ModuleRes( STR_EXCEPTION_ERROR ), _rMessage, _nStyle, OSQLMessageBox::Error, _pAdditionalErrorInfo )
717 : {
718 0 : }
719 :
720 : } // namespace dbaui
721 :
722 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|