Salome HOME
Join modifications from branch OCC_debug_for_3_2_0b1
[modules/gui.git] / src / Qtx / QtxSplash.cxx
1 // Copyright (C) 2005  OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License.
7 //
8 // This library is distributed in the hope that it will be useful
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/
18 //
19 // File:      QtxSplash.cxx
20 // Author:    Vadim SANDLER
21
22 #include "QtxSplash.h"
23
24 #include <qapplication.h>
25 #include <qpainter.h>
26 #include <qpixmap.h>
27 #include <qmessagebox.h>
28
29 const int _PROGRESS_EVENT = QEvent::User + 10;
30 const int _PROGRESS_WIDTH = 10;
31
32 /*!
33   Class ProgressEvent [ internal ].
34 */
35 class ProgressEvent: public QCustomEvent
36 {
37 public:
38   ProgressEvent( const QString& msg, const int progress = 0 )
39     : QCustomEvent( id() ),
40       myMessage( msg ),
41       myProgress( progress )
42   {}
43   QString    message()  const { return myMessage;       } 
44   int        progress() const { return myProgress;      }
45   static int id()             { return _PROGRESS_EVENT; }
46
47 private:
48   QString myMessage;
49   int     myProgress;
50 };
51
52 // Only one instance of splash screen is allowed
53 QtxSplash* QtxSplash::mySplash = 0;
54
55 /*!
56   Construct a splash screen that will display the \a pixmap.
57 */
58 QtxSplash::QtxSplash( const QPixmap& pixmap )
59   : QWidget( 0, 0, WStyle_Customize | WStyle_StaysOnTop | WX11BypassWM | WStyle_NoBorder )
60 {
61   myAlignment    = AlignBottom | AlignRight;
62   myColor        = white;
63   myHideOnClick  = false;
64   myProgress     = 0;
65   myTotal        = 0;
66   myGradientType = Vertical;
67   myError        = 0;
68   myStartColor   = red;
69
70   setPixmap( pixmap );
71 }
72
73 /*!
74   Destructor.
75 */
76 QtxSplash::~QtxSplash()
77 {
78   mySplash = 0;
79 }
80
81 /*!
82   Returns an only instance of splash screen.
83   If \a px is valid sets this pixmap to the splash screen.
84 */
85 QtxSplash* QtxSplash::splash( const QPixmap& px )
86 {
87   if ( !mySplash )
88     mySplash = new QtxSplash( px );
89   else if ( !px.isNull() )
90     mySplash->setPixmap( px );
91   return mySplash;
92 }
93
94 /*!
95   Sends the status message and (optionally) progress to the splash screen.
96   Can be used, for example, from the progress thread.
97 */
98 void QtxSplash::setStatus( const QString& msg, 
99                            const int      progress )
100 {
101   if ( mySplash ) {
102     QApplication::postEvent( mySplash, new ProgressEvent( msg, progress ) );
103     qApp->processEvents();
104   }
105 }
106
107 /*!
108   Sets error status and shows error message box to the user.
109 */
110 void QtxSplash::error( const QString& error, const QString& title, const int code )
111 {
112   printf("QtxSplash::error: %s\n",error.latin1());
113   if ( mySplash ) {
114     mySplash->setError( code );
115     QMessageBox::critical( mySplash, 
116                            title.isEmpty() ? tr( "Error" ) : title,
117                            error,
118                            tr( "&OK" ) );
119   }
120 }
121
122 /*!
123   Sets the pixmap that will be used as the splash screen's image to
124   \a pixmap.
125 */
126 void QtxSplash::setPixmap( const QPixmap& pixmap )
127 {
128   myPixmap = pixmap;
129   QRect r( 0, 0, myPixmap.size().width(), myPixmap.size().height() );
130   resize( myPixmap.size() );
131   move( QApplication::desktop()->screenGeometry().center() - r.center() );
132   repaint();
133 }
134
135 /*!
136   Returns the pixmap that is used in the splash screen.
137 */
138 QPixmap QtxSplash::pixmap() const
139 {
140   return myPixmap;
141 }
142
143 /*!
144   Sets/clear the 'hide on mouse click' flag.
145   Default is FALSE.
146   When this flag is set, user can hide the splash screen window
147   by clicking on it with mouse.
148   But for this to work it is necessary to call periodically
149   QApplication::processEvents() in order to allow event loop to process
150   events because usually main application loop is not yet started
151   at that moment.
152 */
153 void QtxSplash::setHideOnClick( const bool on )
154 {
155   myHideOnClick = on;
156 }
157
158 /*!
159   Returns the 'hide on mouse click' flag.
160 */
161 bool QtxSplash::hideOnClick() const
162 {
163   return myHideOnClick;
164 }
165
166 /*!
167   Sets total progress steps to \a total.
168 */
169 void QtxSplash::setTotalSteps( const int total )
170 {
171   myTotal = total;
172   repaint();
173 }
174
175 /*!
176   Return total progress steps number.
177   \sa setTotalSteps(), setProgress()
178 */
179 int QtxSplash::totalSteps() const
180 {
181   return myTotal;
182 }
183     
184 /*!
185   Sets progress to \a progress.
186 */
187 void QtxSplash::setProgress( const int progress )
188 {
189   myProgress = progress;
190   repaint();
191 }
192
193 /*!
194   Return current progress.
195   \sa setProgress(), setTotalSteps()
196 */
197 int QtxSplash::progress() const
198 {
199   return myProgress;
200 }
201
202 /*!
203   Sets progress to \a progress and total progress steps to \a total.
204 */
205 void QtxSplash::setProgress( const int progress, const int total )
206 {
207   myTotal    = total;
208   myProgress = progress;
209   repaint();
210 }
211
212 /*!
213   Sets progress bar colors to \a startColor and \a endColor.
214   If the colors differ the gradient color bar is drawed.
215   If the \a endColor is not valid, \a startColor is used instead.
216   \a gradientType sets the type of gradient to be used for progress
217   bar - horizontal or vertical. Default is vertical.
218 */
219 void QtxSplash::setProgressColors( const QColor& startColor, 
220                                    const QColor& endColor,
221                                    const int     gradientType )
222 {
223   myStartColor   = startColor;
224   myEndColor     = endColor;
225   myGradientType = gradientType;
226   repaint();
227 }
228
229 /*!
230   Return progress colors and gradient type (horizontal or vertical).
231   \sa setProgressColors()
232 */
233 int QtxSplash::progressColors( QColor& startColor, QColor& endColor )
234 {
235   startColor = myStartColor;
236   endColor   = myEndColor;
237   return myGradientType;
238 }
239
240 /*!
241   Sets message text alignment flags to \a alignment.
242   Default is AlignBottom | AlignRight.
243 */
244 void QtxSplash::setTextAlignment( const int alignment )
245 {
246   myAlignment = alignment;
247   repaint();
248 }
249
250 /*!
251   Return message text alignment flags.
252   \sa setTextAlignment()
253 */
254 int QtxSplash::textAlignment() const
255 {
256   return myAlignment;
257 }
258
259 /*!
260   Sets message text color to \a color.
261   Default is white.
262   \sa setTextColors()
263 */
264 void QtxSplash::setTextColor( const QColor& color )
265 {
266   myColor = color;
267   myShadowColor = QColor();
268   repaint();
269 }
270
271 /*!
272   Return message text color.
273   \sa setTextColor()
274 */
275 QColor QtxSplash::textColor() const
276 {
277   return myColor;
278 }
279
280 /*!
281   Sets message text color to \a color and text shadow color to \a shadow.
282   \sa setTextColor()
283 */
284 void QtxSplash::setTextColors( const QColor& color, const QColor& shadow )
285 {
286   myColor       = color;
287   myShadowColor = shadow;
288   repaint();
289 }
290
291 /*!
292   Return message text color and text shadow color.
293   \sa setTextColors()
294 */
295 void QtxSplash::textColors( QColor& color, QColor& shadow ) const
296 {
297   color  = myColor;
298   shadow = myShadowColor;
299 }
300
301 /*!
302   Returns current status message.
303 */
304 QString QtxSplash::message() const
305 {
306   return myMessage;
307 }
308
309 /*!
310   Return error code. If no errors were occured returns 0.
311   Error code can be set by error( QString&, QString, int ).
312 */
313 int QtxSplash::error() const
314 {
315   return myError;
316 }
317
318 /*!
319     Makes the splash screen wait until the widget \a mainWin is displayed
320     before calling close() on itself.
321 */
322 void QtxSplash::finish( QWidget* mainWin )
323 {
324   if ( mainWin ) {
325 #if defined(Q_WS_X11)
326     extern void qt_wait_for_window_manager( QWidget* w );
327     qt_wait_for_window_manager( mainWin );
328 #endif
329   }
330   close();
331 }
332
333 /*!
334   Repaint the splash screen.
335 */
336 void QtxSplash::repaint()
337 {
338   drawContents();
339   QWidget::repaint();
340   QApplication::flush();
341 }
342
343 /*!
344   Draws the \a message text onto the splash screen with color \a
345   color and aligns the text according to the flags in \a alignment.
346 */
347 void QtxSplash::message( const QString& msg, 
348                          int            alignment,
349                          const QColor&  color )
350 {
351   myMessage   = msg;
352   myAlignment = alignment;
353   myColor     = color;
354   repaint();
355 }
356
357 /*!
358   This is an overloaded member function, provided for convenience. 
359   It behaves essentially like the above function.
360   Draws the \a message text onto the splash screen with default color
361   and aligns the text according to the default alignment flags.
362 */
363 void QtxSplash::message( const QString& msg )
364 {
365   myMessage = msg;
366   repaint();
367 }
368
369 /*!
370   Removes the message being displayed on the splash screen.
371   \sa message()
372 */
373 void QtxSplash::clear()
374 {
375   myMessage = QString::null;
376   repaint();
377 }
378
379 /*!
380   Draw the contents of the splash screen using painter \a painter.
381 */
382 void QtxSplash::drawContents( QPainter* painter )
383 {
384   QRect r = rect();
385   if ( myTotal > 0 ) {
386     // draw progress bar outline rectangle
387     painter->setPen( palette().active().dark() );
388     painter->drawLine( r.x()+5, 
389                        r.height()-5-_PROGRESS_WIDTH,
390                        r.width()-5,
391                        r.height()-5-_PROGRESS_WIDTH );
392     painter->drawLine( r.x()+5,
393                        r.height()-5-_PROGRESS_WIDTH,
394                        r.x()+5,
395                        r.height()-5 );
396     painter->setPen( palette().active().light() );
397     painter->drawLine( r.x()+5,
398                        r.height()-5,
399                        r.width()-5,
400                        r.height()-5 );
401     painter->drawLine( r.width()-5,
402                        r.height()-5-_PROGRESS_WIDTH,
403                        r.width()-5,
404                        r.height()-5 );
405     // draw progress bar
406     if ( myGradientType == Horizontal ) {
407       int tng = r.width() - r.x() - 11;
408       int ng = (int) ( 1.0 * tng * ( myProgress > 0 ? myProgress : 0 ) / myTotal ); 
409       int h1, h2, s1, s2, v1, v2;
410       myStartColor.hsv( &h1, &s1, &v1 );
411       myEndColor.isValid() ? myEndColor.hsv( &h2, &s2, &v2 ) :
412                              myStartColor.hsv( &h2, &s2, &v2 );
413       for ( int i = 0; i < ng; i++ ) {
414         painter->setPen( QColor( h1 + ((h2-h1)*i)/(tng-1),
415                                  s1 + ((s2-s1)*i)/(tng-1),
416                                  v1 + ((v2-v1)*i)/(tng-1), 
417                                  QColor::Hsv ) );
418         painter->drawLine( r.x()+6+i,
419                            r.height()-5-_PROGRESS_WIDTH+1,
420                            r.x()+6+i,
421                            r.height()-6 );
422       }
423     }
424     else {
425       int ng = (int) ( 1.0 * (r.width() - r.x() - 11) * ( myProgress > 0 ? myProgress : 0 ) / myTotal ); 
426       int h1, h2, s1, s2, v1, v2;
427       myStartColor.hsv( &h1, &s1, &v1 );
428       myEndColor.isValid() ? myEndColor.hsv( &h2, &s2, &v2 ) :
429                              myStartColor.hsv( &h2, &s2, &v2 );
430       for ( int i = 0; i < _PROGRESS_WIDTH-1; i++ ) {
431         painter->setPen( QColor( h1 + ((h2-h1)*i)/(_PROGRESS_WIDTH-2),
432                                  s1 + ((s2-s1)*i)/(_PROGRESS_WIDTH-2),
433                                  v1 + ((v2-v1)*i)/(_PROGRESS_WIDTH-2), 
434                                  QColor::Hsv ) );
435         painter->drawLine( r.x()+6,
436                            r.height()-5-_PROGRESS_WIDTH+1+i,
437                            r.x()+6+ng-1,
438                            r.height()-5-_PROGRESS_WIDTH+1+i );
439       }
440     }
441   }
442   // draw status
443   if ( !myMessage.isEmpty() ) {
444     QFontMetrics f( font() );
445     int spacing = f.lineSpacing();
446     int shift = myTotal > 0 ? _PROGRESS_WIDTH : _PROGRESS_WIDTH; // : 0
447     int i = myMessage.length() - 1;
448     while( i >= 0 && myMessage[ i-- ] == '\n' )
449       shift += spacing;
450     QRect r1( r.x() + 5, r.y() + 5, r.width() - 10, r.height() - 10 - shift );
451     QRect r2 = r1;
452     if ( myAlignment & Qt::AlignLeft   ) r2.setLeft  ( r2.left()   + 1 );
453     if ( myAlignment & Qt::AlignTop    ) r2.setTop   ( r2.top()    + 1 );
454     if ( myAlignment & Qt::AlignRight  ) r2.setRight ( r2.right()  + 1 );
455     if ( myAlignment & Qt::AlignBottom ) r2.setBottom( r2.bottom() + 1 );
456     if ( myShadowColor.isValid() ) {
457       painter->setPen( myShadowColor );
458       painter->drawText( r2, myAlignment, myMessage );
459     }
460     painter->setPen( myColor );
461     painter->drawText( r1, myAlignment, myMessage );
462   }
463 }
464
465 /*!
466   Mouse press event.
467   Hides splash screen if the 'hide on mouse click' flag is set.
468   \sa setHideOnClick()
469 */
470 void QtxSplash::mousePressEvent( QMouseEvent* )
471 {
472   if ( myHideOnClick )
473     hide();
474 }
475
476 /*!
477   Processes custom event sent by setStatus() method.
478   \sa setStatus().
479 */
480 void QtxSplash::customEvent( QCustomEvent* ce )
481 {
482   if ( ce->type() == ProgressEvent::id() ) {
483     ProgressEvent* pe = (ProgressEvent*)ce;
484     pe->message().isEmpty() ? clear() : message( pe->message() );
485     setProgress( pe->progress() );
486     qApp->processEvents();
487   }
488 }
489
490 /*!
491   Draws the splash screen window [ internal ].
492 */
493 void QtxSplash::drawContents()
494 {
495   QPixmap textPix = myPixmap;
496   QPainter painter( &textPix, this );
497   drawContents( &painter );
498   setErasePixmap( textPix );
499 }
500
501 /*!
502   Sets error code [ internal ].
503 */
504 void QtxSplash::setError( const int code )
505 {
506   myError = code;
507 }