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