Salome HOME
Join modifications from BR_Dev_For_4_0 tag V4_1_1.
[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/ or email : webmaster.salome@opencascade.com
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   myMargin       = 5;
70
71   setPixmap( pixmap );
72 }
73
74 /*!
75   Destructor.
76 */
77 QtxSplash::~QtxSplash()
78 {
79   mySplash = 0;
80 }
81
82 /*!
83   Returns an only instance of splash screen.
84   If \a px is valid sets this pixmap to the splash screen.
85 */
86 QtxSplash* QtxSplash::splash( const QPixmap& px )
87 {
88   if ( !mySplash )
89     mySplash = new QtxSplash( px );
90   else if ( !px.isNull() )
91     mySplash->setPixmap( px );
92   return mySplash;
93 }
94
95 /*!
96   Sends the status message and (optionally) progress to the splash screen.
97   Can be used, for example, from the progress thread.
98 */
99 void QtxSplash::setStatus( const QString& msg, 
100                            const int      progress )
101 {
102   if ( mySplash ) {
103     QApplication::postEvent( mySplash, new ProgressEvent( msg, progress ) );
104     qApp->processEvents();
105   }
106 }
107
108 /*!
109   Sets error status and shows error message box to the user.
110 */
111 void QtxSplash::error( const QString& error, const QString& title, const int code )
112 {
113   printf("QtxSplash::error: %s\n",error.latin1());
114   if ( mySplash ) {
115     mySplash->setError( code );
116     QMessageBox::critical( mySplash, 
117                            title.isEmpty() ? tr( "Error" ) : title,
118                            error,
119                            tr( "&OK" ) );
120   }
121 }
122
123 /*!
124   Sets the pixmap that will be used as the splash screen's image to
125   \a pixmap.
126 */
127 void QtxSplash::setPixmap( const QPixmap& pixmap )
128 {
129   myPixmap = pixmap;
130   QRect r( 0, 0, myPixmap.size().width(), myPixmap.size().height() );
131   resize( myPixmap.size() );
132   move( QApplication::desktop()->screenGeometry().center() - r.center() );
133   repaint();
134 }
135
136 /*!
137   Returns the pixmap that is used in the splash screen.
138 */
139 QPixmap QtxSplash::pixmap() const
140 {
141   return myPixmap;
142 }
143
144 /*!
145   Sets/clear the 'hide on mouse click' flag.
146   Default is FALSE.
147   When this flag is set, user can hide the splash screen window
148   by clicking on it with mouse.
149   But for this to work it is necessary to call periodically
150   QApplication::processEvents() in order to allow event loop to process
151   events because usually main application loop is not yet started
152   at that moment.
153 */
154 void QtxSplash::setHideOnClick( const bool on )
155 {
156   myHideOnClick = on;
157 }
158
159 /*!
160   Returns the 'hide on mouse click' flag.
161 */
162 bool QtxSplash::hideOnClick() const
163 {
164   return myHideOnClick;
165 }
166
167 /*!
168   Sets total progress steps to \a total.
169 */
170 void QtxSplash::setTotalSteps( const int total )
171 {
172   myTotal = total;
173   repaint();
174 }
175
176 /*!
177   Return total progress steps number.
178   \sa setTotalSteps(), setProgress()
179 */
180 int QtxSplash::totalSteps() const
181 {
182   return myTotal;
183 }
184     
185 /*!
186   Sets progress to \a progress.
187 */
188 void QtxSplash::setProgress( const int progress )
189 {
190   myProgress = progress;
191   repaint();
192 }
193
194 /*!
195   Return current progress.
196   \sa setProgress(), setTotalSteps()
197 */
198 int QtxSplash::progress() const
199 {
200   return myProgress;
201 }
202
203 /*!
204   Sets progress to \a progress and total progress steps to \a total.
205 */
206 void QtxSplash::setProgress( const int progress, const int total )
207 {
208   myTotal    = total;
209   myProgress = progress;
210   repaint();
211 }
212
213 /*!
214   Sets progress bar colors to \a startColor and \a endColor.
215   If the colors differ the gradient color bar is drawed.
216   If the \a endColor is not valid, \a startColor is used instead.
217   \a gradientType sets the type of gradient to be used for progress
218   bar - horizontal or vertical. Default is vertical.
219 */
220 void QtxSplash::setProgressColors( const QColor& startColor, 
221                                    const QColor& endColor,
222                                    const int     gradientType )
223 {
224   myStartColor   = startColor;
225   myEndColor     = endColor;
226   myGradientType = gradientType;
227   repaint();
228 }
229
230 /*!
231   Return progress colors and gradient type (horizontal or vertical).
232   \sa setProgressColors()
233 */
234 int QtxSplash::progressColors( QColor& startColor, QColor& endColor )
235 {
236   startColor = myStartColor;
237   endColor   = myEndColor;
238   return myGradientType;
239 }
240
241 /*!
242   Sets message text alignment flags to \a alignment.
243   Default is AlignBottom | AlignRight.
244 */
245 void QtxSplash::setTextAlignment( const int alignment )
246 {
247   myAlignment = alignment;
248   repaint();
249 }
250
251 /*!
252   Return message text alignment flags.
253   \sa setTextAlignment()
254 */
255 int QtxSplash::textAlignment() const
256 {
257   return myAlignment;
258 }
259
260 /*!
261   \brief Set margin.
262
263   Margin is used when drawing progress bar and status messages.
264   
265   \param m new margin
266   \sa margin()
267 */
268 void QtxSplash::setMargin( const int m )
269 {
270   myMargin = m;
271   repaint();
272 }
273
274 /*!
275   \brief Get margin.
276   \return current margin.
277   \sa setMargin()
278 */
279 int QtxSplash::margin() const
280 {
281   return myMargin;
282 }
283
284 /*!
285   Sets message text color to \a color.
286   Default is white.
287   \sa setTextColors()
288 */
289 void QtxSplash::setTextColor( const QColor& color )
290 {
291   myColor = color;
292   myShadowColor = QColor();
293   repaint();
294 }
295
296 /*!
297   Return message text color.
298   \sa setTextColor()
299 */
300 QColor QtxSplash::textColor() const
301 {
302   return myColor;
303 }
304
305 /*!
306   Sets message text color to \a color and text shadow color to \a shadow.
307   \sa setTextColor()
308 */
309 void QtxSplash::setTextColors( const QColor& color, const QColor& shadow )
310 {
311   myColor       = color;
312   myShadowColor = shadow;
313   repaint();
314 }
315
316 /*!
317   Return message text color and text shadow color.
318   \sa setTextColors()
319 */
320 void QtxSplash::textColors( QColor& color, QColor& shadow ) const
321 {
322   color  = myColor;
323   shadow = myShadowColor;
324 }
325
326 /*!
327   Returns current status message.
328 */
329 QString QtxSplash::message() const
330 {
331   return myMessage;
332 }
333
334 /*!
335   Return error code. If no errors were occured returns 0.
336   Error code can be set by error( QString&, QString, int ).
337 */
338 int QtxSplash::error() const
339 {
340   return myError;
341 }
342
343 /*!
344     Makes the splash screen wait until the widget \a mainWin is displayed
345     before calling close() on itself.
346 */
347 void QtxSplash::finish( QWidget* mainWin )
348 {
349   if ( mainWin ) {
350 #if defined(Q_WS_X11)
351     extern void qt_wait_for_window_manager( QWidget* w );
352     qt_wait_for_window_manager( mainWin );
353 #endif
354   }
355   close();
356 }
357
358 /*!
359   Repaint the splash screen.
360 */
361 void QtxSplash::repaint()
362 {
363   drawContents();
364   QWidget::repaint();
365   QApplication::flush();
366 }
367
368 /*!
369   Draws the \a message text onto the splash screen with color \a
370   color and aligns the text according to the flags in \a alignment.
371 */
372 void QtxSplash::message( const QString& msg, 
373                          int            alignment,
374                          const QColor&  color )
375 {
376   myMessage   = msg;
377   myAlignment = alignment;
378   myColor     = color;
379   repaint();
380 }
381
382 /*!
383   This is an overloaded member function, provided for convenience. 
384   It behaves essentially like the above function.
385   Draws the \a message text onto the splash screen with default color
386   and aligns the text according to the default alignment flags.
387 */
388 void QtxSplash::message( const QString& msg )
389 {
390   myMessage = msg;
391   repaint();
392 }
393
394 /*!
395   Removes the message being displayed on the splash screen.
396   \sa message()
397 */
398 void QtxSplash::clear()
399 {
400   myMessage = QString::null;
401   repaint();
402 }
403
404 /*!
405   Draw the contents of the splash screen using painter \a painter.
406 */
407 void QtxSplash::drawContents( QPainter* painter )
408 {
409   QRect r = rect();
410   int m = margin();
411   if ( myTotal > 0 ) {
412     // draw progress bar
413     if ( myGradientType == Horizontal ) {
414       int tng = r.width() - r.x() - m*2;
415       int ng = (int) ( 1.0 * tng * ( myProgress > 0 ? myProgress : 0 ) / myTotal ); 
416       int h1, h2, s1, s2, v1, v2;
417       myStartColor.hsv( &h1, &s1, &v1 );
418       myEndColor.isValid() ? myEndColor.hsv( &h2, &s2, &v2 ) :
419                              myStartColor.hsv( &h2, &s2, &v2 );
420       for ( int i = 0; i < ng; i++ ) {
421         painter->setPen( QColor( h1 + ((h2-h1)*i)/(tng-1),
422                                  s1 + ((s2-s1)*i)/(tng-1),
423                                  v1 + ((v2-v1)*i)/(tng-1), 
424                                  QColor::Hsv ) );
425         painter->drawLine( r.x()+m+i,
426                            r.height()-m-_PROGRESS_WIDTH,
427                            r.x()+m+i,
428                            r.height()-m );
429       }
430     }
431     else {
432       int ng = (int) ( 1.0 * (r.width() - r.x() - m*2 - 1) * ( myProgress > 0 ? myProgress : 0 ) / myTotal ); 
433       int h1, h2, s1, s2, v1, v2;
434       myStartColor.hsv( &h1, &s1, &v1 );
435       myEndColor.isValid() ? myEndColor.hsv( &h2, &s2, &v2 ) :
436                              myStartColor.hsv( &h2, &s2, &v2 );
437       for ( int i = 0; i < _PROGRESS_WIDTH; i++ ) {
438         painter->setPen( QColor( h1 + ((h2-h1)*i)/(_PROGRESS_WIDTH-1),
439                                  s1 + ((s2-s1)*i)/(_PROGRESS_WIDTH-1),
440                                  v1 + ((v2-v1)*i)/(_PROGRESS_WIDTH-1), 
441                                  QColor::Hsv ) );
442         painter->drawLine( r.x()+m,
443                            r.height()-m-_PROGRESS_WIDTH+i,
444                            r.x()+m+ng,
445                            r.height()-m-_PROGRESS_WIDTH+i );
446       }
447     }
448     // draw progress bar outline rectangle
449     painter->setPen( palette().active().dark() );
450     painter->drawLine( r.x()+m, 
451                        r.height()-m-_PROGRESS_WIDTH,
452                        r.width()-m,
453                        r.height()-m-_PROGRESS_WIDTH );
454     painter->drawLine( r.x()+m,
455                        r.height()-m-_PROGRESS_WIDTH,
456                        r.x()+m,
457                        r.height()-m );
458     painter->setPen( palette().active().light() );
459     painter->drawLine( r.x()+m,
460                        r.height()-m,
461                        r.width()-m,
462                        r.height()-m );
463     painter->drawLine( r.width()-m,
464                        r.height()-m-_PROGRESS_WIDTH,
465                        r.width()-m,
466                        r.height()-m );
467   }
468   // draw status
469   if ( !myMessage.isEmpty() ) {
470     QFontMetrics f( font() );
471     int spacing = f.lineSpacing();
472     int shift = myTotal > 0 ? _PROGRESS_WIDTH : _PROGRESS_WIDTH; // : 0
473     int i = myMessage.length() - 1;
474     while( i >= 0 && myMessage[ i-- ] == '\n' )
475       shift += spacing;
476     QRect r1( r.x() + m, r.y() + m, r.width() - m*2, r.height() - m*2 - shift );
477     QRect r2 = r1;
478     if ( myAlignment & Qt::AlignLeft   ) r2.setLeft  ( r2.left()   + 1 );
479     if ( myAlignment & Qt::AlignTop    ) r2.setTop   ( r2.top()    + 1 );
480     if ( myAlignment & Qt::AlignRight  ) r2.setRight ( r2.right()  + 1 );
481     if ( myAlignment & Qt::AlignBottom ) r2.setBottom( r2.bottom() + 1 );
482     if ( myShadowColor.isValid() ) {
483       painter->setPen( myShadowColor );
484       painter->drawText( r2, myAlignment, myMessage );
485     }
486     painter->setPen( myColor );
487     painter->drawText( r1, myAlignment, myMessage );
488   }
489 }
490
491 /*!
492   Mouse press event.
493   Hides splash screen if the 'hide on mouse click' flag is set.
494   \sa setHideOnClick()
495 */
496 void QtxSplash::mousePressEvent( QMouseEvent* )
497 {
498   if ( myHideOnClick )
499     hide();
500 }
501
502 /*!
503   Processes custom event sent by setStatus() method.
504   \sa setStatus().
505 */
506 void QtxSplash::customEvent( QCustomEvent* ce )
507 {
508   if ( ce->type() == ProgressEvent::id() ) {
509     ProgressEvent* pe = (ProgressEvent*)ce;
510     pe->message().isEmpty() ? clear() : message( pe->message() );
511     setProgress( pe->progress() );
512     qApp->processEvents();
513   }
514 }
515
516 /*!
517   Draws the splash screen window [ internal ].
518 */
519 void QtxSplash::drawContents()
520 {
521   QPixmap textPix = myPixmap;
522   QPainter painter( &textPix, this );
523   drawContents( &painter );
524   setErasePixmap( textPix );
525 }
526
527 /*!
528   Sets error code [ internal ].
529 */
530 void QtxSplash::setError( const int code )
531 {
532   myError = code;
533 }