1 // Copyright (C) 2007-2022 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
24 // Author: Sergey TELKOV
38 #include <QApplication>
39 #include <QDesktopWidget>
41 #include <QSurfaceFormat>
50 #define MAX_VALUE_SIZE 32767 // Limit according to http://msdn.microsoft.com/en-us/library/ms683188.aspx
55 #define BICOLOR_CHANGE_HUE
58 \brief Auxiliary function converting string \a str to the integer value.
59 Parameter \a defVal specifies default value that is returned if conversion can't be done.
60 Parameters \a minVal and \a maxVal limit the resulting value.
61 \param str string being converted
62 \param defVal default value
63 \param minVal minimum allowed value
64 \param maxVal maximum allowed value
65 \return integer value obtained from the string
68 static int stringToInt( const QString& str, int defVal, int minVal, int maxVal )
71 int v = str.toInt( &ok );
72 if ( !ok ) v = defVal;
73 return qMin( qMax( v, minVal ), maxVal );
78 \brief A set of helpful utility functions.
80 The class implements a set of the static functions which can be used
81 for the different purposes:
82 - specify tab order for the set of widgets: setTabOrder()
83 - align one widget to the coordinates of the another one: alignWidget()
84 - remove extra separators from the menu or toolbar: simplifySeparators()
85 - retrieve directory, file name and extension parts of the path:
86 dir(), file(), extension()
87 - get the path to the temporary directory: tmpDir()
88 - create or remove a directory (recursively): mkDir(), rmDir()
89 - convert text file from DOS to UNIX native format: dos2unix()
90 - convert a picture to the gray scale: grayscale()
95 \brief Convert character array (ASCII string) to the QString.
96 \param str character array
97 \param len array length, if < 0, the array should be zero-terminated
98 \return QString object
100 QString Qtx::toQString( const char* str, const int len )
102 return toQString( (unsigned char*)str, len );
106 \brief Convert integer array (UNICODE string) to the QString.
107 \param str integer array
108 \param len array length, if < 0, the array should be zero-terminated
109 \return QString object
111 QString Qtx::toQString( const short* str, const int len )
113 return toQString( (unsigned short*)str, len );
117 \brief Convert character array (ASCII string) to the QString.
118 \param str character array
119 \param len array length, if < 0, the array should be zero-terminated
120 \return QString object
122 QString Qtx::toQString( const unsigned char* str, const int len )
125 const unsigned char* s = str;
126 while ( len < 0 || res.length() < len )
131 res.append( QChar( *s ) );
138 \brief Convert integer array (UNICODE string) to the QString.
139 \param str integer array
140 \param len array length, if < 0, the array should be zero-terminated
141 \return QString object
143 QString Qtx::toQString( const unsigned short* str, const int len )
146 const unsigned short* s = str;
147 while ( len < 0 || res.length() < len )
152 res.append( QChar( *s ) );
159 \brief Set tab order for specified list of widgets.
161 The function has arbitrary number of parameters, each should be
162 hovewer of QWidget* type. Last parameter should be null pointer.
164 \param first first widget in the sequence
166 void Qtx::setTabOrder( QWidget* first, ... )
169 va_start( wids, first );
173 QWidget* cur = first;
176 widList.append( cur );
177 cur = va_arg( wids, QWidget* );
180 setTabOrder( widList );
184 \brief Set tab order for specified list of widgets.
185 \param widgets list of widgets
187 void Qtx::setTabOrder( const QWidgetList& widgets )
189 if ( widgets.count() < 2 )
193 for ( QWidgetList::const_iterator it = widgets.begin(); it!= widgets.end(); ++it )
197 QWidget::setTabOrder( prev, next );
203 \brief Align widget \a src relative to widget \a ref acording to the
204 alignment flags \a alignFlags.
205 \param src source widget (being aligned)
206 \param ref reference widget (source widget being aligned to)
207 \param alignFlags alignment flags (Qtx::AlignmentFlags)
209 void Qtx::alignWidget( QWidget* src, const QWidget* ref, const int alignFlags )
211 if ( !src || !ref || !alignFlags )
214 QPoint srcOri = src->pos();
215 QPoint refOri = ref->pos();
216 if ( src->parentWidget() && !src->isTopLevel() )
217 srcOri = src->parentWidget()->mapToGlobal( srcOri );
218 if ( ref->parentWidget() && !ref->isTopLevel() )
219 refOri = ref->parentWidget()->mapToGlobal( refOri );
221 int x = srcOri.x(), y = srcOri.y();
222 int refWidth = ref->frameGeometry().width(), refHei = ref->frameGeometry().height();
223 int srcWidth = src->frameGeometry().width(), srcHei = src->frameGeometry().height();
226 srcWidth = src->sizeHint().width();
228 srcHei = src->sizeHint().height();
231 if ( ref->isTopLevel() && ref->isMaximized() &&
232 src->isTopLevel() && !src->isMaximized() )
233 border = ( src->frameGeometry().width() - src->width() ) / 2;
235 if ( alignFlags & Qtx::AlignLeft )
236 x = refOri.x() + border;
237 if ( alignFlags & Qtx::AlignOutLeft )
238 x = refOri.x() - srcWidth - border;
239 if ( alignFlags & Qtx::AlignRight )
240 x = refOri.x() + refWidth - srcWidth - border;
241 if ( alignFlags & Qtx::AlignOutRight )
242 x = refOri.x() + refWidth + border;
243 if ( alignFlags & Qtx::AlignTop )
244 y = refOri.y() + border;
245 if ( alignFlags & Qtx::AlignOutTop )
246 y = refOri.y() - srcHei - border;
247 if ( alignFlags & Qtx::AlignBottom )
248 y = refOri.y() + refHei - srcHei - border;
249 if ( alignFlags & Qtx::AlignOutBottom )
250 y = refOri.y() + refHei + border;
251 if ( alignFlags & Qtx::AlignHCenter )
252 x = refOri.x() + ( refWidth - srcWidth ) / 2;
253 if ( alignFlags & Qtx::AlignVCenter )
254 y = refOri.y() + ( refHei - srcHei ) / 2;
256 if ( src->parentWidget() && !src->isTopLevel() )
258 QPoint pos = src->parentWidget()->mapFromGlobal( QPoint( x, y ) );
263 QWidget* desk = QApplication::desktop();
264 if ( desk && x + srcWidth + border > desk->width() )
265 x = desk->width() - srcWidth - border;
266 if ( desk && y + srcHei + border > desk->height() )
267 y = desk->height() - srcHei - border;
276 \brief Remove (recursively) unnecessary separators from the menu or toolbar.
277 \param wid widget, should be of QMenu* or QToolBar* class
279 void Qtx::simplifySeparators( QWidget* wid, const bool recursive )
284 if ( wid->inherits( "QMenu") || wid->inherits( "QMenuBar") )
286 if ( qobject_cast<QMenu*>( wid ) )
287 qobject_cast<QMenu*>( wid )->setSeparatorsCollapsible( true );
290 foreach ( QAction* action, wid->actions() )
292 if ( action->menu() )
293 simplifySeparators( action->menu(), recursive );
299 QList<QAction*> actions = wid->actions();
300 if ( actions.isEmpty() )
303 bool is_action = false;
304 for ( int i = 0; i < actions.count(); i++ )
306 QAction* action = actions[i];
307 if ( action->isSeparator() )
309 action->setVisible( is_action );
312 else if ( action->isVisible() )
318 for ( int i = actions.count() - 1; i > 0; i-- )
320 QAction* action = actions[i];
321 if ( action->isSeparator() )
323 action->setVisible( is_action );
326 else if ( action->isVisible() )
335 \brief Return \c true if specified \a parent is a parent object
336 of given \a child (in terms of QObject).
338 This function works recursively. It means that \a true is also
339 returned if \a parent is a grand-father, grand-grand-father, etc
340 of \a child. If the same object is given as both \a parent and
341 \a child, \c true is also returned.
343 \param child child object
344 \param parent parent object
345 \return \c true if the \a parent is a parent of \a child
347 bool Qtx::isParent( QObject* child, QObject* parent )
349 if ( !child || !parent )
353 QObject* obj = child;
354 while ( !res && obj )
363 \brief Find the parent object of class specified by \a className (in terms of QObject).
365 \param obj current object
366 \param className class name of the parent
367 \return parent object or null pointer if the parent not found
369 QObject* Qtx::findParent( QObject* obj, const char* className )
374 if ( !className || !strlen( className ) )
375 return obj->parent();
378 QObject* p = obj->parent();
381 if ( p->inherits( className ) )
390 \brief Return directory part of the file path.
392 If the file path does not include directory part (the file is in the
393 current directory), null string is returned.
395 \param path file path
396 \param abs if true (default) \a path parameter is treated as absolute file path
397 \return directory part of the file path
399 QString Qtx::dir( const QString& path, const bool abs )
401 QDir aDir = QFileInfo( path ).dir();
402 QString dirPath = abs ? aDir.absolutePath() : aDir.path();
403 if ( dirPath == QString( "." ) )
409 \brief Return file name part of the file path.
411 \param path file path
412 \param withExt if true (default) complete file name (with all
413 extension except the last) is returned, otherwise only base name
415 \return file name part of the file path
417 QString Qtx::file( const QString& path, bool withExt )
419 QString fPath = path;
420 while ( !fPath.isEmpty() && ( fPath[fPath.length() - 1] == '\\' || fPath[fPath.length() - 1] == '/' ) )
421 fPath.remove( fPath.length() - 1, 1 );
424 return QFileInfo( fPath ).fileName();
426 return QFileInfo( fPath ).completeBaseName();
430 \brief Return extension part of the file path.
432 \param path file path
433 \param full if true complete extension (all extensions, dot separated)
434 is returned, otherwise (default) only last extension is returned
435 \return extension part of the file path
437 QString Qtx::extension( const QString& path, const bool full )
439 return full ? QFileInfo( path ).completeSuffix() : QFileInfo( path ).suffix();
443 \brief EXtract base library name.
445 The function removes platform-specific prefix (lib) and suffix (.dll/.so)
446 from the library file name.
447 For example, if \a str = "libmylib.so", "mylib" is returned..
449 \param libName library name
450 \return base library name
452 QString Qtx::libraryName( const QString& libName )
454 QString fullName = file( libName );
456 QString libExt = QString( "dll" );
457 #elif defined(__APPLE__)
458 QString libExt = QString( "dylib" );
460 QString libExt = QString( "so" );
462 if ( extension( fullName ).toLower() == libExt )
463 fullName.truncate( fullName.length() - libExt.length() - 1 );
465 QString prefix = QString( "lib" );
466 if ( fullName.startsWith( prefix ) )
467 fullName.remove( 0, prefix.length() );
473 \brief Convert the given parameter to the platform-specific library name.
475 The function appends platform-specific prefix (lib) and suffix (.dll/.so)
476 to the library file name.
477 For example, if \a libName = "mylib", "libmylib.so" is returned for Linux and
478 mylib.dll for Windows.
480 \param libName short library name
481 \return full library name
483 QString Qtx::library( const QString& libName )
485 QString path = dir( libName, false );
486 QString name = file( libName, false );
487 QString ext = extension( libName );
490 if ( !name.startsWith( "lib" ) )
491 name = QString( "lib" ) + name;
495 QString libExt( "dll" );
496 #elif defined(__APPLE__)
497 QString libExt( "dylib" );
499 QString libExt( "so" );
502 if ( ext.toLower() != QString( "so" ) && ext.toLower() != QString( "dll" ) && ext.toLower() != QString( "dylib" ) )
504 if ( !name.isEmpty() && !ext.isEmpty() )
505 name += QString( "." );
511 QString fileName = addSlash( path ) + name + QString( "." ) + ext;
517 \brief Get the temporary directory name.
518 \return temporary directory (platform specific)
520 QString Qtx::tmpDir()
522 QString tmpdir = getenv( "TEMP" );
523 if ( tmpdir.isEmpty() )
524 tmpdir = getenv ( "TMP" );
525 if ( tmpdir.isEmpty() )
528 tmpdir = QString("C:\\");
530 tmpdir = QString("/tmp");
537 \brief Create directory recursively including all intermediate sub directories.
538 \return \c true if the directory is successfully created and \c false otherwise
540 bool Qtx::mkDir( const QString& dirPath )
542 return QDir().mkpath( dirPath );
546 \brief Remove directory recursively including all subdirectories and files.
547 \return \c true if the directory is successfully removed and \c false otherwise
549 bool Qtx::rmDir( const QString& thePath )
551 QFileInfo fi( thePath );
557 stat = QFile::remove( thePath );
558 else if ( fi.isDir() )
560 QDir aDir( thePath );
561 QFileInfoList anEntries = aDir.entryInfoList();
562 for ( QFileInfoList::iterator it = anEntries.begin(); it != anEntries.end(); ++it )
565 if ( inf.fileName() == "." || inf.fileName() == ".." )
567 stat = stat && rmDir( inf.absoluteFilePath() );
569 stat = stat && aDir.rmdir( thePath );
575 \brief Add a slash (platform-specific) to the end of \a path
576 if it is not already there.
577 \param path directory path
578 \return modified path (with slash added to the end)
580 QString Qtx::addSlash( const QString& path )
583 if ( !res.isEmpty() && res.at( res.length() - 1 ) != QChar( '/' ) &&
584 res.at( res.length() - 1 ) != QChar( '\\' ) )
585 res += QDir::separator();
590 \brief Return full path obtained by joining given components with
591 the native directory separator.
592 \param path Separate path components
593 \return complete path
595 QString Qtx::joinPath( const QStringList& path )
597 return path.join( QDir::separator() );
601 \brief Convert text file from DOS format to UNIX.
603 The function replaces "LF/CR" symbols sequence by "LF" symbol.
605 \param absName file name
606 \return \c true if the file is converted successfully and \c false in
609 bool Qtx::dos2unix( const QString& absName )
611 FILE* src = ::fopen( absName.toUtf8(), "rb" );
615 /* we'll use temporary file */
616 char temp[512] = { '\0' };
617 QString dir = Qtx::dir( absName );
618 FILE* tgt = ::fopen( strcpy( temp, ::tempnam( dir.toUtf8(), "__x" ) ), "wb" );
622 /* temp -> result of conversion */
623 const char CR = 0x0d;
624 const char LF = 0x0a;
625 bool waitingLF = false;
630 char inbuf[512], outbuf[512];
633 int nbread = (int)::fread( inbuf, 1, sizeof( inbuf ), src ); //!< TODO: conversion from 'size_t' to 'int'
634 for ( int incnt = 0; incnt < nbread; incnt++ )
639 if ( inbuf[incnt] == LF )
640 outbuf[outcnt++] = LF;
642 outbuf[outcnt++] = CR;
644 else if ( inbuf[incnt] == CR )
647 outbuf[outcnt++] = inbuf[incnt];
650 /* check last sym in buffer */
651 waitingLF = ( inbuf[nbread - 1] == CR );
653 /* write converted buffer to temp file */
654 int nbwri = (int)::fwrite( outbuf, 1, outcnt, tgt ); //!< TODO: conversion from 'size_t' to 'int'
655 if ( nbwri != outcnt )
659 QFile::remove( QString( temp ) );
662 if ( nbread != sizeof( inbuf ) )
663 break; /* converted ok */
668 /* rename temp -> src */
669 if ( !QFile::remove( absName ) )
672 return QDir().rename( QString( temp ), absName );
676 \brief Create path completer which can be used in the widgets
677 to provide auto completions.
679 Create an instance of QCompleter class and returns the pointer on it.
680 The calling function is responsible to the desstroying of the created
683 The QCompleter class provides completions based on a item model and can be
684 used in such as QLineEdit and QComboBox.
685 When the user starts typing a word, QCompleter suggests possible ways of
686 completing the word, based on a word list.
688 \param type path type (Qtx::PathType)
689 \param filter file/directory filters (list of wildcards, separated by ";;")
690 \return a pointer to the created completer
692 QCompleter* Qtx::pathCompleter( const PathType type, const QString& filter )
695 QStringList filterList = filter.split( ";;" );
696 for ( QStringList::const_iterator it = filterList.begin(); it != filterList.end(); ++it )
698 QRegExp rx( "[\\s\\w,;]*\\(?\\*\\.([\\w]+)\\)?[\\d\\s\\w]*" );
700 while ( ( index = rx.indexIn( *it, index ) ) != -1 )
702 extList.append( QString( "*.%1" ).arg( rx.cap( 1 ) ) );
703 index += rx.matchedLength();
707 QDir::Filters filters = 0;
712 filters = QDir::AllEntries | QDir::AllDirs | QDir::NoDotAndDotDot;
715 filters = QDir::Drives | QDir::Dirs | QDir::NoDotAndDotDot;
719 QDirModel* dm = new QDirModel( extList, filters, QDir::Unsorted );
720 QCompleter* cmp = new QCompleter( dm, 0 );
721 dm->setParent( cmp );
727 \brief Parse given string to retrieve environment variable.
729 Looks through the string for the environment variable patterns.
730 If string contains variable satisfying any pattern, the variable name
731 is returned, start index of the variable is returned in the \a start parameter,
732 and length of the variable is returned in the \a len parameter.
734 Supported environment variables definitions:
735 - ${name} or $name : Linux shell variable
736 - $(name) : GNU make substitution
737 - %name% : Windows shell variable
738 - %(name)s : Python substitutions:
740 \param str string being processed
741 \param start if variable is found, this parameter contains its starting
742 position in the \a str
743 \param len if variable is found, this parameter contains its length
744 \return first found variable or null QString if there is no ones
746 QString Qtx::findEnvVar( const QString& str, int& start, int& len )
752 rxList << "\\$\\{([a-zA-Z][a-zA-Z_0-9]*)\\}"; // ${name}
753 rxList << "\\$([a-zA-Z][a-zA-Z_0-9]*)"; // $name
754 rxList << "\\$\\(([a-zA-Z][a-zA-Z_0-9]*)\\)"; // $(name)
755 rxList << "%([a-zA-Z][a-zA-Z0-9_]*)%"; // %name%
756 rxList << "%\\(([a-zA-Z][a-zA-Z_0-9]*)\\)s"; // %(name)s
758 for ( int i = 0; i < rxList.count() && varName.isEmpty(); ++i )
760 QRegExp rx(rxList[i]);
761 int pos = rx.indexIn( str, start );
764 varName = rx.cap( 1 );
766 len = rx.matchedLength();
773 \brief Substitute environment variables by their values.
775 Environment variable is substituted by its value.
777 \param str string to be processed
778 \return processed string (with all substitutions made)
780 QString Qtx::makeEnvVarSubst( const QString& str, const SubstMode mode )
785 QMap<QString, int> ignoreMap;
787 int start( 0 ), len( 0 );
790 QString envName = findEnvVar( res, start, len );
791 if ( envName.isNull() )
795 if ( getenv( envName ).isEmpty() || mode == Always )
796 newStr = QString( getenv( envName ) );
798 if ( newStr.isNull() )
800 if ( ignoreMap.contains( envName ) )
805 ignoreMap.insert( envName, 0 );
807 res.replace( start, len, newStr );
810 res.replace( "$$", "$" );
811 res.replace( "%%", "%" );
818 \brief Pack the specified color into integer RGB set.
819 \param c unpacked color
822 int Qtx::rgbSet( const QColor& c )
824 return rgbSet( c.red(), c.green(), c.blue() );
828 \brief Pack the specified RGB color components into integer RGB set.
829 \param r red component
830 \param g green component
831 \param b blue component
834 int Qtx::rgbSet( const int r, const int g, const int b )
836 return ( ( ( 0xff & r ) << 16 ) + ( ( 0xff & g ) << 8 ) + ( 0xff & b ) );
840 \brief Unpack the specified integer RGB set to the color.
841 \param rgb packed color
842 \return unpacked color (QColor)
844 QColor Qtx::rgbSet( const int rgb )
847 rgbSet( rgb, r, g, b );
848 return QColor( r, g, b );
852 \brief Unpack the specified integer RGB set to the three RGB components.
853 \param rgb packed color
854 \param r returned unpacked red component
855 \param g returned unpacked green component
856 \param b returned unpacked blue component
858 void Qtx::rgbSet( const int rgb, int& r, int& g, int& b )
860 r = ( rgb >> 16 ) & 0xff;
861 g = ( rgb >> 8 ) & 0xff;
866 \brief Return the color specified by the index between min (blue) and max (red).
867 \param index color index
868 \param min required minimum hue value
869 \param max required maximum hue value
870 \return resulting color
872 QColor Qtx::scaleColor( const int index, const int min, const int max )
874 static const int HUE[10] = {230, 210, 195, 180, 160, 80, 60, 50, 30, 0};
880 double aPosition = 9.0 * ( index - min ) / ( max - min );
881 if ( aPosition > 0.0 )
883 if ( aPosition >= 9.0 )
887 int idx = (int)aPosition;
888 hue = HUE[idx] + int( ( aPosition - idx ) * ( HUE[idx + 1] - HUE[idx] ) );
893 return QColor::fromHsv( hue, 255, 255 );
897 \brief Generate required number of colors aligned from blue to red.
898 \param num required number of colors
899 \param lst returned set of colors
901 void Qtx::scaleColors( const int num, QColorList& lst )
904 for ( int i = 0; i < num; i++ )
905 lst.append( scaleColor( i, 0, num - 1 ) );
909 \brief Scale the pixmap to the required size.
911 If \a h is 0 (default) the value of \a w is used instead (to create
914 \param icon pixmap to be resized
915 \param w required pixmap width
916 \param h required pixmap height
917 \return scaled pixmap
919 QPixmap Qtx::scaleIcon( const QPixmap& icon, const unsigned w, const unsigned h )
922 int aw = w, ah = h <= 0 ? w : h;
923 if ( icon.isNull() || aw <= 0 || ah <= 0 || ( aw == icon.width() && ah == icon.height() ) )
926 p = icon.fromImage( icon.toImage().scaled( aw, ah, Qt::KeepAspectRatio, Qt::SmoothTransformation ) );
931 \brief Convert given image to the grayscale format.
932 \param img initial image
933 \return converted to the grayscale image
935 QImage Qtx::grayscale( const QImage& img )
939 int colNum = res.colorCount();
942 for ( int i = 0; i < colNum; i++ )
943 res.setColor( i, qGray( res.color( i ) ) );
947 for ( int y = 0; y < res.height(); y++ )
949 for ( int x = 0; x < res.width(); x++ )
951 QRgb pix = res.pixel( x, y );
952 res.setPixel( x, y, qRgba( qGray( pix ), qGray( pix ), qGray( pix ), qAlpha( pix ) ) );
961 \brief Convert given pixmap to the grayscale format.
962 \param pix initial pixmap
963 \return converted to the grayscale pixmap
965 QPixmap Qtx::grayscale( const QPixmap& pix )
968 res.fromImage( grayscale( pix.toImage() ) );
973 \brief Create transparent image.
974 \param w required image width
975 \param h required image height
976 \param d required image depth
977 \return generated image
979 QImage Qtx::transparentImage( const int w, const int h, const int d )
985 fmt = QImage::Format_Mono;
988 fmt = QImage::Format_Indexed8;
994 fmt = QImage::Format_ARGB32;
998 QImage img( w, h, fmt );
1001 // img.setAlphaBuffer( true );
1002 for ( int i = 0; i < img.height(); i++ )
1003 for ( int j = 0; j < img.width(); j++ )
1004 img.setPixel( j, i, qRgba( 0, 0, 0, 0 ) );
1010 \brief Create transparent pixmap.
1011 \param w required image width
1012 \param h required pixmap height
1013 \param d required pixmap depth
1014 \return generated pixmap
1016 QPixmap Qtx::transparentPixmap( const int w, const int h, const int d )
1019 QImage img = transparentImage( w, h, d );
1020 if ( !img.isNull() )
1021 pix.fromImage( img );
1026 \brief Create composite pixmap.
1028 Pixmap \a pix is drawn over pixmap \a dest with coordinates
1029 specified relatively to the upper left corner of \a dest.
1030 If \a dest is not given, the new empty pixmap with appropriate size created instead.
1032 \param pix source pixmap
1033 \param x horizontal shift
1034 \param y vertical shift
1035 \param dest background pixmap
1036 \return resulting pixmap
1038 QPixmap Qtx::composite( const QPixmap& pix, const int x, const int y, const QPixmap& dest )
1043 int width = qMax( pix.width() + x, dest.width() );
1044 int height = qMax( pix.height() + y, dest.height() );
1046 QPixmap res( width, height );
1047 QImage img = transparentImage( width, height, 32 );
1051 p.fillRect( 0, 0, width, height, QBrush( Qt::white ) );
1053 if ( !dest.isNull() )
1055 p.drawPixmap( 0, 0, dest );
1056 QImage temp = dest.toImage();
1057 for ( int i = 0; i < temp.width() && i < img.width(); i++ )
1059 for ( int j = 0; j < temp.height() && j < img.height(); j++ )
1061 if ( temp.hasAlphaChannel() )
1062 img.setPixel( i, j, temp.pixel( i, j ) );
1065 QRgb p = temp.pixel( i, j );
1066 img.setPixel( i, j, qRgba( qRed( p ), qGreen( p ), qBlue( p ), 255 ) );
1072 p.drawPixmap( x, y, pix );
1073 QImage temp = pix.toImage();
1074 for ( int c = x; c < temp.width() + x && c < img.width(); c++ )
1076 for ( int r = y; r < temp.height() + y && r < img.height(); r++ )
1078 if ( qAlpha( temp.pixel( c - x, r - y ) ) > 0 )
1079 img.setPixel( c, r, temp.pixel( c - x, r - y ) );
1085 for ( int ai = 0; ai < img.width(); ai++ )
1087 for ( int aj = 0; aj < img.height(); aj++ )
1089 if ( qAlpha( img.pixel( ai, aj ) ) < 1 )
1090 img.setPixel( ai, aj, qRgba( 255, 255, 255, 255 ) );
1092 img.setPixel( ai, aj, qRgba( 0, 0, 0, 0 ) );
1096 QBitmap bmp( width, height );
1097 bmp.fromImage( img, Qt::ColorMode_Mask | Qt::ThresholdDither );
1104 \brief Convert color to the string representation.
1106 The resulting string is in the one of two possible formats
1107 (\c RR, \c GG, \c BB and \c AA value represent red, green, blue
1108 and alpha components of the color):
1109 - if color has alpha channel : "#RR,#GG,#BB,#AA"
1110 - if color does not have alpha channel : "#RRGGBB"
1112 If color is invalid, null string is returned.
1114 Backward conversion can be done with stringToColor() method.
1116 \param color color to be converted
1117 \return string representation of the color
1121 QString Qtx::colorToString( const QColor& color )
1124 if ( color.isValid() )
1126 if ( color.alpha() != 255 )
1129 vals << QString( "#%1" ).arg( color.red(), 0, 16 );
1130 vals << QString( "#%1" ).arg( color.green(), 0, 16 );
1131 vals << QString( "#%1" ).arg( color.blue(), 0, 16 );
1132 vals << QString( "#%1" ).arg( color.alpha(), 0, 16 );
1133 str = vals.join( "," );
1144 \brief Create color from the string representation.
1146 The parameter \a str must be in the one of following formats
1147 (\c RR, \c GG, \c BB and \c AA value represent red, green, blue
1148 and alpha components of the color):
1149 - "#RR,#GG,#BB[,#AA]" or "#RR #GG #BB[ #AA]" (\c RR, \c GG, \c BB
1150 and optional \c AA values represent red, green, blue and alpha
1151 components of the color in hexadecimal form)
1152 - "RR,GG,BB[,AA]" or "RR GG BB[ AA]" (\c RR, \c GG, \c BB
1153 and optional \c AA values represent red, green, blue and alpha
1154 components of the color in decimal form)
1155 - "#RRGGBB" - (\c RR, \c GG and \c BB values represent red, green and blue
1156 components of the color in hexadecimal form)
1157 - an integer value representing packed color components (see rgbSet())
1158 - a name from the list of colors defined in the list of SVG color keyword names
1159 provided by the World Wide Web Consortium; for example, "steelblue" or "gainsboro".
1161 Backward conversion can be done with colorToString() method.
1163 \param str string representation of the color
1164 \param color resulting color value
1165 \return \c true if the conversion is successful and \c false otherwise
1167 \sa colorToString(), rgbSet()
1169 bool Qtx::stringToColor( const QString& str, QColor& color )
1172 QStringList vals = str.split( QRegExp( "[\\s|,]" ), QString::SkipEmptyParts );
1175 for ( QStringList::const_iterator it = vals.begin(); it != vals.end() && res; ++it )
1178 if ( (*it).startsWith( "#" ) )
1179 num = (*it).mid( 1 ).toInt( &res, 16 );
1181 num = (*it).toInt( &res, 10 );
1186 res = res && nums.count() >= 3;
1188 color.setRgb( nums[0], nums[1], nums[2] );
1192 int pack = str.toInt( &res );
1194 color = Qtx::rgbSet( pack );
1199 color = QColor( str );
1200 res = color.isValid();
1207 \brief Convert bi-color value to the string representation.
1209 Bi-color value is specified as main color and integer delta
1210 value that is used to calculate secondary color by changing
1211 paremeters of the main color ("saturation" and "value"
1212 components in HSV notation).
1214 The resulting string consists of two sub-strings separated by
1215 '|' symbol. The first part represents main color
1216 (see colorToString() for more details), the second part is a
1219 Backward conversion can be done with stringToBiColor() method.
1221 \param color color to be converted
1222 \param delta delta value
1223 \return string representation of the bi-color value
1225 \sa stringToBiColor(), stringToColor()
1227 QString Qtx::biColorToString( const QColor& color, const int delta )
1229 return QString("%1|%2").arg( Qtx::colorToString( color ) ).arg( delta );
1233 \brief Restore bi-color value from the string representation.
1235 Bi-color value is specified as main color and integer delta
1236 value that is used to calculate secondary color by changing
1237 paremeters of the main color ("saturation" and "value"
1238 components in HSV notation).
1240 The parameter \a str should consist of two sub-strings separated
1241 by '|' symbol. The first part represents main color
1242 (see stringToColor() for more details), the second part is a
1245 Backward conversion can be done with biColorToString() method.
1247 \param str string representation of the bi-color value
1248 \param color resulting color value
1249 \param delta resulting delta value
1250 \return \c true if the conversion is successful and \c false otherwise
1252 \sa biColorToString(), stringToColor(), rgbSet()
1254 bool Qtx::stringToBiColor( const QString& str, QColor& color, int& delta )
1256 QStringList data = str.split( "|", QString::KeepEmptyParts );
1259 bool ok = data.count() > 0 && Qtx::stringToColor( data[0], c );
1261 if ( data.count() > 1 ) d = data[1].toInt( &dok );
1263 color = ok ? c : QColor();
1269 \brief Compute secondary color value from specified main color
1272 Secondary color is calculated by changing paremeters of the main
1273 color ("saturation" and "value" components in HSV notation) using
1276 If main color is invalid, result of the function is also invalid color.
1278 \param color source main color
1279 \param delta delta value
1280 \return resulting secondary color
1282 \sa biColorToString(), stringToBiColor()
1284 QColor Qtx::mainColorToSecondary( const QColor& color, int delta )
1287 if ( cs.isValid() ) {
1288 int val = qMin( 255, qMax( cs.value() + delta, 0 ) );
1289 int sat = qMin( 255, qMax( cs.saturation() + delta-(val-cs.value()), 0 ) );
1290 #ifdef BICOLOR_CHANGE_HUE
1291 const int BICOLOR_HUE_MAXDELTA = 40;
1292 int dh = delta-(val-cs.value())-(sat-cs.saturation());
1293 dh = qMin( BICOLOR_HUE_MAXDELTA, qAbs( dh ) ) * ( dh > 0 ? 1 : -1 );
1294 //int hue = qMin( 359, qMax( cs.hue() + delta-(val-cs.value())-(sat-cs.saturation()), 0 ) );
1295 //int hue = qMin( 359, qMax( cs.hue() + delta-(val-cs.value())-ds, 0 ) );
1296 int hue = cs.hue() + dh;
1297 if ( hue < 0 ) hue = 360 - hue;
1301 cs.setHsv( hue, sat, val );
1307 \brief Dump linear gradient to the string description.
1308 \param gradient linear gradient to be converted
1309 \return string representation of the linear gradient
1310 \sa stringToLinearGradient()
1312 QString Qtx::gradientToString( const QLinearGradient& gradient )
1316 data << QString::number( gradient.start().x() );
1317 data << QString::number( gradient.start().y() );
1318 data << QString::number( gradient.finalStop().x() );
1319 data << QString::number( gradient.finalStop().y() );
1320 switch( gradient.spread() )
1322 case QGradient::PadSpread:
1325 case QGradient::RepeatSpread:
1328 case QGradient::ReflectSpread:
1334 QGradientStops stops = gradient.stops();
1336 foreach ( stop, stops )
1338 data << QString::number( stop.first );
1339 data << colorToString( stop.second );
1341 return data.join( "|" );
1345 \brief Dump radial gradient to the string description.
1346 \param gradient radial gradient to be converted
1347 \return string representation of the radial gradient
1348 \sa stringToRadialGradient()
1350 QString Qtx::gradientToString( const QRadialGradient& gradient )
1354 data << QString::number( gradient.center().x() );
1355 data << QString::number( gradient.center().y() );
1356 data << QString::number( gradient.focalPoint().x() );
1357 data << QString::number( gradient.focalPoint().y() );
1358 data << QString::number( gradient.radius() );
1359 switch( gradient.spread() )
1361 case QGradient::PadSpread:
1364 case QGradient::RepeatSpread:
1367 case QGradient::ReflectSpread:
1373 QGradientStops stops = gradient.stops();
1375 foreach ( stop, stops )
1377 data << QString::number( stop.first );
1378 data << colorToString( stop.second );
1380 return data.join( "|" );
1384 \brief Dump conical gradient to the string description.
1385 \param gradient conical gradient to be converted
1386 \return string representation of the conical gradient
1387 \sa stringToConicalGradient()
1389 QString Qtx::gradientToString( const QConicalGradient& gradient )
1393 data << QString::number( gradient.center().x() );
1394 data << QString::number( gradient.center().y() );
1395 data << QString::number( gradient.angle() );
1396 switch( gradient.spread() )
1398 case QGradient::PadSpread:
1401 case QGradient::RepeatSpread:
1404 case QGradient::ReflectSpread:
1410 QGradientStops stops = gradient.stops();
1412 foreach ( stop, stops )
1414 data << QString::number( stop.first );
1415 data << colorToString( stop.second );
1417 return data.join( "|" );
1421 \brief Create linear gradient from its string representation.
1422 \param str string representation of the linear gradient
1423 \param gradient resulting linear gradient object
1424 \return \c true if the conversion is successful and \c false otherwise
1425 \sa gradientToString()
1427 bool Qtx::stringToLinearGradient( const QString& str, QLinearGradient& gradient )
1429 bool success = false;
1430 QStringList vals = str.split( "|", QString::SkipEmptyParts );
1431 if ( vals.count() > 4 && ( vals[0] == "linear" || vals[0] == "lg" ) )
1433 // start and end points
1434 double x1, y1, x2, y2;
1435 bool bOk1, bOk2, bOk3, bOk4;
1436 x1 = vals[1].toDouble( &bOk1 );
1437 y1 = vals[2].toDouble( &bOk2 );
1438 x2 = vals[3].toDouble( &bOk3 );
1439 y2 = vals[4].toDouble( &bOk4 );
1440 if ( bOk1 && bOk2 && bOk3 && bOk4 )
1442 gradient = QLinearGradient( x1, y1, x2, y2 );
1444 if ( vals.count() > 5 )
1446 QString spread = vals[ 5 ].trimmed().toLower();
1447 if ( spread == "pad" || spread == "0" )
1448 gradient.setSpread( QGradient::PadSpread );
1449 else if ( spread == "repeat" || spread == "2" )
1450 gradient.setSpread( QGradient::RepeatSpread );
1451 else if ( spread == "reflect" || spread == "1" )
1452 gradient.setSpread( QGradient::ReflectSpread );
1455 QGradientStops stops;
1456 for ( int i = 6; i < vals.count(); i+=2 )
1458 bool bOk5, bOk6 = false;
1460 double stop = vals[i].toDouble( &bOk5 );
1461 if ( i+1 < vals.count() )
1462 bOk6 = stringToColor( vals[ i+1 ], c );
1463 if ( bOk5 && stop >= 0.0 && stop <= 1.0 && bOk6 && c.isValid() )
1464 stops.append( QGradientStop( stop, c ) );
1466 gradient.setStops( stops );
1474 \brief Create radial gradient from its string representation.
1475 \param str string representation of the radial gradient
1476 \param gradient resulting radial gradient object
1477 \return \c true if the conversion is successful and \c false otherwise
1478 \sa gradientToString()
1480 bool Qtx::stringToRadialGradient( const QString& str, QRadialGradient& gradient )
1482 bool success = false;
1483 QStringList vals = str.split( "|", QString::SkipEmptyParts );
1484 if ( vals.count() > 5 && ( vals[0] == "radial" || vals[0] == "rg" ) )
1486 // center, radius and focal point
1487 double cx, cy, r, fx, fy;
1488 bool bOk1, bOk2, bOk3, bOk4, bOk5;
1489 cx = vals[1].toDouble( &bOk1 );
1490 cy = vals[2].toDouble( &bOk2 );
1491 fx = vals[3].toDouble( &bOk4 );
1492 fy = vals[4].toDouble( &bOk5 );
1493 r = vals[5].toDouble( &bOk3 );
1494 if ( bOk1 && bOk2 && bOk3 && bOk4 && bOk5 )
1496 gradient = QRadialGradient( cx, cy, r, fx, fy );
1498 if ( vals.count() > 6 )
1500 QString spread = vals[ 6 ].trimmed().toLower();
1501 if ( spread == "pad" || spread == "0" )
1502 gradient.setSpread( QGradient::PadSpread );
1503 else if ( spread == "repeat" || spread == "2" )
1504 gradient.setSpread( QGradient::RepeatSpread );
1505 else if ( spread == "reflect" || spread == "1" )
1506 gradient.setSpread( QGradient::ReflectSpread );
1509 QGradientStops stops;
1510 for ( int i = 7; i < vals.count(); i+=2 )
1512 bool bOk7, bOk8 = false;
1514 double stop = vals[i].toDouble( &bOk7 );
1515 if ( i+1 < vals.count() )
1516 bOk8 = stringToColor( vals[ i+1 ], c );
1517 if ( bOk7 && stop >= 0.0 && stop <= 1.0 && bOk8 && c.isValid() )
1518 stops.append( QGradientStop( stop, c ) );
1520 gradient.setStops( stops );
1528 \brief Create conical gradient from its string representation.
1529 \param str string representation of the conical gradient
1530 \param gradient resulting conical gradient object
1531 \return \c true if the conversion is successful and \c false otherwise
1532 \sa gradientToString()
1534 bool Qtx::stringToConicalGradient( const QString& str, QConicalGradient& gradient )
1536 bool success = false;
1537 QStringList vals = str.split( "|", QString::SkipEmptyParts );
1538 if ( vals.count() > 3 && ( vals[0] == "conical" || vals[0] == "cg" ) )
1542 bool bOk1, bOk2, bOk3;
1543 cx = vals[1].toDouble( &bOk1 );
1544 cy = vals[2].toDouble( &bOk2 );
1545 a = vals[3].toDouble( &bOk3 );
1546 if ( bOk1 && bOk2 && bOk3 )
1548 gradient = QConicalGradient( cx, cy, a );
1550 if ( vals.count() > 4 )
1552 QString spread = vals[ 4 ].trimmed().toLower();
1553 if ( spread == "pad" || spread == "0" )
1554 gradient.setSpread( QGradient::PadSpread );
1555 else if ( spread == "repeat" || spread == "2" )
1556 gradient.setSpread( QGradient::RepeatSpread );
1557 else if ( spread == "reflect" || spread == "1" )
1558 gradient.setSpread( QGradient::ReflectSpread );
1561 QGradientStops stops;
1562 for ( int i = 5; i < vals.count(); i+=2 )
1564 bool bOk4, bOk5 = false;
1566 double stop = vals[i].toDouble( &bOk4 );
1567 if ( i+1 < vals.count() )
1568 bOk5 = stringToColor( vals[ i+1 ], c );
1569 if ( bOk4 && stop >= 0.0 && stop <= 1.0 && bOk5 && c.isValid() )
1570 stops.append( QGradientStop( stop, c ) );
1572 gradient.setStops( stops );
1580 \brief Convert background data to the string representation.
1581 The resulting string consists of several sub-strings separated by ';' symbol.
1582 These sub-strings represent:
1583 1. background type (enumerator, see Qtx::BackgroundMode)
1584 2. texture image file name (string)
1585 3. texture mode (enumerator, see Qtx::TextureMode)
1586 4. "show texture" flag (boolean)
1587 5. first color (for simple gradient data) or solid color (for single-colored mode)
1588 6. second color (for simple gradient data)
1589 7. type of simple gradient (some integer identifier)
1590 8. complex gradient data (for custom gradient mode)
1591 Each sub-string consists of keyword/value couple, in form of "<keyword>=<value>".
1593 Backward conversion can be done with stringToBackground() method.
1595 \param bgData background data
1596 \return string representation of the background data
1598 \sa stringToBackground()
1600 QString Qtx::backgroundToString( const Qtx::BackgroundData& bgData )
1602 const QString dtSep = ";";
1603 const QString kwSep = "=";
1604 const QString kwBgType = "bt";
1605 const QString kwFileName = "fn";
1606 const QString kwTextureMode = "tm";
1607 const QString kwShowTexture = "ts";
1608 const QString kwFirstColor = "c1";
1609 const QString kwSecondColor = "c2";
1610 const QString kwGrType = "gt";
1611 const QString kwGrData = "gr";
1613 Qtx::BackgroundMode bgMode = bgData.mode();
1615 Qtx::TextureMode textureMode = bgData.texture( fileName );
1616 bool showTexture = bgData.isTextureShown();
1618 int gradientType = bgData.gradient( c1, c2 );
1619 const QGradient* gradient = bgData.gradient();
1622 switch ( gradient->type() ) {
1623 case QGradient::LinearGradient:
1624 grString = gradientToString( *(static_cast<const QLinearGradient*>( gradient )) );
1626 case QGradient::RadialGradient:
1627 grString = gradientToString( *(static_cast<const QRadialGradient*>( gradient )) );
1629 case QGradient::ConicalGradient:
1630 grString = gradientToString( *(static_cast<const QConicalGradient*>( gradient )) );
1637 data << QString( "%1%2%3" ).arg( kwBgType ).arg( kwSep ).arg( (int)bgMode );
1638 data << QString( "%1%2%3" ).arg( kwFileName ).arg( kwSep ).arg( fileName );
1639 data << QString( "%1%2%3" ).arg( kwTextureMode ).arg( kwSep ).arg( (int)textureMode );
1640 data << QString( "%1%2%3" ).arg( kwShowTexture ).arg( kwSep ).arg( showTexture ? "true" : "false" );
1641 data << QString( "%1%2%3" ).arg( kwFirstColor ).arg( kwSep ).arg( Qtx::colorToString( c1 ) );
1642 data << QString( "%1%2%3" ).arg( kwSecondColor ).arg( kwSep ).arg( Qtx::colorToString( c2 ) );
1643 data << QString( "%1%2%3" ).arg( kwGrType ).arg( kwSep ).arg( gradientType );
1644 data << QString( "%1%2%3" ).arg( kwGrData ).arg( kwSep ).arg( grString );
1646 return data.join( dtSep );
1650 \brief Restore background data from the string representation.
1652 The string should consist of several sub-strings separated by ';' symbol.
1653 Each sub-string consists of keyword/value couple, in form of "<keyword>=<value>".
1654 The sub-strings can follow in arbitrary order, some keywords can be missing.
1655 The background data is described by the following values:
1656 - background type (enumerator, see Qtx::BackgroundMode), keyword "bt"
1657 - texture image file name (string), keyword "fn"
1658 - texture mode (enumerator, see Qtx::TextureMode), keyword "tm"
1659 - "show texture" flag (boolean), keyword "ts"
1660 - first color (for simple gradient data) or solid color (for single-colored mode), keyword "c1"
1661 - second color (for simple gradient data), keyword "c2"
1662 - name of gradient type (string), keyword "gt"
1663 - complex gradient data (for custom gradient mode), keyword "gr"
1665 Also, for backward compatibility, background data can be represented by
1666 single color value, see stringToColor().
1668 Backward conversion can be done with backgroundToString() method.
1669 Returns invalid background if conversion could not be done.
1672 Qtx::BackgroundData bgData = Qtx::stringToBackground( str );
1673 if ( bgData.isValid() ) ) doSomething( bgData );
1676 \param theString string representation of the background data
1677 \return resulting background data (invalid if conversion has failed)
1679 \sa backgroundToString()
1682 Qtx::BackgroundData Qtx::stringToBackground( const QString& str )
1684 const QString dtSep = ";";
1685 const QString kwSep = "=";
1686 const QString kwBgType = "bt";
1687 const QString kwFileName = "fn";
1688 const QString kwTextureMode = "tm";
1689 const QString kwShowTexture = "ts";
1690 const QString kwFirstColor = "c1";
1691 const QString kwSecondColor = "c2";
1692 const QString kwGrType = "gt";
1693 const QString kwGrData = "gr";
1695 Qtx::BackgroundData bgData = BackgroundData();
1697 QStringList data = str.split( dtSep, QString::KeepEmptyParts );
1700 if ( data.count() == 1 && !data.contains( kwSep ) && stringToColor( data[0], c ) ) {
1701 // solid color mode, for backward compatibility
1702 bgData.setColor( c );
1705 QMap<QString, QString> dmap;
1707 foreach( QString d, data ) {
1708 QStringList items = d.split( kwSep, QString::KeepEmptyParts );
1709 if ( items.count() > 0 ) {
1710 QString kw = items.takeFirst().trimmed().toLower(); // keyword
1711 QString val = items.join( kwSep ).trimmed(); // if value contains "=" symbol, we have to restore it
1715 QString bgMode = dmap.value( kwBgType, QString() );
1716 QString fileName = dmap.value( kwFileName, QString() );
1717 QString textureMode = dmap.value( kwTextureMode, QString() );
1718 QString showTexture = dmap.value( kwShowTexture, QString() );
1719 QString color1 = dmap.value( kwFirstColor, QString() );
1720 QString color2 = dmap.value( kwSecondColor, QString() );
1721 QString gradientType = dmap.value( kwGrType, QString() );
1722 QString gradient = dmap.value( kwGrData, QString() );
1725 if ( !fileName.isEmpty() || !textureMode.isEmpty() || !showTexture.isEmpty() ) {
1726 Qtx::TextureMode m = (Qtx::TextureMode)( stringToInt( textureMode, Qtx::CenterTexture,
1727 Qtx::CenterTexture, Qtx::StretchTexture ) );
1728 bgData.setTexture( fileName, m );
1729 QStringList boolvars; boolvars << "true" << "yes" << "ok" << "1";
1730 if ( boolvars.contains( showTexture.trimmed().toLower() ) )
1731 bgData.setTextureShown( true );
1735 bool ok = Qtx::stringToColor( color1, c1 );
1737 bgData.setColor( c1 );
1739 // try simple gradient mode
1740 ok = Qtx::stringToColor( color2, c2 );
1741 if ( ok || !gradientType.isEmpty() ) {
1742 int gt = gradientType.toInt( &ok );
1743 bgData.setGradient( ok ? gt : -1, c1, c2 );
1745 // try custom gradient mode
1747 QConicalGradient cg;
1749 ok = Qtx::stringToLinearGradient( gradient, lg );
1751 bgData.setGradient( lg );
1753 ok = Qtx::stringToRadialGradient( gradient, rg );
1755 bgData.setGradient( rg );
1757 ok = Qtx::stringToConicalGradient( gradient, cg );
1759 bgData.setGradient( cg );
1762 // finally set background mode
1763 Qtx::BackgroundMode m = (Qtx::BackgroundMode)( stringToInt( bgMode, Qtx::ColorBackground,
1764 Qtx::NoBackground, Qtx::CustomGradientBackground ) );
1765 bgData.setMode( m );
1772 \class Qtx::Localizer
1773 \brief Localization helper
1775 This helper class can be used to solve the localization problems,
1776 usually related to the textual files reading/writing, namely when
1777 floating point values are read / written with API functions.
1778 The problem relates to such locale specific settings as decimal point
1779 separator, thousands separator, etc.
1781 To use the Localizer class, just create a local variable in the beginning
1782 of the code where you need to read / write data from textual file(s).
1783 The constructor of the class forces setting "C" locale temporarily.
1784 The destructor switches back to the initial locale.
1786 There are two ways to create a localizer.
1787 First constructor accepts category and locale value to be forced as parameters.
1788 The second constructor does not take parameters, and is just a shortcut to the
1789 first one, setting LC_NUMERIC as a category and "C" as a locale to force.
1799 \brief Default constructor. Forces "C" locale to be set as LC_NUMERIC.
1801 Qtx::Localizer::Localizer()
1803 init( LC_NUMERIC, "C" );
1807 \brief Constructor. Forces \a locale to be set for \a category.
1809 Qtx::Localizer::Localizer( int category, const char* locale )
1811 init( category, locale );
1815 \brief Internal initialization
1818 void Qtx::Localizer::init( int category, const char* locale )
1820 myCategory = category;
1821 myOriginalLocale = setlocale( category, NULL );
1822 setlocale( category, locale );
1826 \brief Destructor. Reverts back to the initial locale.
1828 Qtx::Localizer::~Localizer()
1830 setlocale( myCategory, myOriginalLocale.toLatin1().constData() );
1834 \class Qtx::BackgroundData
1835 \brief Stores background data
1837 This class is used to store background data. Depending on the mode,
1838 the background can be specified by:
1839 - image (by assigning the file name to be used as background texture), see setTexture(), setTextureShown()
1840 - single color (by assigning any color), see setColor()
1841 - simple two-color gradient (with the gradient type id and two colors), see setGradient( int, const QColor&, const QColor& )
1842 - complex gradient (by assigning arbitrary gradient data), see setGradient( const QGradient& )
1844 The class stores all the data passed to it, so switching between different modes can be done
1845 just by calling setMode() function.
1847 \note Texture is used with combination of the background mode.
1849 \note Two-color gradient is specified by two colors and integer identifier. The interpretation of
1850 this identifier should be done in the calling code.
1853 Qtx::BackgroundData bg;
1854 bg.setColor( QColor(100, 100, 100) ); // bg is switched to Qtx::ColorBackground mode
1855 bg.setGradient( Qt::Horizontal, Qt::gray, Qt::white ); // bg is switched to Qtx::ColorBackground mode
1856 QLinearGradient grad( 0,0,1,1 );
1857 grad.setColorAt( 0.0, Qt::gray );
1858 grad.setColorAt( 0.5, Qt::white );
1859 grad.setColorAt( 1.0, Qt::green );
1860 grad.setSpread( QGradient::PadSpread );
1861 bg.setGradient( grad ); // bg is switched to Qtx::CustomGradientBackground mode
1862 bg.setMode( Qtx::ColorBackground ); // bg is switched back to Qtx::ColorBackground mode
1863 bg.setTexture( "/data/images/background.png" ); // specify texture (in the centered mode by default)
1864 bg.setTextureShown( true ); // draw texture on the solid color background
1869 \brief Default constructor.
1870 Creates invalid background data.
1872 Qtx::BackgroundData::BackgroundData()
1873 : myTextureMode( Qtx::CenterTexture ), myGradientType( -1 ), myTextureShown( false )
1875 setMode( Qtx::NoBackground );
1880 Creates background data initialized with the specified color
1883 Qtx::BackgroundData::BackgroundData( const QColor& c )
1884 : myTextureMode( Qtx::CenterTexture ), myGradientType( -1 ), myTextureShown( false )
1891 Creates background data initialized with the specified two-color gradient
1892 \param type gradient type identifier
1893 \param c1 first gradient color
1894 \param c2 second gradient color
1895 \note the interpretation of the gradient identifier should be done in the calling code
1897 Qtx::BackgroundData::BackgroundData( int type, const QColor& c1, const QColor& c2 )
1898 : myTextureMode( Qtx::CenterTexture ), myGradientType( -1 ), myTextureShown( false )
1900 setGradient( type, c1, c2 );
1905 Creates background data initialized with the arbirtary gradient data
1906 \param grad gradient data
1908 Qtx::BackgroundData::BackgroundData( const QGradient& grad )
1909 : myTextureMode( Qtx::CenterTexture ), myGradientType( -1 ), myTextureShown( false )
1911 setGradient( grad );
1917 Qtx::BackgroundData::~BackgroundData()
1922 \brief Compares two background data objects
1924 bool Qtx::BackgroundData::operator==( const Qtx::BackgroundData& other ) const
1927 ( myMode == other.myMode ) &&
1928 ( myTextureMode == other.myTextureMode ) &&
1929 ( myFileName == other.myFileName ) &&
1930 ( myColors == other.myColors ) &&
1931 ( myGradientType == other.myGradientType ) &&
1932 ( myGradient == other.myGradient ) &&
1933 ( myTextureShown == other.myTextureShown );
1937 \brief Returns \c false if background data is not set (invalid)
1938 \return \c true if background data is valid or \c false otherwise
1941 bool Qtx::BackgroundData::isValid() const
1943 return myMode != Qtx::NoBackground;
1947 \brief Get background mode
1948 \return current background mode
1951 Qtx::BackgroundMode Qtx::BackgroundData::mode() const
1957 \brief Set background mode
1958 \param m background mode being set
1961 void Qtx::BackgroundData::setMode( const Qtx::BackgroundMode m )
1967 \brief Get file name used as a texture image
1968 \return path to the texture image file
1969 \sa setTexture(), setTextureShown()
1971 Qtx::TextureMode Qtx::BackgroundData::texture( QString& fileName ) const
1973 fileName = myFileName;
1974 return myTextureMode;
1978 \brief Set file name to be used as a texture image.
1980 \note To show texture image on the background it is necessary to call additionally
1981 setTextureShown() method.
1983 \param fileName path to the texture image file name
1984 \param m texture mode (Qtx::CenterTexture by default)
1985 \sa texture(), setTextureShown()
1987 void Qtx::BackgroundData::setTexture( const QString& fileName, const Qtx::TextureMode m )
1989 myFileName = fileName;
1994 \brief Check if "show texture" flag is switched on
1995 \return \c true if "show texture" flag is set or \c false otherwise
1996 \sa setTextureShown(), texture()
1998 bool Qtx::BackgroundData::isTextureShown() const
2000 return myTextureShown;
2004 \brief Specify if texture should be shown on the background or no.
2005 \param on \c true if texture should be shown or \c false otherwise
2006 \sa isTextureShown(), texture()
2008 void Qtx::BackgroundData::setTextureShown( bool on )
2010 myTextureShown = on;
2014 \brief Get background color. Returns null QColor if color is not set
2015 \return solid background color
2016 \sa setColor(), mode()
2018 QColor Qtx::BackgroundData::color() const
2020 return myColors.count() > 0 ? myColors[0] : QColor();
2024 \brief Set background color and switch to the Qtx::ColorBackground mode
2028 void Qtx::BackgroundData::setColor( const QColor& c )
2032 setMode( Qtx::ColorBackground );
2036 \brief Get simple gradient data.
2037 Returns -1 and null QColor for \a c1 and \a c2 if gradient data is not set
2038 \param c1 first gradient color is returned via this parameter
2039 \param c2 second gradient color is returned via this parameter
2040 \return current two-colored gradient mode type identifier
2041 \note the interpretation of the gradient identifier should be done in the calling code
2042 \sa setGradient(int, const QColor&, const QColor&), mode()
2044 int Qtx::BackgroundData::gradient( QColor& c1, QColor& c2 ) const
2046 c1 = myColors.count() > 0 ? myColors[0] : QColor();
2047 c2 = myColors.count() > 1 ? myColors[1] : ( myColors.count() > 0 ? myColors[0] : QColor() );
2048 return myGradientType;
2052 \brief Set simple background gradient data and switch to the Qtx::SimpleGradientBackground mode
2053 \param type two-colored gradient mode type identifier
2054 \param c1 first gradient color is returned via this parameter
2055 \param c2 second gradient color is returned via this parameter
2056 \note the interpretation of the gradient identifier should be done in the calling code
2057 \sa gradient(QColor&, QColor&), mode()
2059 void Qtx::BackgroundData::setGradient( int type, const QColor& c1, const QColor& c2 )
2062 myColors << c1 << c2;
2063 myGradientType = type;
2064 setMode( Qtx::SimpleGradientBackground );
2068 \brief Get complex gradient data.
2069 Returns QGradient of QGradient::NoGradient if gradient data is not set
2070 \note This function does not transform simple gradient data set with
2071 setGradient( const QString&, const QColor&, const QColor& ) to QGradient class
2072 \return gradient data
2073 \sa setGradient(const QGradient&), mode()
2075 const QGradient* Qtx::BackgroundData::gradient() const
2081 \brief Set complex background gradient data and switch to the Qtx::CustomGradientBackground mode
2082 \param grad gradient data (QLinearGradient, QRadialGradient or QConicalGradient)
2083 \sa gradient(), mode()
2085 void Qtx::BackgroundData::setGradient( const QGradient& grad )
2088 setMode( Qtx::CustomGradientBackground );
2092 \brief Convert string representation of version identifier to the numerical value.
2093 Resulting value can be used for comparison of different versions (lower, higher, equal).
2095 String representation of the version consists of zero or more components:
2097 [major[.minor[.release[patchid]]]]
2100 - major is version major number
2101 - minor is version minor number
2102 - release is version release number
2103 - patchid is a version dev identifier which is one of the following
2104 * 1 letter optionally followed by 1 or 2 digits, e.g. "a" for "alpha", "b1" for "beta 1"
2105 * "rc" optionally followed by 1 or 2 digits, e.g. "rc1" for "release candidate 1"
2106 * "dev" for development version (note: 7.4.0dev > 7.4.0, 7.4.0dev < 7.4.1, 7.4.0dev < 7.4.0a1)
2108 If version string does not include any component or has invalid format, the function returns 0.
2112 1.2.3a - version 1.2.3 alpha
2113 3.3.3b1 - version 3.3.3 beta 1
2114 7.4.0rc1 - version 7.4.0 release candidate 1
2115 7.4.0dev - dev version, i.e. future version 7.4.1 (or 7.5.0)
2117 \param version string representation of version
2118 \return numerical identifier of the version
2120 long Qtx::versionToId( const QString& version )
2124 QRegExp vers_exp( "^([0-9]+)([A-Z]|RC|DEV)?([0-9]{0,2})$", Qt::CaseInsensitive );
2126 QStringList vers = version.split( ".", QString::SkipEmptyParts );
2127 int major=0, minor=0;
2128 int release = 0, dev1 = 0, dev2 = 0;
2129 if ( vers.count() > 0 ) major = vers[0].toInt();
2130 if ( vers.count() > 1 ) minor = vers[1].toInt();
2131 if ( vers.count() > 2 ) {
2132 if ( vers_exp.indexIn( vers[2] ) != -1 ) {
2133 release = vers_exp.cap( 1 ).toInt();
2134 QString tag = vers_exp.cap( 2 ).toLower();
2135 if ( !tag.isEmpty() ) {
2136 // patchid is subtracted from version number
2137 // a = 55 --> -(55 * 100) + patch number --> 4500..4599, e.g. 7.4.1a1 -> 704004501
2138 // b = 54 --> -(54 * 100) + patch number --> 4600..4699, e.g. 7.4.1b1 -> 704004601
2139 // c = 53 --> -(53 * 100) + patch number --> 4700..4799, e.g. 7.4.1c1 -> 704004701
2141 // z = 30 --> -( 1 * 100) + patch number --> 7000..7099, e.g. 7.4.1z1 -> 704007001
2142 // rc = 1 --> -( 1 * 100) + patch number --> 9900..9999, e.g. 7.4.1rc1 -> 704009901
2143 // dev = -1 --> +( 1 * 100) + patch number --> 0100..0199, e.g. 7.4.1dev -> 704010100
2145 // i.e. "a" < "b" < ... < "z" < "rc" < [stable] < "dev"
2148 else if ( tag == "dev" )
2151 dev1 = (int)( QChar('z').toLatin1() ) - (int)( tag[ 0 ].toLatin1() ) + 30;
2153 if ( !vers_exp.cap( 3 ).isEmpty() )
2154 dev2 = vers_exp.cap( 3 ).toInt();
2158 int dev = dev1*100-dev2;
2161 id*=100; id+=release;
2169 \brief Get Qt installation directory
2171 The function tries to detect qt installation directory by analyzing the system variables in the following order:
2176 Optional parameter \a context allows obtaining subdirectory in the Qt installation directory.
2178 \param context optional sub-directory
2179 \return path to the Qt installation directory (or its sub-folder, if \a context is specified)
2182 QString Qtx::qtDir( const QString& context )
2185 QStringList vars = { "QT5_ROOT_DIR", "QT_ROOT_DIR", "QTDIR" };
2187 for (int i = 0; i < vars.length() && qtPath.isEmpty(); i++ ) {
2188 qtPath = getenv(vars[i]);
2190 if ( !qtPath.isEmpty() && !context.isEmpty() )
2191 qtPath = QDir( qtPath ).absoluteFilePath( context );
2196 Creates font from string description
2198 QFont Qtx::stringToFont( const QString& fontDescription )
2201 if ( fontDescription.trimmed().isEmpty() || !font.fromString( fontDescription ) )
2202 font = QFont( "Courier", 11 );
2206 QString Qtx::getenv(const QString & envVar)
2210 value = qgetenv(envVar.toLocal8Bit().constData());
2212 LPTSTR buff = new TCHAR[MAX_VALUE_SIZE];
2214 LPTSTR anEnvVar = new TCHAR[envVar.length() + 1];
2215 anEnvVar[envVar.toWCharArray(anEnvVar)] = '\0';
2217 const TCHAR* anEnvVar = envVar.toLocal8Bit(buff).constData();
2219 const DWORD ret = GetEnvironmentVariable(anEnvVar, buff, MAX_VALUE_SIZE);
2223 value = QString::fromWCharArray(buff);
2225 value = QString::fromLocal8Bit(buff);
2236 #if !defined WIN32 && !defined __APPLE__
2238 #include <X11/Xlib.h>
2242 \brief Open the default X display and returns pointer to it.
2243 This method is available on Linux only.
2244 \return Pointer to X display.
2247 void* Qtx::getDisplay()
2249 static Display* pDisplay = NULL;
2251 pDisplay = XOpenDisplay( NULL );
2256 \brief Returns pointer to X visual suitable for 3D rendering.
2257 This method is available on Linux only.
2258 \return Pointer to X visual.
2261 Qt::HANDLE Qtx::getVisual()
2263 Qt::HANDLE res = (Qt::HANDLE)NULL;
2265 Display* pDisplay = (Display*)getDisplay();
2272 // Make sure OpenGL's GLX extension supported
2273 if( !glXQueryExtension( pDisplay, &errorBase, &eventBase ) ){
2274 qCritical( "Could not find glx extension" );
2278 // Find an appropriate visual
2280 int doubleBufferVisual[] = {
2281 GLX_RENDER_TYPE, GLX_RGBA_BIT, // Needs to support OpenGL
2286 GLX_DEPTH_SIZE, 16, // Needs to support a 16 bit depth buffer
2287 GLX_DOUBLEBUFFER, 1, // Needs to support double-buffering
2288 GLX_STEREO, 1, // Needs to support stereo rendering
2289 GLX_STENCIL_SIZE, 1,
2290 0x20B2, 1, // Needs to support srgb profile
2294 // Try for the double-bufferd visual first
2295 XVisualInfo *visualInfo = NULL;
2296 visualInfo = glXChooseVisual( pDisplay, DefaultScreen(pDisplay), doubleBufferVisual );
2298 if( visualInfo == NULL ){
2299 qCritical( "Could not find matching glx visual" );
2303 qDebug() << "Picked visual 0x" << hex << XVisualIDFromVisual( visualInfo->visual );
2304 res = (Qt::HANDLE)( visualInfo->visual );
2312 \brief Set default QSurfaceFormat for an application.
2314 This application property should be set before a creation of the QApplication.
2316 void Qtx::initDefaultSurfaceFormat()
2318 // Settings from Paraview:
2319 // This piece of code was taken from QVTKOpenGLWidget::defaultFormat() method in
2320 // order to avoid dependency of the SALOME_Session_Server on vtk libraries
2322 fmt.setRenderableType(QSurfaceFormat::OpenGL);
2323 fmt.setVersion(3, 2);
2324 fmt.setProfile(QSurfaceFormat::CoreProfile);
2325 fmt.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
2326 fmt.setRedBufferSize(1);
2327 fmt.setGreenBufferSize(1);
2328 fmt.setBlueBufferSize(1);
2329 fmt.setDepthBufferSize(1);
2330 fmt.setStencilBufferSize(0);
2332 fmt.setAlphaBufferSize(0);
2334 fmt.setAlphaBufferSize(0);
2336 fmt.setStereo(false);
2339 // Settings for OCCT viewer window:
2340 fmt.setDepthBufferSize(16);
2341 fmt.setStencilBufferSize(1);
2342 // fmt.setProfile(QSurfaceFormat::CompatibilityProfile);
2344 QSurfaceFormat::setDefaultFormat(fmt);
2348 \class Qtx::CmdLineArgs
2349 \brief Get access to the command line arguments in the C-like manner.
2351 This class translates command line arguments stored in QApplication in form of QStrlingList
2352 to the char* array, in the same way as they specified to main() function.
2354 Constructor of class allocates required memory to store arguments; destructor deallocates it,
2355 This allows using this class as a local variable:
2358 Qtx::CmdLineArgs args;
2359 some_function(args.argc(), args.argv()); // function that has main()-like syntax.
2364 \brief Default constructor.
2366 Qtx::CmdLineArgs::CmdLineArgs()
2368 QStringList args = QCoreApplication::arguments();
2369 myArgc = args.size();
2370 myArgv = new char*[myArgc];
2371 for ( int i = 0; i < myArgc; i++ ) {
2372 QByteArray ba = args[i].toUtf8();
2373 myArgv[i] = qstrdup(ba.constData());
2378 \brief Destructor. Deallocates the array with command line arguments
2380 Qtx::CmdLineArgs::~CmdLineArgs()
2382 for ( int i = 0; i < myArgc; i++ )
2388 \brief Get number of command line arguments
2389 \return number of arguments
2391 int Qtx::CmdLineArgs::argc() const
2397 \brief Get command line arguments
2398 \return command line arguments
2400 char** Qtx::CmdLineArgs::argv() const