X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FQtx%2FQtx.cxx;h=d596874ce2988a8647757aed20e31913fb0f7b8e;hb=6d95e8aac480cc46df35de17c533dbe7bdb7a3d1;hp=884d811551f094be7cd20ec3a3105070dfb9c3be;hpb=853edb23512e9e7c180134be3ddb29c37601a8b3;p=modules%2Fgui.git diff --git a/src/Qtx/Qtx.cxx b/src/Qtx/Qtx.cxx index 884d81155..d596874ce 100755 --- a/src/Qtx/Qtx.cxx +++ b/src/Qtx/Qtx.cxx @@ -1,60 +1,190 @@ +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + // File: Qtx.cxx // Author: Sergey TELKOV - +// #include "Qtx.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include +#include + +#define BICOLOR_CHANGE_HUE + +/*! + \brief Auxiliary function converting string \a str to the integer value. + Parameter \a defVal specifies default value that is returned if conversion can't be done. + Parameters \a minVal and \a maxVal limit the resulting value. + \param str string being converted + \param defVal default value + \param minVal minimum allowed value + \param maxVal maximum allowed value + \return integer value obtained from the string + \internal +*/ +static int stringToInt( const QString& str, int defVal, int minVal, int maxVal ) +{ + bool ok; + int v = str.toInt( &ok ); + if ( !ok ) v = defVal; + return qMin( qMax( v, minVal ), maxVal ); +} /*! - Name: setTabOrder [static public] - Desc: Set tab order for specified list of widgets. Last parameter should be null pointer. + \class Qtx + \brief A set of helpful utility functions. + + The class implements a set of the static functions which can be used + for the different purposes: + - specify tab order for the set of widgets: setTabOrder() + - align one widget to the coordinates of the another one: alignWidget() + - remove extra separators from the menu or toolbar: simplifySeparators() + - retrieve directory, file name and extension parts of the path: + dir(), file(), extension() + - get the path to the temporary directory: tmpDir() + - create or remove a directory (recursively): mkDir(), rmDir() + - convert text file from DOS to UNIX native format: dos2unix() + - convert a picture to the gray scale: grayscale() + - other */ +/*! + \brief Convert character array (ASCII string) to the QString. + \param str character array + \param len array length, if < 0, the array should be zero-terminated + \return QString object + */ +QString Qtx::toQString( const char* str, const int len ) +{ + return toQString( (unsigned char*)str, len ); +} + +/*! + \brief Convert integer array (UNICODE string) to the QString. + \param str integer array + \param len array length, if < 0, the array should be zero-terminated + \return QString object + */ +QString Qtx::toQString( const short* str, const int len ) +{ + return toQString( (unsigned short*)str, len ); +} + +/*! + \brief Convert character array (ASCII string) to the QString. + \param str character array + \param len array length, if < 0, the array should be zero-terminated + \return QString object + */ +QString Qtx::toQString( const unsigned char* str, const int len ) +{ + QString res; + const unsigned char* s = str; + while ( len < 0 || res.length() < len ) + { + if ( *s == '\0' ) + break; + + res.append( QChar( *s ) ); + s++; + } + return res; +} + +/*! + \brief Convert integer array (UNICODE string) to the QString. + \param str integer array + \param len array length, if < 0, the array should be zero-terminated + \return QString object + */ +QString Qtx::toQString( const unsigned short* str, const int len ) +{ + QString res; + const unsigned short* s = str; + while ( len < 0 || res.length() < len ) + { + if ( *s == '\0' ) + break; + + res.append( QChar( *s ) ); + s++; + } + return res; +} + +/*! + \brief Set tab order for specified list of widgets. + + The function has arbitrary number of parameters, each should be + hovewer of QWidget* type. Last parameter should be null pointer. + + \param first first widget in the sequence +*/ void Qtx::setTabOrder( QWidget* first, ... ) { va_list wids; - va_start( wids, first ); + va_start( wids, first ); - QWidgetList widList; + QWidgetList widList; - QWidget* cur = first; - while ( cur ) - { - widList.append( cur ); - cur = va_arg( wids, QWidget* ); + QWidget* cur = first; + while ( cur ) + { + widList.append( cur ); + cur = va_arg( wids, QWidget* ); } - setTabOrder( widList ); + setTabOrder( widList ); } /*! - Name: setTabOrder [static public] - Desc: Set tab order for specified list of widgets. + \brief Set tab order for specified list of widgets. + \param widgets list of widgets */ - void Qtx::setTabOrder( const QWidgetList& widgets ) { if ( widgets.count() < 2 ) return; - + QWidget* prev = 0; - for ( QWidgetListIt it( widgets ); it.current(); ++it ) + for ( QWidgetList::const_iterator it = widgets.begin(); it!= widgets.end(); ++it ) { - QWidget* next = it.current(); + QWidget* next = *it; if ( prev && next ) QWidget::setTabOrder( prev, next ); prev = next; @@ -62,157 +192,125 @@ void Qtx::setTabOrder( const QWidgetList& widgets ) } /*! - Name: alignWidget [static public] - Desc: Align widget 'src' relative to widget 'ref' acording to alignment flags. - Alignment flags: - Qtx::AlignLeft - Align left side of 'src' to left side of 'ref'. - Qtx::AlignRight - Align right side of 'src' to right side of 'ref'. - Qtx::AlignTop - Align top side of 'src' to top side of 'ref'. - Qtx::AlignBottom - Align bottom side of 'src' to bottom side of 'ref'. - Qtx::AlignHCenter - Align 'src' to center of 'ref' in horizontal dimension. - Qtx::AlignVCenter - Align 'src' to center of 'ref' in vertical dimension. - Qtx::AlignCenter - Align 'src' to center of 'ref' in both dimensions. - Qtx::AlignOutLeft - Align right side of 'src' to left side of 'ref'. - Qtx::AlignOutRight - Align left side of 'src' to right side of 'ref'. - Qtx::AlignOutTop - Align bottom side of 'src' to top side of 'ref'. - Qtx::AlignOutBottom - Align top side of 'src' to bottom side of 'ref'. + \brief Align widget \a src relative to widget \a ref acording to the + alignment flags \a alignFlags. + \param src source widget (being aligned) + \param ref reference widget (source widget being aligned to) + \param alignFlags alignment flags (Qtx::AlignmentFlags) */ - void Qtx::alignWidget( QWidget* src, const QWidget* ref, const int alignFlags ) { - if ( !src || !ref || !alignFlags ) - return; + if ( !src || !ref || !alignFlags ) + return; - QPoint srcOri = src->pos(); - QPoint refOri = ref->pos(); - if ( src->parentWidget() && !src->isTopLevel() ) - srcOri = src->parentWidget()->mapToGlobal( srcOri ); - if ( ref->parentWidget() && !ref->isTopLevel() ) - refOri = ref->parentWidget()->mapToGlobal( refOri ); + QPoint srcOri = src->pos(); + QPoint refOri = ref->pos(); + if ( src->parentWidget() && !src->isTopLevel() ) + srcOri = src->parentWidget()->mapToGlobal( srcOri ); + if ( ref->parentWidget() && !ref->isTopLevel() ) + refOri = ref->parentWidget()->mapToGlobal( refOri ); - int x = srcOri.x(), y = srcOri.y(); - int refWidth = ref->frameGeometry().width(), refHei = ref->frameGeometry().height(); - int srcWidth = src->frameGeometry().width(), srcHei = src->frameGeometry().height(); + int x = srcOri.x(), y = srcOri.y(); + int refWidth = ref->frameGeometry().width(), refHei = ref->frameGeometry().height(); + int srcWidth = src->frameGeometry().width(), srcHei = src->frameGeometry().height(); - if ( srcWidth <= 0 ) - srcWidth = src->sizeHint().width(); + if ( srcWidth <= 0 ) + srcWidth = src->sizeHint().width(); if ( srcHei <= 0 ) srcHei = src->sizeHint().height(); - int border = 0; + int border = 0; if ( ref->isTopLevel() && ref->isMaximized() && src->isTopLevel() && !src->isMaximized() ) border = ( src->frameGeometry().width() - src->width() ) / 2; - if ( alignFlags & Qtx::AlignLeft ) - x = refOri.x() + border; - if ( alignFlags & Qtx::AlignOutLeft ) - x = refOri.x() - srcWidth - border; - if ( alignFlags & Qtx::AlignRight ) - x = refOri.x() + refWidth - srcWidth - border; - if ( alignFlags & Qtx::AlignOutRight ) - x = refOri.x() + refWidth + border; - if ( alignFlags & Qtx::AlignTop ) - y = refOri.y() + border; - if ( alignFlags & Qtx::AlignOutTop ) - y = refOri.y() - srcHei - border; - if ( alignFlags & Qtx::AlignBottom ) - y = refOri.y() + refHei - srcHei - border; - if ( alignFlags & Qtx::AlignOutBottom ) - y = refOri.y() + refHei + border; - if ( alignFlags & Qtx::AlignHCenter ) - x = refOri.x() + ( refWidth - srcWidth ) / 2; - if ( alignFlags & Qtx::AlignVCenter ) - y = refOri.y() + ( refHei - srcHei ) / 2; - - if ( src->parentWidget() && !src->isTopLevel() ) - { - QPoint pos = src->parentWidget()->mapFromGlobal( QPoint( x, y ) ); - x = pos.x(); - y = pos.y(); - } - - QWidget* desk = QApplication::desktop(); - if ( desk && x + srcWidth + border > desk->width() ) - x = desk->width() - srcWidth - border; - if ( desk && y + srcHei + border > desk->height() ) - y = desk->height() - srcHei - border; - - x = QMAX( x, 0 ); - y = QMAX( y, 0 ); - - src->move( x, y ); -} - -/*! - Name: simplifySeparators [static public] - Desc: Checks toolbar for unnecessary separators and removes them -*/ -void Qtx::simplifySeparators( QToolBar* toolbar ) -{ - if ( !toolbar ) - return; - - const QObjectList* objList = toolbar->children(); - if ( !objList ) - return; - - QObjectList delList; - - bool isPrevSep = true; - for ( QObjectListIt it( *objList ); it.current(); ++it ) + if ( alignFlags & Qtx::AlignLeft ) + x = refOri.x() + border; + if ( alignFlags & Qtx::AlignOutLeft ) + x = refOri.x() - srcWidth - border; + if ( alignFlags & Qtx::AlignRight ) + x = refOri.x() + refWidth - srcWidth - border; + if ( alignFlags & Qtx::AlignOutRight ) + x = refOri.x() + refWidth + border; + if ( alignFlags & Qtx::AlignTop ) + y = refOri.y() + border; + if ( alignFlags & Qtx::AlignOutTop ) + y = refOri.y() - srcHei - border; + if ( alignFlags & Qtx::AlignBottom ) + y = refOri.y() + refHei - srcHei - border; + if ( alignFlags & Qtx::AlignOutBottom ) + y = refOri.y() + refHei + border; + if ( alignFlags & Qtx::AlignHCenter ) + x = refOri.x() + ( refWidth - srcWidth ) / 2; + if ( alignFlags & Qtx::AlignVCenter ) + y = refOri.y() + ( refHei - srcHei ) / 2; + + if ( src->parentWidget() && !src->isTopLevel() ) { - bool isSep = it.current()->isA( "QToolBarSeparator" ); - if ( isPrevSep && isSep ) - delList.append( it.current() ); - isPrevSep = isSep; + QPoint pos = src->parentWidget()->mapFromGlobal( QPoint( x, y ) ); + x = pos.x(); + y = pos.y(); } - for ( QObjectListIt itr( delList ); itr.current(); ++itr ) - delete itr.current(); + QWidget* desk = QApplication::desktop(); + if ( desk && x + srcWidth + border > desk->width() ) + x = desk->width() - srcWidth - border; + if ( desk && y + srcHei + border > desk->height() ) + y = desk->height() - srcHei - border; - if ( toolbar->children() && !toolbar->children()->isEmpty() && - toolbar->children()->getFirst()->isA( "QToolBarSeparator" ) ) - delete toolbar->children()->getFirst(); + x = qMax( x, 0 ); + y = qMax( y, 0 ); - if ( toolbar->children() && !toolbar->children()->isEmpty() && - toolbar->children()->getLast()->isA( "QToolBarSeparator" ) ) - delete toolbar->children()->getLast(); + src->move( x, y ); } /*! - Name: simplifySeparators [static public] - Desc: Checks popup menu recursively for unnecessary separators and removes them + \brief Remove (recursively) unnecessary separators from the menu or toolbar. + \param wid widget, should be of QMenu* or QToolBar* class */ -void Qtx::simplifySeparators( QPopupMenu* popup, const bool recursive ) +void Qtx::simplifySeparators( QWidget* wid, const bool recursive ) { - if ( !popup || !popup->count() ) + if ( !wid ) + return; + + QList items = wid->actions(); + if ( items.isEmpty() ) return; - QIntList idRemove; - for ( uint i = 1; i < popup->count(); i++ ) + QList toRemove; + for ( int i = 1; i < items.count(); i++ ) { - if ( popup->findItem( popup->idAt( i ) )->isSeparator() && - popup->findItem( popup->idAt( i - 1 ) )->isSeparator() ) - idRemove.append( popup->idAt( i ) ); + if ( items[i]->isSeparator() && items[i - 1]->isSeparator() ) + toRemove.append( items[i] ); - if ( recursive ) - simplifySeparators( popup->findItem( popup->idAt( i ) )->popup() ); + if ( recursive && items[i]->menu() ) + simplifySeparators( items[i]->menu(), recursive ); } - for ( QIntList::const_iterator it = idRemove.begin(); it != idRemove.end(); ++it ) - popup->removeItem( *it ); + for ( QList::iterator it = toRemove.begin(); it != toRemove.end(); ++it ) + wid->removeAction( *it ); - if ( popup->count() > 0 && popup->findItem( popup->idAt( 0 ) )->isSeparator() ) - popup->removeItem( popup->idAt( 0 ) ); + items = wid->actions(); + if ( !items.isEmpty() && items[0]->isSeparator() ) + wid->removeAction( items[0] ); - if ( popup->count() > 0 && popup->findItem( popup->idAt( popup->count() - 1 ) )->isSeparator() ) - popup->removeItem( popup->idAt( popup->count() - 1 ) ); + items = wid->actions(); + if ( !items.isEmpty() && items[items.count() - 1]->isSeparator() ) + wid->removeAction( items[items.count() - 1] ); } /*! - Name: isParent [static public] - Desc: Returns 'true' if specified 'parent' is parent object of given 'child'. + \brief Return \c true if specified \a parent is a parent object + of given \a child (in terms of QObject). + + This function works recursively. It means that \a true is also + returned if \a parent is a grand-father, grand-grand-father, etc + of \a child. If the same object is given as both \a parent and + \a child, \c true is also returned. + + \param child child object + \param parent parent object + \return \c true if the \a parent is a parent of \a child */ bool Qtx::isParent( QObject* child, QObject* parent ) { @@ -230,42 +328,95 @@ bool Qtx::isParent( QObject* child, QObject* parent ) } /*! - Name: dir [static public] - Desc: Returns dir name or null string. + \brief Find the parent object of class specified by \a className (in terms of QObject). + + \param obj current object + \param className class name of the parent + \return parent object or null pointer if the parent not found +*/ +QObject* Qtx::findParent( QObject* obj, const char* className ) +{ + if ( !obj ) + return 0; + + if ( !className || !strlen( className ) ) + return obj->parent(); + + QObject* res = 0; + QObject* p = obj->parent(); + while ( p && !res ) + { + if ( p->inherits( className ) ) + res = p; + p = p->parent(); + } + + return res; +} + +/*! + \brief Return directory part of the file path. + + If the file path does not include directory part (the file is in the + current directory), null string is returned. + + \param path file path + \param abs if true (default) \a path parameter is treated as absolute file path + \return directory part of the file path */ QString Qtx::dir( const QString& path, const bool abs ) { - QString dirPath = QFileInfo( path ).dirPath( abs ); + QDir aDir = QFileInfo( path ).dir(); + QString dirPath = abs ? aDir.absolutePath() : aDir.path(); if ( dirPath == QString( "." ) ) - dirPath = QString::null; + dirPath = QString(); return dirPath; } -/*! - Name: file [static public] - Desc: Returns file with or without extension. +/*! + \brief Return file name part of the file path. + + \param path file path + \param withExt if true (default) complete file name (with all + extension except the last) is returned, otherwise only base name + is returned + \return file name part of the file path */ QString Qtx::file( const QString& path, bool withExt ) { + QString fPath = path; + while ( !fPath.isEmpty() && ( fPath[fPath.length() - 1] == '\\' || fPath[fPath.length() - 1] == '/' ) ) + fPath.remove( fPath.length() - 1, 1 ); + if ( withExt ) - return QFileInfo( path ).fileName(); - else - return QFileInfo( path ).baseName(); + return QFileInfo( fPath ).fileName(); + else + return QFileInfo( fPath ).completeBaseName(); } /*! - Name: extension [static public] - Desc: Returns the file extension only or null string. + \brief Return extension part of the file path. + + \param path file path + \param full if true complete extension (all extensions, dot separated) + is returned, otherwise (default) only last extension is returned + \return extension part of the file path */ -QString Qtx::extension( const QString& path ) -{ - return QFileInfo( path ).extension(); +QString Qtx::extension( const QString& path, const bool full ) +{ + return full ? QFileInfo( path ).completeSuffix() : QFileInfo( path ).suffix(); } /*! - Name: library [static public] - Desc: Generate library file name. - Append required prefix (lib) and suffix (.dll/.so) to the library file name. + \brief Convert the given parameter to the platform-specific library name. + + The function appends platform-specific prefix (lib) and suffix (.dll/.so) + to the library file name. + For example, if \a str = "mylib", "libmylib.so" is returned for Linux and + mylib.dll for Windows. + + \param str short library name + \return full library name */ QString Qtx::library( const QString& str ) { @@ -278,13 +429,15 @@ QString Qtx::library( const QString& str ) name = QString( "lib" ) + name; #endif -#ifdef WIN32 +#if defined(WIN32) QString libExt( "dll" ); +#elif defined(__APPLE__) + QString libExt( "dylib" ); #else QString libExt( "so" ); #endif - if ( ext.lower() != QString( "so" ) && ext.lower() != QString( "dll" ) ) + if ( ext.toLower() != QString( "so" ) && ext.toLower() != QString( "dll" ) && ext.toLower() != QString( "dylib" ) ) { if ( !name.isEmpty() && !ext.isEmpty() ) name += QString( "." ); @@ -299,134 +452,120 @@ QString Qtx::library( const QString& str ) } /*! - Name: tmpDir [static public] - Desc: Returns path to temporary directory. + \brief Get the temporary directory name. + \return temporary directory (platform specific) */ QString Qtx::tmpDir() { - char* tmpdir = ::getenv( "TEMP" ); - if ( !tmpdir ) - tmpdir = ::getenv ( "TMP" ); - if ( !tmpdir ) - { + const char* tmpdir = ::getenv( "TEMP" ); + if ( !tmpdir ) + tmpdir = ::getenv ( "TMP" ); + if ( !tmpdir ) + { #ifdef WIN32 - tmpdir = "C:\\"; + tmpdir = "C:\\"; #else - tmpdir = "/tmp"; + tmpdir = "/tmp"; #endif - } - return QString( tmpdir ); + } + return QString( tmpdir ); } /*! - Name: mkDir [static public] - Desc: Creates directory with intermediate perent directories. - Returns true in successfull case. + \brief Create directory recursively including all intermediate sub directories. + \return \c true if the directory is successfully created and \c false otherwise */ bool Qtx::mkDir( const QString& dirPath ) { - QString path = QDir::convertSeparators( dirPath ); - -#ifdef WIN32 - while ( !path.isEmpty() && path.at( path.length() - 1 ) == QDir::separator() ) - path.remove( path.length() - 1, 1 ); - - if ( path.at( path.length() - 1 ) == ':' ) - return QFileInfo( path ).exists(); -#endif - - QFileInfo fInfo( path ); - if ( fInfo.exists() ) - return fInfo.isDir(); - - if ( !mkDir( fInfo.dirPath() ) ) - return false; - - return QDir( fInfo.dirPath() ).mkdir( fInfo.fileName() ); + return QDir().mkpath( dirPath ); } /*! - Name: rmDir [static public] - Desc: Removes directory with its subdirectories and files. - Returns true in successfull case. + \brief Remove directory recursively including all subdirectories and files. + \return \c true if the directory is successfully removed and \c false otherwise */ bool Qtx::rmDir( const QString& thePath ) { - QFileInfo fi( thePath ); - if ( !fi.exists() ) - return true; - - bool stat = true; - if ( fi.isFile() ) - stat = QFile::remove( thePath ); - else if ( fi.isDir() ) - { - QDir aDir( thePath ); - const QFileInfoList* anEntries = aDir.entryInfoList(); - if ( anEntries ) - { - for ( QPtrListIterator it( *anEntries ); it.current(); ++it ) - { - if ( it.current()->fileName() == "." || it.current()->fileName() == ".." ) - continue; - stat = stat && rmDir( it.current()->absFilePath() ); - } - } - stat = stat && aDir.rmdir( thePath ); - } - return stat; -} - -/*! - Name: addSlash [static public] - Desc: Adds a slash to the end of 'path' if it is not already there. + QFileInfo fi( thePath ); + if ( !fi.exists() ) + return true; + + bool stat = true; + if ( fi.isFile() ) + stat = QFile::remove( thePath ); + else if ( fi.isDir() ) + { + QDir aDir( thePath ); + QFileInfoList anEntries = aDir.entryInfoList(); + for ( QFileInfoList::iterator it = anEntries.begin(); it != anEntries.end(); ++it ) + { + QFileInfo inf = *it; + if ( inf.fileName() == "." || inf.fileName() == ".." ) + continue; + stat = stat && rmDir( inf.absoluteFilePath() ); + } + stat = stat && aDir.rmdir( thePath ); + } + return stat; +} + +/*! + \brief Add a slash (platform-specific) to the end of \a path + if it is not already there. + \param path directory path + \return modified path (with slash added to the end) */ QString Qtx::addSlash( const QString& path ) { - QString res = path; + QString res = path; if ( !res.isEmpty() && res.at( res.length() - 1 ) != QChar( '/' ) && - res.at( res.length() - 1 ) != QChar( '\\' ) ) + res.at( res.length() - 1 ) != QChar( '\\' ) ) res += QDir::separator(); return res; } /*! - Name: dos2unix [static public] - Desc: Convert text file. Replace symbols "LF/CR" by symbol "LF". + \brief Convert text file from DOS format to UNIX. + + The function replaces "LF/CR" symbols sequence by "LF" symbol. + + \param absName file name + \return \c true if the file is converted successfully and \c false in + case of any error */ -bool Qtx::dos2unix( const QString& absName ) -{ - FILE* src = ::fopen( absName, "rb" ); +bool Qtx::dos2unix( const QString& absName ) +{ + FILE* src = ::fopen( absName.toLatin1(), "rb" ); if ( !src ) - return false; + return false; /* we'll use temporary file */ - char temp[512] = { '\0' }; + char temp[512] = { '\0' }; QString dir = Qtx::dir( absName ); - FILE* tgt = ::fopen( strcpy( temp, ::tempnam( dir, "__x" ) ), "wb" ); + FILE* tgt = ::fopen( strcpy( temp, ::tempnam( dir.toLatin1(), "__x" ) ), "wb" ); if ( !tgt ) - return false; + return false; /* temp -> result of conversion */ const char CR = 0x0d; - const char LF = 0x0a; - bool waitingLF = false; + const char LF = 0x0a; + bool waitingLF = false; while( true ) - { + { int outcnt = 0; char inbuf[512], outbuf[512]; - + /* convert buffer */ int nbread = ::fread( inbuf, 1, sizeof( inbuf ), src ); for ( int incnt = 0; incnt < nbread; incnt++ ) - { + { if ( waitingLF ) { waitingLF = false; if ( inbuf[incnt] == LF ) outbuf[outcnt++] = LF; - else + else outbuf[outcnt++] = CR; } else if ( inbuf[incnt] == CR ) @@ -443,7 +582,7 @@ bool Qtx::dos2unix( const QString& absName ) if ( nbwri != outcnt ) { ::fclose( src ); - ::fclose( tgt ); + ::fclose( tgt ); QFile::remove( QString( temp ) ); return false; } @@ -451,7 +590,7 @@ bool Qtx::dos2unix( const QString& absName ) break; /* converted ok */ } ::fclose( src ); - ::fclose( tgt ); + ::fclose( tgt ); /* rename temp -> src */ if ( !QFile::remove( absName ) ) @@ -461,8 +600,151 @@ bool Qtx::dos2unix( const QString& absName ) } /*! - Name: rgbSet [static public] - Desc: Pack the specified color into one integer RGB set. + \brief Create path completer which can be used in the widgets + to provide auto completions. + + Create an instance of QCompleter class and returns the pointer on it. + The calling function is responsible to the desstroying of the created + completer object. + + The QCompleter class provides completions based on a item model and can be + used in such as QLineEdit and QComboBox. + When the user starts typing a word, QCompleter suggests possible ways of + completing the word, based on a word list. + + \param type path type (Qtx::PathType) + \param filter file/directory filters (list of wildcards, separated by ";;") + \return a pointer to the created completer +*/ +QCompleter* Qtx::pathCompleter( const PathType type, const QString& filter ) +{ + QStringList extList; + QStringList filterList = filter.split( ";;" ); + for ( QStringList::const_iterator it = filterList.begin(); it != filterList.end(); ++it ) + { + QRegExp rx( "[\\s\\w,;]*\\(?\\*\\.([\\w]+)\\)?[\\d\\s\\w]*" ); + int index = 0; + while ( ( index = rx.indexIn( *it, index ) ) != -1 ) + { + extList.append( QString( "*.%1" ).arg( rx.cap( 1 ) ) ); + index += rx.matchedLength(); + } + } + + QDir::Filters filters = 0; + switch ( type ) + { + case PT_OpenFile: + case PT_SaveFile: + filters = QDir::AllEntries | QDir::AllDirs | QDir::NoDotAndDotDot; + break; + case PT_Directory: + filters = QDir::Drives | QDir::Dirs | QDir::NoDotAndDotDot; + break; + } + + QDirModel* dm = new QDirModel( extList, filters, QDir::Unsorted ); + QCompleter* cmp = new QCompleter( dm, 0 ); + dm->setParent( cmp ); + + return cmp; +} + +/*! + \brief Parse given string to retrieve environment variable. + + Looks through the string for the environment variable patterns. + If string contains variable satisfying any pattern, the variable name + is returned, start index of the variable is returned in the \a start parameter, + and length of the variable is returned in the \a len parameter. + + Supported environment variables definitions: + - ${name} or $name : Linux shell variable + - $(name) : GNU make substitution + - %name% : Windows shell variable + - %(name)s : Python substitutions: + + \param str string being processed + \param start if variable is found, this parameter contains its starting + position in the \a str + \param len if variable is found, this parameter contains its length + \return first found variable or null QString if there is no ones +*/ +QString Qtx::findEnvVar( const QString& str, int& start, int& len ) +{ + QString varName; + len = 0; + + QStringList rxList; + rxList << "\\$\\{([a-zA-Z][a-zA-Z_0-9]*)\\}"; // ${name} + rxList << "\\$([a-zA-Z][a-zA-Z_0-9]*)"; // $name + rxList << "\\$\\(([a-zA-Z][a-zA-Z_0-9]*)\\)"; // $(name) + rxList << "%([a-zA-Z][a-zA-Z0-9_]*)%"; // %name% + rxList << "%\\(([a-zA-Z][a-zA-Z_0-9]*)\\)s"; // %(name)s + + for ( int i = 0; i < rxList.count() && varName.isEmpty(); ++i ) + { + QRegExp rx(rxList[i]); + int pos = rx.indexIn( str, start ); + if ( pos != -1 ) + { + varName = rx.cap( 1 ); + start = pos; + len = rx.matchedLength(); + } + } + return varName; +} + +/*! + \brief Substitute environment variables by their values. + + Environment variable is substituted by its value. + + \param str string to be processed + \return processed string (with all substitutions made) +*/ +QString Qtx::makeEnvVarSubst( const QString& str, const SubstMode mode ) +{ + QString res = str; + if ( mode != Never ) + { + QMap ignoreMap; + + int start( 0 ), len( 0 ); + while ( true ) + { + QString envName = findEnvVar( res, start, len ); + if ( envName.isNull() ) + break; + + QString newStr; + if ( ::getenv( envName.toLatin1() ) || mode == Always ) + newStr = QString( ::getenv( envName.toLatin1() ) ); + + if ( newStr.isNull() ) + { + if ( ignoreMap.contains( envName ) ) + { + start += len; + continue; + } + ignoreMap.insert( envName, 0 ); + } + res.replace( start, len, newStr ); + } + + res.replace( "$$", "$" ); + res.replace( "%%", "%" ); + } + + return res; +} + +/*! + \brief Pack the specified color into integer RGB set. + \param c unpacked color + \return packed color */ int Qtx::rgbSet( const QColor& c ) { @@ -470,8 +752,11 @@ int Qtx::rgbSet( const QColor& c ) } /*! - Name: rgbSet [static public] - Desc: Pack the specified color components into one integer RGB set. + \brief Pack the specified RGB color components into integer RGB set. + \param r red component + \param g green component + \param b blue component + \return packed color */ int Qtx::rgbSet( const int r, const int g, const int b ) { @@ -479,19 +764,23 @@ int Qtx::rgbSet( const int r, const int g, const int b ) } /*! - Name: rgbSet [static public] - Desc: Unpack the specified integer RGB set into the color. + \brief Unpack the specified integer RGB set to the color. + \param rgb packed color + \return unpacked color (QColor) */ -void Qtx::rgbSet( const int rgb, QColor& c ) +QColor Qtx::rgbSet( const int rgb ) { int r, g, b; rgbSet( rgb, r, g, b ); - c = QColor( r, g, b ); + return QColor( r, g, b ); } /*! - Name: rgbSet [static public] - Desc: Unpack the specified integer RGB set into the color components. + \brief Unpack the specified integer RGB set to the three RGB components. + \param rgb packed color + \param r returned unpacked red component + \param g returned unpacked green component + \param b returned unpacked blue component */ void Qtx::rgbSet( const int rgb, int& r, int& g, int& b ) { @@ -501,8 +790,11 @@ void Qtx::rgbSet( const int rgb, int& r, int& g, int& b ) } /*! - Name: scaleColor [static public] - Desc: Returns the color specified by the index between min (blue) and max (red). + \brief Return the color specified by the index between min (blue) and max (red). + \param index color index + \param min required minimum hue value + \param max required maximum hue value + \return resulting color */ QColor Qtx::scaleColor( const int index, const int min, const int max ) { @@ -510,7 +802,7 @@ QColor Qtx::scaleColor( const int index, const int min, const int max ) int hue = HUE[0]; - if ( min != max ) + if ( min != max ) { double aPosition = 9.0 * ( index - min ) / ( max - min ); if ( aPosition > 0.0 ) @@ -525,16 +817,1419 @@ QColor Qtx::scaleColor( const int index, const int min, const int max ) } } - return QColor( hue, 255, 255, QColor::Hsv ); + return QColor::fromHsv( hue, 255, 255 ); } /*! - Name: scaleColors [static public] - Desc: Returns the 'num' number of colors from blue to red. + \brief Generate required number of colors aligned from blue to red. + \param num required number of colors + \param lst returned set of colors */ -void Qtx::scaleColors( const int num, QValueList& lst ) +void Qtx::scaleColors( const int num, QColorList& lst ) { lst.clear(); for ( int i = 0; i < num; i++ ) lst.append( scaleColor( i, 0, num - 1 ) ); } + +/*! + \brief Scale the pixmap to the required size. + + If \a h is 0 (default) the value of \a w is used instead (to create + square pixmap). + + \param icon pixmap to be resized + \param w required pixmap width + \param h required pixmap height + \return scaled pixmap +*/ +QPixmap Qtx::scaleIcon( const QPixmap& icon, const unsigned w, const unsigned h ) +{ + QPixmap p; + int aw = w, ah = h <= 0 ? w : h; + if ( icon.isNull() || aw <= 0 || ah <= 0 || ( aw == icon.width() && ah == icon.height() ) ) + p = icon; + else + p = icon.fromImage( icon.toImage().scaled( aw, ah, Qt::KeepAspectRatio, Qt::SmoothTransformation ) ); + return p; +} + +/*! + \brief Convert given image to the grayscale format. + \param img initial image + \return converted to the grayscale image +*/ +QImage Qtx::grayscale( const QImage& img ) +{ + QImage res = img; + + int colNum = res.colorCount(); + if ( colNum ) + { + for ( int i = 0; i < colNum; i++ ) + res.setColor( i, qGray( res.color( i ) ) ); + } + else + { + for ( int y = 0; y < res.height(); y++ ) + { + for ( int x = 0; x < res.width(); x++ ) + { + QRgb pix = res.pixel( x, y ); + res.setPixel( x, y, qRgba( qGray( pix ), qGray( pix ), qGray( pix ), qAlpha( pix ) ) ); + } + } + } + + return res; +} + +/*! + \brief Convert given pixmap to the grayscale format. + \param pix initial pixmap + \return converted to the grayscale pixmap +*/ +QPixmap Qtx::grayscale( const QPixmap& pix ) +{ + QPixmap res; + res.fromImage( grayscale( pix.toImage() ) ); + return res; +} + +/*! + \brief Create transparent image. + \param w required image width + \param h required image height + \param d required image depth + \return generated image +*/ +QImage Qtx::transparentImage( const int w, const int h, const int d ) +{ + QImage::Format fmt; + switch ( d ) + { + case 1: + fmt = QImage::Format_Mono; + break; + case 8: + fmt = QImage::Format_Indexed8; + break; + case 16: + case 24: + case 32: + default: + fmt = QImage::Format_ARGB32; + break; + } + + QImage img( w, h, fmt ); + if ( !img.isNull() ) + { +// img.setAlphaBuffer( true ); + for ( int i = 0; i < img.height(); i++ ) + for ( int j = 0; j < img.width(); j++ ) + img.setPixel( j, i, qRgba( 0, 0, 0, 0 ) ); + } + return img; +} + +/*! + \brief Create transparent pixmap. + \param w required image width + \param h required pixmap height + \param d required pixmap depth + \return generated pixmap +*/ +QPixmap Qtx::transparentPixmap( const int w, const int h, const int d ) +{ + QPixmap pix; + QImage img = transparentImage( w, h, d ); + if ( !img.isNull() ) + pix.fromImage( img ); + return pix; +} + +/*! + \brief Create composite pixmap. + + Pixmap \a pix is drawn over pixmap \a dest with coordinates + specified relatively to the upper left corner of \a dest. + If \a dest is not given, the new empty pixmap with appropriate size created instead. + + \param pix source pixmap + \param x horizontal shift + \param y vertical shift + \param dest background pixmap + \return resulting pixmap +*/ +QPixmap Qtx::composite( const QPixmap& pix, const int x, const int y, const QPixmap& dest ) +{ + if ( pix.isNull() ) + return dest; + + int width = qMax( pix.width() + x, dest.width() ); + int height = qMax( pix.height() + y, dest.height() ); + + QPixmap res( width, height ); + QImage img = transparentImage( width, height, 32 ); + + QPainter p; + p.begin( &res ); + p.fillRect( 0, 0, width, height, QBrush( Qt::white ) ); + + if ( !dest.isNull() ) + { + p.drawPixmap( 0, 0, dest ); + QImage temp = dest.toImage(); + for ( int i = 0; i < temp.width() && i < img.width(); i++ ) + { + for ( int j = 0; j < temp.height() && j < img.height(); j++ ) + { + if ( temp.hasAlphaChannel() ) + img.setPixel( i, j, temp.pixel( i, j ) ); + else + { + QRgb p = temp.pixel( i, j ); + img.setPixel( i, j, qRgba( qRed( p ), qGreen( p ), qBlue( p ), 255 ) ); + } + } + } + } + + p.drawPixmap( x, y, pix ); + QImage temp = pix.toImage(); + for ( int c = x; c < temp.width() + x && c < img.width(); c++ ) + { + for ( int r = y; r < temp.height() + y && r < img.height(); r++ ) + { + if ( qAlpha( temp.pixel( c - x, r - y ) ) > 0 ) + img.setPixel( c, r, temp.pixel( c - x, r - y ) ); + } + } + + p.end(); + + for ( int ai = 0; ai < img.width(); ai++ ) + { + for ( int aj = 0; aj < img.height(); aj++ ) + { + if ( qAlpha( img.pixel( ai, aj ) ) < 1 ) + img.setPixel( ai, aj, qRgba( 255, 255, 255, 255 ) ); + else + img.setPixel( ai, aj, qRgba( 0, 0, 0, 0 ) ); + } + } + + QBitmap bmp( width, height ); + bmp.fromImage( img, Qt::ColorMode_Mask | Qt::ThresholdDither ); + res.setMask( bmp ); + + return res; +} + +/*! + \brief Convert color to the string representation. + + The resulting string is in the one of two possible formats + (\c RR, \c GG, \c BB and \c AA value represent red, green, blue + and alpha components of the color): + - if color has alpha channel : "#RR,#GG,#BB,#AA" + - if color does not have alpha channel : "#RRGGBB" + + If color is invalid, null string is returned. + + Backward conversion can be done with stringToColor() method. + + \param color color to be converted + \return string representation of the color + + \sa stringToColor() +*/ +QString Qtx::colorToString( const QColor& color ) +{ + QString str; + if ( color.isValid() ) + { + if ( color.alpha() != 255 ) + { + QStringList vals; + vals << QString( "#%1" ).arg( color.red(), 0, 16 ); + vals << QString( "#%1" ).arg( color.green(), 0, 16 ); + vals << QString( "#%1" ).arg( color.blue(), 0, 16 ); + vals << QString( "#%1" ).arg( color.alpha(), 0, 16 ); + str = vals.join( "," ); + } + else + { + str = color.name(); + } + } + return str; +} + +/*! + \brief Create color from the string representation. + + The parameter \a str must be in the one of following formats + (\c RR, \c GG, \c BB and \c AA value represent red, green, blue + and alpha components of the color): + - "#RR,#GG,#BB[,#AA]" or "#RR #GG #BB[ #AA]" (\c RR, \c GG, \c BB + and optional \c AA values represent red, green, blue and alpha + components of the color in hexadecimal form) + - "RR,GG,BB[,AA]" or "RR GG BB[ AA]" (\c RR, \c GG, \c BB + and optional \c AA values represent red, green, blue and alpha + components of the color in decimal form) + - "#RRGGBB" - (\c RR, \c GG and \c BB values represent red, green and blue + components of the color in hexadecimal form) + - an integer value representing packed color components (see rgbSet()) + - a name from the list of colors defined in the list of SVG color keyword names + provided by the World Wide Web Consortium; for example, "steelblue" or "gainsboro". + + Backward conversion can be done with colorToString() method. + + \param str string representation of the color + \param color resulting color value + \return \c true if the conversion is successful and \c false otherwise + + \sa colorToString(), rgbSet() +*/ +bool Qtx::stringToColor( const QString& str, QColor& color ) +{ + bool res = true; + QStringList vals = str.split( QRegExp( "[\\s|,]" ), QString::SkipEmptyParts ); + + QIntList nums; + for ( QStringList::const_iterator it = vals.begin(); it != vals.end() && res; ++it ) + { + int num = 0; + if ( (*it).startsWith( "#" ) ) + num = (*it).mid( 1 ).toInt( &res, 16 ); + else + num = (*it).toInt( &res, 10 ); + if ( res ) + nums.append( num ); + } + + res = res && nums.count() >= 3; + if ( res ) + color.setRgb( nums[0], nums[1], nums[2] ); + + if ( !res ) + { + int pack = str.toInt( &res ); + if ( res ) + color = Qtx::rgbSet( pack ); + } + + if ( !res ) + { + color = QColor( str ); + res = color.isValid(); + } + + return res; +} + +/*! + \brief Convert bi-color value to the string representation. + + Bi-color value is specified as main color and integer delta + value that is used to calculate secondary color by changing + paremeters of the main color ("saturation" and "value" + components in HSV notation). + + The resulting string consists of two sub-strings separated by + '|' symbol. The first part represents main color + (see colorToString() for more details), the second part is a + delta value. + + Backward conversion can be done with stringToBiColor() method. + + \param color color to be converted + \param delta delta value + \return string representation of the bi-color value + + \sa stringToBiColor(), stringToColor() +*/ +QString Qtx::biColorToString( const QColor& color, const int delta ) +{ + return QString("%1|%2").arg( Qtx::colorToString( color ) ).arg( delta ); +} + +/*! + \brief Restore bi-color value from the string representation. + + Bi-color value is specified as main color and integer delta + value that is used to calculate secondary color by changing + paremeters of the main color ("saturation" and "value" + components in HSV notation). + + The parameter \a str should consist of two sub-strings separated + by '|' symbol. The first part represents main color + (see stringToColor() for more details), the second part is a + delta value. + + Backward conversion can be done with biColorToString() method. + + \param str string representation of the bi-color value + \param color resulting color value + \param delta resulting delta value + \return \c true if the conversion is successful and \c false otherwise + + \sa biColorToString(), stringToColor(), rgbSet() +*/ +bool Qtx::stringToBiColor( const QString& str, QColor& color, int& delta ) +{ + QStringList data = str.split( "|", QString::KeepEmptyParts ); + QColor c; + int d = 0; + bool ok = data.count() > 0 && Qtx::stringToColor( data[0], c ); + bool dok = false; + if ( data.count() > 1 ) d = data[1].toInt( &dok ); + ok = ok && dok; + color = ok ? c : QColor(); + delta = ok ? d : 0; + return ok; +} + +/*! + \brief Compute secondary color value from specified main color + and delta. + + Secondary color is calculated by changing paremeters of the main + color ("saturation" and "value" components in HSV notation) using + specified delta. + + If main color is invalid, result of the function is also invalid color. + + \param color source main color + \param delta delta value + \return resulting secondary color + + \sa biColorToString(), stringToBiColor() +*/ +QColor Qtx::mainColorToSecondary( const QColor& color, int delta ) +{ + QColor cs = color; + if ( cs.isValid() ) { + int val = qMin( 255, qMax( cs.value() + delta, 0 ) ); + int sat = qMin( 255, qMax( cs.saturation() + delta-(val-cs.value()), 0 ) ); +#ifdef BICOLOR_CHANGE_HUE + const int BICOLOR_HUE_MAXDELTA = 40; + int dh = delta-(val-cs.value())-(sat-cs.saturation()); + dh = qMin( BICOLOR_HUE_MAXDELTA, qAbs( dh ) ) * ( dh > 0 ? 1 : -1 ); + //int hue = qMin( 359, qMax( cs.hue() + delta-(val-cs.value())-(sat-cs.saturation()), 0 ) ); + //int hue = qMin( 359, qMax( cs.hue() + delta-(val-cs.value())-ds, 0 ) ); + int hue = cs.hue() + dh; + if ( hue < 0 ) hue = 360 - hue; +#else + int hue = cs.hue(); +#endif + cs.setHsv( hue, sat, val ); + } + return cs; +} + +/*! + \brief Dump linear gradient to the string description. + \param gradient linear gradient to be converted + \return string representation of the linear gradient + \sa stringToLinearGradient() +*/ +QString Qtx::gradientToString( const QLinearGradient& gradient ) +{ + QStringList data; + data << "linear"; + data << QString::number( gradient.start().x() ); + data << QString::number( gradient.start().y() ); + data << QString::number( gradient.finalStop().x() ); + data << QString::number( gradient.finalStop().y() ); + switch( gradient.spread() ) + { + case QGradient::PadSpread: + data << "pad"; + break; + case QGradient::RepeatSpread: + data << "repeat"; + break; + case QGradient::ReflectSpread: + data << "reflect"; + break; + default: + break; + } + QGradientStops stops = gradient.stops(); + QGradientStop stop; + foreach ( stop, stops ) + { + data << QString::number( stop.first ); + data << colorToString( stop.second ); + } + return data.join( "|" ); +} + +/*! + \brief Dump radial gradient to the string description. + \param gradient radial gradient to be converted + \return string representation of the radial gradient + \sa stringToRadialGradient() +*/ +QString Qtx::gradientToString( const QRadialGradient& gradient ) +{ + QStringList data; + data << "radial"; + data << QString::number( gradient.center().x() ); + data << QString::number( gradient.center().y() ); + data << QString::number( gradient.focalPoint().x() ); + data << QString::number( gradient.focalPoint().y() ); + data << QString::number( gradient.radius() ); + switch( gradient.spread() ) + { + case QGradient::PadSpread: + data << "pad"; + break; + case QGradient::RepeatSpread: + data << "repeat"; + break; + case QGradient::ReflectSpread: + data << "reflect"; + break; + default: + break; + } + QGradientStops stops = gradient.stops(); + QGradientStop stop; + foreach ( stop, stops ) + { + data << QString::number( stop.first ); + data << colorToString( stop.second ); + } + return data.join( "|" ); +} + +/*! + \brief Dump conical gradient to the string description. + \param gradient conical gradient to be converted + \return string representation of the conical gradient + \sa stringToConicalGradient() +*/ +QString Qtx::gradientToString( const QConicalGradient& gradient ) +{ + QStringList data; + data << "conical"; + data << QString::number( gradient.center().x() ); + data << QString::number( gradient.center().y() ); + data << QString::number( gradient.angle() ); + switch( gradient.spread() ) + { + case QGradient::PadSpread: + data << "pad"; + break; + case QGradient::RepeatSpread: + data << "repeat"; + break; + case QGradient::ReflectSpread: + data << "reflect"; + break; + default: + break; + } + QGradientStops stops = gradient.stops(); + QGradientStop stop; + foreach ( stop, stops ) + { + data << QString::number( stop.first ); + data << colorToString( stop.second ); + } + return data.join( "|" ); +} + +/*! + \brief Create linear gradient from its string representation. + \param str string representation of the linear gradient + \param gradient resulting linear gradient object + \return \c true if the conversion is successful and \c false otherwise + \sa gradientToString() +*/ +bool Qtx::stringToLinearGradient( const QString& str, QLinearGradient& gradient ) +{ + bool success = false; + QStringList vals = str.split( "|", QString::SkipEmptyParts ); + if ( vals.count() > 4 && ( vals[0] == "linear" || vals[0] == "lg" ) ) + { + // start and end points + double x1, y1, x2, y2; + bool bOk1, bOk2, bOk3, bOk4; + x1 = vals[1].toDouble( &bOk1 ); + y1 = vals[2].toDouble( &bOk2 ); + x2 = vals[3].toDouble( &bOk3 ); + y2 = vals[4].toDouble( &bOk4 ); + if ( bOk1 && bOk2 && bOk3 && bOk4 ) + { + gradient = QLinearGradient( x1, y1, x2, y2 ); + // spread type + if ( vals.count() > 5 ) + { + QString spread = vals[ 5 ].trimmed().toLower(); + if ( spread == "pad" || spread == "0" ) + gradient.setSpread( QGradient::PadSpread ); + else if ( spread == "repeat" || spread == "2" ) + gradient.setSpread( QGradient::RepeatSpread ); + else if ( spread == "reflect" || spread == "1" ) + gradient.setSpread( QGradient::ReflectSpread ); + } + // stop points + QGradientStops stops; + for ( int i = 6; i < vals.count(); i+=2 ) + { + bool bOk5, bOk6 = false; + QColor c; + double stop = vals[i].toDouble( &bOk5 ); + if ( i+1 < vals.count() ) + bOk6 = stringToColor( vals[ i+1 ], c ); + if ( bOk5 && stop >= 0.0 && stop <= 1.0 && bOk6 && c.isValid() ) + stops.append( QGradientStop( stop, c ) ); + } + gradient.setStops( stops ); + success = true; + } + } + return success; +} + +/*! + \brief Create radial gradient from its string representation. + \param str string representation of the radial gradient + \param gradient resulting radial gradient object + \return \c true if the conversion is successful and \c false otherwise + \sa gradientToString() +*/ +bool Qtx::stringToRadialGradient( const QString& str, QRadialGradient& gradient ) +{ + bool success = false; + QStringList vals = str.split( "|", QString::SkipEmptyParts ); + if ( vals.count() > 5 && ( vals[0] == "radial" || vals[0] == "rg" ) ) + { + // center, radius and focal point + double cx, cy, r, fx, fy; + bool bOk1, bOk2, bOk3, bOk4, bOk5; + cx = vals[1].toDouble( &bOk1 ); + cy = vals[2].toDouble( &bOk2 ); + fx = vals[3].toDouble( &bOk4 ); + fy = vals[4].toDouble( &bOk5 ); + r = vals[5].toDouble( &bOk3 ); + if ( bOk1 && bOk2 && bOk3 && bOk4 && bOk5 ) + { + gradient = QRadialGradient( cx, cy, r, fx, fy ); + // spread type + if ( vals.count() > 6 ) + { + QString spread = vals[ 6 ].trimmed().toLower(); + if ( spread == "pad" || spread == "0" ) + gradient.setSpread( QGradient::PadSpread ); + else if ( spread == "repeat" || spread == "2" ) + gradient.setSpread( QGradient::RepeatSpread ); + else if ( spread == "reflect" || spread == "1" ) + gradient.setSpread( QGradient::ReflectSpread ); + } + // stop points + QGradientStops stops; + for ( int i = 7; i < vals.count(); i+=2 ) + { + bool bOk7, bOk8 = false; + QColor c; + double stop = vals[i].toDouble( &bOk7 ); + if ( i+1 < vals.count() ) + bOk8 = stringToColor( vals[ i+1 ], c ); + if ( bOk7 && stop >= 0.0 && stop <= 1.0 && bOk8 && c.isValid() ) + stops.append( QGradientStop( stop, c ) ); + } + gradient.setStops( stops ); + success = true; + } + } + return success; +} + +/*! + \brief Create conical gradient from its string representation. + \param str string representation of the conical gradient + \param gradient resulting conical gradient object + \return \c true if the conversion is successful and \c false otherwise + \sa gradientToString() +*/ +bool Qtx::stringToConicalGradient( const QString& str, QConicalGradient& gradient ) +{ + bool success = false; + QStringList vals = str.split( "|", QString::SkipEmptyParts ); + if ( vals.count() > 3 && ( vals[0] == "conical" || vals[0] == "cg" ) ) + { + // center and angle + double cx, cy, a; + bool bOk1, bOk2, bOk3; + cx = vals[1].toDouble( &bOk1 ); + cy = vals[2].toDouble( &bOk2 ); + a = vals[3].toDouble( &bOk3 ); + if ( bOk1 && bOk2 && bOk3 ) + { + gradient = QConicalGradient( cx, cy, a ); + // spread type + if ( vals.count() > 4 ) + { + QString spread = vals[ 4 ].trimmed().toLower(); + if ( spread == "pad" || spread == "0" ) + gradient.setSpread( QGradient::PadSpread ); + else if ( spread == "repeat" || spread == "2" ) + gradient.setSpread( QGradient::RepeatSpread ); + else if ( spread == "reflect" || spread == "1" ) + gradient.setSpread( QGradient::ReflectSpread ); + } + // stop points + QGradientStops stops; + for ( int i = 5; i < vals.count(); i+=2 ) + { + bool bOk4, bOk5 = false; + QColor c; + double stop = vals[i].toDouble( &bOk4 ); + if ( i+1 < vals.count() ) + bOk5 = stringToColor( vals[ i+1 ], c ); + if ( bOk4 && stop >= 0.0 && stop <= 1.0 && bOk5 && c.isValid() ) + stops.append( QGradientStop( stop, c ) ); + } + gradient.setStops( stops ); + success = true; + } + } + return success; +} + +/*! + \brief Convert background data to the string representation. + The resulting string consists of several sub-strings separated by ';' symbol. + These sub-strings represent: + 1. background type (enumerator, see Qtx::BackgroundMode) + 2. texture image file name (string) + 3. texture mode (enumerator, see Qtx::TextureMode) + 4. "show texture" flag (boolean) + 5. first color (for simple gradient data) or solid color (for single-colored mode) + 6. second color (for simple gradient data) + 7. type of simple gradient (some integer identifier) + 8. complex gradient data (for custom gradient mode) + Each sub-string consists of keyword/value couple, in form of "=". + + Backward conversion can be done with stringToBackground() method. + + \param bgData background data + \return string representation of the background data + + \sa stringToBackground() +*/ +QString Qtx::backgroundToString( const Qtx::BackgroundData& bgData ) +{ + const QString dtSep = ";"; + const QString kwSep = "="; + const QString kwBgType = "bt"; + const QString kwFileName = "fn"; + const QString kwTextureMode = "tm"; + const QString kwShowTexture = "ts"; + const QString kwFirstColor = "c1"; + const QString kwSecondColor = "c2"; + const QString kwGrType = "gt"; + const QString kwGrData = "gr"; + + Qtx::BackgroundMode bgMode = bgData.mode(); + QString fileName; + Qtx::TextureMode textureMode = bgData.texture( fileName ); + bool showTexture = bgData.isTextureShown(); + QColor c1, c2; + int gradientType = bgData.gradient( c1, c2 ); + const QGradient* gradient = bgData.gradient(); + QString grString; + if ( gradient ) { + switch ( gradient->type() ) { + case QGradient::LinearGradient: + grString = gradientToString( *(static_cast( gradient )) ); + break; + case QGradient::RadialGradient: + grString = gradientToString( *(static_cast( gradient )) ); + break; + case QGradient::ConicalGradient: + grString = gradientToString( *(static_cast( gradient )) ); + break; + default: + break; + } + } + QStringList data; + data << QString( "%1%2%3" ).arg( kwBgType ).arg( kwSep ).arg( (int)bgMode ); + data << QString( "%1%2%3" ).arg( kwFileName ).arg( kwSep ).arg( fileName ); + data << QString( "%1%2%3" ).arg( kwTextureMode ).arg( kwSep ).arg( (int)textureMode ); + data << QString( "%1%2%3" ).arg( kwShowTexture ).arg( kwSep ).arg( showTexture ? "true" : "false" ); + data << QString( "%1%2%3" ).arg( kwFirstColor ).arg( kwSep ).arg( Qtx::colorToString( c1 ) ); + data << QString( "%1%2%3" ).arg( kwSecondColor ).arg( kwSep ).arg( Qtx::colorToString( c2 ) ); + data << QString( "%1%2%3" ).arg( kwGrType ).arg( kwSep ).arg( gradientType ); + data << QString( "%1%2%3" ).arg( kwGrData ).arg( kwSep ).arg( grString ); + + return data.join( dtSep ); +} + +/*! + \brief Restore background data from the string representation. + + The string should consist of several sub-strings separated by ';' symbol. + Each sub-string consists of keyword/value couple, in form of "=". + The sub-strings can follow in arbitrary order, some keywords can be missing. + The background data is described by the following values: + - background type (enumerator, see Qtx::BackgroundMode), keyword "bt" + - texture image file name (string), keyword "fn" + - texture mode (enumerator, see Qtx::TextureMode), keyword "tm" + - "show texture" flag (boolean), keyword "ts" + - first color (for simple gradient data) or solid color (for single-colored mode), keyword "c1" + - second color (for simple gradient data), keyword "c2" + - name of gradient type (string), keyword "gt" + - complex gradient data (for custom gradient mode), keyword "gr" + + Also, for backward compatibility, background data can be represented by + single color value, see stringToColor(). + + Backward conversion can be done with backgroundToString() method. + Returns invalid background if conversion could not be done. + + \code + Qtx::BackgroundData bgData = Qtx::stringToBackground( str ); + if ( bgData.isValid() ) ) doSomething( bgData ); + \endcode + + \param theString string representation of the background data + \return resulting background data (invalid if conversion has failed) + + \sa backgroundToString() +*/ + +Qtx::BackgroundData Qtx::stringToBackground( const QString& str ) +{ + const QString dtSep = ";"; + const QString kwSep = "="; + const QString kwBgType = "bt"; + const QString kwFileName = "fn"; + const QString kwTextureMode = "tm"; + const QString kwShowTexture = "ts"; + const QString kwFirstColor = "c1"; + const QString kwSecondColor = "c2"; + const QString kwGrType = "gt"; + const QString kwGrData = "gr"; + + Qtx::BackgroundData bgData = BackgroundData(); + + QStringList data = str.split( dtSep, QString::KeepEmptyParts ); + + QColor c; + if ( data.count() == 1 && !data.contains( kwSep ) && stringToColor( data[0], c ) ) { + // solid color mode, for backward compatibility + bgData.setColor( c ); + } + else { + QMap dmap; + // background data + foreach( QString d, data ) { + QStringList items = d.split( kwSep, QString::KeepEmptyParts ); + if ( items.count() > 0 ) { + QString kw = items.takeFirst().trimmed().toLower(); // keyword + QString val = items.join( kwSep ).trimmed(); // if value contains "=" symbol, we have to restore it + dmap[ kw ] = val; + } + } + QString bgMode = dmap.value( kwBgType, QString() ); + QString fileName = dmap.value( kwFileName, QString() ); + QString textureMode = dmap.value( kwTextureMode, QString() ); + QString showTexture = dmap.value( kwShowTexture, QString() ); + QString color1 = dmap.value( kwFirstColor, QString() ); + QString color2 = dmap.value( kwSecondColor, QString() ); + QString gradientType = dmap.value( kwGrType, QString() ); + QString gradient = dmap.value( kwGrData, QString() ); + + // texture data + if ( !fileName.isEmpty() || !textureMode.isEmpty() || !showTexture.isEmpty() ) { + Qtx::TextureMode m = (Qtx::TextureMode)( stringToInt( textureMode, Qtx::CenterTexture, + Qtx::CenterTexture, Qtx::StretchTexture ) ); + bgData.setTexture( fileName, m ); + QStringList boolvars; boolvars << "true" << "yes" << "ok" << "1"; + if ( boolvars.contains( showTexture.trimmed().toLower() ) ) + bgData.setTextureShown( true ); + } + QColor c1, c2; + // try color mode + bool ok = Qtx::stringToColor( color1, c1 ); + if ( ok ) { + bgData.setColor( c1 ); + } + // try simple gradient mode + ok = Qtx::stringToColor( color2, c2 ); + if ( ok || !gradientType.isEmpty() ) { + int gt = gradientType.toInt( &ok ); + bgData.setGradient( ok ? gt : -1, c1, c2 ); + } + // try custom gradient mode + QLinearGradient lg; + QConicalGradient cg; + QRadialGradient rg; + ok = Qtx::stringToLinearGradient( gradient, lg ); + if ( ok ) { + bgData.setGradient( lg ); + } + ok = Qtx::stringToRadialGradient( gradient, rg ); + if ( ok ) { + bgData.setGradient( rg ); + } + ok = Qtx::stringToConicalGradient( gradient, cg ); + if ( ok ) { + bgData.setGradient( cg ); + } + + // finally set background mode + Qtx::BackgroundMode m = (Qtx::BackgroundMode)( stringToInt( bgMode, Qtx::ColorBackground, + Qtx::NoBackground, Qtx::CustomGradientBackground ) ); + bgData.setMode( m ); + } + + return bgData; +} + +/*! + \class Qtx::Localizer + \brief Localization helper + + This helper class can be used to solve the localization problems, + usually related to the textual files reading/writing, namely when + floating point values are read / written with API functions. + The problem relates to such locale specific settings as decimal point + separator, thousands separator, etc. + + To use the Localizer class, just create a local variable in the beginning + of the code where you need to read / write data from textual file(s). + The constructor of the class forces setting "C" locale temporariy. + The destructor switches back to the initial locale. + + \code + Qtx::Localizer loc; + readSomething(); + writeSomething(); + \endcode +*/ + +/*! + \brief Constructor. Forces "C" locale to be set. +*/ +Qtx::Localizer::Localizer() +{ + myCurLocale = setlocale( LC_NUMERIC, 0 ); + setlocale( LC_NUMERIC, "C" ); +} + +/*! + \brief Destructor. Reverts back to the initial locale. +*/ +Qtx::Localizer::~Localizer() +{ + setlocale( LC_NUMERIC, myCurLocale.toLatin1().constData() ); +} + +/*! + \class Qtx::BackgroundData + \brief Stores background data + + This class is used to store background data. Depending on the mode, + the background can be specified by: + - image (by assigning the file name to be used as background texture), see setTexture(), setTextureShown() + - single color (by assigning any color), see setColor() + - simple two-color gradient (with the gradient type id and two colors), see setGradient( int, const QColor&, const QColor& ) + - complex gradient (by assigning arbitrary gradient data), see setGradient( const QGradient& ) + + The class stores all the data passed to it, so switching between different modes can be done + just by calling setMode() function. + + \note Texture is used with combination of the background mode. + + \note Two-color gradient is specified by two colors and integer identifier. The interpretation of + this identifier should be done in the calling code. + + \code + Qtx::BackgroundData bg; + bg.setColor( QColor(100, 100, 100) ); // bg is switched to Qtx::ColorBackground mode + bg.setGradient( Qt::Horizontal, Qt::gray, Qt::white ); // bg is switched to Qtx::ColorBackground mode + QLinearGradient grad( 0,0,1,1 ); + grad.setColorAt( 0.0, Qt::gray ); + grad.setColorAt( 0.5, Qt::white ); + grad.setColorAt( 1.0, Qt::green ); + grad.setSpread( QGradient::PadSpread ); + bg.setGradient( grad ); // bg is switched to Qtx::CustomGradientBackground mode + bg.setMode( Qtx::ColorBackground ); // bg is switched back to Qtx::ColorBackground mode + bg.setTexture( "/data/images/background.png" ); // specify texture (in the centered mode by default) + bg.setTextureShown( true ); // draw texture on the solid color background + \endcode +*/ + +/*! + \brief Default constructor. + Creates invalid background data. +*/ +Qtx::BackgroundData::BackgroundData() + : myTextureMode( Qtx::CenterTexture ), myGradientType( -1 ), myTextureShown( false ) +{ + setMode( Qtx::NoBackground ); +} + +/*! + \brief Constructor. + Creates background data initialized with the specified color + \param c color +*/ +Qtx::BackgroundData::BackgroundData( const QColor& c ) + : myTextureMode( Qtx::CenterTexture ), myGradientType( -1 ), myTextureShown( false ) +{ + setColor( c ); +} + +/*! + \brief Constructor. + Creates background data initialized with the specified two-color gradient + \param type gradient type identifier + \param c1 first gradient color + \param c2 second gradient color + \note the interpretation of the gradient identifier should be done in the calling code +*/ +Qtx::BackgroundData::BackgroundData( int type, const QColor& c1, const QColor& c2 ) + : myTextureMode( Qtx::CenterTexture ), myGradientType( -1 ), myTextureShown( false ) +{ + setGradient( type, c1, c2 ); +} + +/*! + \brief Constructor. + Creates background data initialized with the arbirtary gradient data + \param grad gradient data +*/ +Qtx::BackgroundData::BackgroundData( const QGradient& grad ) + : myTextureMode( Qtx::CenterTexture ), myGradientType( -1 ), myTextureShown( false ) +{ + setGradient( grad ); +} + +/*! + \brief Destructor. +*/ +Qtx::BackgroundData::~BackgroundData() +{ +} + +/*! + \brief Compares two background data objects +*/ +bool Qtx::BackgroundData::operator==( const Qtx::BackgroundData& other ) const +{ + return + ( myMode == other.myMode ) && + ( myTextureMode == other.myTextureMode ) && + ( myFileName == other.myFileName ) && + ( myColors == other.myColors ) && + ( myGradientType == other.myGradientType ) && + ( myGradient == other.myGradient ) && + ( myTextureShown == other.myTextureShown ); +} + +/*! + \brief Returns \c false if background data is not set (invalid) + \return \c true if background data is valid or \c false otherwise + \sa mode() +*/ +bool Qtx::BackgroundData::isValid() const +{ + return myMode != Qtx::NoBackground; +} + +/*! + \brief Get background mode + \return current background mode + \sa setMode() +*/ +Qtx::BackgroundMode Qtx::BackgroundData::mode() const +{ + return myMode; +} + +/*! + \brief Set background mode + \param m background mode being set + \sa mode() +*/ +void Qtx::BackgroundData::setMode( const Qtx::BackgroundMode m ) +{ + myMode = m; +} + +/*! + \brief Get file name used as a texture image + \return path to the texture image file + \sa setTexture(), setTextureShown() +*/ +Qtx::TextureMode Qtx::BackgroundData::texture( QString& fileName ) const +{ + fileName = myFileName; + return myTextureMode; +} + +/*! + \brief Set file name to be used as a texture image. + + \note To show texture image on the background it is necessary to call additionally + setTextureShown() method. + + \param fileName path to the texture image file name + \param m texture mode (Qtx::CenterTexture by default) + \sa texture(), setTextureShown() +*/ +void Qtx::BackgroundData::setTexture( const QString& fileName, const Qtx::TextureMode m ) +{ + myFileName = fileName; + myTextureMode = m; +} + +/*! + \brief Check if "show texture" flag is switched on + \return \c true if "show texture" flag is set or \c false otherwise + \sa setTextureShown(), texture() +*/ +bool Qtx::BackgroundData::isTextureShown() const +{ + return myTextureShown; +} + +/*! + \brief Specify if texture should be shown on the background or no. + \param on \c true if texture should be shown or \c false otherwise + \sa isTextureShown(), texture() +*/ +void Qtx::BackgroundData::setTextureShown( bool on ) +{ + myTextureShown = on; +} + +/*! + \brief Get background color. Returns null QColor if color is not set + \return solid background color + \sa setColor(), mode() +*/ +QColor Qtx::BackgroundData::color() const +{ + return myColors.count() > 0 ? myColors[0] : QColor(); +} + +/*! + \brief Set background color and switch to the Qtx::ColorBackground mode + \param c color + \sa color(), mode() +*/ +void Qtx::BackgroundData::setColor( const QColor& c ) +{ + myColors.clear(); + myColors << c; + setMode( Qtx::ColorBackground ); +} + +/*! + \brief Get simple gradient data. + Returns -1 and null QColor for \a c1 and \a c2 if gradient data is not set + \param c1 first gradient color is returned via this parameter + \param c2 second gradient color is returned via this parameter + \return current two-colored gradient mode type identifier + \note the interpretation of the gradient identifier should be done in the calling code + \sa setGradient(int, const QColor&, const QColor&), mode() +*/ +int Qtx::BackgroundData::gradient( QColor& c1, QColor& c2 ) const +{ + c1 = myColors.count() > 0 ? myColors[0] : QColor(); + c2 = myColors.count() > 1 ? myColors[1] : ( myColors.count() > 0 ? myColors[0] : QColor() ); + return myGradientType; +} + +/*! + \brief Set simple background gradient data and switch to the Qtx::SimpleGradientBackground mode + \param type two-colored gradient mode type identifier + \param c1 first gradient color is returned via this parameter + \param c2 second gradient color is returned via this parameter + \note the interpretation of the gradient identifier should be done in the calling code + \sa gradient(QColor&, QColor&), mode() +*/ +void Qtx::BackgroundData::setGradient( int type, const QColor& c1, const QColor& c2 ) +{ + myColors.clear(); + myColors << c1 << c2; + myGradientType = type; + setMode( Qtx::SimpleGradientBackground ); +} + +/*! + \brief Get complex gradient data. + Returns QGradient of QGradient::NoGradient if gradient data is not set + \note This function does not transform simple gradient data set with + setGradient( const QString&, const QColor&, const QColor& ) to QGradient class + \return gradient data + \sa setGradient(const QGradient&), mode() +*/ +const QGradient* Qtx::BackgroundData::gradient() const +{ + return &myGradient; +} + +/*! + \brief Set complex background gradient data and switch to the Qtx::CustomGradientBackground mode + \param grad gradient data (QLinearGradient, QRadialGradient or QConicalGradient) + \sa gradient(), mode() +*/ +void Qtx::BackgroundData::setGradient( const QGradient& grad ) +{ + myGradient = grad; + setMode( Qtx::CustomGradientBackground ); +} + +/*! + \brief Convert string representation of version identifier to the numerical value. + Resulting value can be used for comparison of different versions (lower, higher, equal). + + String representation of the version consists of zero or more components: + + [major[.minor[.release[patchid]]]] + + where + - major is version major number + - minor is version minor number + - release is version release number + - patchid is a version dev identifier which is one of the following + * 1 letter optionally followed by 1 or 2 digits, e.g. "a" for "alpha", "b1" for "beta 1" + * "rc" optionally followed by 1 or 2 digits, e.g. "rc1" for "release candidate 1" + * "dev" for development version (note: 7.4.0dev > 7.4.0, 7.4.0dev < 7.4.1, 7.4.0dev < 7.4.0a1) + + If version string does not include any component or has invalid format, the function returns 0. + + Examples: + 1.0 - version 1.0 + 1.2.3a - version 1.2.3 alpha + 3.3.3b1 - version 3.3.3 beta 1 + 7.4.0rc1 - version 7.4.0 release candidate 1 + 7.4.0dev - dev version, i.e. future version 7.4.1 (or 7.5.0) + + \param version string representation of version + \return numerical identifier of the version +*/ +long Qtx::versionToId( const QString& version ) +{ + long id = 0; + + QRegExp vers_exp( "^([0-9]+)([A-Z]|RC|DEV)?([0-9]{0,2})$", Qt::CaseInsensitive ); + + QStringList vers = version.split( ".", QString::SkipEmptyParts ); + int major=0, minor=0; + int release = 0, dev1 = 0, dev2 = 0; + if ( vers.count() > 0 ) major = vers[0].toInt(); + if ( vers.count() > 1 ) minor = vers[1].toInt(); + if ( vers.count() > 2 ) { + if ( vers_exp.indexIn( vers[2] ) != -1 ) { + release = vers_exp.cap( 1 ).toInt(); + QString tag = vers_exp.cap( 2 ).toLower(); + if ( !tag.isEmpty() ) { + // patchid is subtracted from version number + // a = 55 --> -(55 * 100) + patch number --> 4500..4599, e.g. 7.4.1a1 -> 704004501 + // b = 54 --> -(54 * 100) + patch number --> 4600..4699, e.g. 7.4.1b1 -> 704004601 + // c = 53 --> -(53 * 100) + patch number --> 4700..4799, e.g. 7.4.1c1 -> 704004701 + // ... + // z = 30 --> -( 1 * 100) + patch number --> 7000..7099, e.g. 7.4.1z1 -> 704007001 + // rc = 1 --> -( 1 * 100) + patch number --> 9900..9999, e.g. 7.4.1rc1 -> 704009901 + // dev = -1 --> +( 1 * 100) + patch number --> 0100..0199, e.g. 7.4.1dev -> 704010100 + // --- + // i.e. "a" < "b" < ... < "z" < "rc" < [stable] < "dev" + if ( tag == "rc" ) + dev1 = 1; + else if ( tag == "dev" ) + dev1 = -1; + else + dev1 = (int)( QChar('z').toLatin1() ) - (int)( tag[ 0 ].toLatin1() ) + 30; + } + if ( !vers_exp.cap( 3 ).isEmpty() ) + dev2 = vers_exp.cap( 3 ).toInt(); + } + } + + int dev = dev1*100-dev2; + id = major; + id*=100; id+=minor; + id*=100; id+=release; + id*=10000; + id-=dev; + + return id; +} + +/*! + \brief Get Qt installation directory + + The function tries to detect qt installation directory by analyzing the system variables in the following order: + - QT5_ROOT_DIR + - QT4_ROOT_DIR + - QT_ROOT_DIR + - QTDIR + + Optional parameter \a context allows obtaining subdirectory in the Qt installation directory. + + \param context optional sub-directory + \return path to the Qt installation directory (or its sub-folder, if \a context is specified) +*/ + +QString Qtx::qtDir( const QString& context ) +{ + const char* vars[] = { "QT5_ROOT_DIR", "QT4_ROOT_DIR", "QT_ROOT_DIR", "QTDIR" }; + QString qtPath; + for (uint i = 0; i < sizeof(vars)/sizeof(vars[0]) && qtPath.isEmpty(); i++ ) + qtPath = qgetenv( vars[i] ); + if ( !qtPath.isEmpty() && !context.isEmpty() ) + qtPath = QDir( qtPath ).absoluteFilePath( context ); + return qtPath; +} + +/*! + Creates font from string description +*/ +QFont Qtx::stringToFont( const QString& fontDescription ) +{ + QFont font; + if ( fontDescription.trimmed().isEmpty() || !font.fromString( fontDescription ) ) + font = QFont( "Courier", 11 ); + return font; +} + +#if !defined WIN32 && !defined __APPLE__ + +#include +#include + +/*! + \brief Open the default X display and returns pointer to it. + This method is available on Linux only. + \return Pointer to X display. + \sa getVisual() +*/ +void* Qtx::getDisplay() +{ + static Display* pDisplay = NULL; + if ( !pDisplay ) + pDisplay = XOpenDisplay( NULL ); + return pDisplay; +} + +/*! + \brief Returns pointer to X visual suitable for 3D rendering. + This method is available on Linux only. + \return Pointer to X visual. + \sa getDisplay() +*/ +Qt::HANDLE Qtx::getVisual() +{ + Qt::HANDLE res = (Qt::HANDLE)NULL; + + Display* pDisplay = (Display*)getDisplay(); + if ( !pDisplay ) + return res; + + int errorBase; + int eventBase; + + // Make sure OpenGL's GLX extension supported + if( !glXQueryExtension( pDisplay, &errorBase, &eventBase ) ){ + qCritical( "Could not find glx extension" ); + return res; + } + + // Find an appropriate visual + + int doubleBufferVisual[] = { + GLX_RGBA, // Needs to support OpenGL + GLX_DEPTH_SIZE, 16, // Needs to support a 16 bit depth buffer + GLX_DOUBLEBUFFER, // Needs to support double-buffering + GLX_STEREO, // Needs to support stereo rendering + GLX_STENCIL_SIZE, 1, + None // end of list + }; + + // Try for the double-bufferd visual first + XVisualInfo *visualInfo = NULL; + visualInfo = glXChooseVisual( pDisplay, DefaultScreen(pDisplay), doubleBufferVisual ); + + if( visualInfo == NULL ){ + qCritical( "Could not find matching glx visual" ); + return res; + } + + qDebug() << "Picked visual 0x" << hex << XVisualIDFromVisual( visualInfo->visual ); + res = (Qt::HANDLE)( visualInfo->visual ); + + return res; +} + +#endif // WIN32 + +/*! + \class Qtx::CmdLineArgs + \brief Get access to the command line arguments in the C-like manner. + + This class translates command line arguments stored in QApplication in form of QStrlingList + to the char* array, in the same way as they specified to main() function. + + Constructor of class allocates required memory to store arguments; destructor deallocates it, + This allows using this class as a local variable: + + \code + Qtx::CmdLineArgs args; + some_function(args.argc(), args.argv()); // function that has main()-like syntax. + \endcode +*/ + +/*! + \brief Default constructor. +*/ +Qtx::CmdLineArgs::CmdLineArgs() +{ + QStringList args = QCoreApplication::arguments(); + myArgc = args.size(); + myArgv = new char*[myArgc]; + for ( int i = 0; i < myArgc; i++ ) { + QByteArray ba = args[i].toUtf8(); + myArgv[i] = qstrdup(ba.constData()); + } +} + +/*! + \brief Destructor. Deallocates the array with command line arguments +*/ +Qtx::CmdLineArgs::~CmdLineArgs() +{ + for ( int i = 0; i < myArgc; i++ ) + delete[] myArgv[i]; + delete[] myArgv; +} + +/*! + \brief Get number of command line arguments + \return number of arguments +*/ +int Qtx::CmdLineArgs::argc() const +{ + return myArgc; +} + +/*! + \brief Get command line arguments + \return command line arguments +*/ +char** Qtx::CmdLineArgs::argv() const +{ + return myArgv; +}