Salome HOME
884d811551f094be7cd20ec3a3105070dfb9c3be
[modules/gui.git] / src / Qtx / Qtx.cxx
1 // File:      Qtx.cxx
2 // Author:    Sergey TELKOV
3
4 #include "Qtx.h"
5
6 #include <qdir.h>
7 #include <qstring.h>
8 #include <qwidget.h>
9 #include <qlayout.h>
10 #include <qtoolbar.h>
11 #include <qgroupbox.h>
12 #include <qfileinfo.h>
13 #include <qpopupmenu.h>
14 #include <qobjectlist.h>
15 #include <qwidgetlist.h>
16 #include <qapplication.h>
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <stdarg.h>
21
22 /*!
23         Name: setTabOrder [static public]
24         Desc: Set tab order for specified list of widgets. Last parameter should be null pointer.
25 */
26
27 void Qtx::setTabOrder( QWidget* first, ... )
28 {
29   va_list wids;
30         va_start( wids, first );
31
32         QWidgetList widList;
33
34         QWidget* cur = first;
35         while ( cur )
36         {
37           widList.append( cur );
38                 cur = va_arg( wids, QWidget* );
39   }
40
41         setTabOrder( widList );
42 }
43
44 /*!
45         Name: setTabOrder [static public]
46         Desc: Set tab order for specified list of widgets.
47 */
48
49 void Qtx::setTabOrder( const QWidgetList& widgets )
50 {
51   if ( widgets.count() < 2 )
52     return;
53     
54   QWidget* prev = 0;
55   for ( QWidgetListIt it( widgets ); it.current(); ++it )
56   {
57     QWidget* next = it.current();
58     if ( prev && next )
59       QWidget::setTabOrder( prev, next );
60     prev = next;
61   }
62 }
63
64 /*!
65         Name: alignWidget [static public]
66         Desc: Align widget 'src' relative to widget 'ref' acording to alignment flags.
67               Alignment flags:
68                           Qtx::AlignLeft      - Align left side of 'src' to left side of 'ref'.
69                           Qtx::AlignRight     - Align right side of 'src' to right side of 'ref'.
70                           Qtx::AlignTop       - Align top side of 'src' to top side of 'ref'.
71                           Qtx::AlignBottom    - Align bottom side of 'src' to bottom side of 'ref'.
72                           Qtx::AlignHCenter   - Align 'src' to center of 'ref' in horizontal dimension.
73                           Qtx::AlignVCenter   - Align 'src' to center of 'ref' in vertical dimension.
74                           Qtx::AlignCenter    - Align 'src' to center of 'ref' in both dimensions.
75                           Qtx::AlignOutLeft   - Align right side of 'src' to left side of 'ref'.
76                           Qtx::AlignOutRight  - Align left side of 'src' to right side of 'ref'.
77                           Qtx::AlignOutTop    - Align bottom side of 'src' to top side of 'ref'.
78                           Qtx::AlignOutBottom - Align top side of 'src' to bottom side of 'ref'.
79 */
80
81 void Qtx::alignWidget( QWidget* src, const QWidget* ref, const int alignFlags )
82 {
83         if ( !src || !ref || !alignFlags )
84                 return;
85
86         QPoint srcOri = src->pos();
87         QPoint refOri = ref->pos();
88         if ( src->parentWidget() && !src->isTopLevel() )
89                 srcOri = src->parentWidget()->mapToGlobal( srcOri );
90         if ( ref->parentWidget() && !ref->isTopLevel() )
91                 refOri = ref->parentWidget()->mapToGlobal( refOri );
92
93         int x = srcOri.x(), y = srcOri.y();
94         int refWidth = ref->frameGeometry().width(), refHei = ref->frameGeometry().height();
95         int srcWidth = src->frameGeometry().width(), srcHei = src->frameGeometry().height();
96
97         if ( srcWidth <= 0 )
98                 srcWidth = src->sizeHint().width();
99   if ( srcHei <= 0 )
100     srcHei = src->sizeHint().height();
101
102         int border = 0;
103   if ( ref->isTopLevel() && ref->isMaximized() &&
104        src->isTopLevel() && !src->isMaximized() )
105     border = ( src->frameGeometry().width() - src->width() ) / 2;
106
107         if ( alignFlags & Qtx::AlignLeft )
108                 x = refOri.x() + border;
109         if ( alignFlags & Qtx::AlignOutLeft )
110                 x = refOri.x() - srcWidth - border;
111         if ( alignFlags & Qtx::AlignRight )
112                 x = refOri.x() + refWidth - srcWidth - border;
113         if ( alignFlags & Qtx::AlignOutRight )
114                 x = refOri.x() + refWidth + border;
115         if ( alignFlags & Qtx::AlignTop )
116                 y = refOri.y() + border;
117         if ( alignFlags & Qtx::AlignOutTop )
118                 y = refOri.y() - srcHei - border;
119         if ( alignFlags & Qtx::AlignBottom )
120                 y = refOri.y() + refHei - srcHei - border;
121         if ( alignFlags & Qtx::AlignOutBottom )
122                 y = refOri.y() + refHei + border;
123         if ( alignFlags & Qtx::AlignHCenter )
124                 x = refOri.x() + ( refWidth - srcWidth ) / 2;
125         if ( alignFlags & Qtx::AlignVCenter )
126                 y = refOri.y() + ( refHei - srcHei ) / 2;
127
128         if ( src->parentWidget() && !src->isTopLevel() )
129         {
130                 QPoint pos = src->parentWidget()->mapFromGlobal( QPoint( x, y ) );
131                 x = pos.x();
132                 y = pos.y();
133         }
134
135         QWidget* desk = QApplication::desktop();
136         if ( desk && x + srcWidth + border > desk->width() )
137                 x = desk->width() - srcWidth - border;
138         if ( desk && y + srcHei + border > desk->height() )
139                 y = desk->height() - srcHei - border;
140
141         x = QMAX( x, 0 );
142         y = QMAX( y, 0 );
143
144         src->move( x, y );
145 }
146
147 /*!
148         Name: simplifySeparators [static public]
149         Desc: Checks toolbar for unnecessary separators and removes them
150 */
151 void Qtx::simplifySeparators( QToolBar* toolbar )
152 {
153   if ( !toolbar )
154     return;
155
156   const QObjectList* objList = toolbar->children();
157   if ( !objList )
158     return;
159
160   QObjectList delList;
161
162   bool isPrevSep = true;
163   for ( QObjectListIt it( *objList ); it.current(); ++it )
164   {
165     bool isSep = it.current()->isA( "QToolBarSeparator" );
166     if ( isPrevSep && isSep )
167       delList.append( it.current() );
168     isPrevSep = isSep;
169   }
170
171   for ( QObjectListIt itr( delList ); itr.current(); ++itr )
172     delete itr.current();
173
174   if ( toolbar->children() && !toolbar->children()->isEmpty() &&
175        toolbar->children()->getFirst()->isA( "QToolBarSeparator" ) )
176     delete toolbar->children()->getFirst();
177
178   if ( toolbar->children() && !toolbar->children()->isEmpty() &&
179        toolbar->children()->getLast()->isA( "QToolBarSeparator" ) )
180     delete toolbar->children()->getLast();
181 }
182
183 /*!
184         Name: simplifySeparators [static public]
185         Desc: Checks popup menu recursively for unnecessary separators and removes them
186 */
187 void Qtx::simplifySeparators( QPopupMenu* popup, const bool recursive )
188 {
189   if ( !popup || !popup->count() )
190     return;
191
192   QIntList idRemove;
193   for ( uint i = 1; i < popup->count(); i++ )
194   {
195     if ( popup->findItem( popup->idAt( i ) )->isSeparator() &&
196          popup->findItem( popup->idAt( i - 1 ) )->isSeparator() )
197       idRemove.append( popup->idAt( i ) );
198
199     if ( recursive )
200       simplifySeparators( popup->findItem( popup->idAt( i ) )->popup() );
201   }
202
203   for ( QIntList::const_iterator it = idRemove.begin(); it != idRemove.end(); ++it )
204     popup->removeItem( *it );
205
206   if ( popup->count() > 0 && popup->findItem( popup->idAt( 0 ) )->isSeparator() )
207     popup->removeItem( popup->idAt( 0 ) );
208
209   if ( popup->count() > 0 && popup->findItem( popup->idAt( popup->count() - 1 ) )->isSeparator() )
210     popup->removeItem( popup->idAt( popup->count() - 1 ) );
211 }
212
213 /*!
214         Name: isParent [static public]
215         Desc: Returns 'true' if specified 'parent' is parent object of given 'child'.
216 */
217 bool Qtx::isParent( QObject* child, QObject* parent )
218 {
219   if ( !child || !parent )
220     return false;
221
222   bool res = false;
223   QObject* obj = child;
224   while ( !res && obj )
225   {
226     res = obj == parent;
227     obj = obj->parent();
228   }
229   return res;
230 }
231
232 /*!
233         Name: dir [static public]
234         Desc: Returns dir name or null string.
235 */
236 QString Qtx::dir( const QString& path, const bool abs )
237 {
238   QString dirPath = QFileInfo( path ).dirPath( abs );
239   if ( dirPath == QString( "." ) )
240     dirPath = QString::null;
241   return dirPath;
242 }
243
244 /*!    
245         Name: file [static public]
246         Desc: Returns file with or without extension.
247 */
248 QString Qtx::file( const QString& path, bool withExt )
249 {
250   if ( withExt )
251     return QFileInfo( path ).fileName();    
252   else 
253     return QFileInfo( path ).baseName();
254 }
255
256 /*!
257         Name: extension [static public]
258         Desc: Returns the file extension only or null string.
259 */
260 QString Qtx::extension( const QString& path )
261 {  
262   return QFileInfo( path ).extension();
263 }
264
265 /*!
266         Name: library [static public]
267         Desc: Generate library file name.
268         Append required prefix (lib) and suffix (.dll/.so) to the library file name.
269 */
270 QString Qtx::library( const QString& str )
271 {
272   QString path = dir( str, false );
273   QString name = file( str, false );
274   QString ext  = extension( str );
275
276 #ifndef WIN32
277   if ( !name.startsWith( "lib" ) )
278     name = QString( "lib" ) + name;
279 #endif
280
281 #ifdef WIN32
282   QString libExt( "dll" );
283 #else
284   QString libExt( "so" );
285 #endif
286
287   if ( ext.lower() != QString( "so" ) && ext.lower() != QString( "dll" ) )
288   {
289     if ( !name.isEmpty() && !ext.isEmpty() )
290       name += QString( "." );
291     name += ext;
292   }
293
294   ext = libExt;
295
296   QString fileName = addSlash( path ) + name + QString( "." ) + ext;
297
298   return fileName;
299 }
300
301 /*!
302         Name: tmpDir [static public]
303         Desc: Returns path to temporary directory.
304 */
305 QString Qtx::tmpDir()
306 {
307         char* tmpdir = ::getenv( "TEMP" );
308         if ( !tmpdir )
309                 tmpdir = ::getenv ( "TMP" );
310         if ( !tmpdir )
311         {
312 #ifdef WIN32
313                 tmpdir = "C:\\";
314 #else
315                 tmpdir = "/tmp";
316 #endif
317         }
318         return QString( tmpdir );
319 }
320
321 /*!
322         Name: mkDir [static public]
323         Desc: Creates directory with intermediate perent directories.
324                     Returns true in successfull case.
325 */
326 bool Qtx::mkDir( const QString& dirPath )
327 {
328         QString path = QDir::convertSeparators( dirPath );
329
330 #ifdef WIN32
331         while ( !path.isEmpty() && path.at( path.length() - 1 ) == QDir::separator() )
332                 path.remove( path.length() - 1, 1 );
333
334         if ( path.at( path.length() - 1 ) == ':' )
335                 return QFileInfo( path ).exists();
336 #endif
337
338         QFileInfo fInfo( path );
339         if ( fInfo.exists() )
340                 return fInfo.isDir();
341
342         if ( !mkDir( fInfo.dirPath() ) )
343                 return false;
344
345         return QDir( fInfo.dirPath() ).mkdir( fInfo.fileName() );
346 }
347
348 /*!
349         Name: rmDir [static public]
350         Desc: Removes directory with its subdirectories and files.
351                     Returns true in successfull case.
352 */
353 bool Qtx::rmDir( const QString& thePath )
354 {
355         QFileInfo fi( thePath );
356         if ( !fi.exists() )
357                 return true;
358
359         bool stat = true;
360         if ( fi.isFile() )
361                 stat = QFile::remove( thePath );
362         else if ( fi.isDir() )
363         {
364                 QDir aDir( thePath );
365                 const QFileInfoList* anEntries = aDir.entryInfoList();
366                 if ( anEntries )
367                 {
368                         for ( QPtrListIterator<QFileInfo> it( *anEntries ); it.current(); ++it )
369                         {
370                                 if ( it.current()->fileName() == "." || it.current()->fileName() == ".." )
371                                         continue;
372                                 stat = stat && rmDir( it.current()->absFilePath() );
373                         }
374                 }
375                 stat = stat && aDir.rmdir( thePath );
376         }
377         return stat;
378 }
379
380 /*!
381         Name: addSlash [static public]
382         Desc: Adds a slash to the end of 'path' if it is not already there.
383 */
384 QString Qtx::addSlash( const QString& path )
385 {
386         QString res = path;
387   if ( !res.isEmpty() && res.at( res.length() - 1 ) != QChar( '/' ) &&
388           res.at( res.length() - 1 ) != QChar( '\\' ) )
389   res += QDir::separator();
390   return res;
391 }
392
393 /*!
394         Name: dos2unix [static public]
395         Desc: Convert text file. Replace symbols "LF/CR" by symbol "LF".
396 */
397 bool Qtx::dos2unix( const QString& absName )   
398 {    
399   FILE* src = ::fopen( absName, "rb" );
400   if ( !src )
401                 return false;
402
403   /* we'll use temporary file */
404   char temp[512] = { '\0' };        
405   QString dir = Qtx::dir( absName );
406   FILE* tgt = ::fopen( strcpy( temp, ::tempnam( dir, "__x" ) ), "wb" );
407   if ( !tgt )
408                 return false;
409
410   /* temp -> result of conversion */
411   const char CR = 0x0d;
412   const char LF = 0x0a;    
413   bool waitingLF = false;            
414
415   while( true )
416   {                
417     int  outcnt = 0;
418     char inbuf[512], outbuf[512];
419                 
420     /* convert buffer */
421     int nbread = ::fread( inbuf, 1, sizeof( inbuf ), src );
422     for ( int incnt = 0; incnt < nbread; incnt++  )
423     {   
424       if ( waitingLF )
425       {
426         waitingLF = false;
427         if ( inbuf[incnt] == LF )
428           outbuf[outcnt++] = LF;
429         else 
430           outbuf[outcnt++] = CR;
431       }
432       else if ( inbuf[incnt] == CR )
433         waitingLF = true;
434       else
435         outbuf[outcnt++] = inbuf[incnt];
436     }
437
438     /* check last sym in buffer */
439     waitingLF = ( inbuf[nbread - 1] == CR );
440
441     /* write converted buffer to temp file */
442     int nbwri = ::fwrite( outbuf, 1, outcnt, tgt );
443     if ( nbwri != outcnt )
444     {
445       ::fclose( src );
446                         ::fclose( tgt );
447       QFile::remove( QString( temp ) );
448       return false;
449     }
450     if ( nbread != sizeof( inbuf ) )
451       break;              /* converted ok */
452   }
453   ::fclose( src );
454         ::fclose( tgt );
455
456   /* rename temp -> src */
457   if ( !QFile::remove( absName ) )
458     return false;
459
460   return QDir().rename( QString( temp ), absName );
461 }
462
463 /*!
464         Name: rgbSet [static public]
465         Desc: Pack the specified color into one integer RGB set.
466 */
467 int Qtx::rgbSet( const QColor& c )
468 {
469   return rgbSet( c.red(), c.green(), c.blue() );
470 }
471
472 /*!
473         Name: rgbSet [static public]
474         Desc: Pack the specified color components into one integer RGB set.
475 */
476 int Qtx::rgbSet( const int r, const int g, const int b )
477 {
478   return ( ( ( 0xff & r ) << 16 ) + ( ( 0xff & g ) << 8 ) + ( 0xff & b ) );
479 }
480
481 /*!
482         Name: rgbSet [static public]
483         Desc: Unpack the specified integer RGB set into the color.
484 */
485 void Qtx::rgbSet( const int rgb, QColor& c )
486 {
487   int r, g, b;
488   rgbSet( rgb, r, g, b );
489   c = QColor( r, g, b );
490 }
491
492 /*!
493         Name: rgbSet [static public]
494         Desc: Unpack the specified integer RGB set into the color components.
495 */
496 void Qtx::rgbSet( const int rgb, int& r, int& g, int& b )
497 {
498   r = ( rgb >> 16 ) & 0xff;
499   g = ( rgb >> 8 ) & 0xff;
500   b = rgb & 0xff;
501 }
502
503 /*!
504         Name: scaleColor [static public]
505         Desc: Returns the color specified by the index between min (blue) and max (red).
506 */
507 QColor Qtx::scaleColor( const int index, const int min, const int max )
508 {
509   static const int HUE[10] = {230, 210, 195, 180, 160, 80, 60, 50, 30, 0};
510
511   int hue = HUE[0];
512
513         if ( min != max )
514   {
515     double aPosition = 9.0 * ( index - min ) / ( max - min );
516     if ( aPosition > 0.0 )
517     {
518       if ( aPosition >= 9.0 )
519         hue = HUE[9];
520       else
521       {
522         int idx = (int)aPosition;
523         hue = HUE[idx] + int( ( aPosition - idx ) * ( HUE[idx + 1] - HUE[idx] ) );
524       }
525     }
526   }
527
528   return QColor( hue, 255, 255, QColor::Hsv );
529 }
530
531 /*!
532         Name: scaleColors [static public]
533         Desc: Returns the 'num' number of colors from blue to red.
534 */
535 void Qtx::scaleColors( const int num, QValueList<QColor>& lst )
536 {
537   lst.clear();
538   for ( int i = 0; i < num; i++ )
539     lst.append( scaleColor( i, 0, num - 1 ) );
540 }