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 != "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 = static_cast<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: useless 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 = static_cast<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 : class OExceptionChainDialog : public ModalDialog
294 : {
295 : VclPtr<SvTreeListBox> m_pExceptionList;
296 : VclPtr<VclMultiLineEdit> m_pExceptionText;
297 :
298 : OUString m_sStatusLabel;
299 : OUString m_sErrorCodeLabel;
300 :
301 : ExceptionDisplayChain m_aExceptions;
302 :
303 : public:
304 : OExceptionChainDialog( vcl::Window* pParent, const ExceptionDisplayChain& _rExceptions );
305 0 : virtual ~OExceptionChainDialog() { disposeOnce(); }
306 0 : virtual void dispose() SAL_OVERRIDE
307 : {
308 0 : m_pExceptionList.clear();
309 0 : m_pExceptionText.clear();
310 0 : ModalDialog::dispose();
311 0 : }
312 :
313 : protected:
314 : DECL_LINK(OnExceptionSelected, void*);
315 : };
316 :
317 0 : OExceptionChainDialog::OExceptionChainDialog(vcl::Window* pParent, const ExceptionDisplayChain& _rExceptions)
318 : : ModalDialog(pParent, "SQLExceptionDialog", "dbaccess/ui/sqlexception.ui")
319 0 : , m_aExceptions(_rExceptions)
320 : {
321 0 : get(m_pExceptionList, "list");
322 0 : Size aListSize(LogicToPixel(Size(85, 93), MAP_APPFONT));
323 0 : m_pExceptionList->set_width_request(aListSize.Width());
324 0 : m_pExceptionList->set_height_request(aListSize.Height());
325 0 : get(m_pExceptionText, "description");
326 0 : Size aTextSize(LogicToPixel(Size(125 , 93), MAP_APPFONT));
327 0 : m_pExceptionText->set_width_request(aTextSize.Width());
328 0 : m_pExceptionText->set_height_request(aTextSize.Height());
329 :
330 0 : m_sStatusLabel = ModuleRes( STR_EXCEPTION_STATUS );
331 0 : m_sErrorCodeLabel = ModuleRes( STR_EXCEPTION_ERRORCODE );
332 :
333 0 : m_pExceptionList->SetSelectionMode(SINGLE_SELECTION);
334 0 : m_pExceptionList->SetDragDropMode(DragDropMode::NONE);
335 0 : m_pExceptionList->EnableInplaceEditing(false);
336 0 : m_pExceptionList->SetStyle(m_pExceptionList->GetStyle() | WB_HASLINES | WB_HASBUTTONS | WB_HASBUTTONSATROOT | WB_HSCROLL);
337 :
338 0 : m_pExceptionList->SetSelectHdl(LINK(this, OExceptionChainDialog, OnExceptionSelected));
339 0 : m_pExceptionList->SetNodeDefaultImages( );
340 :
341 0 : bool bHave22018 = false;
342 0 : size_t elementPos = 0;
343 :
344 0 : for ( ExceptionDisplayChain::const_iterator loop = m_aExceptions.begin();
345 0 : loop != m_aExceptions.end();
346 : ++loop, ++elementPos
347 : )
348 : {
349 0 : lcl_insertExceptionEntry( *m_pExceptionList, elementPos, *loop );
350 0 : bHave22018 = loop->sSQLState == "22018";
351 : }
352 :
353 : // if the error has the code 22018, then add an additional explanation
354 : // #i24021#
355 0 : if ( bHave22018 )
356 : {
357 0 : ProviderFactory aProviderFactory;
358 :
359 0 : ExceptionDisplayInfo aInfo22018;
360 0 : aInfo22018.sMessage = ModuleRes( STR_EXPLAN_STRINGCONVERSION_ERROR );
361 0 : aInfo22018.pLabelProvider = aProviderFactory.getLabelProvider( SQLExceptionInfo::SQL_CONTEXT, false );
362 0 : aInfo22018.pImageProvider = aProviderFactory.getImageProvider( SQLExceptionInfo::SQL_CONTEXT );
363 0 : m_aExceptions.push_back( aInfo22018 );
364 :
365 0 : lcl_insertExceptionEntry( *m_pExceptionList, m_aExceptions.size() - 1, aInfo22018 );
366 : }
367 0 : }
368 :
369 0 : IMPL_LINK_NOARG(OExceptionChainDialog, OnExceptionSelected)
370 : {
371 0 : SvTreeListEntry* pSelected = m_pExceptionList->FirstSelected();
372 : OSL_ENSURE(!pSelected || !m_pExceptionList->NextSelected(pSelected), "OExceptionChainDialog::OnExceptionSelected : multi selection ?");
373 :
374 0 : OUString sText;
375 :
376 0 : if ( pSelected )
377 : {
378 0 : size_t pos = reinterpret_cast< size_t >( pSelected->GetUserData() );
379 0 : const ExceptionDisplayInfo& aExceptionInfo( m_aExceptions[ pos ] );
380 :
381 0 : if ( !aExceptionInfo.sSQLState.isEmpty() )
382 : {
383 0 : sText += m_sStatusLabel;
384 0 : sText += ": ";
385 0 : sText += aExceptionInfo.sSQLState;
386 0 : sText += "\n";
387 : }
388 :
389 0 : if ( !aExceptionInfo.sErrorCode.isEmpty() )
390 : {
391 0 : sText += m_sErrorCodeLabel;
392 0 : sText += ": ";
393 0 : sText += aExceptionInfo.sErrorCode;
394 0 : sText += "\n";
395 : }
396 :
397 0 : if ( !sText.isEmpty() )
398 0 : sText += "\n";
399 :
400 0 : sText += aExceptionInfo.sMessage;
401 : }
402 :
403 0 : m_pExceptionText->SetText(sText);
404 :
405 0 : return 0L;
406 : }
407 :
408 : // SQLMessageBox_Impl
409 0 : struct SQLMessageBox_Impl
410 : {
411 : ExceptionDisplayChain aDisplayInfo;
412 :
413 0 : SQLMessageBox_Impl( const SQLExceptionInfo& _rExceptionInfo )
414 0 : {
415 : // transform the exception chain to a form more suitable for displaying it here
416 0 : ProviderFactory aProviderFactory;
417 0 : lcl_buildExceptionChain( _rExceptionInfo, aProviderFactory, aDisplayInfo );
418 0 : }
419 : };
420 :
421 : namespace
422 : {
423 0 : void lcl_positionInAppFont( const vcl::Window& _rParent, vcl::Window& _rChild, long _nX, long _nY, long _Width, long _Height )
424 : {
425 0 : Point aPos = _rParent.LogicToPixel( Point( _nX, _nY ), MAP_APPFONT );
426 0 : Size aSize = _rParent.LogicToPixel( Size( _Width, _Height ), MAP_APPFONT );
427 0 : _rChild.SetPosSizePixel( aPos, aSize );
428 0 : }
429 :
430 0 : void lcl_addButton( ButtonDialog& _rDialog, StandardButtonType _eType, bool _bDefault )
431 : {
432 0 : sal_uInt16 nButtonID = 0;
433 0 : switch ( _eType )
434 : {
435 0 : case StandardButtonType::Yes: nButtonID = RET_YES; break;
436 0 : case StandardButtonType::No: nButtonID = RET_NO; break;
437 0 : case StandardButtonType::OK: nButtonID = RET_OK; break;
438 0 : case StandardButtonType::Cancel: nButtonID = RET_CANCEL; break;
439 0 : case StandardButtonType::Retry: nButtonID = RET_RETRY; break;
440 0 : case StandardButtonType::Help: nButtonID = RET_HELP; break;
441 : default:
442 : OSL_FAIL( "lcl_addButton: invalid button id!" );
443 0 : break;
444 : }
445 0 : _rDialog.AddButton( _eType, nButtonID, _bDefault ? ButtonDialogFlags::Default | ButtonDialogFlags::Focus : ButtonDialogFlags::NONE );
446 0 : }
447 : }
448 :
449 0 : void OSQLMessageBox::impl_positionControls()
450 : {
451 : OSL_PRECOND( !m_pImpl->aDisplayInfo.empty(), "OSQLMessageBox::impl_positionControls: nothing to display at all?" );
452 :
453 0 : if ( m_pImpl->aDisplayInfo.empty() )
454 0 : return;
455 0 : const ExceptionDisplayInfo* pSecondInfo = NULL;
456 :
457 0 : const ExceptionDisplayInfo& rFirstInfo = *m_pImpl->aDisplayInfo.begin();
458 0 : if ( m_pImpl->aDisplayInfo.size() > 1 )
459 0 : pSecondInfo = &m_pImpl->aDisplayInfo[1];
460 0 : OUString sPrimary, sSecondary;
461 0 : sPrimary = rFirstInfo.sMessage;
462 : // one or two texts to display?
463 0 : if ( pSecondInfo )
464 : {
465 : // we show two elements in the main dialog if and only if one of
466 : // - the first element in the chain is an SQLContext, and the second
467 : // element denotes its sub entry
468 : // - the first and the second element are both independent (i.e. the second
469 : // is no sub entry), and none of them is a context.
470 0 : bool bFirstElementIsContext = ( rFirstInfo.eType == SQLExceptionInfo::SQL_CONTEXT );
471 0 : bool bSecondElementIsContext = ( pSecondInfo->eType == SQLExceptionInfo::SQL_CONTEXT );
472 :
473 0 : if ( bFirstElementIsContext && pSecondInfo->bSubEntry )
474 0 : sSecondary = pSecondInfo->sMessage;
475 0 : if ( !bFirstElementIsContext && !bSecondElementIsContext )
476 0 : sSecondary = pSecondInfo->sMessage;
477 : }
478 :
479 : // image
480 0 : lcl_positionInAppFont( *this, *m_aInfoImage.get(), OUTER_MARGIN, OUTER_MARGIN, IMAGE_SIZE, IMAGE_SIZE );
481 0 : m_aInfoImage->Show();
482 :
483 : // primary text
484 0 : lcl_positionInAppFont( *this, *m_aTitle.get(), TEXT_POS_X, OUTER_MARGIN, DIALOG_WIDTH - TEXT_POS_X - 2 * OUTER_MARGIN, 16 );
485 0 : sPrimary = lcl_stripOOoBaseVendor( sPrimary );
486 0 : m_aTitle->SetText( sPrimary );
487 0 : m_aTitle->Show();
488 :
489 0 : Rectangle aPrimaryRect( m_aTitle->GetPosPixel(), m_aTitle->GetSizePixel() );
490 :
491 : // secondary text (if applicable)
492 0 : m_aMessage->SetStyle( m_aMessage->GetStyle() | WB_NOLABEL );
493 0 : sSecondary = lcl_stripOOoBaseVendor( sSecondary );
494 0 : m_aMessage->SetText( sSecondary );
495 :
496 0 : lcl_positionInAppFont( *this, *m_aMessage.get(), TEXT_POS_X, OUTER_MARGIN + 16 + 3, DIALOG_WIDTH - TEXT_POS_X - 2 * OUTER_MARGIN, 8 );
497 0 : Rectangle aSecondaryRect( m_aMessage->GetPosPixel(), m_aMessage->GetSizePixel() );
498 :
499 0 : bool bHaveSecondaryText = !sSecondary.isEmpty();
500 :
501 : // determine which space the secondary text would occupy
502 0 : if ( bHaveSecondaryText )
503 0 : aSecondaryRect = GetTextRect( aSecondaryRect, sSecondary, DrawTextFlags::WordBreak | DrawTextFlags::MultiLine | DrawTextFlags::Left );
504 : else
505 0 : aSecondaryRect.Bottom() = aSecondaryRect.Top() - 1;
506 :
507 : // adjust secondary control height accordingly
508 0 : m_aMessage->SetSizePixel( aSecondaryRect.GetSize() );
509 0 : m_aMessage->Show( aSecondaryRect.GetHeight() > 0 );
510 :
511 : // if there's no secondary text ...
512 0 : if ( !bHaveSecondaryText )
513 : { // then give the primary text as much horizontal space as it needs
514 0 : Rectangle aSuggestedRect( GetTextRect( aPrimaryRect, sPrimary, DrawTextFlags::WordBreak | DrawTextFlags::MultiLine | DrawTextFlags::Center ) );
515 0 : aPrimaryRect.Right() = aPrimaryRect.Left() + aSuggestedRect.GetWidth();
516 0 : aPrimaryRect.Bottom() = aPrimaryRect.Top() + aSuggestedRect.GetHeight();
517 : // and center it horizontally
518 0 : m_aTitle->SetStyle( ( m_aTitle->GetStyle() & ~WB_LEFT ) | WB_CENTER );
519 :
520 0 : Rectangle aInfoRect( m_aInfoImage->GetPosPixel(), m_aInfoImage->GetSizePixel() );
521 : // also, if it's not as high as the image ...
522 0 : if ( aPrimaryRect.GetHeight() < m_aInfoImage->GetSizePixel().Height() )
523 : { // ... make it fit the image height
524 0 : aPrimaryRect.Bottom() += aInfoRect.GetHeight() - aPrimaryRect.GetHeight();
525 : // and center it vertically
526 0 : m_aTitle->SetStyle( m_aTitle->GetStyle() | WB_VCENTER );
527 : }
528 : else
529 : { // ... otherwise, center the image vertically, relative to the primary text
530 0 : aInfoRect.Move( 0, ( aPrimaryRect.GetHeight() - aInfoRect.GetHeight() ) / 2 );
531 0 : m_aInfoImage->SetPosSizePixel( aInfoRect.TopLeft(), aInfoRect.GetSize() );
532 : }
533 :
534 0 : m_aTitle->SetPosSizePixel( aPrimaryRect.TopLeft(), aPrimaryRect.GetSize() );
535 : }
536 :
537 : // adjust dialog size accordingly
538 0 : const Rectangle& rBottomTextRect( bHaveSecondaryText ? aSecondaryRect : aPrimaryRect );
539 0 : Size aBorderSize = LogicToPixel( Size( OUTER_MARGIN, OUTER_MARGIN ), MAP_APPFONT );
540 0 : Size aDialogSize( LogicToPixel( Size( DIALOG_WIDTH, 30 ), MAP_APPFONT ) );
541 0 : aDialogSize.Height() = rBottomTextRect.Bottom() + aBorderSize.Height();
542 0 : aDialogSize.Width() = aPrimaryRect.Right() + aBorderSize.Width();
543 :
544 0 : SetSizePixel( aDialogSize );
545 0 : SetPageSizePixel( aDialogSize );
546 : }
547 :
548 0 : void OSQLMessageBox::impl_initImage( MessageType _eImage )
549 : {
550 0 : switch (_eImage)
551 : {
552 : default:
553 : OSL_FAIL( "OSQLMessageBox::impl_initImage: unsupported image type!" );
554 : /* Fall through */
555 : case Info:
556 0 : m_aInfoImage->SetImage(InfoBox::GetStandardImage());
557 0 : break;
558 : case Warning:
559 0 : m_aInfoImage->SetImage(WarningBox::GetStandardImage());
560 0 : break;
561 : case Error:
562 0 : m_aInfoImage->SetImage(ErrorBox::GetStandardImage());
563 0 : break;
564 : case Query:
565 0 : m_aInfoImage->SetImage(QueryBox::GetStandardImage());
566 0 : break;
567 : }
568 0 : }
569 :
570 0 : void OSQLMessageBox::impl_createStandardButtons( WinBits _nStyle )
571 : {
572 0 : if ( _nStyle & WB_YES_NO_CANCEL )
573 : {
574 0 : lcl_addButton( *this, StandardButtonType::Yes, ( _nStyle & WB_DEF_YES ) != 0 );
575 0 : lcl_addButton( *this, StandardButtonType::No, ( _nStyle & WB_DEF_NO ) != 0 );
576 0 : lcl_addButton( *this, StandardButtonType::Cancel, ( _nStyle & WB_DEF_CANCEL ) != 0 );
577 : }
578 0 : else if ( _nStyle & WB_OK_CANCEL )
579 : {
580 0 : lcl_addButton( *this, StandardButtonType::OK, ( _nStyle & WB_DEF_OK ) != 0 );
581 0 : lcl_addButton( *this, StandardButtonType::Cancel, ( _nStyle & WB_DEF_CANCEL ) != 0 );
582 : }
583 0 : else if ( _nStyle & WB_YES_NO )
584 : {
585 0 : lcl_addButton( *this, StandardButtonType::Yes, ( _nStyle & WB_DEF_YES ) != 0 );
586 0 : lcl_addButton( *this, StandardButtonType::No, ( _nStyle & WB_DEF_NO ) != 0 );
587 : }
588 0 : else if ( _nStyle & WB_RETRY_CANCEL )
589 : {
590 0 : lcl_addButton( *this, StandardButtonType::Retry, ( _nStyle & WB_DEF_RETRY ) != 0 );
591 0 : lcl_addButton( *this, StandardButtonType::Cancel, ( _nStyle & WB_DEF_CANCEL ) != 0 );
592 : }
593 : else
594 : {
595 : OSL_ENSURE( WB_OK & _nStyle, "OSQLMessageBox::impl_createStandardButtons: unsupported dialog style requested!" );
596 0 : AddButton( StandardButtonType::OK, RET_OK, ButtonDialogFlags::Default | ButtonDialogFlags::Focus );
597 : }
598 :
599 0 : if ( !m_sHelpURL.isEmpty() )
600 : {
601 0 : lcl_addButton( *this, StandardButtonType::Help, false );
602 :
603 0 : OUString aTmp;
604 0 : INetURLObject aHID( m_sHelpURL );
605 0 : if ( aHID.GetProtocol() == INetProtocol::Hid )
606 0 : aTmp = aHID.GetURLPath();
607 : else
608 0 : aTmp = m_sHelpURL;
609 :
610 0 : SetHelpId( OUStringToOString( aTmp, RTL_TEXTENCODING_UTF8 ) );
611 : }
612 0 : }
613 :
614 0 : void OSQLMessageBox::impl_addDetailsButton()
615 : {
616 0 : size_t nFirstPageVisible = m_aMessage->IsVisible() ? 2 : 1;
617 :
618 0 : bool bMoreDetailsAvailable = m_pImpl->aDisplayInfo.size() > nFirstPageVisible;
619 0 : if ( !bMoreDetailsAvailable )
620 : {
621 : // even if the text fits into what we can display, we might need to details button
622 : // if there is more non-trivial information in the errors than the mere messages
623 0 : for ( ExceptionDisplayChain::const_iterator error = m_pImpl->aDisplayInfo.begin();
624 0 : error != m_pImpl->aDisplayInfo.end();
625 : ++error
626 : )
627 : {
628 0 : if ( lcl_hasDetails( *error ) )
629 : {
630 0 : bMoreDetailsAvailable = true;
631 0 : break;
632 : }
633 : }
634 : }
635 :
636 0 : if ( bMoreDetailsAvailable )
637 : {
638 0 : AddButton( StandardButtonType::More, RET_MORE);
639 0 : PushButton* pButton = GetPushButton( RET_MORE );
640 : OSL_ENSURE( pButton, "OSQLMessageBox::impl_addDetailsButton: just added this button, why isn't it there?" );
641 0 : pButton->SetClickHdl( LINK( this, OSQLMessageBox, ButtonClickHdl ) );
642 0 : pButton->SetUniqueId( UID_SQLERROR_BUTTONMORE );
643 : }
644 0 : }
645 :
646 0 : void OSQLMessageBox::Construct( WinBits _nStyle, MessageType _eImage )
647 : {
648 0 : SetText( utl::ConfigManager::getProductName() + " Base" );
649 :
650 : // position and size the controls and the dialog, depending on whether we have one or two texts to display
651 0 : impl_positionControls();
652 :
653 : // init the image
654 0 : MessageType eType( _eImage );
655 0 : if ( eType == AUTO )
656 : {
657 0 : switch ( m_pImpl->aDisplayInfo[0].eType )
658 : {
659 0 : case SQLExceptionInfo::SQL_EXCEPTION: eType = Error; break;
660 0 : case SQLExceptionInfo::SQL_WARNING: eType = Warning; break;
661 0 : case SQLExceptionInfo::SQL_CONTEXT: eType = Info; break;
662 : default: OSL_FAIL( "OSQLMessageBox::Construct: invalid type!" );
663 : }
664 : }
665 0 : impl_initImage( eType );
666 :
667 : // create buttons
668 0 : impl_createStandardButtons( _nStyle );
669 0 : impl_addDetailsButton();
670 0 : }
671 :
672 0 : OSQLMessageBox::OSQLMessageBox(vcl::Window* _pParent, const SQLExceptionInfo& _rException, WinBits _nStyle, const OUString& _rHelpURL )
673 : :ButtonDialog( _pParent, WB_HORZ | WB_STDDIALOG )
674 : ,m_aInfoImage( VclPtr<FixedImage>::Create(this) )
675 : ,m_aTitle( VclPtr<FixedText>::Create(this, WB_WORDBREAK | WB_LEFT) )
676 : ,m_aMessage( VclPtr<FixedText>::Create(this, WB_WORDBREAK | WB_LEFT) )
677 : ,m_sHelpURL( _rHelpURL )
678 0 : ,m_pImpl( new SQLMessageBox_Impl( _rException ) )
679 : {
680 0 : Construct( _nStyle, AUTO );
681 0 : }
682 :
683 0 : OSQLMessageBox::OSQLMessageBox( vcl::Window* _pParent, const OUString& _rTitle, const OUString& _rMessage, WinBits _nStyle, MessageType _eType, const ::dbtools::SQLExceptionInfo* _pAdditionalErrorInfo )
684 : :ButtonDialog( _pParent, WB_HORZ | WB_STDDIALOG )
685 : ,m_aInfoImage( VclPtr<FixedImage>::Create(this) )
686 : ,m_aTitle( VclPtr<FixedText>::Create(this, WB_WORDBREAK | WB_LEFT) )
687 0 : ,m_aMessage( VclPtr<FixedText>::Create(this, WB_WORDBREAK | WB_LEFT) )
688 : {
689 0 : SQLContext aError;
690 0 : aError.Message = _rTitle;
691 0 : aError.Details = _rMessage;
692 0 : if ( _pAdditionalErrorInfo )
693 0 : aError.NextException = _pAdditionalErrorInfo->get();
694 :
695 0 : m_pImpl.reset( new SQLMessageBox_Impl( SQLExceptionInfo( aError ) ) );
696 :
697 0 : Construct( _nStyle, _eType );
698 0 : }
699 :
700 0 : OSQLMessageBox::~OSQLMessageBox()
701 : {
702 0 : disposeOnce();
703 0 : }
704 :
705 0 : void OSQLMessageBox::dispose()
706 : {
707 0 : m_aInfoImage.disposeAndClear();
708 0 : m_aTitle.disposeAndClear();
709 0 : m_aMessage.disposeAndClear();
710 0 : ButtonDialog::dispose();
711 0 : }
712 :
713 0 : IMPL_LINK( OSQLMessageBox, ButtonClickHdl, Button *, /*pButton*/ )
714 : {
715 0 : ScopedVclPtrInstance< OExceptionChainDialog > aDlg( this, m_pImpl->aDisplayInfo );
716 0 : aDlg->Execute();
717 0 : return 0;
718 : }
719 :
720 : // OSQLWarningBox
721 0 : OSQLWarningBox::OSQLWarningBox( vcl::Window* _pParent, const OUString& _rMessage, WinBits _nStyle,
722 : const ::dbtools::SQLExceptionInfo* _pAdditionalErrorInfo )
723 0 : :OSQLMessageBox( _pParent, ModuleRes( STR_EXCEPTION_WARNING ), _rMessage, _nStyle, OSQLMessageBox::Warning, _pAdditionalErrorInfo )
724 : {
725 0 : }
726 :
727 : // OSQLErrorBox
728 0 : OSQLErrorBox::OSQLErrorBox( vcl::Window* _pParent, const OUString& _rMessage, WinBits _nStyle,
729 : const ::dbtools::SQLExceptionInfo* _pAdditionalErrorInfo )
730 0 : :OSQLMessageBox( _pParent, ModuleRes( STR_EXCEPTION_ERROR ), _rMessage, _nStyle, OSQLMessageBox::Error, _pAdditionalErrorInfo )
731 : {
732 0 : }
733 :
734 36 : } // namespace dbaui
735 :
736 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|